Title: [284930] trunk/Tools
Revision
284930
Author
[email protected]
Date
2021-10-27 11:18:34 -0700 (Wed, 27 Oct 2021)

Log Message

Store WPT-style fuzzy pixel matching data in ImageDiffResult
https://bugs.webkit.org/show_bug.cgi?id=232352

Reviewed by Martin Robinson.

Always run ImageDiff with `--difference` so that it prints the "maxDifference=; totalPixels="
output, and parse and store this output in ImageDiffResult.

* Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
(RunTest.test_tolerance.ImageDiffTestPort.diff_image):
* Scripts/webkitpy/port/image_diff.py:
(ImageDiffResult.__init__):
(ImageDiffResult.__eq__):
(ImageDiffResult.__repr__):
(ImageDiffer._start):
(ImageDiffer._read):
* Scripts/webkitpy/port/port_testcase.py:
(PortTestCase.test_diff_image.make_proc):
(PortTestCase.test_diff_image):
(PortTestCase.test_diff_image_passed):
(PortTestCase.test_diff_image_passed_with_tolerance):
(PortTestCase.test_diff_image_failed_with_rounded_diff):
(PortTestCase.test_diff_image_failed):
* Scripts/webkitpy/port/test.py:

Modified Paths

Diff

Modified: trunk/Tools/ChangeLog (284929 => 284930)


--- trunk/Tools/ChangeLog	2021-10-27 18:08:54 UTC (rev 284929)
+++ trunk/Tools/ChangeLog	2021-10-27 18:18:34 UTC (rev 284930)
@@ -1,3 +1,30 @@
+2021-10-27  Simon Fraser  <[email protected]>
+
+        Store WPT-style fuzzy pixel matching data in ImageDiffResult
+        https://bugs.webkit.org/show_bug.cgi?id=232352
+
+        Reviewed by Martin Robinson.
+
+        Always run ImageDiff with `--difference` so that it prints the "maxDifference=; totalPixels="
+        output, and parse and store this output in ImageDiffResult.
+
+        * Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py:
+        (RunTest.test_tolerance.ImageDiffTestPort.diff_image):
+        * Scripts/webkitpy/port/image_diff.py:
+        (ImageDiffResult.__init__):
+        (ImageDiffResult.__eq__):
+        (ImageDiffResult.__repr__):
+        (ImageDiffer._start):
+        (ImageDiffer._read):
+        * Scripts/webkitpy/port/port_testcase.py:
+        (PortTestCase.test_diff_image.make_proc):
+        (PortTestCase.test_diff_image):
+        (PortTestCase.test_diff_image_passed):
+        (PortTestCase.test_diff_image_passed_with_tolerance):
+        (PortTestCase.test_diff_image_failed_with_rounded_diff):
+        (PortTestCase.test_diff_image_failed):
+        * Scripts/webkitpy/port/test.py:
+
 2021-10-27  Jonathan Bedard  <[email protected]>
 
         [webkitscmpy] Ensure empty line before canonicalization

Modified: trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py (284929 => 284930)


--- trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py	2021-10-27 18:08:54 UTC (rev 284929)
+++ trunk/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_integrationtest.py	2021-10-27 18:18:34 UTC (rev 284930)
@@ -752,7 +752,7 @@
         class ImageDiffTestPort(test.TestPort):
             def diff_image(self, expected_contents, actual_contents, tolerance=None):
                 self.tolerance_used_for_diff_image = self._options.tolerance
-                return ImageDiffResult(passed=False, diff_image=b'', difference=1, tolerance=self._options.tolerance or 0)
+                return ImageDiffResult(passed=False, diff_image=b'', difference=1, fuzzy_data=None, tolerance=self._options.tolerance or 0)
 
         def get_port_for_run(args):
             options, parsed_args = run_webkit_tests.parse_args(args)

Modified: trunk/Tools/Scripts/webkitpy/port/image_diff.py (284929 => 284930)


