add --readJsonSummaryPath to render_pictures

BUG=skia:1942
R=borenet@google.com

Author: epoger@google.com

Review URL: https://codereview.chromium.org/273783004

git-svn-id: http://skia.googlecode.com/svn/trunk@14695 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/tools/tests/render_pictures_test.py b/tools/tests/render_pictures_test.py
index d378a54..4b11e56 100755
--- a/tools/tests/render_pictures_test.py
+++ b/tools/tests/render_pictures_test.py
@@ -10,6 +10,7 @@
 """
 
 # System-level imports
+import copy
 import json
 import os
 import shutil
@@ -27,100 +28,138 @@
 }
 
 # Manually verified: 640x400 red rectangle with black border
+# Standard expectations will be set up in such a way that this image fails
+# the comparison.
 RED_WHOLEIMAGE = {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 11092453015575919668,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "failed",
     "filepath" : "red_skp.png",
 }
 
 # Manually verified: 640x400 green rectangle with black border
+# Standard expectations will be set up in such a way that this image passes
+# the comparison.
 GREEN_WHOLEIMAGE = {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 8891695120562235492,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "succeeded",
     "filepath" : "green_skp.png",
 }
 
 # Manually verified these 6 images, all 256x256 tiles,
 # consistent with a tiled version of the 640x400 red rect
 # with black borders.
+# Standard expectations will be set up in such a way that these images fail
+# the comparison.
 RED_TILES = [{
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 5815827069051002745,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "failed",
     "filepath" : "red_skp-tile0.png",
 },{
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 9323613075234140270,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "failed",
     "filepath" : "red_skp-tile1.png",
 }, {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 16670399404877552232,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "failed",
     "filepath" : "red_skp-tile2.png",
 }, {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 2507897274083364964,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "failed",
     "filepath" : "red_skp-tile3.png",
 }, {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 7325267995523877959,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "failed",
     "filepath" : "red_skp-tile4.png",
 }, {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 2181381724594493116,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "failed",
     "filepath" : "red_skp-tile5.png",
 }]
 
 # Manually verified these 6 images, all 256x256 tiles,
 # consistent with a tiled version of the 640x400 green rect
 # with black borders.
+# Standard expectations will be set up in such a way that these images pass
+# the comparison.
 GREEN_TILES = [{
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 12587324416545178013,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "succeeded",
     "filepath" : "green_skp-tile0.png",
 }, {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 7624374914829746293,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "succeeded",
     "filepath" : "green_skp-tile1.png",
 }, {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 5686489729535631913,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "succeeded",
     "filepath" : "green_skp-tile2.png",
 }, {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 7980646035555096146,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "succeeded",
     "filepath" : "green_skp-tile3.png",
 }, {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 17817086664365875131,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "succeeded",
     "filepath" : "green_skp-tile4.png",
 }, {
     "checksumAlgorithm" : "bitmap-64bitMD5",
     "checksumValue" : 10673669813016809363,
-    "comparisonResult" : "no-comparison",
+    "comparisonResult" : "succeeded",
     "filepath" : "green_skp-tile5.png",
 }]
 
 
+def modified_dict(input_dict, modification_dict):
+  """Returns a dict, with some modifications applied to it.
+
+  Args:
+    input_dict: a dictionary (which will be copied, not modified in place)
+    modification_dict: a set of key/value pairs to overwrite in the dict
+  """
+  output_dict = input_dict.copy()
+  output_dict.update(modification_dict)
+  return output_dict
+
+
+def modified_list_of_dicts(input_list, modification_dict):
+  """Returns a list of dicts, with some modifications applied to each dict.
+
+  Args:
+    input_list: a list of dictionaries; these dicts will be copied, not
+        modified in place
+    modification_dict: a set of key/value pairs to overwrite in each dict
+        within input_list
+  """
+  output_list = []
+  for input_dict in input_list:
+    output_dict = modified_dict(input_dict, modification_dict)
+    output_list.append(output_dict)
+  return output_list
+
+
 class RenderPicturesTest(base_unittest.TestCase):
 
   def setUp(self):
+    self.maxDiff = MAX_DIFF_LENGTH
+    self._expectations_dir = tempfile.mkdtemp()
     self._input_skp_dir = tempfile.mkdtemp()
     self._temp_dir = tempfile.mkdtemp()
-    self.maxDiff = MAX_DIFF_LENGTH
 
   def tearDown(self):
+    shutil.rmtree(self._expectations_dir)
     shutil.rmtree(self._input_skp_dir)
     shutil.rmtree(self._temp_dir)
 
@@ -137,14 +176,17 @@
     probably shouldn't write out red_skp.png and green_skp.png at all!
     See http://skbug.com/2464
     """
