1#!/usr/bin/env python 2# Copyright 2015 The PDFium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import distutils.spawn 7import itertools 8import os 9import shutil 10import sys 11 12# pylint: disable=relative-import 13import common 14 15 16class PNGDiffer(): 17 18 def __init__(self, finder, reverse_byte_order): 19 self.pdfium_diff_path = finder.ExecutablePath('pdfium_diff') 20 self.os_name = finder.os_name 21 self.reverse_byte_order = reverse_byte_order 22 23 def CheckMissingTools(self, regenerate_expected): 24 if (regenerate_expected and self.os_name == 'linux' and 25 not distutils.spawn.find_executable('optipng')): 26 return 'Please install "optipng" to regenerate expected images.' 27 return None 28 29 def GetActualFiles(self, input_filename, source_dir, working_dir): 30 actual_paths = [] 31 path_templates = PathTemplates(input_filename, source_dir, working_dir) 32 33 for page in itertools.count(): 34 actual_path = path_templates.GetActualPath(page) 35 expected_path = path_templates.GetExpectedPath(page) 36 platform_expected_path = path_templates.GetPlatformExpectedPath( 37 self.os_name, page) 38 if os.path.exists(platform_expected_path): 39 expected_path = platform_expected_path 40 elif not os.path.exists(expected_path): 41 break 42 actual_paths.append(actual_path) 43 44 return actual_paths 45 46 def HasDifferences(self, input_filename, source_dir, working_dir): 47 path_templates = PathTemplates(input_filename, source_dir, working_dir) 48 49 for page in itertools.count(): 50 actual_path = path_templates.GetActualPath(page) 51 expected_path = path_templates.GetExpectedPath(page) 52 # PDFium tests should be platform independent. Platform based results are 53 # used to capture platform dependent implementations. 54 platform_expected_path = path_templates.GetPlatformExpectedPath( 55 self.os_name, page) 56 if (not os.path.exists(expected_path) and 57 not os.path.exists(platform_expected_path)): 58 if page == 0: 59 print "WARNING: no expected results files for " + input_filename 60 if os.path.exists(actual_path): 61 print('FAILURE: Missing expected result for 0-based page %d of %s' % 62 (page, input_filename)) 63 return True 64 break 65 print "Checking " + actual_path 66 sys.stdout.flush() 67 if os.path.exists(expected_path): 68 cmd = [self.pdfium_diff_path] 69 if self.reverse_byte_order: 70 cmd.append('--reverse-byte-order') 71 cmd.extend([expected_path, actual_path]) 72 error = common.RunCommand(cmd) 73 else: 74 error = 1 75 if error: 76 # When failed, we check against platform based results. 77 if os.path.exists(platform_expected_path): 78 cmd = [self.pdfium_diff_path] 79 if self.reverse_byte_order: 80 cmd.append('--reverse-byte-order') 81 cmd.extend([platform_expected_path, actual_path]) 82 error = common.RunCommand(cmd) 83 if error: 84 print "FAILURE: " + input_filename + "; " + str(error) 85 return True 86 87 return False 88 89 def Regenerate(self, input_filename, source_dir, working_dir, platform_only): 90 path_templates = PathTemplates(input_filename, source_dir, working_dir) 91 92 for page in itertools.count(): 93 # Loop through the generated page images. Stop when there is a page 94 # missing a png, which means the document ended. 95 actual_path = path_templates.GetActualPath(page) 96 if not os.path.isfile(actual_path): 97 break 98 99 platform_expected_path = path_templates.GetPlatformExpectedPath( 100 self.os_name, page) 101 102 # If there is a platform expected png, we will overwrite it. Otherwise, 103 # overwrite the generic png in "all" mode, or do nothing in "platform" 104 # mode. 105 if os.path.exists(platform_expected_path): 106 expected_path = platform_expected_path 107 elif not platform_only: 108 expected_path = path_templates.GetExpectedPath(page) 109 else: 110 continue 111 112 shutil.copyfile(actual_path, expected_path) 113 common.RunCommand(['optipng', expected_path]) 114 115 116ACTUAL_TEMPLATE = '.pdf.%d.png' 117EXPECTED_TEMPLATE = '_expected' + ACTUAL_TEMPLATE 118PLATFORM_EXPECTED_TEMPLATE = '_expected_%s' + ACTUAL_TEMPLATE 119 120 121class PathTemplates(object): 122 123 def __init__(self, input_filename, source_dir, working_dir): 124 input_root, _ = os.path.splitext(input_filename) 125 self.actual_path_template = os.path.join(working_dir, 126 input_root + ACTUAL_TEMPLATE) 127 self.expected_path = os.path.join(source_dir, 128 input_root + EXPECTED_TEMPLATE) 129 self.platform_expected_path = os.path.join( 130 source_dir, input_root + PLATFORM_EXPECTED_TEMPLATE) 131 132 def GetActualPath(self, page): 133 return self.actual_path_template % page 134 135 def GetExpectedPath(self, page): 136 return self.expected_path % page 137 138 def GetPlatformExpectedPath(self, platform, page): 139 return self.platform_expected_path % (platform, page) 140