[gegl] tools/gegl-tester: compute and verify hashes



commit 9e46838a5cf67ac1229b9d884cc925d6ab29e229
Author: Øyvind Kolås <pippin gimp org>
Date:   Thu Mar 9 18:38:51 2017 +0100

    tools/gegl-tester: compute and verify hashes

 tools/gegl-tester.c |  199 +++++++++++++++++++--------------------------------
 1 files changed, 73 insertions(+), 126 deletions(-)
---
diff --git a/tools/gegl-tester.c b/tools/gegl-tester.c
index 816fa62..4f1a856 100644
--- a/tools/gegl-tester.c
+++ b/tools/gegl-tester.c
@@ -23,23 +23,20 @@
 #include <string.h>
 #include <glib/gprintf.h>
 
-
 static GRegex   *regex, *exc_regex;
 static gchar    *data_dir        = NULL;
-static gchar    *reference_dir   = NULL;
 static gchar    *output_dir      = NULL;
 static gchar    *pattern         = "";
 static gchar    *exclusion_pattern = "a^"; /* doesn't match anything by default */
 static gboolean *output_all      = FALSE;
+static gint      failed          = 0;
+static GString  *failed_ops      = NULL;
 
 static const GOptionEntry options[] =
 {
   {"data-directory", 'd', 0, G_OPTION_ARG_FILENAME, &data_dir,
    "Root directory of files used in the composition", NULL},
 
-  {"reference-directory", 'r', 0, G_OPTION_ARG_FILENAME, &reference_dir,
-   "Directory where reference images are located", NULL},
-
   {"output-directory", 'o', 0, G_OPTION_ARG_FILENAME, &output_dir,
    "Directory where composition output and diff files are saved", NULL},
 
@@ -77,96 +74,8 @@ operation_to_path (const gchar *op_name,
   return output_path;
 }
 
-static gboolean
-test_operation (const gchar *op_name,
-                const gchar *image,
-                gchar       *output_path)
-{
-  gchar         *ref_path;
-  GeglNode      *img, *ref_img, *gegl;
-  GeglRectangle  ref_bounds, comp_bounds;
-  gint           ref_pixels;
-  gboolean       result = TRUE;
-
-  gegl = gegl_node_new ();
-
-  ref_path = g_build_path (G_DIR_SEPARATOR_S, reference_dir, image, NULL);
-  ref_img = gegl_node_new_child (gegl,
-                                 "operation", "gegl:load",
-                                 "path", ref_path,
-                                 NULL);
-  g_free (ref_path);
-
-  img = gegl_node_new_child (gegl,
-                             "operation", "gegl:load",
-                             "path", output_path,
-                             NULL);
-
-  ref_bounds  = gegl_node_get_bounding_box (ref_img);
-  comp_bounds = gegl_node_get_bounding_box (img);
-  ref_pixels  = ref_bounds.width * ref_bounds.height;
-
-  if (ref_bounds.width != comp_bounds.width ||
-      ref_bounds.height != comp_bounds.height)
-    {
-      g_printf ("FAIL\n  Reference and composition differ in size\n");
-      result = FALSE;
-    }
-  else
-    {
-      GeglNode *comparison;
-      gdouble   max_diff;
-
-      comparison = gegl_node_create_child (gegl, "gegl:image-compare");
-      gegl_node_link (img, comparison);
-      gegl_node_connect_to (ref_img, "output", comparison, "aux");
-      gegl_node_process (comparison);
-      gegl_node_get (comparison, "max diff", &max_diff, NULL);
-
-      if (max_diff < 1.0)
-        {
-          g_printf ("PASS\n");
-          result = TRUE;
-        }
-      else
-        {
-          GeglNode *output;
-          gchar    *diff_path;
-          gdouble   avg_diff_wrong, avg_diff_total;
-          gint      wrong_pixels;
-
-          gegl_node_get (comparison, "avg_diff_wrong", &avg_diff_wrong,
-                         "avg_diff_total", &avg_diff_total, "wrong_pixels",
-                         &wrong_pixels, NULL);
-
-          g_printf ("FAIL\n  Reference image and composition differ\n"
-                    "    wrong pixels : %i/%i (%2.2f%%)\n"
-                    "    max Δe       : %2.3f\n"
-                    "    avg Δe       : %2.3f (wrong) %2.3f (total)\n",
-                    wrong_pixels, ref_pixels,
-                    (wrong_pixels * 100.0 / ref_pixels),
-                    max_diff, avg_diff_wrong, avg_diff_total);
-
-          diff_path = operation_to_path (op_name, TRUE);
-          output = gegl_node_new_child (gegl,
-                                        "operation", "gegl:png-save",
-                                        "path", diff_path,
-                                        NULL);
-          gegl_node_link (comparison, output);
-          gegl_node_process (output);
-
-          g_free (diff_path);
-
-          result = FALSE;
-        }
-    }
-
-  g_object_unref (gegl);
-  return result;
-}
-
 static void
-standard_output (const gchar *op_name)
+standard_output (const gchar *op_name, const gchar *ref_hash)
 {
   GeglNode *composition, *input, *aux, *operation, *crop, *output, *translate;
   GeglNode *background,  *over;
@@ -236,11 +145,30 @@ standard_output (const gchar *op_name)
   g_object_unref (composition);
 }
 
-static gboolean
+static gchar *
+compute_hash_for_path (const gchar *path)
+{
+  gchar *ret = NULL;
+  GeglNode *gegl = gegl_node_new ();
+  GeglRectangle comp_bounds;
+  guchar *buf;
+  GeglNode *img = gegl_node_new_child (gegl,
+                                 "operation", "gegl:load",
+                                 "path", path,
+                                 NULL);
+  comp_bounds = gegl_node_get_bounding_box (img);
+  buf = g_malloc0 (comp_bounds.width * comp_bounds.height * 4);
+  gegl_node_blit (img, 1.0, &comp_bounds, babl_format("R'G'B'A u8"), buf, GEGL_AUTO_ROWSTRIDE, 
GEGL_BLIT_DEFAULT);
+  ret = g_compute_checksum_for_data (G_CHECKSUM_MD5, buf, comp_bounds.width * comp_bounds.height * 4);
+  g_free (buf);
+  g_object_unref (gegl);
+  return ret;
+}
+
+static void
 process_operations (GType type)
 {
   GType    *operations;
-  gboolean  result = TRUE;
   guint     count;
   gint      i;
 
@@ -249,23 +177,23 @@ process_operations (GType type)
   if (!operations)
     {
       g_free (operations);
-      return TRUE;
+      return;
     }
 
   for (i = 0; i < count; i++)
     {
       GeglOperationClass *operation_class;
-      const gchar        *image, *xml, *name;
+      const gchar        *xml, *name, *hash;
       gboolean            matches;
 
       operation_class = g_type_class_ref (operations[i]);
-      image           = gegl_operation_class_get_key (operation_class, "reference-image");
+      hash            = gegl_operation_class_get_key (operation_class, "reference-hash");
       xml             = gegl_operation_class_get_key (operation_class, "reference-composition");
       name            = gegl_operation_class_get_key (operation_class, "name");
 
       if (name == NULL)
         {
-          result = result && process_operations (operations[i]);
+          process_operations (operations[i]);
           continue;
         }
 
@@ -276,19 +204,15 @@ process_operations (GType type)
         {
           GeglNode *composition;
 
-          if (output_all)
-            g_printf ("%s\n", name);
-          else if (image)
-            g_printf ("%s: ", name); /* more information will follow
+          g_printf ("%s: ", name); /* more information will follow
                                         if we're testing */
 
           composition = gegl_node_new_from_xml (xml, data_dir);
           if (!composition)
             {
               g_printf ("FAIL\n  Composition graph is flawed\n");
-              result = FALSE;
             }
-          else if (image || output_all)
+          else if (output_all)
             {
               gchar    *output_path = operation_to_path (name, FALSE);
               GeglNode *output      =
@@ -301,10 +225,6 @@ process_operations (GType type)
               gegl_node_process (output);
               g_object_unref (composition);
 
-              /* don't test if run with --all */
-              if (!output_all && image)
-                result = test_operation (name, image, output_path) && result;
-
               g_free (output_path);
             }
         }
@@ -314,23 +234,45 @@ process_operations (GType type)
                !(g_type_is_a (operations[i], GEGL_TYPE_OPERATION_SINK) ||
                  g_type_is_a (operations[i], GEGL_TYPE_OPERATION_TEMPORAL)))
         {
-          g_printf ("%s\n", name);
-          standard_output (name);
+          g_printf ("%s ", name);
+          standard_output (name, hash);
         }
 
-      result = process_operations (operations[i]) && result;
+      if (matches && hash)
+      {
+        gchar *output_path = operation_to_path (name, FALSE);
+        gchar *gothash = compute_hash_for_path (output_path);
+        if (g_str_equal (hash, gothash))
+          g_printf (" OK\n");
+        else
+        {
+          g_printf (" FAIL %s != %s\n", hash, gothash);
+          failed ++;
+          g_string_append_printf (failed_ops, " %s", name);
+        }
+        g_free (gothash);
+        g_free (output_path);
+      } else if (matches &&
+               !(g_type_is_a (operations[i], GEGL_TYPE_OPERATION_SINK) ||
+                 g_type_is_a (operations[i], GEGL_TYPE_OPERATION_TEMPORAL)))
+      {
+        gchar *output_path = operation_to_path (name, FALSE);
+        gchar *gothash = compute_hash_for_path (output_path);
+        g_printf (" hash = %s [%s]\n", gothash, name);
+        g_free (gothash);
+        g_free (output_path);
+      }
+
+      process_operations (operations[i]);
     }
 
   g_free (operations);
-
-  return result;
 }
 
 gint
 main (gint    argc,
       gchar **argv)
 {
-  gboolean        result;
   GError         *error = NULL;
   GOptionContext *context;
 
@@ -343,29 +285,30 @@ main (gint    argc,
   g_object_set (gegl_config (),
                 "application-license", "GPL3",
                 NULL);
+  failed_ops = g_string_new ("");
 
   if (!g_option_context_parse (context, &argc, &argv, &error))
     {
       g_printf ("%s\n", error->message);
       g_error_free (error);
-      result = FALSE;
+      return -1;
     }
   else if (output_all && !(data_dir && output_dir))
     {
       g_printf ("Data and output directories must be specified\n");
-      result = FALSE;
+      return -1;
     }
-  else if (!(output_all || (data_dir && output_dir && reference_dir)))
+  else if (!(output_all || (data_dir && output_dir)))
     {
-      g_printf ("Data, reference and output directories must be specified\n");
-      result = FALSE;
+      g_printf ("Data and output directories must be specified\n");
+      return -1;
     }
   else
     {
       regex = g_regex_new (pattern, 0, 0, NULL);
       exc_regex = g_regex_new (exclusion_pattern, 0, 0, NULL);
 
-      result = process_operations (GEGL_TYPE_OPERATION);
+      process_operations (GEGL_TYPE_OPERATION);
 
       g_regex_unref (regex);
       g_regex_unref (exc_regex);
@@ -373,8 +316,12 @@ main (gint    argc,
 
   gegl_exit ();
 
-  if (output_all)
-    return 0;
-  else
-    return result;
+  if (failed != 0)
+  {
+    g_warning ("%i operations not producing the expected result: %s\n", failed, failed_ops->str);
+    return -1;
+  }
+  g_string_free (failed_ops, TRUE);
+
+  return 0;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]