From 04bde362b745aecf3ba118a202be0f35783b91cc Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Wed, 14 Aug 2019 17:41:29 +0100
Subject: [PATCH] Design for test: Add a way to redirect the helpers path

We can use this to connect up a mock implementation if necessary.

Signed-off-by: Simon McVittie <smcv@collabora.com>
---
 steam-runtime-tools/architecture-internal.h |  3 +-
 steam-runtime-tools/architecture.c          | 13 +++--
 steam-runtime-tools/library-internal.h      |  8 +++
 steam-runtime-tools/library.c               | 20 ++++++-
 steam-runtime-tools/system-info.c           | 62 +++++++++++++++------
 steam-runtime-tools/system-info.h           |  2 +
 tests/meson.build                           |  7 +++
 tests/system-info.c                         |  9 +++
 8 files changed, 98 insertions(+), 26 deletions(-)

diff --git a/steam-runtime-tools/architecture-internal.h b/steam-runtime-tools/architecture-internal.h
index 06825aad7..f0d28543e 100644
--- a/steam-runtime-tools/architecture-internal.h
+++ b/steam-runtime-tools/architecture-internal.h
@@ -28,4 +28,5 @@
 
 #include <glib.h>
 
-G_GNUC_INTERNAL gboolean _srt_architecture_can_run (const char *multiarch);
+G_GNUC_INTERNAL gboolean _srt_architecture_can_run (const char *helpers_path,
+                                                    const char *multiarch);
diff --git a/steam-runtime-tools/architecture.c b/steam-runtime-tools/architecture.c
index 44616d4d4..b92d49122 100644
--- a/steam-runtime-tools/architecture.c
+++ b/steam-runtime-tools/architecture.c
@@ -40,7 +40,8 @@
  */
 
 gboolean