--- trunk/Tools/Scripts/webkitpy/port/image_diff.py	2021-10-27 18:08:54 UTC (rev 284929)
+++ trunk/Tools/Scripts/webkitpy/port/image_diff.py	2021-10-27 18:18:34 UTC (rev 284930)
@@ -40,10 +40,11 @@
 
 
 class ImageDiffResult(object):
-    def __init__(self, passed, diff_image, difference, tolerance=0, error_string=None):
+    def __init__(self, passed, diff_image, difference, tolerance=0, fuzzy_data=None, error_string=None):
         self.passed = passed
         self.diff_image = diff_image
         self.diff_percent = difference
+        self.fuzzy_data = fuzzy_data
         self.tolerance = tolerance
         self.error_string = error_string
 
@@ -52,6 +53,7 @@
             return (self.passed == other.passed and
                     self.diff_image == other.diff_image and
                     self.diff_percent == other.diff_percent and
+                    self.fuzzy_data == other.fuzzy_data and
                     self.tolerance == other.tolerance and
                     self.error_string == other.error_string)
 
@@ -61,7 +63,7 @@
         return not self.__eq__(other)
 
     def __repr__(self):
-        return 'ImageDiffResult(Passed {} {} diff {} tolerance {} {})'.format(self.passed, self.diff_image, self.diff_percent, self.tolerance, self.error_string)
+        return 'ImageDiffResult(Passed {} {} diff {} tolerance {} fuzzy data {} {})'.format(self.passed, self.diff_image, self.diff_percent, self.tolerance, self.fuzzy_data, self.error_string)
 
 class ImageDiffer(object):
     def __init__(self, port):
@@ -91,7 +93,7 @@
             return (None, 0, "Failed to compute an image diff: %s" % str(exception))
 
     def _start(self, tolerance):
-        command = [self._port._path_to_image_diff(), '--tolerance', str(tolerance)]
+        command = [self._port._path_to_image_diff(), '--difference', '--tolerance', str(tolerance)]
         if self._port._should_use_jhbuild():
             command = self._port._jhbuild_wrapper + command
         environment = self._port.setup_environ_for_server('ImageDiff')
@@ -103,6 +105,7 @@
         deadline = time.time() + 2.0
         output_image = None
         diff_output = None
+        fuzzy_data = None
 
         while not self._process.timed_out and not self._process.has_crashed():
             output = self._process.read_stdout_line(deadline)
@@ -115,6 +118,9 @@
             if output.startswith(b'diff:'):
                 diff_output = output
 
+            if output.startswith(b'maxDifference='):
+                fuzzy_data = output
+
             if output.startswith(b'Content-Length'):
                 m = re.match(br'Content-Length: (\d+)', output)
                 content_length = int(string_utils.decode(m.group(1), target_type=str))
@@ -129,15 +135,22 @@
         if self._process.has_crashed():
             err_str += "ImageDiff crashed\n"
 
-        if not diff_output:
-            return ImageDiffResult(passed=False, diff_image=None, difference=0, tolerance=self._tolerance, error_string=err_str or "Failed to read ImageDiff output")
+        if not diff_output or not fuzzy_data:
+            return ImageDiffResult(passed=False, diff_image=None, difference=0, tolerance=self._tolerance, fuzzy_data=None, error_string=err_str or "Failed to read ImageDiff output")
 
         m = re.match(b'diff: (.+)%', diff_output)
         if not m:
-            return ImageDiffResult(passed=False, diff_image=None, difference=0, tolerance=self._tolerance, error_string=err_str or 'Failed to match ImageDiff output {}'.format(diff_output))
+            return ImageDiffResult(passed=False, diff_image=None, difference=0, tolerance=self._tolerance, fuzzy_data=None, error_string=err_str or 'Failed to match ImageDiff diff output {}'.format(diff_output))
 
         diff_percent = float(string_utils.decode(m.group(1), target_type=str))
 
