1 #!/usr/bin/python 2 3 """ 4 Copyright 2014 Google Inc. 5 6 Use of this source code is governed by a BSD-style license that can be 7 found in the LICENSE file. 8 9 Test the render_pictures binary. 10 """ 11 12 # System-level imports 13 import copy 14 import json 15 import os 16 import shutil 17 import tempfile 18 19 # Must fix up PYTHONPATH before importing from within Skia 20 import fix_pythonpath # pylint: disable=W0611 21 22 # Imports from within Skia 23 import base_unittest 24 import find_run_binary 25 26 # Maximum length of text diffs to show when tests fail 27 MAX_DIFF_LENGTH = 30000 28 29 EXPECTED_HEADER_CONTENTS = { 30 "type" : "ChecksummedImages", 31 "revision" : 1, 32 } 33 34 # Manually verified: 640x400 red rectangle with black border 35 # Standard expectations will be set up in such a way that this image fails 36 # the comparison. 37 RED_WHOLEIMAGE = { 38 "checksumAlgorithm" : "bitmap-64bitMD5", 39 "checksumValue" : 2853310525600416231, 40 "comparisonResult" : "failed", 41 "filepath" : "red_skp.png", 42 } 43 44 # Manually verified: 640x400 green rectangle with black border 45 # Standard expectations will be set up in such a way that this image passes 46 # the comparison. 47 GREEN_WHOLEIMAGE = { 48 "checksumAlgorithm" : "bitmap-64bitMD5", 49 "checksumValue" : 11143979097452425335, 50 "comparisonResult" : "succeeded", 51 "filepath" : "green_skp.png", 52 } 53 54 # Manually verified these 6 images, all 256x256 tiles, 55 # consistent with a tiled version of the 640x400 red rect 56 # with black borders. 57 # Standard expectations will be set up in such a way that these images fail 58 # the comparison. 59 RED_TILES = [{ 60 "checksumAlgorithm" : "bitmap-64bitMD5", 61 "checksumValue" : 5815827069051002745, 62 "comparisonResult" : "failed", 63 "filepath" : "red_skp-tile0.png", 64 },{ 65 "checksumAlgorithm" : "bitmap-64bitMD5", 66 "checksumValue" : 9323613075234140270, 67 "comparisonResult" : "failed", 68 "filepath" : "red_skp-tile1.png", 69 }, { 70 "checksumAlgorithm" : "bitmap-64bitMD5", 71 "checksumValue" : 15939355025996362179, 72 "comparisonResult" : "failed", 73 "filepath" : "red_skp-tile2.png", 74 }, { 75 "checksumAlgorithm" : "bitmap-64bitMD5", 76 "checksumValue" : 649771916797529222, 77 "comparisonResult" : "failed", 78 "filepath" : "red_skp-tile3.png", 79 }, { 80 "checksumAlgorithm" : "bitmap-64bitMD5", 81 "checksumValue" : 8132820002266077288, 82 "comparisonResult" : "failed", 83 "filepath" : "red_skp-tile4.png", 84 }, { 85 "checksumAlgorithm" : "bitmap-64bitMD5", 86 "checksumValue" : 2406160701181324581, 87 "comparisonResult" : "failed", 88 "filepath" : "red_skp-tile5.png", 89 }] 90 91 # Manually verified these 6 images, all 256x256 tiles, 92 # consistent with a tiled version of the 640x400 green rect 93 # with black borders. 94 # Standard expectations will be set up in such a way that these images pass 95 # the comparison. 96 GREEN_TILES = [{ 97 "checksumAlgorithm" : "bitmap-64bitMD5", 98 "checksumValue" : 12587324416545178013, 99 "comparisonResult" : "succeeded", 100 "filepath" : "green_skp-tile0.png", 101 }, { 102 "checksumAlgorithm" : "bitmap-64bitMD5", 103 "checksumValue" : 7624374914829746293, 104 "comparisonResult" : "succeeded", 105 "filepath" : "green_skp-tile1.png", 106 }, { 107 "checksumAlgorithm" : "bitmap-64bitMD5", 108 "checksumValue" : 11866144860997809880, 109 "comparisonResult" : "succeeded", 110 "filepath" : "green_skp-tile2.png", 111 }, { 112 "checksumAlgorithm" : "bitmap-64bitMD5", 113 "checksumValue" : 3893392565127823822, 114 "comparisonResult" : "succeeded", 115 "filepath" : "green_skp-tile3.png", 116 }, { 117 "checksumAlgorithm" : "bitmap-64bitMD5", 118 "checksumValue" : 2083084978343901738, 119 "comparisonResult" : "succeeded", 120 "filepath" : "green_skp-tile4.png", 121 }, { 122 "checksumAlgorithm" : "bitmap-64bitMD5", 123 "checksumValue" : 89620927366502076, 124 "comparisonResult" : "succeeded", 125 "filepath" : "green_skp-tile5.png", 126 }] 127 128 129 def modified_dict(input_dict, modification_dict): 130 """Returns a dict, with some modifications applied to it. 131 132 Args: 133 input_dict: a dictionary (which will be copied, not modified in place) 134 modification_dict: a set of key/value pairs to overwrite in the dict 135 """ 136 output_dict = input_dict.copy() 137 output_dict.update(modification_dict) 138 return output_dict 139 140 141 def modified_list_of_dicts(input_list, modification_dict): 142 """Returns a list of dicts, with some modifications applied to each dict. 143 144 Args: 145 input_list: a list of dictionaries; these dicts will be copied, not 146 modified in place 147 modification_dict: a set of key/value pairs to overwrite in each dict 148 within input_list 149 """ 150 output_list = [] 151 for input_dict in input_list: 152 output_dict = modified_dict(input_dict, modification_dict) 153 output_list.append(output_dict) 154 return output_list 155 156 157 class RenderPicturesTest(base_unittest.TestCase): 158 159 def setUp(self): 160 self.maxDiff = MAX_DIFF_LENGTH 161 self._expectations_dir = tempfile.mkdtemp() 162 self._input_skp_dir = tempfile.mkdtemp() 163 # All output of render_pictures binary will go into this directory. 164 self._output_dir = tempfile.mkdtemp() 165 166 def tearDown(self): 167 shutil.rmtree(self._expectations_dir) 168 shutil.rmtree(self._input_skp_dir) 169 shutil.rmtree(self._output_dir) 170 171 def test_tiled_whole_image(self): 172 """Run render_pictures with tiles and --writeWholeImage flag. 173 174 TODO(epoger): This test generates undesired results! The JSON summary 175 includes both whole-image and tiled-images (as it should), but only 176 whole-images are written out to disk. See http://skbug.com/2463 177 Once I fix that, I should add a similar test that exercises mismatchPath. 178 179 TODO(epoger): I noticed that when this is run without --writePath being 180 specified, this test writes red_skp.png and green_skp.png to the current 181 directory. We should fix that... if --writePath is not specified, this 182 probably shouldn't write out red_skp.png and green_skp.png at all! 183 See http://skbug.com/2464 184 """ 185 output_json_path = os.path.join(self._output_dir, 'actuals.json') 186 write_path_dir = self.create_empty_dir( 187 path=os.path.join(self._output_dir, 'writePath')) 188 self._generate_skps() 189 expectations_path = self._create_expectations() 190 self._run_render_pictures([ 191 '-r', self._input_skp_dir, 192 '--bbh', 'grid', '256', '256', 193 '--mode', 'tile', '256', '256', 194 '--readJsonSummaryPath', expectations_path, 195 '--writeJsonSummaryPath', output_json_path, 196 '--writePath', write_path_dir, 197 '--writeWholeImage']) 198 expected_summary_dict = { 199 "header" : EXPECTED_HEADER_CONTENTS, 200 "image-base-gs-url" : None, 201 "descriptions" : None, 202 "actual-results" : { 203 "red.skp": { 204 "tiled-images": RED_TILES, 205 "whole-image": RED_WHOLEIMAGE, 206 }, 207 "green.skp": { 208 "tiled-images": GREEN_TILES, 209 "whole-image": GREEN_WHOLEIMAGE, 210 } 211 } 212 } 213 self._assert_json_contents(output_json_path, expected_summary_dict) 214 self._assert_directory_contents( 215 write_path_dir, ['red_skp.png', 'green_skp.png']) 216 217 def test_ignore_some_failures(self): 218 """test_tiled_whole_image, but ignoring some failed tests. 219 """ 220 output_json_path = os.path.join(self._output_dir, 'actuals.json') 221 write_path_dir = self.create_empty_dir( 222 path=os.path.join(self._output_dir, 'writePath')) 223 self._generate_skps() 224 expectations_path = self._create_expectations(ignore_some_failures=True) 225 self._run_render_pictures([ 226 '-r', self._input_skp_dir, 227 '--bbh', 'grid', '256', '256', 228 '--mode', 'tile', '256', '256', 229 '--readJsonSummaryPath', expectations_path, 230 '--writeJsonSummaryPath', output_json_path, 231 '--writePath', write_path_dir, 232 '--writeWholeImage']) 233 modified_red_tiles = copy.deepcopy(RED_TILES) 234 modified_red_tiles[5]['comparisonResult'] = 'failure-ignored' 235 expected_summary_dict = { 236 "header" : EXPECTED_HEADER_CONTENTS, 237 "image-base-gs-url" : None, 238 "descriptions" : None, 239 "actual-results" : { 240 "red.skp": { 241 "tiled-images": modified_red_tiles, 242 "whole-image": modified_dict( 243 RED_WHOLEIMAGE, {"comparisonResult" : "failure-ignored"}), 244 }, 245 "green.skp": { 246 "tiled-images": GREEN_TILES, 247 "whole-image": GREEN_WHOLEIMAGE, 248 } 249 } 250 } 251 self._assert_json_contents(output_json_path, expected_summary_dict) 252 self._assert_directory_contents( 253 write_path_dir, ['red_skp.png', 'green_skp.png']) 254 255 def test_missing_tile_and_whole_image(self): 256 """test_tiled_whole_image, but missing expectations for some images. 257 """ 258 output_json_path = os.path.join(self._output_dir, 'actuals.json') 259 write_path_dir = self.create_empty_dir( 260 path=os.path.join(self._output_dir, 'writePath')) 261 self._generate_skps() 262 expectations_path = self._create_expectations(missing_some_images=True) 263 self._run_render_pictures([ 264 '-r', self._input_skp_dir, 265 '--bbh', 'grid', '256', '256', 266 '--mode', 'tile', '256', '256', 267 '--readJsonSummaryPath', expectations_path, 268 '--writeJsonSummaryPath', output_json_path, 269 '--writePath', write_path_dir, 270 '--writeWholeImage']) 271 modified_red_tiles = copy.deepcopy(RED_TILES) 272 modified_red_tiles[5]['comparisonResult'] = 'no-comparison' 273 expected_summary_dict = { 274 "header" : EXPECTED_HEADER_CONTENTS, 275 "image-base-gs-url" : None, 276 "descriptions" : None, 277 "actual-results" : { 278 "red.skp": { 279 "tiled-images": modified_red_tiles, 280 "whole-image": modified_dict( 281 RED_WHOLEIMAGE, {"comparisonResult" : "no-comparison"}), 282 }, 283 "green.skp": { 284 "tiled-images": GREEN_TILES, 285 "whole-image": GREEN_WHOLEIMAGE, 286 } 287 } 288 } 289 self._assert_json_contents(output_json_path, expected_summary_dict) 290 291 def _test_untiled(self, expectations_path=None, expected_summary_dict=None, 292 additional_args=None): 293 """Base for multiple tests without tiles. 294 295 Args: 296 expectations_path: path we should pass using --readJsonSummaryPath, or 297 None if we should create the default expectations file 298 expected_summary_dict: dict we should compare against the output actual 299 results summary, or None if we should use a default comparison dict 300 additional_args: array of command-line args to add when we run 301 render_pictures 302 """ 303 output_json_path = os.path.join(self._output_dir, 'actuals.json') 304 write_path_dir = self.create_empty_dir( 305 path=os.path.join(self._output_dir, 'writePath')) 306 self._generate_skps() 307 if expectations_path == None: 308 expectations_path = self._create_expectations() 309 args = [ 310 '-r', self._input_skp_dir, 311 '--readJsonSummaryPath', expectations_path, 312 '--writePath', write_path_dir, 313 '--writeJsonSummaryPath', output_json_path, 314 ] 315 if additional_args: 316 args.extend(additional_args) 317 self._run_render_pictures(args) 318 if expected_summary_dict == None: 319 expected_summary_dict = { 320 "header" : EXPECTED_HEADER_CONTENTS, 321 "image-base-gs-url" : None, 322 "descriptions" : None, 323 "actual-results" : { 324 "red.skp": { 325 "whole-image": RED_WHOLEIMAGE, 326 }, 327 "green.skp": { 328 "whole-image": GREEN_WHOLEIMAGE, 329 } 330 } 331 } 332 self._assert_json_contents(output_json_path, expected_summary_dict) 333 self._assert_directory_contents( 334 write_path_dir, ['red_skp.png', 'green_skp.png']) 335 336 def test_untiled(self): 337 """Basic test without tiles.""" 338 self._test_untiled() 339 340 def test_untiled_empty_expectations_file(self): 341 """Same as test_untiled, but with an empty expectations file.""" 342 expectations_path = os.path.join(self._expectations_dir, 'empty') 343 with open(expectations_path, 'w'): 344 pass 345 expected_summary_dict = { 346 "header" : EXPECTED_HEADER_CONTENTS, 347 "image-base-gs-url" : None, 348 "descriptions" : None, 349 "actual-results" : { 350 "red.skp": { 351 "whole-image": modified_dict( 352 RED_WHOLEIMAGE, {"comparisonResult" : "no-comparison"}), 353 }, 354 "green.skp": { 355 "whole-image": modified_dict( 356 GREEN_WHOLEIMAGE, {"comparisonResult" : "no-comparison"}), 357 } 358 } 359 } 360 self._test_untiled(expectations_path=expectations_path, 361 expected_summary_dict=expected_summary_dict) 362 363 def test_untiled_writeChecksumBasedFilenames(self): 364 """Same as test_untiled, but with --writeChecksumBasedFilenames.""" 365 output_json_path = os.path.join(self._output_dir, 'actuals.json') 366 write_path_dir = self.create_empty_dir( 367 path=os.path.join(self._output_dir, 'writePath')) 368 self._generate_skps() 369 self._run_render_pictures([ 370 '-r', self._input_skp_dir, 371 '--descriptions', 'builder=builderName', 'renderMode=renderModeName', 372 '--writeChecksumBasedFilenames', 373 '--writePath', write_path_dir, 374 '--writeJsonSummaryPath', output_json_path, 375 ]) 376 expected_summary_dict = { 377 "header" : EXPECTED_HEADER_CONTENTS, 378 "image-base-gs-url" : None, 379 "descriptions" : { 380 "builder": "builderName", 381 "renderMode": "renderModeName", 382 }, 383 "actual-results" : { 384 "red.skp": { 385 # Manually verified: 640x400 red rectangle with black border 386 "whole-image": { 387 "checksumAlgorithm" : "bitmap-64bitMD5", 388 "checksumValue" : 2853310525600416231, 389 "comparisonResult" : "no-comparison", 390 "filepath" : 391 "red_skp/bitmap-64bitMD5_2853310525600416231.png", 392 }, 393 }, 394 "green.skp": { 395 # Manually verified: 640x400 green rectangle with black border 396 "whole-image": { 397 "checksumAlgorithm" : "bitmap-64bitMD5", 398 "checksumValue" : 11143979097452425335, 399 "comparisonResult" : "no-comparison", 400 "filepath" : 401 "green_skp/bitmap-64bitMD5_11143979097452425335.png", 402 }, 403 } 404 } 405 } 406 self._assert_json_contents(output_json_path, expected_summary_dict) 407 self._assert_directory_contents(write_path_dir, ['red_skp', 'green_skp']) 408 self._assert_directory_contents( 409 os.path.join(write_path_dir, 'red_skp'), 410 ['bitmap-64bitMD5_2853310525600416231.png']) 411 self._assert_directory_contents( 412 os.path.join(write_path_dir, 'green_skp'), 413 ['bitmap-64bitMD5_11143979097452425335.png']) 414 415 def test_untiled_validate(self): 416 """Same as test_untiled, but with --validate.""" 417 self._test_untiled(additional_args=['--validate']) 418 419 def test_untiled_without_writePath(self): 420 """Same as test_untiled, but without --writePath.""" 421 output_json_path = os.path.join(self._output_dir, 'actuals.json') 422 self._generate_skps() 423 expectations_path = self._create_expectations() 424 self._run_render_pictures([ 425 '-r', self._input_skp_dir, 426 '--readJsonSummaryPath', expectations_path, 427 '--writeJsonSummaryPath', output_json_path]) 428 expected_summary_dict = { 429 "header" : EXPECTED_HEADER_CONTENTS, 430 "image-base-gs-url" : None, 431 "descriptions" : None, 432 "actual-results" : { 433 "red.skp": { 434 "whole-image": RED_WHOLEIMAGE, 435 }, 436 "green.skp": { 437 "whole-image": GREEN_WHOLEIMAGE, 438 } 439 } 440 } 441 self._assert_json_contents(output_json_path, expected_summary_dict) 442 443 def test_tiled(self): 444 """Generate individual tiles.""" 445 output_json_path = os.path.join(self._output_dir, 'actuals.json') 446 write_path_dir = self.create_empty_dir( 447 path=os.path.join(self._output_dir, 'writePath')) 448 self._generate_skps() 449 expectations_path = self._create_expectations() 450 self._run_render_pictures([ 451 '-r', self._input_skp_dir, 452 '--bbh', 'grid', '256', '256', 453 '--mode', 'tile', '256', '256', 454 '--readJsonSummaryPath', expectations_path, 455 '--writePath', write_path_dir, 456 '--writeJsonSummaryPath', output_json_path]) 457 expected_summary_dict = { 458 "header" : EXPECTED_HEADER_CONTENTS, 459 "image-base-gs-url" : None, 460 "descriptions" : None, 461 "actual-results" : { 462 "red.skp": { 463 "tiled-images": RED_TILES, 464 }, 465 "green.skp": { 466 "tiled-images": GREEN_TILES, 467 } 468 } 469 } 470 self._assert_json_contents(output_json_path, expected_summary_dict) 471 self._assert_directory_contents( 472 write_path_dir, 473 ['red_skp-tile0.png', 'red_skp-tile1.png', 'red_skp-tile2.png', 474 'red_skp-tile3.png', 'red_skp-tile4.png', 'red_skp-tile5.png', 475 'green_skp-tile0.png', 'green_skp-tile1.png', 'green_skp-tile2.png', 476 'green_skp-tile3.png', 'green_skp-tile4.png', 'green_skp-tile5.png', 477 ]) 478 479 def test_tiled_mismatches(self): 480 """Same as test_tiled, but only write out mismatching images.""" 481 output_json_path = os.path.join(self._output_dir, 'actuals.json') 482 mismatch_path_dir = self.create_empty_dir( 483 path=os.path.join(self._output_dir, 'mismatchPath')) 484 self._generate_skps() 485 expectations_path = self._create_expectations() 486 self._run_render_pictures([ 487 '-r', self._input_skp_dir, 488 '--bbh', 'grid', '256', '256', 489 '--mode', 'tile', '256', '256', 490 '--readJsonSummaryPath', expectations_path, 491 '--mismatchPath', mismatch_path_dir, 492 '--writeJsonSummaryPath', output_json_path]) 493 expected_summary_dict = { 494 "header" : EXPECTED_HEADER_CONTENTS, 495 "image-base-gs-url" : None, 496 "descriptions" : None, 497 "actual-results" : { 498 "red.skp": { 499 "tiled-images": RED_TILES, 500 }, 501 "green.skp": { 502 "tiled-images": GREEN_TILES, 503 } 504 } 505 } 506 self._assert_json_contents(output_json_path, expected_summary_dict) 507 self._assert_directory_contents( 508 mismatch_path_dir, 509 ['red_skp-tile0.png', 'red_skp-tile1.png', 'red_skp-tile2.png', 510 'red_skp-tile3.png', 'red_skp-tile4.png', 'red_skp-tile5.png', 511 ]) 512 513 def test_tiled_writeChecksumBasedFilenames(self): 514 """Same as test_tiled, but with --writeChecksumBasedFilenames.""" 515 output_json_path = os.path.join(self._output_dir, 'actuals.json') 516 write_path_dir = self.create_empty_dir( 517 path=os.path.join(self._output_dir, 'writePath')) 518 self._generate_skps() 519 self._run_render_pictures(['-r', self._input_skp_dir, 520 '--bbh', 'grid', '256', '256', 521 '--mode', 'tile', '256', '256', 522 '--writeChecksumBasedFilenames', 523 '--writePath', write_path_dir, 524 '--writeJsonSummaryPath', output_json_path]) 525 expected_summary_dict = { 526 "header" : EXPECTED_HEADER_CONTENTS, 527 "image-base-gs-url" : None, 528 "descriptions" : None, 529 "actual-results" : { 530 "red.skp": { 531 # Manually verified these 6 images, all 256x256 tiles, 532 # consistent with a tiled version of the 640x400 red rect 533 # with black borders. 534 "tiled-images": [{ 535 "checksumAlgorithm" : "bitmap-64bitMD5", 536 "checksumValue" : 5815827069051002745, 537 "comparisonResult" : "no-comparison", 538 "filepath" : 539 "red_skp/bitmap-64bitMD5_5815827069051002745.png", 540 }, { 541 "checksumAlgorithm" : "bitmap-64bitMD5", 542 "checksumValue" : 9323613075234140270, 543 "comparisonResult" : "no-comparison", 544 "filepath" : 545 "red_skp/bitmap-64bitMD5_9323613075234140270.png", 546 }, { 547 "checksumAlgorithm" : "bitmap-64bitMD5", 548 "checksumValue" : 15939355025996362179, 549 "comparisonResult" : "no-comparison", 550 "filepath" : 551 "red_skp/bitmap-64bitMD5_15939355025996362179.png", 552 }, { 553 "checksumAlgorithm" : "bitmap-64bitMD5", 554 "checksumValue" : 649771916797529222, 555 "comparisonResult" : "no-comparison", 556 "filepath" : 557 "red_skp/bitmap-64bitMD5_649771916797529222.png", 558 }, { 559 "checksumAlgorithm" : "bitmap-64bitMD5", 560 "checksumValue" : 8132820002266077288, 561 "comparisonResult" : "no-comparison", 562 "filepath" : 563 "red_skp/bitmap-64bitMD5_8132820002266077288.png", 564 }, { 565 "checksumAlgorithm" : "bitmap-64bitMD5", 566 "checksumValue" : 2406160701181324581, 567 "comparisonResult" : "no-comparison", 568 "filepath" : 569 "red_skp/bitmap-64bitMD5_2406160701181324581.png", 570 }], 571 }, 572 "green.skp": { 573 # Manually verified these 6 images, all 256x256 tiles, 574 # consistent with a tiled version of the 640x400 green rect 575 # with black borders. 576 "tiled-images": [{ 577 "checksumAlgorithm" : "bitmap-64bitMD5", 578 "checksumValue" : 12587324416545178013, 579 "comparisonResult" : "no-comparison", 580 "filepath" : 581 "green_skp/bitmap-64bitMD5_12587324416545178013.png", 582 }, { 583 "checksumAlgorithm" : "bitmap-64bitMD5", 584 "checksumValue" : 7624374914829746293, 585 "comparisonResult" : "no-comparison", 586 "filepath" : 587 "green_skp/bitmap-64bitMD5_7624374914829746293.png", 588 }, { 589 "checksumAlgorithm" : "bitmap-64bitMD5", 590 "checksumValue" : 11866144860997809880, 591 "comparisonResult" : "no-comparison", 592 "filepath" : 593 "green_skp/bitmap-64bitMD5_11866144860997809880.png", 594 }, { 595 "checksumAlgorithm" : "bitmap-64bitMD5", 596 "checksumValue" : 3893392565127823822, 597 "comparisonResult" : "no-comparison", 598 "filepath" : 599 "green_skp/bitmap-64bitMD5_3893392565127823822.png", 600 }, { 601 "checksumAlgorithm" : "bitmap-64bitMD5", 602 "checksumValue" : 2083084978343901738, 603 "comparisonResult" : "no-comparison", 604 "filepath" : 605 "green_skp/bitmap-64bitMD5_2083084978343901738.png", 606 }, { 607 "checksumAlgorithm" : "bitmap-64bitMD5", 608 "checksumValue" : 89620927366502076, 609 "comparisonResult" : "no-comparison", 610 "filepath" : 611 "green_skp/bitmap-64bitMD5_89620927366502076.png", 612 }], 613 } 614 } 615 } 616 self._assert_json_contents(output_json_path, expected_summary_dict) 617 self._assert_directory_contents(write_path_dir, ['red_skp', 'green_skp']) 618 self._assert_directory_contents( 619 os.path.join(write_path_dir, 'red_skp'), 620 ['bitmap-64bitMD5_5815827069051002745.png', 621 'bitmap-64bitMD5_9323613075234140270.png', 622 'bitmap-64bitMD5_15939355025996362179.png', 623 'bitmap-64bitMD5_649771916797529222.png', 624 'bitmap-64bitMD5_8132820002266077288.png', 625 'bitmap-64bitMD5_2406160701181324581.png']) 626 self._assert_directory_contents( 627 os.path.join(write_path_dir, 'green_skp'), 628 ['bitmap-64bitMD5_12587324416545178013.png', 629 'bitmap-64bitMD5_7624374914829746293.png', 630 'bitmap-64bitMD5_11866144860997809880.png', 631 'bitmap-64bitMD5_3893392565127823822.png', 632 'bitmap-64bitMD5_2083084978343901738.png', 633 'bitmap-64bitMD5_89620927366502076.png']) 634 635 def _run_render_pictures(self, args): 636 binary = find_run_binary.find_path_to_program('render_pictures') 637 return find_run_binary.run_command( 638 [binary, '--config', '8888'] + args) 639 640 def _create_expectations(self, missing_some_images=False, 641 ignore_some_failures=False, 642 rel_path='expectations.json'): 643 """Creates expectations JSON file within self._expectations_dir . 644 645 Args: 646 missing_some_images: (bool) whether to remove expectations for a subset 647 of the images 648 ignore_some_failures: (bool) whether to ignore some failing tests 649 rel_path: (string) relative path within self._expectations_dir to write 650 the expectations into 651 652 Returns: full path to the expectations file created. 653 """ 654 expectations_dict = { 655 "header" : EXPECTED_HEADER_CONTENTS, 656 "descriptions" : None, 657 "expected-results" : { 658 # red.skp: these should fail the comparison 659 "red.skp": { 660 "tiled-images": modified_list_of_dicts( 661 RED_TILES, {'checksumValue': 11111}), 662 "whole-image": modified_dict( 663 RED_WHOLEIMAGE, {'checksumValue': 22222}), 664 }, 665 # green.skp: these should pass the comparison 666 "green.skp": { 667 "tiled-images": GREEN_TILES, 668 "whole-image": GREEN_WHOLEIMAGE, 669 } 670 } 671 } 672 if missing_some_images: 673 red_subdict = expectations_dict['expected-results']['red.skp'] 674 del red_subdict['whole-image'] 675 del red_subdict['tiled-images'][-1] 676 elif ignore_some_failures: 677 red_subdict = expectations_dict['expected-results']['red.skp'] 678 red_subdict['whole-image']['ignoreFailure'] = True 679 red_subdict['tiled-images'][-1]['ignoreFailure'] = True 680 path = os.path.join(self._expectations_dir, rel_path) 681 with open(path, 'w') as fh: 682 json.dump(expectations_dict, fh) 683 return path 684 685 def _generate_skps(self): 686 """Runs the skpmaker binary to generate files in self._input_skp_dir.""" 687 self._run_skpmaker( 688 output_path=os.path.join(self._input_skp_dir, 'red.skp'), red=255) 689 self._run_skpmaker( 690 output_path=os.path.join(self._input_skp_dir, 'green.skp'), green=255) 691 692 def _run_skpmaker(self, output_path, red=0, green=0, blue=0, 693 width=640, height=400): 694 """Runs the skpmaker binary to generate SKP with known characteristics. 695 696 Args: 697 output_path: Filepath to write the SKP into. 698 red: Value of red color channel in image, 0-255. 699 green: Value of green color channel in image, 0-255. 700 blue: Value of blue color channel in image, 0-255. 701 width: Width of canvas to create. 702 height: Height of canvas to create. 703 """ 704 binary = find_run_binary.find_path_to_program('skpmaker') 705 return find_run_binary.run_command([ 706 binary, 707 '--red', str(red), 708 '--green', str(green), 709 '--blue', str(blue), 710 '--width', str(width), 711 '--height', str(height), 712 '--writePath', str(output_path), 713 ]) 714 715 def _assert_directory_contents(self, dir_path, expected_filenames): 716 """Asserts that files found in a dir are identical to expected_filenames. 717 718 Args: 719 dir_path: Path to a directory on local disk. 720 expected_filenames: Set containing the expected filenames within the dir. 721 722 Raises: 723 AssertionError: contents of the directory are not identical to 724 expected_filenames. 725 """ 726 self.assertEqual(set(os.listdir(dir_path)), set(expected_filenames)) 727 728 def _assert_json_contents(self, json_path, expected_dict): 729 """Asserts that contents of a JSON file are identical to expected_dict. 730 731 Args: 732 json_path: Path to a JSON file. 733 expected_dict: Dictionary indicating the expected contents of the JSON 734 file. 735 736 Raises: 737 AssertionError: contents of the JSON file are not identical to 738 expected_dict. 739 """ 740 prettyprinted_expected_dict = json.dumps(expected_dict, sort_keys=True, 741 indent=2) 742 with open(json_path, 'r') as fh: 743 prettyprinted_json_dict = json.dumps(json.load(fh), sort_keys=True, 744 indent=2) 745 self.assertMultiLineEqual(prettyprinted_expected_dict, 746 prettyprinted_json_dict) 747 748 749 def main(): 750 base_unittest.main(RenderPicturesTest) 751 752 753 if __name__ == '__main__': 754 main() 755