-_srt_architecture_can_run (const char *multiarch)
+_srt_architecture_can_run (const char *helpers_path,
+                           const char *multiarch)
 {
   gchar *helper = NULL;
   const gchar *argv[] = { "true", NULL };
@@ -48,8 +49,10 @@ _srt_architecture_can_run (const char *multiarch)
   GError *error = NULL;
   gboolean ret = FALSE;
 
-  helper = g_strdup_printf ("%s/%s-true",
-                            _srt_get_helpers_path (), multiarch);
+  if (helpers_path == NULL)
+    helpers_path = _srt_get_helpers_path ();
+
+  helper = g_strdup_printf ("%s/%s-true", helpers_path, multiarch);
   argv[0] = helper;
   g_debug ("Testing architecture %s with %s", multiarch, helper);
 
@@ -108,7 +111,7 @@ out:
 gboolean
 srt_architecture_can_run_i386 (void)
 {
-  return _srt_architecture_can_run (SRT_ABI_I386);
+  return _srt_architecture_can_run (NULL, SRT_ABI_I386);
 }
 
 /**
@@ -126,5 +129,5 @@ srt_architecture_can_run_i386 (void)
 gboolean
 srt_architecture_can_run_x86_64 (void)
 {
-  return _srt_architecture_can_run (SRT_ABI_X86_64);
+  return _srt_architecture_can_run (NULL, SRT_ABI_X86_64);
 }
diff --git a/steam-runtime-tools/library-internal.h b/steam-runtime-tools/library-internal.h
index 670071d63..ecb947bf2 100644
--- a/steam-runtime-tools/library-internal.h
+++ b/steam-runtime-tools/library-internal.h
@@ -80,3 +80,11 @@ _srt_library_new (const char *multiarch_tuple,
                        NULL);
 }
 #endif
+
+G_GNUC_INTERNAL
+SrtLibraryIssues _srt_check_library_presence (const char *helpers_path,
+                                              const char *soname,
+                                              const char *multiarch,
+                                              const char *symbols_path,
+                                              SrtLibrarySymbolsFormat symbols_format,
+                                              SrtLibrary **more_details_out);
diff --git a/steam-runtime-tools/library.c b/steam-runtime-tools/library.c
index f22800bfc..8cf77cdfc 100644
--- a/steam-runtime-tools/library.c
+++ b/steam-runtime-tools/library.c
@@ -421,13 +421,25 @@ srt_library_get_misversioned_symbols (SrtLibrary *self)
  * Returns: A bitfield containing problems, or %SRT_LIBRARY_ISSUES_NONE
  *  if no problems were found.
  */
-
 SrtLibraryIssues
 srt_check_library_presence (const char *soname,
                             const char *multiarch,
                             const char *symbols_path,
                             SrtLibrarySymbolsFormat symbols_format,
                             SrtLibrary **more_details_out)
+{
+  return _srt_check_library_presence (NULL, soname, multiarch,
+                                      symbols_path, symbols_format,
+                                      more_details_out);
+}
+
+SrtLibraryIssues
+_srt_check_library_presence (const char *helpers_path,
+                             const char *soname,
+                             const char *multiarch,
+                             const char *symbols_path,
+                             SrtLibrarySymbolsFormat symbols_format,
+                             SrtLibrary **more_details_out)
 {
   gchar *helper = NULL;
   gchar *output = NULL;
@@ -473,8 +485,10 @@ srt_check_library_presence (const char *soname,
   if (symbols_path == NULL)
     issues |= SRT_LIBRARY_ISSUES_UNKNOWN_EXPECTATIONS;
 
-  helper = g_strdup_printf ("%s/%s-inspect-library",
-                            _srt_get_helpers_path (), multiarch);
+  if (helpers_path == NULL)
+    helpers_path = _srt_get_helpers_path ();
+
+  helper = g_strdup_printf ("%s/%s-inspect-library", helpers_path, multiarch);
   argv[0] = helper;
   g_debug ("Checking library %s integrity with %s", soname, helper);
 
diff --git a/steam-runtime-tools/system-info.c b/steam-runtime-tools/system-info.c
index 0b6179d1c..8507e0c11 100644
--- a/steam-runtime-tools/system-info.c
+++ b/steam-runtime-tools/system-info.c
@@ -28,6 +28,7 @@
 #include "steam-runtime-tools/architecture.h"
 #include "steam-runtime-tools/architecture-internal.h"
 #include "steam-runtime-tools/glib-compat.h"
+#include "steam-runtime-tools/library-internal.h"
 #include "steam-runtime-tools/utils-internal.h"
 
 #include <errno.h>
@@ -79,6 +80,8 @@ struct _SrtSystemInfo
   gchar *expectations;
   /* Fake environment variables, or %NULL to use the real environment */
   gchar **env;
+  /* Path to find helper executables, or %NULL to use the real helpers */
+  gchar *helpers_path;
   Tristate can_write_uinput;
   /* (element-type Abi) */
   GPtrArray *abis;
@@ -202,6 +205,7 @@ srt_system_info_finalize (GObject *object)
 
   g_clear_pointer (&self->abis, g_ptr_array_unref);
   g_free (self->expectations);
+  g_free (self->helpers_path);
   g_strfreev (self->env);
 
   G_OBJECT_CLASS (srt_system_info_parent_class)->finalize (object);
@@ -299,7 +303,7 @@ srt_system_info_can_run (SrtSystemInfo *self,
 
   if (abi->can_run == TRI_MAYBE)
     {
-      if (_srt_architecture_can_run (multiarch_tuple))
+      if (_srt_architecture_can_run (self->helpers_path, multiarch_tuple))
         abi->can_run = TRI_YES;
       else
         abi->can_run = TRI_NO;
@@ -485,15 +489,16 @@ srt_system_info_check_libraries (SrtSystemInfo *self,
           if (line[0] != '#' && line[0] != '*' && line[0] != '|' && line[0] != ' ')
             {
               /* This line introduces a new SONAME. We extract it and call
-                * `srt_check_library_presence` with the symbols file where we
+                * `_srt_check_library_presence` with the symbols file where we
                 * found it, as an argument. */
               SrtLibrary *library = NULL;
               char *soname = g_strdup (strsep (&pointer_into_line, " \t"));
-              abi->cached_combined_issues |= srt_check_library_presence (soname,
-                                                                         multiarch_tuple,
-                                                                         symbols_file,
-                                                                         SRT_LIBRARY_SYMBOLS_FORMAT_DEB_SYMBOLS,
-                                                                         &library);
+              abi->cached_combined_issues |= _srt_check_library_presence (self->helpers_path,
+                                                                          soname,
+                                                                          multiarch_tuple,
+                                                                          symbols_file,
+                                                                          SRT_LIBRARY_SYMBOLS_FORMAT_DEB_SYMBOLS,
+                                                                          &library);
               g_hash_table_insert (abi->cached_results, soname, library);
             }
         }
@@ -622,11 +627,12 @@ srt_system_info_check_library (SrtSystemInfo *self,
               char *soname_found = g_strdup (strsep (&pointer_into_line, " \t"));
               if (g_strcmp0 (soname_found, soname) == 0)
                 {
-                  issues = srt_check_library_presence (soname_found,
-                                                       multiarch_tuple,
-                                                       symbols_file,
-                                                       SRT_LIBRARY_SYMBOLS_FORMAT_DEB_SYMBOLS,
-                                                       &library);
+                  issues = _srt_check_library_presence (self->helpers_path,
+                                                        soname_found,
+                                                        multiarch_tuple,
+                                                        symbols_file,
+                                                        SRT_LIBRARY_SYMBOLS_FORMAT_DEB_SYMBOLS,
+                                                        &library);
                   g_hash_table_insert (abi->cached_results, soname_found, library);
                   abi->cached_combined_issues |= issues;
                   if (more_details_out != NULL)
@@ -645,11 +651,12 @@ srt_system_info_check_library (SrtSystemInfo *self,
 
   /* The SONAME's symbols file is not available.
    * We do instead a simple absence/presence check. */
-  issues = srt_check_library_presence (soname,
-                                       multiarch_tuple,
-                                       NULL,
-                                       SRT_LIBRARY_SYMBOLS_FORMAT_DEB_SYMBOLS,
-                                       &library);
+  issues = _srt_check_library_presence (self->helpers_path,
+                                        soname,
+                                        multiarch_tuple,
+                                        NULL,
+                                        SRT_LIBRARY_SYMBOLS_FORMAT_DEB_SYMBOLS,
+                                        &library);
   g_hash_table_insert (abi->cached_results, g_strdup (soname), library);
   abi->cached_combined_issues |= issues;
   if (more_details_out != NULL)
@@ -709,3 +716,24 @@ srt_system_info_set_environ (SrtSystemInfo *self,
   g_strfreev (self->env);
   self->env = g_strdupv ((gchar **) env);
 }
+
+/**
+ * srt_system_info_set_helpers_path:
+ * @self: The #SrtSystemInfo
+ * @path: (nullable) (type filename) (transfer none): An absolute path
+ *
+ * Look for helper executables used to inspect the system state in @path,
+ * instead of the normal installed location.
+ *
+ * If @path is %NULL, go back to using the installed location.
+ */
+void
+srt_system_info_set_helpers_path (SrtSystemInfo *self,
+                                  const gchar *path)
+{
+  g_return_if_fail (SRT_IS_SYSTEM_INFO (self));
+
+  forget_libraries (self);
+  free (self->helpers_path);
+  self->helpers_path = g_strdup (path);
+}
diff --git a/steam-runtime-tools/system-info.h b/steam-runtime-tools/system-info.h
index 33b6132b3..2bc83880b 100644
--- a/steam-runtime-tools/system-info.h
+++ b/steam-runtime-tools/system-info.h
@@ -61,3 +61,5 @@ SrtLibraryIssues srt_system_info_check_library (SrtSystemInfo *self,
 
 void srt_system_info_set_environ (SrtSystemInfo *self,
                                   gchar * const *env);
+void srt_system_info_set_helpers_path (SrtSystemInfo *self,
+                                       const gchar *path);
diff --git a/tests/meson.build b/tests/meson.build
index 53a323a8a..d494f0860 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -49,6 +49,13 @@ install_subdir('expectations', install_dir : tests_dir)
 install_subdir('expectations_with_missings', install_dir : tests_dir)
 install_subdir('fake-steam-runtime', install_dir : tests_dir)
 
+executable(
+  'mock-true',
+  join_paths('..', 'helpers', 'true.c'),
+  install : get_option('installed_tests'),
+  install_dir : tests_dir,
+)
+
 foreach test_name : tests
   exe = executable(
     'test-' + test_name,
diff --git a/tests/system-info.c b/tests/system-info.c
index afe4d58b1..92b8f639e 100644
--- a/tests/system-info.c
+++ b/tests/system-info.c
@@ -138,6 +138,15 @@ test_object (Fixture *f,
   g_free (expectations_in);
   g_free (expectations);
   g_object_unref (info);
+
+  info = srt_system_info_new (NULL);
+  g_assert_nonnull (info);
+  srt_system_info_set_helpers_path (info, f->builddir);
+  g_assert_true (srt_system_info_can_run (info, "mock"));
+  /* The real helpers are not present here */
+  g_assert_false (srt_system_info_can_run (info, SRT_ABI_I386));
+  g_assert_false (srt_system_info_can_run (info, SRT_ABI_X86_64));
+  g_object_unref (info);
 }
 
 static void
-- 
GitLab