+        m = re.match(br'maxDifference=(\d+); totalPixels=(\d+)', fuzzy_data)
+        if not m:
+            return ImageDiffResult(passed=False, diff_image=None, difference=0, tolerance=self._tolerance, fuzzy_data=None, error_string=err_str or 'Failed to match ImageDiff fuzzy data output {}'.format(fuzzy_data))
+
+        max_difference = int(string_utils.decode(m.group(1), target_type=str))
+        total_pixels = int(string_utils.decode(m.group(2), target_type=str))
+
         passed = diff_percent <= self._tolerance
         if not passed:
             # FIXME: This prettification should happen at display time.
@@ -144,7 +157,7 @@
             diff_percent = round(diff_percent * 100) / 100
             diff_percent = max(diff_percent, 0.01)
 
-        return ImageDiffResult(passed=passed, diff_image=output_image, difference=diff_percent, tolerance=self._tolerance, error_string=err_str or None)
+        return ImageDiffResult(passed=passed, diff_image=output_image, difference=diff_percent, tolerance=self._tolerance, fuzzy_data={'max_difference': max_difference, 'total_pixels': total_pixels}, error_string=err_str or None)
 
     def stop(self):
         if self._process:

Modified: trunk/Tools/Scripts/webkitpy/port/port_testcase.py (284929 => 284930)


--- trunk/Tools/Scripts/webkitpy/port/port_testcase.py	2021-10-27 18:08:54 UTC (rev 284929)
+++ trunk/Tools/Scripts/webkitpy/port/port_testcase.py	2021-10-27 18:18:34 UTC (rev 284930)
@@ -284,7 +284,17 @@
         self.proc = None
 
         def make_proc(port, nm, cmd, env, crash_message=None):
-            self.proc = MockServerProcess(port, nm, cmd, env, lines=['Content-Length: 6\n', 'image1', 'diff: 90%\n', '#EOF\n', 'Content-Length: 6\n', 'image2', 'diff: 100%\n', '#EOF\n'])
+            self.proc = MockServerProcess(port, nm, cmd, env, lines=[
+                'Content-Length: 6\n',
+                'image1',
+                'diff: 90%\n',
+                'maxDifference=6; totalPixels=50\n',
+                '#EOF\n',
+                'Content-Length: 6\n',
+                'image2',
+                'maxDifference=7; totalPixels=60\n',
+                'diff: 100%\n',
+                '#EOF\n'])
             return self.proc
 
         # FIXME: Can't pretend to run setup for some ports, so just skip this test.
@@ -297,27 +307,29 @@
         # First test the case of not using the JHBuild wrapper.
         self.assertFalse(port._should_use_jhbuild())
 
-        self.assertEqual(port.diff_image(b'foo', b'bar'), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, tolerance=0.1))
-        self.assertEqual(self.proc.cmd, [port._path_to_image_diff(), "--tolerance", "0.1"])
+        result_fuzzy_data = {'max_difference': 6, 'total_pixels': 50}
 
-        self.assertEqual(port.diff_image(b'foo', b'bar', tolerance=None), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, tolerance=0.1))
-        self.assertEqual(self.proc.cmd, [port._path_to_image_diff(), "--tolerance", "0.1"])
+        self.assertEqual(port.diff_image(b'foo', b'bar'), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, tolerance=0.1, fuzzy_data=result_fuzzy_data))
+        self.assertEqual(self.proc.cmd, [port._path_to_image_diff(), "--difference", "--tolerance", "0.1"])
 
-        self.assertEqual(port.diff_image(b'foo', b'bar', tolerance=0), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0))
-        self.assertEqual(self.proc.cmd, [port._path_to_image_diff(), "--tolerance", "0"])
+        self.assertEqual(port.diff_image(b'foo', b'bar', tolerance=None), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, tolerance=0.1, fuzzy_data=result_fuzzy_data))
+        self.assertEqual(self.proc.cmd, [port._path_to_image_diff(), "--difference", "--tolerance", "0.1"])
 