-    output_json_path = os.path.join(self._temp_dir, 'output.json')
+    output_json_path = os.path.join(self._temp_dir, 'actuals.json')
     self._generate_skps()
-    self._run_render_pictures(['-r', self._input_skp_dir,
-                               '--bbh', 'grid', '256', '256',
-                               '--mode', 'tile', '256', '256',
-                               '--writeJsonSummaryPath', output_json_path,
-                               '--writePath', self._temp_dir,
-                               '--writeWholeImage'])
+    expectations_path = self._create_expectations()
+    self._run_render_pictures([
+        '-r', self._input_skp_dir,
+        '--bbh', 'grid', '256', '256',
+        '--mode', 'tile', '256', '256',
+        '--readJsonSummaryPath', expectations_path,
+        '--writeJsonSummaryPath', output_json_path,
+        '--writePath', self._temp_dir,
+        '--writeWholeImage'])
     expected_summary_dict = {
         "header" : EXPECTED_HEADER_CONTENTS,
         "actual-results" : {
@@ -160,15 +202,50 @@
     }
     self._assert_json_contents(output_json_path, expected_summary_dict)
     self._assert_directory_contents(
-        self._temp_dir, ['red_skp.png', 'green_skp.png', 'output.json'])
+        self._temp_dir, ['red_skp.png', 'green_skp.png', 'actuals.json'])
+
+  def test_missing_tile_and_whole_image(self):
+    """test_tiled_whole_image, but missing expectations for some images.
+    """
+    output_json_path = os.path.join(self._temp_dir, 'actuals.json')
+    self._generate_skps()
+    expectations_path = self._create_expectations(missing_some_images=True)
+    self._run_render_pictures([
+        '-r', self._input_skp_dir,
+        '--bbh', 'grid', '256', '256',
+        '--mode', 'tile', '256', '256',
+        '--readJsonSummaryPath', expectations_path,
+        '--writeJsonSummaryPath', output_json_path,
+        '--writePath', self._temp_dir,
+        '--writeWholeImage'])
+    modified_red_tiles = copy.deepcopy(RED_TILES)
+    modified_red_tiles[5]['comparisonResult'] = 'no-comparison'
+    expected_summary_dict = {
+        "header" : EXPECTED_HEADER_CONTENTS,
+        "actual-results" : {
+            "red.skp": {
+                "tiled-images": modified_red_tiles,
+                "whole-image": modified_dict(
+                    RED_WHOLEIMAGE, {"comparisonResult" : "no-comparison"}),
+            },
+            "green.skp": {
+                "tiled-images": GREEN_TILES,
+                "whole-image": GREEN_WHOLEIMAGE,
+            }
+        }
+    }
+    self._assert_json_contents(output_json_path, expected_summary_dict)
 
   def test_untiled(self):
     """Run without tiles."""
-    output_json_path = os.path.join(self._temp_dir, 'output.json')
+    output_json_path = os.path.join(self._temp_dir, 'actuals.json')
     self._generate_skps()
