diff --git a/examples/meson.build b/examples/meson.build
index 56d300e66732c1c6773c58b449f216f427ad1246..83af1519d55213073b5bed7d42dd816e93050245 100644
--- a/examples/meson.build
+++ b/examples/meson.build
@@ -24,7 +24,7 @@
 executable(
   'steam-runtime-system-info',
   'system-info.c',
-  dependencies : [glib, libsteamrt_dep],
+  dependencies : [glib, libsteamrt_dep, json_glib],
   install : true,
 )
 
diff --git a/examples/system-info.c b/examples/system-info.c
index aca0ed52c50fbbb6b7a2bbfc2b6c2a3be5eab64e..2946d0f6f47950105d6b018d1c2e9aeb6719e930 100644
--- a/examples/system-info.c
+++ b/examples/system-info.c
@@ -27,30 +27,337 @@
  * Output basic information about the system on which the tool is run.
  * The output is a JSON object with the following keys:
  *
- * can-run:
- *   An object. The keys are strings representing multiarch tuples, as
- *   used in Debian and the freedesktop.org SDK runtime. The values are
- *   boolean: true if we can definitely run executables of this
- *   architecture, or false if we cannot prove that we can do so.
+ * can-write-uinput:
+ *   The values are boolean: true if we can write to `/dev/uninput`,
+ *   false if we are not able to do it.
+ *
+ * architectures:
+ *   An object. The keys are multiarch tuples like %SRT_ABI_I386,
+ *   as used in Debian and the freedesktop.org SDK runtime.
+ *   The values are objects with more details of the architecture:
+ *
+ *   can-run:
+ *     The values are boolean: true if we can definitely run
+ *     executables of this architecture, or false if we cannot prove
+ *     that we can do so.
+ *
+ *   library-issues-summary:
+ *     A string array listing all the libraries problems that has been found
+ *     in the running system. Possible values can be: "cannot-load",
+ *     "missing-symbols", "misversioned-symbols" and "internal-error".
+ *     If "can-run" for this architecture is false we skip the library check
+ *     and this "library-issues-summary" will not be printed at all.
+ *
+ *   library-details:
+ *     An object. The keys are library SONAMEs, such as `libjpeg.so.62`.
+ *     The values are objects with more details of the library:
+ *
+ *     path:
+ *       The value is a string representing the full path about where the
+ *       @library has been found. The value is `null` if the library is
+ *       not available in the system.
+ *
+ *     issues:
+ *       A string array listing all the @library problems that has been
+ *       found in the running system. For possible values check
+ *       `library-issues-summary`. This object will be available only if
+ *       there are some issues.
+ *
+ *     missing-symbols:
+ *       A string array listing all the symbols that were expected to be
+ *       provided by @library but were not found. This object will be
+ *       available only if there are sone missing symbols.
+ *
+ *     misversioned-symbols:
+ *       A string array listing all the symbols that were expected to be
+ *       provided by @library but were available with a different version.
+ *       This object will be available only if there are some misversioned
+ *       symbols.
  */
 
 #include <steam-runtime-tools/steam-runtime-tools.h>
 
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
 #include <glib.h>
 