+        self.assertEqual(port.diff_image(b'foo', b'bar', tolerance=0), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, fuzzy_data=result_fuzzy_data))
+        self.assertEqual(self.proc.cmd, [port._path_to_image_diff(), "--difference", "--tolerance", "0"])
+
         # Now test the case of using JHBuild wrapper.
         port._filesystem.maybe_make_directory(port.path_from_webkit_base('WebKitBuild', 'Dependencies%s' % port.port_name.upper()))
         self.assertTrue(port._should_use_jhbuild())
 
-        self.assertEqual(port.diff_image(b'foo', b'bar'), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, tolerance=0.1))
-        self.assertEqual(self.proc.cmd, port._jhbuild_wrapper + [port._path_to_image_diff(), "--tolerance", "0.1"])
+        self.assertEqual(port.diff_image(b'foo', b'bar'), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, tolerance=0.1, fuzzy_data=result_fuzzy_data))
+        self.assertEqual(self.proc.cmd, port._jhbuild_wrapper + [port._path_to_image_diff(), "--difference", "--tolerance", "0.1"])
 
-        self.assertEqual(port.diff_image(b'foo', b'bar', tolerance=None), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, tolerance=0.1))
-        self.assertEqual(self.proc.cmd, port._jhbuild_wrapper + [port._path_to_image_diff(), "--tolerance", "0.1"])
+        self.assertEqual(port.diff_image(b'foo', b'bar', tolerance=None), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, tolerance=0.1, fuzzy_data=result_fuzzy_data))
+        self.assertEqual(self.proc.cmd, port._jhbuild_wrapper + [port._path_to_image_diff(), "--difference", "--tolerance", "0.1"])
 
-        self.assertEqual(port.diff_image(b'foo', b'bar', tolerance=0), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0))
-        self.assertEqual(self.proc.cmd, port._jhbuild_wrapper + [port._path_to_image_diff(), "--tolerance", "0"])
+        self.assertEqual(port.diff_image(b'foo', b'bar', tolerance=0), ImageDiffResult(passed=False, diff_image=b'image1', difference=90.0, fuzzy_data=result_fuzzy_data))
+        self.assertEqual(self.proc.cmd, port._jhbuild_wrapper + [port._path_to_image_diff(), "--difference", "--tolerance", "0"])
 
         port.clean_up_test_run()
         self.assertTrue(self.proc.stopped)
@@ -325,27 +337,27 @@
 
     def test_diff_image_passed(self):
         port = self.make_port()
-        port._server_process_constructor = lambda port, nm, cmd, env, crash_message=None: MockServerProcess(lines=['diff: 0%\n', '#EOF\n'])
+        port._server_process_constructor = lambda port, nm, cmd, env, crash_message=None: MockServerProcess(lines=['diff: 0%\n', 'maxDifference=0; totalPixels=0\n', '#EOF\n'])
         image_differ = ImageDiffer(port)
-        self.assertEqual(image_differ.diff_image(b'foo', b'foo', tolerance=0), ImageDiffResult(passed=True, diff_image=None, difference=0, tolerance=0))
+        self.assertEqual(image_differ.diff_image(b'foo', b'foo', tolerance=0), ImageDiffResult(passed=True, diff_image=None, difference=0, tolerance=0, fuzzy_data={'max_difference': 0, 'total_pixels': 0}))
 
     def test_diff_image_passed_with_tolerance(self):
         port = self.make_port()
-        port._server_process_constructor = lambda port, nm, cmd, env, crash_message=None: MockServerProcess(lines=['Content-Length: 4\n', 'test', 'diff: 0.05%\n', '#EOF\n'])
+        port._server_process_constructor = lambda port, nm, cmd, env, crash_message=None: MockServerProcess(lines=['Content-Length: 4\n', 'test', 'diff: 0.05%\n', 'maxDifference=4; totalPixels=10\n', '#EOF\n'])
         image_differ = ImageDiffer(port)