-    self._run_render_pictures(['-r', self._input_skp_dir,
-                               '--writePath', self._temp_dir,
-                               '--writeJsonSummaryPath', output_json_path])
+    expectations_path = self._create_expectations()
+    self._run_render_pictures([
+        '-r', self._input_skp_dir,
+        '--readJsonSummaryPath', expectations_path,
+        '--writePath', self._temp_dir,
+        '--writeJsonSummaryPath', output_json_path])
     expected_summary_dict = {
         "header" : EXPECTED_HEADER_CONTENTS,
         "actual-results" : {
@@ -182,11 +259,11 @@
     }
     self._assert_json_contents(output_json_path, expected_summary_dict)
     self._assert_directory_contents(
-        self._temp_dir, ['red_skp.png', 'green_skp.png', 'output.json'])
+        self._temp_dir, ['red_skp.png', 'green_skp.png', 'actuals.json'])
 
   def test_untiled_writeChecksumBasedFilenames(self):
     """Same as test_untiled, but with --writeChecksumBasedFilenames."""
-    output_json_path = os.path.join(self._temp_dir, 'output.json')
+    output_json_path = os.path.join(self._temp_dir, 'actuals.json')
     self._generate_skps()
     self._run_render_pictures(['-r', self._input_skp_dir,
                                '--writeChecksumBasedFilenames',
@@ -217,7 +294,7 @@
     }
     self._assert_json_contents(output_json_path, expected_summary_dict)
     self._assert_directory_contents(self._temp_dir, [
-        'red_skp', 'green_skp', 'output.json'])
+        'red_skp', 'green_skp', 'actuals.json'])
     self._assert_directory_contents(
         os.path.join(self._temp_dir, 'red_skp'),
         ['bitmap-64bitMD5_11092453015575919668.png'])
@@ -227,12 +304,15 @@
 
   def test_untiled_validate(self):
     """Same as test_untiled, but with --validate."""
-    output_json_path = os.path.join(self._temp_dir, 'output.json')
+    output_json_path = os.path.join(self._temp_dir, 'actuals.json')
     self._generate_skps()
-    self._run_render_pictures(['-r', self._input_skp_dir,
-                               '--validate',
-                               '--writePath', self._temp_dir,
-                               '--writeJsonSummaryPath', output_json_path])
+    expectations_path = self._create_expectations()
+    self._run_render_pictures([
+        '-r', self._input_skp_dir,
+        '--readJsonSummaryPath', expectations_path,
+        '--validate',
+        '--writePath', self._temp_dir,
+        '--writeJsonSummaryPath', output_json_path])
     expected_summary_dict = {
         "header" : EXPECTED_HEADER_CONTENTS,
         "actual-results" : {
@@ -246,14 +326,17 @@
     }
     self._assert_json_contents(output_json_path, expected_summary_dict)
     self._assert_directory_contents(
-        self._temp_dir, ['red_skp.png', 'green_skp.png', 'output.json'])
+        self._temp_dir, ['red_skp.png', 'green_skp.png', 'actuals.json'])
 
   def test_untiled_without_writePath(self):
     """Same as test_untiled, but without --writePath."""
-    output_json_path = os.path.join(self._temp_dir, 'output.json')
+    output_json_path = os.path.join(self._temp_dir, 'actuals.json')
     self._generate_skps()
-    self._run_render_pictures(['-r', self._input_skp_dir,
-                               '--writeJsonSummaryPath', output_json_path])
+    expectations_path = self._create_expectations()
+    self._run_render_pictures([
+        '-r', self._input_skp_dir,
+        '--readJsonSummaryPath', expectations_path,
+        '--writeJsonSummaryPath', output_json_path])
     expected_summary_dict = {
         "header" : EXPECTED_HEADER_CONTENTS,
         "actual-results" : {
@@ -269,13 +352,16 @@
 
   def test_tiled(self):
     """Generate individual tiles."""
-    output_json_path = os.path.join(self._temp_dir, 'output.json')
+    output_json_path = os.path.join(self._temp_dir, 'actuals.json')
     self._generate_skps()
-    self._run_render_pictures(['-r', self._input_skp_dir,
-                               '--bbh', 'grid', '256', '256',
-                               '--mode', 'tile', '256', '256',
-                               '--writePath', self._temp_dir,
-                               '--writeJsonSummaryPath', output_json_path])
+    expectations_path = self._create_expectations()
+    self._run_render_pictures([
+        '-r', self._input_skp_dir,
+        '--bbh', 'grid', '256', '256',
+        '--mode', 'tile', '256', '256',
+        '--readJsonSummaryPath', expectations_path,
+        '--writePath', self._temp_dir,
+        '--writeJsonSummaryPath', output_json_path])
     expected_summary_dict = {
         "header" : EXPECTED_HEADER_CONTENTS,
         "actual-results" : {
@@ -294,11 +380,11 @@
          'red_skp-tile3.png', 'red_skp-tile4.png', 'red_skp-tile5.png',
          'green_skp-tile0.png', 'green_skp-tile1.png', 'green_skp-tile2.png',
          'green_skp-tile3.png', 'green_skp-tile4.png', 'green_skp-tile5.png',
-         'output.json'])
+         'actuals.json'])
 
   def test_tiled_writeChecksumBasedFilenames(self):
     """Same as test_tiled, but with --writeChecksumBasedFilenames."""