+#include <json-glib/json-glib.h>
+
+enum
+{
+  OPTION_HELP = 1,
+  OPTION_EXPECTATION,
+  OPTION_VERBOSE,
+};
+
+struct option long_options[] =
+{
+    { "expectations", required_argument, NULL, OPTION_EXPECTATION },
+    { "verbose", no_argument, NULL, OPTION_VERBOSE },
+    { "help", no_argument, NULL, OPTION_HELP },
+    { NULL, 0, NULL, 0 }
+};
+
+static void usage (int code) __attribute__((__noreturn__));
+
+/*
+ * Print usage information and exit with status @code.
+ */
+static void
+usage (int code)
+{
+  FILE *fp;
+
+  if (code == 0)
+    fp = stdout;
+  else
+    fp = stderr;
+
+  fprintf (fp, "Usage: %s [OPTIONS]\n",
+           program_invocation_short_name);
+  exit (code);
+}
+
+static FILE *
+divert_stdout_to_stderr (GError **error)
+{
+  int original_stdout_fd;
+  FILE *original_stdout;
+
+  /* Duplicate the original stdout so that we still have a way to write
+   * machine-readable output. */
+  original_stdout_fd = dup (STDOUT_FILENO);
+
+  if (original_stdout_fd < 0)
+    {
+      int saved_errno = errno;
+
+      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
+                   "Unable to duplicate fd %d: %s",
+                   STDOUT_FILENO, g_strerror (saved_errno));
+      return NULL;
+    }
+
+  /* If something like g_debug writes to stdout, make it come out of
+   * our original stderr. */
+  if (dup2 (STDERR_FILENO, STDOUT_FILENO) != STDOUT_FILENO)
+    {
+      int saved_errno = errno;
+
+      close (original_stdout_fd);
+      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
+                   "Unable to make fd %d a copy of fd %d: %s",
+                   STDOUT_FILENO, STDERR_FILENO, g_strerror (saved_errno));
+      return NULL;
+    }
+
+  /* original_stdout takes ownership of original_stdout_fd on success */
+  original_stdout = fdopen (original_stdout_fd, "w");
+
+  if (original_stdout == NULL)
+    {
+      int saved_errno = errno;
+
+      close (original_stdout_fd);
+      g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno),
+                   "Unable to create a stdio wrapper for fd %d: %s",
+                   original_stdout_fd, g_strerror (saved_errno));
+      return NULL;
+    }
+
+  return original_stdout;
+}
+
+static void
+jsonify_library_issues (JsonBuilder *builder,
+                        SrtLibraryIssues issues)
+{
+  if ((issues & SRT_LIBRARY_ISSUES_CANNOT_LOAD) != 0)
+    json_builder_add_string_value (builder, "cannot-load");
+
+  if ((issues & SRT_LIBRARY_ISSUES_MISSING_SYMBOLS) != 0)
+    json_builder_add_string_value (builder, "missing-symbols");
+
+  if ((issues & SRT_LIBRARY_ISSUES_MISVERSIONED_SYMBOLS) != 0)
+    json_builder_add_string_value (builder, "misversioned-symbols");
+
+  if ((issues & SRT_LIBRARY_ISSUES_INTERNAL_ERROR) != 0)
+    json_builder_add_string_value (builder, "internal-error");
+}
+
+static void
+print_libraries_details (JsonBuilder *builder,
+                         GList *libraries,
+                         gboolean verbose)
+{
+  json_builder_set_member_name (builder, "library-details");
+  json_builder_begin_object (builder);
+  for (GList *l = libraries; l != NULL; l = l->next)
+    {
+      if (verbose || srt_library_get_issues (l->data) != SRT_LIBRARY_ISSUES_NONE)
+        {
+          const char * const *missing_symbols;
+          const char * const *misversioned_symbols;
+          json_builder_set_member_name (builder, srt_library_get_soname (l->data));
+          json_builder_begin_object (builder);
+          json_builder_set_member_name (builder, "path");
+          json_builder_add_string_value (builder, srt_library_get_absolute_path (l->data));
+
+          if (srt_library_get_issues (l->data) != SRT_LIBRARY_ISSUES_NONE)
+            {
+              json_builder_set_member_name (builder, "issues");
+              json_builder_begin_array (builder);
+              jsonify_library_issues (builder, srt_library_get_issues (l->data));
+              json_builder_end_array (builder);
+            }
+
+          missing_symbols = srt_library_get_missing_symbols (l->data);
+          if (missing_symbols[0] != NULL)
+            {
+              json_builder_set_member_name (builder, "missing-symbols");
+              json_builder_begin_array (builder);
+              for (gsize i = 0; missing_symbols[i] != NULL; i++)
+                json_builder_add_string_value (builder, missing_symbols[i]);
+              json_builder_end_array (builder);
+            }
+
+          misversioned_symbols = srt_library_get_misversioned_symbols (l->data);
+          if (misversioned_symbols[0] != NULL)
+            {
+              json_builder_set_member_name (builder, "misversioned-symbols");
+              json_builder_begin_array (builder);
+              for (gsize i = 0; misversioned_symbols[i] != NULL; i++)
+                json_builder_add_string_value (builder, misversioned_symbols[i]);
+              json_builder_end_array (builder);
+            }
+
+          json_builder_end_object (builder);
+        }
+    }
+  json_builder_end_object (builder);
+
+  return;
+}
+
 int
 main (int argc,
       char **argv)
 {
-  g_print ("{\n");
+  FILE *original_stdout = NULL;
+  GError *error = NULL;
+  SrtSystemInfo *info;
+  SrtLibraryIssues issues = SRT_LIBRARY_ISSUES_NONE;
+  char *expectations = NULL;
+  gboolean verbose = FALSE;
+  JsonBuilder *builder;
+  JsonGenerator *generator;
+  gboolean can_run = FALSE;
+  gchar *json_output;
+  GList *libraries = NULL;
+  GList *detailed_errors = NULL;
+  int opt;
+  static const char * const multiarch_tuples[] = { SRT_ABI_I386, SRT_ABI_X86_64 };
+
+  while ((opt = getopt_long (argc, argv, "", long_options, NULL)) != -1)
+    {
+      switch (opt)
+        {
+          case OPTION_EXPECTATION:
+            expectations = optarg;
+            break;
+
+          case OPTION_VERBOSE:
+            verbose = TRUE;
+            break;
+
+          case OPTION_HELP:
+            usage (0);
+            break;
+
+          case '?':
+          default:
+            usage (1);
+            break;  /* not reached */
+        }
+    }
+
+  if (optind != argc)
+    usage (1);
+
+  /* stdout is reserved for machine-readable output, so avoid having
+   * things like g_debug() pollute it. */
+  original_stdout = divert_stdout_to_stderr (&error);
+
+  if (original_stdout == NULL)
+    {
+      g_warning ("%s", error->message);
+      g_clear_error (&error);
+      return 1;
+    }
+
+  info = srt_system_info_new (expectations);
+
+  builder = json_builder_new ();
+  json_builder_begin_object (builder);
+
+  json_builder_set_member_name (builder, "can-write-uinput");
+  json_builder_add_boolean_value (builder, srt_system_info_can_write_to_uinput (info));
+
+  json_builder_set_member_name (builder, "architectures");
+  json_builder_begin_object (builder);
+
+  for (gsize i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+    {
+      json_builder_set_member_name (builder, multiarch_tuples[i]);
+      json_builder_begin_object (builder);
+      json_builder_set_member_name (builder, "can-run");
+      can_run = srt_system_info_can_run (info, multiarch_tuples[i]);
+      json_builder_add_boolean_value (builder, can_run);
+
+      if (can_run && expectations != NULL)
+        {
+          json_builder_set_member_name (builder, "library-issues-summary");
+          json_builder_begin_array (builder);
+          issues = srt_system_info_check_libraries (info,
+                                                    multiarch_tuples[i],
+                                                    &libraries);
+          jsonify_library_issues (builder, issues);
+          json_builder_end_array (builder);
+        }
+
+      if (libraries != NULL && (issues != SRT_LIBRARY_ISSUES_NONE || verbose))
+          print_libraries_details (builder, libraries, verbose);
+
+      json_builder_end_object (builder);
+      g_list_free_full (detailed_errors, g_free);
+      g_list_free_full (libraries, g_object_unref);
+    }
+
+  json_builder_end_object (builder);
+  json_builder_end_object (builder);
+
+  JsonNode *root = json_builder_get_root (builder);
+  generator = json_generator_new ();
+  json_generator_set_root (generator, root);
+  json_generator_set_pretty (generator, TRUE);
+  json_output = json_generator_to_data (generator, NULL);
+
+  if (fputs (json_output, original_stdout) < 0)
+    g_warning ("Unable to write output: %s", g_strerror (errno));
+
+  if (fputs ("\n", original_stdout) < 0)
+    g_warning ("Unable to write final newline: %s", g_strerror (errno));
+
+  if (fclose (original_stdout) != 0)
+    g_warning ("Unable to close stdout: %s", g_strerror (errno));
 
-  g_print ("  \"can-run\": {\n");
-  g_print ("    \"%s\": %s,\n", SRT_ABI_I386,
-           srt_architecture_can_run_i386 () ? "true" : "false");
-  g_print ("    \"%s\": %s\n", SRT_ABI_X86_64,
-           srt_architecture_can_run_x86_64 () ? "true" : "false");
-  g_print ("  }\n");
+  g_free (json_output);
+  g_object_unref (generator);
+  json_node_free (root);
+  g_object_unref (builder);
+  g_object_unref (info);
 
-  g_print ("}\n");
   return 0;
 }
diff --git a/helpers/check-gl.c b/helpers/check-gl.c
index 3d81ad9d472fbfdfb600a83418a8bfd7f84df8af..b2ac307f980ee27d2ff02988bd711aeec71b8a78 100644
--- a/helpers/check-gl.c
+++ b/helpers/check-gl.c
@@ -69,9 +69,6 @@
  * [3] http://git.compiz.org/fusion/misc/compiz-manager/tree/compiz-manager
  */
 
-/* for strcasestr */
-#define _GNU_SOURCE
-
 #include <ctype.h>
 #include <locale.h>
 #include <stdio.h>
diff --git a/helpers/check-gles.c b/helpers/check-gles.c
index e8571470d927ebd15fed41ffd961094bb12f3613..39192c8d2a025fddbad1a54c83e88c410ed0178c 100644
--- a/helpers/check-gles.c
+++ b/helpers/check-gles.c
@@ -23,9 +23,6 @@
  *   Cosimo Cecchi <cosimo@endlessm.com>
  */
 
-/* for strcasestr */
-#define _GNU_SOURCE
-
 #include <locale.h>
 #include <stdlib.h>
 #include <string.h>
diff --git a/helpers/meson.build b/helpers/meson.build
index dc993675d01675b187a717794d59e6322a2dd167..1e94285861befeafde76801ca04481cfdbdde85e 100644
--- a/helpers/meson.build
+++ b/helpers/meson.build
@@ -35,9 +35,6 @@ executable(
   multiarch + '-inspect-library',
   'inspect-library.c',
   dependencies : [libdl],
-  c_args : [
-      '-D_GNU_SOURCE',
-    ],
   install : true,
   install_dir : join_paths(
     get_option('libexecdir'),
diff --git a/meson.build b/meson.build
index dc8c9e606d1236bf0eb0e4b01d9f050ab318ab66..1a2c000cd0883282d5dc5577013ad5f411b41de4 100644
--- a/meson.build
+++ b/meson.build
@@ -91,6 +91,8 @@ endforeach
 
 add_project_arguments(['-std=c99'], language : 'c')
 
+add_project_arguments(['-D_GNU_SOURCE'], language : 'c')
+
 glib = dependency(
   'glib-2.0',
   version : '>= 2.32',
diff --git a/steam-runtime-tools/meson.build b/steam-runtime-tools/meson.build
index 1211aebc96a0134578611dec3caa341dfba1d525..5d3d0a0dccc5873c31f09f7652067e18b79537e6 100644
--- a/steam-runtime-tools/meson.build
+++ b/steam-runtime-tools/meson.build
@@ -56,7 +56,6 @@ libsteamrt = library(
   c_args : [
     '-DG_LOG_DOMAIN="' + meson.project_name() + '"',
     '-D_SRT_COMPILATION',
-    '-D_GNU_SOURCE',
     '-D_SRT_SONAME="libsteam-runtime-tools-' + api_major + '.so.' + abi_major + '"',
     '-D_SRT_MULTIARCH="' + multiarch + '"',
     '-D_SRT_API_MAJOR="' + api_major + '"',
diff --git a/tests/examples-system-info.c b/tests/examples-system-info.c
new file mode 100644
index 0000000000000000000000000000000000000000..2a330d5ddd241b05c00e900b0c3a99380e414a79
--- /dev/null
+++ b/tests/examples-system-info.c
@@ -0,0 +1,457 @@
+/*
+ * 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 <steam-runtime-tools/glib-compat.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <json-glib/json-glib.h>
+
+#include "test-utils.h"
+
+static const char *argv0;
+static const char * const multiarch_tuples[] = { SRT_ABI_I386, SRT_ABI_X86_64 };
+
+typedef struct
+{
+  gchar *srcdir;
+  gchar *builddir;
+} Fixture;
+
+typedef struct
+{
+  int unused;
+} Config;
+
+static void
+setup (Fixture *f,
+       gconstpointer context)
+{
+  G_GNUC_UNUSED const Config *config = context;
+
+  f->srcdir = g_strdup (g_getenv ("G_TEST_SRCDIR"));
+  f->builddir = g_strdup (g_getenv ("G_TEST_BUILDDIR"));
+
+  if (f->srcdir == NULL)
+    f->srcdir = g_path_get_dirname (argv0);
+
+  if (f->builddir == NULL)
+    f->builddir = g_path_get_dirname (argv0);
+}
+
+static void
+teardown (Fixture *f,
+          gconstpointer context)
+{
+  G_GNUC_UNUSED const Config *config = context;
+
+  g_free (f->srcdir);
+  g_free (f->builddir);
+}
+
+/*
+ * Test if the expected libraries are available in the
+ * running system.
+ */
+static void
+libraries_presence (Fixture *f,
+                    gconstpointer context)
+{
+  int exit_status = -1;
+  JsonParser *parser = NULL;
+  JsonNode *node = NULL;
+  JsonObject *json;
+  JsonObject *json_arch;
+  GError *error = NULL;
+  gchar *output = NULL;
+  gchar *examples = NULL;
+  SrtSystemInfo *info = srt_system_info_new (NULL);
+  gchar *expectations_in = g_build_filename (f->srcdir, "expectations", NULL);
+  const gchar *argv[] =
+    {
+      "steam-runtime-system-info", "--expectations", expectations_in, NULL
+    };
+
+  g_assert_true (g_spawn_sync (NULL,    /* working directory */
+                               (gchar **) argv,
+                               NULL,    /* envp */
+                               G_SPAWN_SEARCH_PATH,
+                               NULL,    /* child setup */
+                               NULL,    /* user data */
+                               &output, /* stdout */
+                               NULL,    /* stderr */
+                               &exit_status,
+                               &error));
+  g_assert_cmpint (exit_status, ==, 0);
+  g_assert_null (error);
+  g_assert_nonnull (output);
+
+  /* We can't use `json_from_string()` directly because we are targeting an
+   * older json-glib version */
+  parser = json_parser_new ();
+  g_assert_true (json_parser_load_from_data (parser, output, -1, NULL));
+  node = json_parser_get_root (parser);
+  json = json_node_get_object (node);
+
+  g_assert_true (json_object_has_member (json, "can-write-uinput"));
+
+  g_assert_true (json_object_has_member (json, "architectures"));
+  json = json_object_get_object_member (json, "architectures");
+
+  for (gsize i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+    {
+      g_assert_true (json_object_has_member (json, multiarch_tuples[i]));
+      json_arch = json_object_get_object_member (json, multiarch_tuples[i]);
+      g_assert_true (json_object_has_member (json_arch, "can-run"));
+      g_assert_cmpint (json_object_get_boolean_member (json_arch, "can-run"),
+                      ==, srt_system_info_can_run (info, multiarch_tuples[i]));
+      g_assert_cmpint (json_object_has_member (json_arch, "library-issues-summary"),
+                      ==, srt_system_info_can_run (info, multiarch_tuples[i]));
+      if (json_object_has_member (json_arch, "library-issues-summary"))
+        {
+          JsonArray *array;
+          array = json_object_get_array_member (json_arch, "library-issues-summary");
+          g_assert_cmpint (json_array_get_length (array), ==, 0);
+        }
+    }
+  
+  g_object_unref (parser);
+  g_object_unref (info);
+  g_free (examples);
+  g_free (expectations_in);
+  g_free (output);
+  g_clear_error (&error);
+}
+
+static void
+check_libraries_missing (JsonObject *json_arch)
+{
+  JsonArray *array;
+  JsonObject *json_details;
+  JsonObject *json_lib;
+  if (json_object_has_member (json_arch, "library-issues-summary"))
+    {
+      array = json_object_get_array_member (json_arch, "library-issues-summary");
+      g_assert_cmpint (json_array_get_length (array), ==, 3);
+      g_assert_cmpstr (json_array_get_string_element (array, 0), ==, "cannot-load");
+      g_assert_cmpstr (json_array_get_string_element (array, 1), ==, "missing-symbols");
+      g_assert_cmpstr (json_array_get_string_element (array, 2), ==, "misversioned-symbols");
+
+      g_assert_true (json_object_has_member (json_arch, "library-details"));
+      json_details = json_object_get_object_member (json_arch, "library-details");
+
+      g_assert_true (json_object_has_member (json_details, "libgio-MISSING-2.0.so.0"));
+      json_lib = json_object_get_object_member (json_details, "libgio-MISSING-2.0.so.0");
+      g_assert_true (json_object_has_member (json_lib, "path"));
+      g_assert_cmpstr (json_object_get_string_member (json_lib, "path"), ==, NULL);
+      g_assert_true (json_object_has_member (json_lib, "issues"));
+      array = json_object_get_array_member (json_lib, "issues");
+      g_assert_cmpint (json_array_get_length (array), ==, 1);
+      g_assert_cmpstr (json_array_get_string_element (array, 0), ==, "cannot-load");
+      g_assert_false (json_object_has_member (json_lib, "missing-symbols"));
+      g_assert_false (json_object_has_member (json_lib, "misversioned-symbols"));
+
+      g_assert_true (json_object_has_member (json_details, "libz.so.1"));
+      json_lib = json_object_get_object_member (json_details, "libz.so.1");
+      g_assert_true (json_object_has_member (json_lib, "path"));
+      g_assert_cmpstr (json_object_get_string_member (json_lib, "path"), !=, NULL);
+      g_assert_true (json_object_has_member (json_lib, "issues"));
+      array = json_object_get_array_member (json_lib, "issues");
+      g_assert_cmpint (json_array_get_length (array), ==, 2);
+      g_assert_cmpstr (json_array_get_string_element (array, 0), ==, "missing-symbols");
+      g_assert_cmpstr (json_array_get_string_element (array, 1), ==, "misversioned-symbols");
+      array = json_object_get_array_member (json_lib, "missing-symbols");
+      g_assert_cmpint (json_array_get_length (array), ==, 1);
+      g_assert_cmpstr (json_array_get_string_element (array, 0), ==, "missing@NotAvailable");
+      array = json_object_get_array_member (json_lib, "misversioned-symbols");
+      g_assert_cmpint (json_array_get_length (array), ==, 1);
+      g_assert_cmpstr (json_array_get_string_element (array, 0), ==, "crc32@WRONG_VERSION");
+    }
+}
+
+/*
+ * Test libraries that are either not available or with missing and
+ * misversioned symbols.
+ */
+static void
+libraries_missing (Fixture *f,
+                   gconstpointer context)
+{
+  int exit_status = -1;
+  JsonParser *parser = NULL;
+  JsonNode *node = NULL;
+  JsonObject *json;
+  JsonObject *json_arch;
+  GError *error = NULL;
+  gchar *output = NULL;
+  gchar *examples = NULL;
+  SrtSystemInfo *info = srt_system_info_new (NULL);
+  gchar *expectations_in = g_build_filename (f->srcdir, "expectations_with_missings", NULL);
+  const gchar *argv[] =
+    {
+      "steam-runtime-system-info", "--expectations", expectations_in, NULL
+    };
+
+  g_assert_true (g_spawn_sync (NULL,    /* working directory */
+                               (gchar **) argv,
+                               NULL,    /* envp */
+                               G_SPAWN_SEARCH_PATH,
+                               NULL,    /* child setup */
+                               NULL,    /* user data */
+                               &output, /* stdout */
+                               NULL,    /* stderr */
+                               &exit_status,
+                               &error));
+  g_assert_cmpint (exit_status, ==, 0);
+  g_assert_null (error);
+  g_assert_nonnull (output);
+
+  /* We can't use `json_from_string()` directly because we are targeting an
+   * older json-glib version */
+  parser = json_parser_new ();
+  g_assert_true (json_parser_load_from_data (parser, output, -1, NULL));
+  node = json_parser_get_root (parser);
+  json = json_node_get_object (node);
+
+  g_assert_true (json_object_has_member (json, "can-write-uinput"));
+  
+  g_assert_true (json_object_has_member (json, "architectures"));
+  json = json_object_get_object_member (json, "architectures");
+
+  for (gsize i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+    {
+      g_assert_true (json_object_has_member (json, multiarch_tuples[i]));
+      json_arch = json_object_get_object_member (json, multiarch_tuples[i]);
+      g_assert_true (json_object_has_member (json_arch, "can-run"));
+      g_assert_cmpint (json_object_get_boolean_member (json_arch, "can-run"),
+                      ==, srt_system_info_can_run (info, multiarch_tuples[i]));
+      g_assert_cmpint (json_object_has_member (json_arch, "library-issues-summary"),
+                      ==, srt_system_info_can_run (info, multiarch_tuples[i]));
+
+      check_libraries_missing (json_arch);
+    }
+  
+  g_object_unref (parser);
+  g_object_unref (info);
+  g_free (examples);
+  g_free (expectations_in);
+  g_free (output);
+  g_clear_error (&error);
+}
+
+static void
+check_library_no_errors (JsonObject *json_details,
+                         const char *library_soname)
+{
+  JsonObject *json_lib;
+
+  g_assert_true (json_object_has_member (json_details, library_soname));
+  json_lib = json_object_get_object_member (json_details, library_soname);
+  g_assert_true (json_object_has_member (json_lib, "path"));
+  g_assert_cmpstr (json_object_get_string_member (json_lib, "path"), !=, NULL);
+  g_assert_false (json_object_has_member (json_lib, "issues"));
+  g_assert_false (json_object_has_member (json_lib, "missing-symbols"));
+  g_assert_false (json_object_has_member (json_lib, "misversioned-symbols"));
+}
+
+static void
+check_libraries_verbose (JsonObject *json_arch)
+{
+  JsonArray *array;
+  JsonObject *json_details;
+  if (json_object_has_member (json_arch, "library-issues-summary"))
+    {
+      array = json_object_get_array_member (json_arch, "library-issues-summary");
+      g_assert_cmpint (json_array_get_length (array), ==, 0);
+
+      g_assert_true (json_object_has_member (json_arch, "library-details"));
+      json_details = json_object_get_object_member (json_arch, "library-details");
+
+      check_library_no_errors (json_details, "libgio-2.0.so.0");
+
+      check_library_no_errors (json_details, "libglib-2.0.so.0");
+
+      check_library_no_errors (json_details, "libz.so.1");
+    }
+}
+
+/*
+ * Test the presence of libraries with the verbose option
+ */
+static void
+libraries_presence_verbose (Fixture *f,
+                            gconstpointer context)
+{
+  int exit_status = -1;
+  JsonParser *parser = NULL;
+  JsonNode *node = NULL;
+  JsonObject *json;
+  JsonObject *json_arch;
+  GError *error = NULL;
+  gchar *output = NULL;
+  gchar *examples = NULL;
+  SrtSystemInfo *info = srt_system_info_new (NULL);
+  gchar *expectations_in = g_build_filename (f->srcdir, "expectations", NULL);
+  const gchar *argv[] =
+    {
+      "steam-runtime-system-info", "--expectations", expectations_in, "--verbose", NULL
+    };
+
+  g_assert_true (g_spawn_sync (NULL,    /* working directory */
+                               (gchar **) argv,
+                               NULL,    /* envp */
+                               G_SPAWN_SEARCH_PATH,
+                               NULL,    /* child setup */
+                               NULL,    /* user data */
+                               &output, /* stdout */
+                               NULL,    /* stderr */
+                               &exit_status,
+                               &error));
+  g_assert_cmpint (exit_status, ==, 0);
+  g_assert_null (error);
+  g_assert_nonnull (output);
+
+  /* We can't use `json_from_string()` directly because we are targeting an
+   * older json-glib version */
+  parser = json_parser_new ();
+  g_assert_true (json_parser_load_from_data (parser, output, -1, NULL));
+  node = json_parser_get_root (parser);
+  json = json_node_get_object (node);
+
+  g_assert_true (json_object_has_member (json, "can-write-uinput"));
+  
+  g_assert_true (json_object_has_member (json, "architectures"));
+  json = json_object_get_object_member (json, "architectures");
+
+  for (gsize i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+    {
+      g_assert_true (json_object_has_member (json, multiarch_tuples[i]));
+      json_arch = json_object_get_object_member (json, multiarch_tuples[i]);
+      g_assert_true (json_object_has_member (json_arch, "can-run"));
+      g_assert_cmpint (json_object_get_boolean_member (json_arch, "can-run"),
+                      ==, srt_system_info_can_run (info, multiarch_tuples[i]));
+      g_assert_cmpint (json_object_has_member (json_arch, "library-issues-summary"),
+                      ==, srt_system_info_can_run (info, multiarch_tuples[i]));
+
+      check_libraries_verbose (json_arch);
+    }
+  
+  g_object_unref (parser);
+  g_object_unref (info);
+  g_free (examples);
+  g_free (expectations_in);
+  g_free (output);
+  g_clear_error (&error);
+}
+
+/*
+ * Test `steam-runtime-system-info` with no additional arguments
+ */
+static void
+no_arguments (Fixture *f,
+              gconstpointer context)
+{
+  int exit_status = -1;
+  JsonParser *parser = NULL;
+  JsonNode *node = NULL;
+  JsonObject *json;
+  JsonObject *json_arch;
+  GError *error = NULL;
+  gchar *output = NULL;
+  gchar *examples = NULL;
+  SrtSystemInfo *info = srt_system_info_new (NULL);
+  gchar *expectations_in = g_build_filename (f->srcdir, "expectations", NULL);
+  const gchar *argv[] = { "steam-runtime-system-info", NULL };
+
+  g_assert_true (g_spawn_sync (NULL,    /* working directory */
+                               (gchar **) argv,
+                               NULL,    /* envp */
+                               G_SPAWN_SEARCH_PATH,
+                               NULL,    /* child setup */
+                               NULL,    /* user data */
+                               &output, /* stdout */
+                               NULL,    /* stderr */
+                               &exit_status,
+                               &error));
+  g_assert_cmpint (exit_status, ==, 0);
+  g_assert_null (error);
+  g_assert_nonnull (output);
+
+  /* We can't use `json_from_string()` directly because we are targeting an
+   * older json-glib version */
+  parser = json_parser_new ();
+  g_assert_true (json_parser_load_from_data (parser, output, -1, NULL));
+  node = json_parser_get_root (parser);
+  json = json_node_get_object (node);
+
+  g_assert_true (json_object_has_member (json, "can-write-uinput"));
+  
+  g_assert_true (json_object_has_member (json, "architectures"));
+  json = json_object_get_object_member (json, "architectures");
+
+  for (gsize i = 0; i < G_N_ELEMENTS (multiarch_tuples); i++)
+    {
+      g_assert_true (json_object_has_member (json, multiarch_tuples[i]));
+      json_arch = json_object_get_object_member (json, multiarch_tuples[i]);
+      g_assert_true (json_object_has_member (json_arch, "can-run"));
+      g_assert_cmpint (json_object_get_boolean_member (json_arch, "can-run"),
+                      ==, srt_system_info_can_run (info, multiarch_tuples[i]));
+    }
+  
+  g_object_unref (parser);
+  g_object_unref (info);
+  g_free (examples);
+  g_free (expectations_in);
+  g_free (output);
+  g_clear_error (&error);
+}
+
+int
+main (int argc,
+      char **argv)
+{
+  argv0 = argv[0];
+
+  g_test_init (&argc, &argv, NULL);
+  g_test_add ("/system-info/libraries_presence", Fixture, NULL,
+              setup, libraries_presence, teardown);
+  g_test_add ("/system-info/libraries_missing", Fixture, NULL,
+              setup, libraries_missing, teardown);
+  g_test_add ("/system-info/libraries_presence_verbose", Fixture, NULL,
+              setup, libraries_presence_verbose, teardown);
+  g_test_add ("/system-info/no_arguments", Fixture, NULL,
+              setup, no_arguments, teardown);
+
+  return g_test_run ();
+}
diff --git a/tests/meson.build b/tests/meson.build
index 5ff5cf52ef99b9a57f71ecfb243e17c4c1c26eec..4a9d6e0d3dc28a3aa969e49af6a1c820aeef62fd 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -25,9 +25,11 @@ test_env = environment()
 test_env.set('G_TEST_SRCDIR', meson.current_source_dir())
 test_env.set('G_TEST_BUILDDIR', meson.current_build_dir())
 test_env.set('SRT_HELPERS_PATH', join_paths(meson.current_build_dir(), '..', 'helpers'))
+test_env.prepend('PATH', join_paths(meson.current_build_dir(), '..', 'examples'))
 
 tests = [
   'architecture',
+  'examples-system-info',
   'library',
   'system-info',
 ]
@@ -53,7 +55,7 @@ foreach test_name : tests
     c_args : [
       '-D_SRT_MULTIARCH="' + multiarch + '"',
     ],
-    dependencies : [glib, gobject, libsteamrt_dep],
+    dependencies : [glib, gobject, libsteamrt_dep, json_glib],
     install : get_option('installed_tests'),
     install_dir : tests_dir,
   )