-        self.assertEqual(image_differ.diff_image(b'foo', b'bar', tolerance=0.1), ImageDiffResult(passed=True, diff_image=b'test', difference=0.05, tolerance=0.1))
+        self.assertEqual(image_differ.diff_image(b'foo', b'bar', tolerance=0.1), ImageDiffResult(passed=True, diff_image=b'test', difference=0.05, tolerance=0.1, fuzzy_data={'max_difference': 4, 'total_pixels': 10}))
 
     def test_diff_image_failed_with_rounded_diff(self):
         port = self.make_port()
-        port._server_process_constructor = lambda port, nm, cmd, env, crash_message=None: MockServerProcess(lines=['Content-Length: 4\n', 'test', 'diff: 0.101234%\n', '#EOF\n'])
+        port._server_process_constructor = lambda port, nm, cmd, env, crash_message=None: MockServerProcess(lines=['Content-Length: 4\n', 'test', 'diff: 0.101234%\n', 'maxDifference=8; totalPixels=20\n', '#EOF\n'])
         image_differ = ImageDiffer(port)
-        self.assertEqual(image_differ.diff_image(b'foo', b'bar', tolerance=0.1), ImageDiffResult(passed=False, diff_image=b'test', difference=0.1, tolerance=0.1))
+        self.assertEqual(image_differ.diff_image(b'foo', b'bar', tolerance=0.1), ImageDiffResult(passed=False, diff_image=b'test', difference=0.1, tolerance=0.1, fuzzy_data={'max_difference': 8, 'total_pixels': 20}))
 
     def test_diff_image_failed(self):
         port = self.make_port()
-        port._server_process_constructor = lambda port, nm, cmd, env, crash_message=None: MockServerProcess(lines=['Content-Length: 4\n', 'test', 'diff: 10%\n', '#EOF\n'])
+        port._server_process_constructor = lambda port, nm, cmd, env, crash_message=None: MockServerProcess(lines=['Content-Length: 4\n', 'test', 'diff: 10%\n', 'maxDifference=5; totalPixels=13\n', '#EOF\n'])
         image_differ = ImageDiffer(port)
-        self.assertEqual(image_differ.diff_image(b'foo', b'bar', tolerance=0.1), ImageDiffResult(passed=False, diff_image=b'test', difference=10, tolerance=0.1))
+        self.assertEqual(image_differ.diff_image(b'foo', b'bar', tolerance=0.1), ImageDiffResult(passed=False, diff_image=b'test', difference=10, tolerance=0.1, fuzzy_data={'max_difference': 5, 'total_pixels': 13}))
 
     def test_diff_image_crashed(self):
         port = self.make_port()

Modified: trunk/Tools/Scripts/webkitpy/port/test.py (284929 => 284930)


--- trunk/Tools/Scripts/webkitpy/port/test.py	2021-10-27 18:08:54 UTC (rev 284929)
+++ trunk/Tools/Scripts/webkitpy/port/test.py	2021-10-27 18:18:34 UTC (rev 284930)
@@ -423,9 +423,10 @@
                     string_utils.decode(actual_contents, target_type=str),
                 ),
                 difference=1,
-                tolerance=tolerance or 0)
+                tolerance=tolerance or 0,
+                fuzzy_data={'max_difference': 10, 'total_pixels': 20})
 
-        return ImageDiffResult(passed=True, diff_image=None, difference=0, tolerance=tolerance or 0)
+        return ImageDiffResult(passed=True, diff_image=None, difference=0, tolerance=tolerance or 0, fuzzy_data={'max_difference': 0, 'total_pixels': 0})
 
     def layout_tests_dir(self):
         return LAYOUT_TEST_DIR
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to