-    output_json_path = os.path.join(self._temp_dir, 'output.json')
+    output_json_path = os.path.join(self._temp_dir, 'actuals.json')
     self._generate_skps()
     self._run_render_pictures(['-r', self._input_skp_dir,
                                '--bbh', 'grid', '256', '256',
@@ -385,7 +471,7 @@
     }
     self._assert_json_contents(output_json_path, expected_summary_dict)
     self._assert_directory_contents(self._temp_dir, [
-        'red_skp', 'green_skp', 'output.json'])
+        'red_skp', 'green_skp', 'actuals.json'])
     self._assert_directory_contents(
         os.path.join(self._temp_dir, 'red_skp'),
         ['bitmap-64bitMD5_5815827069051002745.png',
@@ -410,6 +496,43 @@
                              '--config', '8888',
                              ] + args)
 
+  def _create_expectations(self, missing_some_images=False,
+                           rel_path='expectations.json'):
+    """Creates expectations JSON file within self._expectations_dir .
+
+    Args:
+      missing_some_images: (bool) whether to remove expectations for a subset
+          of the images
+      rel_path: (string) relative path within self._expectations_dir to write
+          the expectations into
+
+    Returns: full path to the expectations file created.
+    """
+    expectations_dict = {
+        "header" : EXPECTED_HEADER_CONTENTS,
+        "expected-results" : {
+            # red.skp: these should fail the comparison
+            "red.skp": {
+                "tiled-images": modified_list_of_dicts(
+                    RED_TILES, {'checksumValue': 11111}),
+                "whole-image": modified_dict(
+                    RED_WHOLEIMAGE, {'checksumValue': 22222}),
+            },
+            # green.skp: these should pass the comparison
+            "green.skp": {
+                "tiled-images": GREEN_TILES,
+                "whole-image": GREEN_WHOLEIMAGE,
+            }
+        }
+    }
+    if missing_some_images:
+      del expectations_dict['expected-results']['red.skp']['whole-image']
+      del expectations_dict['expected-results']['red.skp']['tiled-images'][-1]
+    path = os.path.join(self._expectations_dir, rel_path)
+    with open(path, 'w') as fh:
+      json.dump(expectations_dict, fh)
+    return path
+
   def _generate_skps(self):
     """Runs the skpmaker binary to generate files in self._input_skp_dir."""
     self._run_skpmaker(
@@ -452,7 +575,6 @@
     """
     self.assertEqual(set(os.listdir(dir_path)), set(expected_filenames))
 
-
   def _assert_json_contents(self, json_path, expected_dict):
     """Asserts that contents of a JSON file are identical to expected_dict.
 
@@ -465,9 +587,13 @@
       AssertionError: contents of the JSON file are not identical to
                       expected_dict.
     """
-    file_contents = open(json_path, 'r').read()
-    actual_dict = json.loads(file_contents)
-    self.assertEqual(actual_dict, expected_dict)
+    prettyprinted_expected_dict = json.dumps(expected_dict, sort_keys=True,
+                                             indent=2)
+    with open(json_path, 'r') as fh:
+      prettyprinted_json_dict = json.dumps(json.load(fh), sort_keys=True,
+                                           indent=2)
+    self.assertMultiLineEqual(prettyprinted_expected_dict,
+                              prettyprinted_json_dict)
 
 
 def main():