diff --git a/steam-runtime-tools/graphics-internal.h b/steam-runtime-tools/graphics-internal.h
index d8bcb9b64a79fa1532b7e21e6794e6d210f29bd4..174a0998b1f8706460f3dc552b8124fdcafe5822 100644
--- a/steam-runtime-tools/graphics-internal.h
+++ b/steam-runtime-tools/graphics-internal.h
@@ -26,7 +26,7 @@
 
 #pragma once
 
-#include "steam-runtime-tools/graphics.h"
+#include "steam-runtime-tools/steam-runtime-tools.h"
 
 /*
  * _srt_graphics_new:
@@ -68,5 +68,13 @@ _srt_graphics_new (const char *multiarch_tuple,
                        "version-string", version_string,
                        NULL);
 }
+
+static inline int _srt_graphics_hash_key(SrtWindowSystem window_system, SrtRenderingInterface rendering_interface)
+{
+  /* This allows us to have up to 100 unique renderers, we won't need nearly that
+     many, but setting to 100 just to allow room to grow */
+  return (int)window_system * 100 + (int)rendering_interface;
+}
+
 #endif
 
diff --git a/steam-runtime-tools/graphics-test-defines.h b/steam-runtime-tools/graphics-test-defines.h
new file mode 100644
index 0000000000000000000000000000000000000000..708deb66619f1ed2299b9a976c57535664155980
--- /dev/null
+++ b/steam-runtime-tools/graphics-test-defines.h
@@ -0,0 +1,34 @@
+/*< internal_header >*/
+/*
+ * Copyright © 2019 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+
+// Test strings for use in mock and graphics test
+#define SRT_TEST_GOOD_GRAPHICS_RENDERER "Mesa DRI Intel(R) Haswell Desktop "
+#define SRT_TEST_SOFTWARE_GRAPHICS_RENDERER "llvmpipe (LLVM 8.0, 256 bits)"
+#define SRT_TEST_GOOD_GRAPHICS_VERSION "3.0 Mesa 19.1.3"
+#define SRT_TEST_SOFTWARE_GRAPHICS_VERSION "3.1 Mesa 19.1.3"
+
diff --git a/steam-runtime-tools/graphics.c b/steam-runtime-tools/graphics.c
index 891d9f680ca8a43d3be4f6fed17ca0742c1489a8..dee4c03732ab829de9927310b12b3e3c159a7abc 100644
--- a/steam-runtime-tools/graphics.c
+++ b/steam-runtime-tools/graphics.c
@@ -235,7 +235,19 @@ srt_graphics_class_init (SrtGraphicsClass *cls)
   g_object_class_install_properties (object_class, N_PROPERTIES, properties);
 }
 
-G_GNUC_INTERNAL SrtGraphicsIssues
+/**
+ * srt_check_graphics:
+ * @multiarch_tuple: A multiarch tuple to check e.g. i386-linux-gnu
+ * @winsys: The window system to check.
+ * @renderer: The graphics renderer to check.
+ * @details_out: The SrtGraphics object containing the details of the check.
+ *
+ * Return the problems found when checking the graphics stack given.
+ *
+ * Returns: A bitfield containing problems, or %SRT_GRAPHICS_ISSUES_NONE
+ *  if no problems were found
+ */
+SrtGraphicsIssues
 srt_check_graphics (const char *multiarch_tuple,
                      SrtWindowSystem window_system,
                      SrtRenderingInterface rendering_interface,
diff --git a/tests/graphics.c b/tests/graphics.c
new file mode 100644
index 0000000000000000000000000000000000000000..83e8f1dc2ea850dee55e1d4aabc999d55b65b0be
--- /dev/null
+++ b/tests/graphics.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright © 2019 Collabora Ltd.
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <steam-runtime-tools/steam-runtime-tools.h>
+
+#include <string.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include "steam-runtime-tools/graphics-internal.h"
+#include "steam-runtime-tools/graphics-test-defines.h"
+#include "test-utils.h"
+
+typedef struct
+{
+  int unused;
+} Fixture;
+
+typedef struct
+{
+  int unused;
+} Config;
+
+static void
+setup (Fixture *f,
+       gconstpointer context)
+{
+  G_GNUC_UNUSED const Config *config = context;
+}
+
+static void
+teardown (Fixture *f,
+          gconstpointer context)
+{
+  G_GNUC_UNUSED const Config *config = context;
+}
+
+/*
+ * Test basic functionality of the SrtGraphics object.
+ */
+static void
+test_object (Fixture *f,
+             gconstpointer context)
+{
+  SrtGraphics *graphics;
+  SrtGraphicsIssues issues;
+  gchar *tuple;
+  gchar *renderer;
+  gchar *version;
+
+  graphics = _srt_graphics_new("mock-good",
+                               SRT_WINDOW_SYSTEM_GLX,
+                               SRT_RENDERING_INTERFACE_GL,
+                               SRT_TEST_GOOD_GRAPHICS_RENDERER,
+                               SRT_TEST_GOOD_GRAPHICS_VERSION,
+                               SRT_LIBRARY_ISSUES_NONE);
+  g_assert_cmpint (srt_graphics_get_issues (graphics), ==,
+                   SRT_GRAPHICS_ISSUES_NONE);
+  g_assert_cmpstr (srt_graphics_get_multiarch_tuple (graphics), ==,
+                   "mock-good");
+  g_assert_cmpstr (srt_graphics_get_renderer_string (graphics), ==,
+                   SRT_TEST_GOOD_GRAPHICS_RENDERER);
+  g_assert_cmpstr (srt_graphics_get_version_string (graphics), ==,
+                   SRT_TEST_GOOD_GRAPHICS_VERSION);
+  g_object_get (graphics,
+                "multiarch-tuple", &tuple,
+                "issues", &issues,
+                "renderer-string", &renderer,
+                "version-string", &version,
+                NULL);
+  g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_NONE);
+  g_assert_cmpstr (tuple, ==, "mock-good");
+  g_assert_cmpstr (renderer, ==, SRT_TEST_GOOD_GRAPHICS_RENDERER);
+  g_assert_cmpstr (version, ==, SRT_TEST_GOOD_GRAPHICS_VERSION);
+  g_free (tuple);
+  g_object_unref (graphics);
+}
+
+/*
+ * Test a mock system with hardware graphics stack
+ */
+static void
+test_good_graphics (Fixture *f,
+                    gconstpointer context)
+{
+  SrtGraphics *graphics = NULL;
+  SrtGraphicsIssues issues;
+  gchar *tuple;
+  gchar *renderer;
+  gchar *version;
+
+  issues = srt_check_graphics ("mock-good",
+                               SRT_WINDOW_SYSTEM_GLX,
+                               SRT_RENDERING_INTERFACE_GL,
+                               &graphics);
+  g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_NONE);
+  g_assert_cmpstr (srt_graphics_get_renderer_string (graphics), ==,
+                   SRT_TEST_GOOD_GRAPHICS_RENDERER);
+  g_assert_cmpstr (srt_graphics_get_version_string (graphics), ==,
+                   SRT_TEST_GOOD_GRAPHICS_VERSION);
+  g_object_get (graphics,
+                "multiarch-tuple", &tuple,
+                "issues", &issues,
+                "renderer-string", &renderer,
+                "version-string", &version,
+                NULL);
+  g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_NONE);
+  g_assert_cmpstr (tuple, ==, "mock-good");
+  g_assert_cmpstr (renderer, ==, SRT_TEST_GOOD_GRAPHICS_RENDERER);
+  g_assert_cmpstr (version, ==, SRT_TEST_GOOD_GRAPHICS_VERSION);
+  g_free (tuple);
+  g_free (renderer);
+  g_free (version);
+
+  g_object_unref (graphics);
+}
+
+/*
+ * Test a mock system with no graphics stack
+ */
+static void
+test_bad_graphics (Fixture *f,
+                   gconstpointer context)
+{
+  SrtGraphics *graphics = NULL;
+  SrtGraphicsIssues issues;
+  gchar *tuple;
+  gchar *renderer;
+  gchar *version;
+
+  issues = srt_check_graphics ("mock-bad",
+                               SRT_WINDOW_SYSTEM_GLX,
+                               SRT_RENDERING_INTERFACE_GL,
+                               &graphics);
+  g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_CANNOT_LOAD);
+  g_assert_cmpstr (srt_graphics_get_renderer_string (graphics), ==,
+                   NULL);
+  g_assert_cmpstr (srt_graphics_get_version_string (graphics), ==,
+                   NULL);
+  g_object_get (graphics,
+                "multiarch-tuple", &tuple,
+                "issues", &issues,
+                "renderer-string", &renderer,
+                "version-string", &version,
+                NULL);
+  g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_CANNOT_LOAD);
+  g_assert_cmpstr (tuple, ==, "mock-bad");
+  g_assert_cmpstr (renderer, ==, NULL);
+  g_assert_cmpstr (version, ==, NULL);
+  g_free (tuple);
+  g_free (renderer);
+  g_free (version);
+
+  g_object_unref (graphics);
+}
+
+/*
+ * Test a mock system with software rendering
+ */
+static void
+test_software_rendering (Fixture *f,
+                         gconstpointer context)
+{
+  SrtGraphics *graphics = NULL;
+  SrtGraphicsIssues issues;
+  gchar *tuple;
+  gchar *renderer;
+  gchar *version;
+
+  issues = srt_check_graphics ("mock-software",
+                               SRT_WINDOW_SYSTEM_GLX,
+                               SRT_RENDERING_INTERFACE_GL,
+                               &graphics);
+  g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_SOFTWARE_RENDERING);
+  g_assert_cmpstr (srt_graphics_get_renderer_string (graphics), ==,
+                   SRT_TEST_SOFTWARE_GRAPHICS_RENDERER);
+  g_assert_cmpstr (srt_graphics_get_version_string (graphics), ==,
+                   SRT_TEST_SOFTWARE_GRAPHICS_VERSION);
+  g_object_get (graphics,
+                "multiarch-tuple", &tuple,
+                "issues", &issues,
+                "renderer-string", &renderer,
+                "version-string", &version,
+                NULL);
+  g_assert_cmpint (issues, ==, SRT_GRAPHICS_ISSUES_SOFTWARE_RENDERING);
+  g_assert_cmpstr (tuple, ==, "mock-software");
+  g_assert_cmpstr (renderer, ==, SRT_TEST_SOFTWARE_GRAPHICS_RENDERER);
+  g_assert_cmpstr (version, ==, SRT_TEST_SOFTWARE_GRAPHICS_VERSION);
+  g_free (tuple);
+  g_free (renderer);
+  g_free (version);
+
+  g_object_unref (graphics);
+}
+
+int
+main (int argc,
+      char **argv)
+{
+  g_test_init (&argc, &argv, NULL);
+  g_test_add ("/object", Fixture, NULL,
+              setup, test_object, teardown);
+  g_test_add ("/good", Fixture, NULL,
+              setup, test_good_graphics, teardown);
+  g_test_add ("/bad", Fixture, NULL,
+              setup, test_bad_graphics, teardown);
+  g_test_add ("/software", Fixture, NULL,
+              setup, test_software_rendering, teardown);
+
+  return g_test_run ();
+}
diff --git a/tests/meson.build b/tests/meson.build
index a8deb031cfd550ba271500b5618da4beaf2e0140..5ac44fb8bf7a34a5886027a79ccdc8246ce20d67 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -29,6 +29,7 @@ test_env.prepend('PATH', join_paths(meson.current_build_dir(), '..', 'bin'))
 
 tests = [
   'architecture',
+  'graphics',
   'library',
   'system-info',
   'system-info-cli',
diff --git a/tests/mock-good-wflinfo.c b/tests/mock-good-wflinfo.c
index 9be7fabd8920db4c393caecde5c96cb43b0daa93..eec8d5da2c1b2640bf2d5bbf74d9650686080b8c 100644
--- a/tests/mock-good-wflinfo.c
+++ b/tests/mock-good-wflinfo.c
@@ -25,7 +25,7 @@
 
 #include <stdio.h>
 
-void usage(void);
+#include "../steam-runtime-tools/graphics-test-defines.h"
 
 int
 main (int argc,
@@ -33,7 +33,11 @@ main (int argc,
 {
   // Give good output
   printf ("{\n\t\"waffle\": {\n\t\t\"platform\": \"glx\",\n\t\t\"api\": \"gl\"\n\t},\n\t\"OpenGL\": {\n\t\t\"vendor string\": \"Intel Open Source Technology Center\",\n"
-          "\t\t\"renderer string\": \"Mesa DRI Intel(R) Haswell Desktop \",\n\t\t\"version string\": \"3.0 Mesa 19.1.3\",\n\t\t\"shading language version string\": \"1.30\",\n"
+          "\t\t\"renderer string\": \""
+          SRT_TEST_GOOD_GRAPHICS_RENDERER
+          "\",\n\t\t\"version string\": \""
+          SRT_TEST_GOOD_GRAPHICS_VERSION
+          "\",\n\t\t\"shading language version string\": \"1.30\",\n"
           "\t\t\"extensions\": [\n"
           "\t\t]\n\t}\n}\n");
   return 0;
diff --git a/tests/mock-software-wflinfo.c b/tests/mock-software-wflinfo.c
index 7814889e0658dcfb7950fecefbbf7c04a24ffd8b..ed03f69a087a4e1b149f733de3e7199ee475d3d1 100644
--- a/tests/mock-software-wflinfo.c
+++ b/tests/mock-software-wflinfo.c
@@ -25,13 +25,19 @@
 
 #include <stdio.h>
 
+#include "../steam-runtime-tools/graphics-test-defines.h"
+
 int
 main (int argc,
       char **argv)
 {
   // Give software renderer output
   printf ("{\n\t\"waffle\": {\n\t\t\"platform\": \"glx\",\n\t\t\"api\": \"gl\"\n\t\t},\n\t\"OpenGL\": {\n\t\t\"vendor string\": \"VMware, Inc.\",\n"
-          "\t\t\"renderer string\": \"llvmpipe (LLVM 8.0, 256 bits)\",\n\t\t\"version string\": \"3.1 Mesa 19.1.3\",\n\t\t\"shading language version string\": \"1.40\",\n"
+          "\t\t\"renderer string\": \""
+          SRT_TEST_SOFTWARE_GRAPHICS_RENDERER
+          "\",\n\t\t\"version string\": \""
+          SRT_TEST_SOFTWARE_GRAPHICS_VERSION
+          "\",\n\t\t\"shading language version string\": \"1.40\",\n"
           "\t\t\"extensions\": [\n"
           "\t\t]\n\t}\n}\n");
   return 0;