Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(384)

Side by Side Diff: testing/tools/test_runner.py

Issue 1430623006: One test runner to rule them all. (Closed) Base URL: https://pdfium.googlesource.com/pdfium.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « testing/tools/run_pixel_tests.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
6 import cStringIO
7 import functools
8 import multiprocessing
9 import optparse
10 import os
11 import re
12 import shutil
13 import subprocess
14 import sys
15
16 import common
17 import pngdiffer
18 import suppressor
19
20 class KeyboardInterruptError(Exception): pass
21
22 # Nomenclature:
23 # x_root - "x"
24 # x_filename - "x.ext"
25 # x_path - "path/to/a/b/c/x.ext"
26 # c_dir - "path/to/a/b/c"
27
28 def TestOneFileParallel(this, test_case):
29 """Wrapper function to call GenerateAndTest() and redirect output
30 to stdout."""
31 try:
32 old_stdout = sys.stdout
33 old_stderr = sys.stderr
34 sys.stdout = cStringIO.StringIO()
35 sys.stderr = sys.stdout
36
37 input_filename, source_dir = test_case
38 result = this.GenerateAndTest(input_filename, source_dir, True);
39
40 output = sys.stdout
41 sys.stdout = old_stdout
42 sys.stderr = old_stderr
43 return (result, output.getvalue(), input_filename, source_dir)
44 except KeyboardInterrupt:
45 raise KeyboardInterruptError()
46
47
48 class TestRunner:
49 def __init__(self, dirname):
50 self.test_dir = dirname
51
52
53 def GenerateAndTest(self, input_filename, source_dir, redirect_output=False):
54 input_root, _ = os.path.splitext(input_filename)
55 expected_txt_path = os.path.join(source_dir, input_root + '_expected.txt')
56
57 pdf_path = os.path.join(self.working_dir, input_root + '.pdf')
58
59 # Remove any existing generated images from previous runs.
60 actual_images = self.image_differ.GetActualFiles(input_filename, source_dir,
61 self.working_dir)
62 for image in actual_images:
63 if os.path.exists(image):
64 os.remove(image)
65
66 sys.stdout.flush()
67
68 raised_exception = self.Generate(source_dir, input_filename, input_root,
69 pdf_path, redirect_output)
70
71 if raised_exception != None:
72 print "FAILURE: " + input_filename + "; " + str(raised_exception)
73 return False
74
75 if os.path.exists(expected_txt_path):
76 raised_exception = self.TestText(input_root, expected_txt_path, pdf_path,
77 redirect_output)
78 else:
79 raised_exception = self.TestPixel(pdf_path, redirect_output)
80
81 if raised_exception != None:
82 print "FAILURE: " + input_filename + "; " + str(raised_exception)
83 return False
84
85 if len(actual_images):
86 if self.image_differ.HasDifferences(input_filename, source_dir,
87 self.working_dir, redirect_output):
88 return False
89
90 return True
91
92
93 def Generate(self, source_dir, input_filename, input_root, pdf_path,
94 redirect_output):
95 original_path = os.path.join(source_dir, input_filename)
96 input_path = os.path.join(source_dir, input_root + '.in')
97
98 if os.path.exists(original_path) and not os.path.exists(input_path):
99 shutil.copyfile(original_path, pdf_path)
100
101 if not os.path.exists(input_path):
102 return None
103
104 cmd = [sys.executable, self.fixup_path,
105 '--output-dir=' + self.working_dir, input_path]
106 return common.RunCommand(cmd, redirect_output)
107
108
109 def TestText(self, input_root, expected_txt_path, pdf_path, redirect_output):
110 txt_path = os.path.join(self.working_dir, input_root + '.txt')
111 with open(txt_path, 'w') as outfile:
112 subprocess.check_call([self.pdfium_test_path, pdf_path], stdout=outfile)
113
114 cmd = [sys.executable, self.text_diff_path, expected_txt_path, txt_path]
115 return common.RunCommand(cmd, redirect_output)
116
117
118 def TestPixel(self, pdf_path, redirect_output):
119 return common.RunCommand(
120 [self.pdfium_test_path, '--png', pdf_path], redirect_output)
121
122
123 def HandleResult(self, input_filename, input_path, result):
124 if self.test_suppressor.IsSuppressed(input_filename):
125 if result:
126 self.surprises.append(input_path)
127 else:
128 if not result:
129 self.failures.append(input_path)
130
131
132 def Run(self):
133 parser = optparse.OptionParser()
134 parser.add_option('--build-dir', default=os.path.join('out', 'Debug'),
135 help='relative path from the base source directory')
136 parser.add_option('-j', default=multiprocessing.cpu_count(),
137 dest='num_workers', type='int',
138 help='run NUM_WORKERS jobs in parallel')
139 options, args = parser.parse_args()
140
141 finder = common.DirectoryFinder(options.build_dir)
142 self.fixup_path = finder.ScriptPath('fixup_pdf_template.py')
143 self.text_diff_path = finder.ScriptPath('text_diff.py')
144
145 self.source_dir = finder.TestingDir()
146
147 if self.test_dir != 'corpus':
148 test_dir = finder.TestingDir(os.path.join('resources', self.test_dir))
149 else:
150 test_dir = finder.TestingDir(self.test_dir)
151
152 self.pdfium_test_path = finder.ExecutablePath('pdfium_test')
153 if not os.path.exists(self.pdfium_test_path):
154 print "FAILURE: Can't find test executable '%s'" % self.pdfium_test_path
155 print "Use --build-dir to specify its location."
156 return 1
157
158 self.working_dir = finder.WorkingDir(os.path.join('testing', self.test_dir))
159 if not os.path.exists(self.working_dir):
160 os.makedirs(self.working_dir)
161
162 self.test_suppressor = suppressor.Suppressor(finder)
163 self.image_differ = pngdiffer.PNGDiffer(finder)
164
165 walk_from_dir = finder.TestingDir(test_dir);
166
167 test_cases = []
168 input_file_re = re.compile('^[a-zA-Z0-9_.]+[.](in|pdf)$')
169
170 if len(args):
171 for file_name in args:
172 file_name.replace(".pdf", ".in")
173 input_path = os.path.join(walk_from_dir, file_name)
174 if not os.path.isfile(input_path):
175 print "Can't find test file '%s'" % file_name
176 return 1
177
178 test_cases.append((os.path.basename(input_path),
179 os.path.dirname(input_path)))
180 else:
181 for file_dir, _, filename_list in os.walk(walk_from_dir):
182 for input_filename in filename_list:
183 if input_file_re.match(input_filename):
184 input_path = os.path.join(file_dir, input_filename)
185 if os.path.isfile(input_path):
186 test_cases.append((input_filename, file_dir))
187
188 self.failures = []
189 self.surprises = []
190
191 if options.num_workers > 1 and not len(args):
192 try:
193 pool = multiprocessing.Pool(options.num_workers)
194 worker_func = functools.partial(TestOneFileParallel, self)
195
196 worker_results = pool.imap(worker_func, test_cases)
197 for worker_result in worker_results:
198 result, output, input_filename, source_dir = worker_result
199 input_path = os.path.join(source_dir, input_filename)
200 sys.stdout.write(output)
201
202 self.HandleResult(input_filename, input_path, result)
203 except KeyboardInterrupt:
204 pool.terminate()
205 finally:
206 pool.close()
207 pool.join()
208 else:
209 for test_case in test_cases:
210 input_filename, input_file_dir = test_case
211 result = self.GenerateAndTest(input_filename, input_file_dir)
212 self.HandleResult(input_filename,
213 os.path.join(input_file_dir, input_filename), result)
214
215 if self.surprises:
216 self.surprises.sort()
217 print '\n\nUnexpected Successes:'
218 for surprise in self.surprises:
219 print surprise;
220
221 if self.failures:
222 self.failures.sort()
223 print '\n\nSummary of Failures:'
224 for failure in self.failures:
225 print failure
226 return 1
227
228 return 0
229
OLDNEW
« no previous file with comments | « testing/tools/run_pixel_tests.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698