[gegl] tools/gegl-tester: compute and verify hashes
- From: Øyvind Kolås <ok src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] tools/gegl-tester: compute and verify hashes
- Date: Thu, 9 Mar 2017 17:40:05 +0000 (UTC)
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]