OLD | NEW |
---|---|
1 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 # Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 # for details. All rights reserved. Use of this source code is governed by a | 2 # for details. All rights reserved. Use of this source code is governed by a |
3 # BSD-style license that can be found in the LICENSE file. | 3 # BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 """Common Testconfiguration subclasses used to define a class of tests.""" | |
6 | |
5 import atexit | 7 import atexit |
6 import fileinput | 8 import fileinput |
7 import os | 9 import os |
8 import test | |
9 import platform | |
10 import re | 10 import re |
11 import shutil | 11 import shutil |
12 import sys | |
13 import tempfile | |
14 | 12 |
13 | |
14 import test | |
15 from testing import test_case | 15 from testing import test_case |
16 import test | |
17 import utils | 16 import utils |
18 | 17 |
19 from os.path import join, exists, basename | |
20 | |
21 import utils | |
22 | 18 |
23 class Error(Exception): | 19 class Error(Exception): |
24 pass | 20 pass |
25 | 21 |
22 | |
26 class TestConfigurationError(Error): | 23 class TestConfigurationError(Error): |
27 pass | 24 pass |
28 | 25 |
26 | |
29 class StandardTestConfiguration(test.TestConfiguration): | 27 class StandardTestConfiguration(test.TestConfiguration): |
28 """Configuration that looks for .dart files in the tests/*/src dirs.""" | |
ngeoffray
2011/10/13 08:03:38
*Test.dart?
zundel
2011/10/13 11:07:44
Done.
| |
30 LEGAL_KINDS = set(['compile-time error', | 29 LEGAL_KINDS = set(['compile-time error', |
31 'runtime error', | 30 'runtime error', |
32 'static type error', | 31 'static type error', |
33 'dynamic type error']) | 32 'dynamic type error']) |
34 | 33 |
35 def __init__(self, context, root): | 34 def __init__(self, context, root): |
36 super(StandardTestConfiguration, self).__init__(context, root) | 35 super(StandardTestConfiguration, self).__init__(context, root) |
37 | 36 |
38 def _cleanup(self, tests): | 37 def _Cleanup(self, tests): |
39 if self.context.keep_temporary_files: return | 38 """Remove any temporary files created by running the test.""" |
39 if self.context.keep_temporary_files: | |
40 return | |
40 | 41 |
41 dirs = [] | 42 dirs = [] |
42 for t in tests: | 43 for t in tests: |
43 if t.run_arch != None: | 44 if t.run_arch: |
44 temp_dir = t.run_arch.temp_dir | 45 temp_dir = t.run_arch.temp_dir |
45 if temp_dir != None: dirs.append(temp_dir) | 46 if temp_dir: |
46 | 47 dirs.append(temp_dir) |
47 if len(dirs) == 0: return | 48 if not dirs: |
48 if not utils.Daemonize(): return | 49 return |
49 | 50 if not utils.Daemonize(): |
51 return | |
50 os.execlp('rm', *(['rm', '-rf'] + dirs)) | 52 os.execlp('rm', *(['rm', '-rf'] + dirs)) |
51 | 53 |
52 | |
53 def CreateTestCases(self, test_path, path, filename, mode, arch): | 54 def CreateTestCases(self, test_path, path, filename, mode, arch): |
55 """Given a .dart filename, create a StandardTestCase from it.""" | |
54 tags = {} | 56 tags = {} |
55 if filename.endswith(".dart"): | 57 if filename.endswith('.dart'): |
56 tags = self.SplitMultiTest(test_path, filename) | 58 tags = self.SplitMultiTest(test_path, filename) |
57 if arch in ['dartium', 'chromium']: | 59 if arch in ['dartium', 'chromium']: |
58 if tags: | 60 if tags: |
59 return [] | 61 return [] |
60 else: | 62 else: |
61 return [test_case.BrowserTestCase( | 63 return [test_case.BrowserTestCase( |
62 self.context, test_path, filename, False, mode, arch)] | 64 self.context, test_path, filename, False, mode, arch)] |
63 else: | 65 else: |
64 tests = [] | 66 tests = [] |
65 if tags: | 67 if tags: |
66 for tag in sorted(tags): | 68 for tag in sorted(tags): |
67 kind, test_source = tags[tag] | 69 kind, test_source = tags[tag] |
68 if not self.Contains(path, test_path + [tag]): | 70 if not self.Contains(path, test_path + [tag]): |
69 continue | 71 continue |
70 tests.append(test_case.MultiTestCase(self.context, | 72 tests.append(test_case.MultiTestCase(self.context, |
71 test_path + [tag], test_source, kind, mode, arch)) | 73 test_path + [tag], |
74 test_source, | |
75 kind, | |
76 mode, arch)) | |
72 else: | 77 else: |
73 tests.append(test_case.StandardTestCase(self.context, | 78 tests.append(test_case.StandardTestCase(self.context, |
74 test_path, filename, mode, arch)) | 79 test_path, |
80 filename, | |
81 mode, arch)) | |
75 return tests | 82 return tests |
76 | 83 |
77 def ListTests(self, current_path, path, mode, arch): | 84 def ListTests(self, current_path, path, mode, arch): |
85 """Searches for .dart files that qualify and returns list of TestCases.""" | |
ngeoffray
2011/10/13 08:03:38
ditto
zundel
2011/10/13 11:07:44
Done.
| |
78 tests = [] | 86 tests = [] |
79 for root, dirs, files in os.walk(join(self.root, 'src')): | 87 for root, unused_dirs, files in os.walk(os.path.join(self.root, 'src')): |
80 for f in [x for x in files if self.IsTest(x)]: | 88 for f in [x for x in files if self.IsTest(x)]: |
81 if f.endswith(".dart"): | 89 if f.endswith('.dart'): |
82 test_path = current_path + [ f[:-5] ] # Remove .dart suffix. | 90 test_path = current_path + [f[:-5]] # Remove .dart suffix. |
83 elif f.endswith(".app"): | 91 elif f.endswith('.app'): |
84 test_path = current_path + [ f[:-4] ] # Remove .app suffix. | 92 # TODO(zundel): .app files are used only the dromaeo test |
93 # and should be removed. | |
94 test_path = current_path + [f[:-4]] # Remove .app suffix. | |
85 if not self.Contains(path, test_path): | 95 if not self.Contains(path, test_path): |
86 continue | 96 continue |
87 tests.extend(self.CreateTestCases(test_path, path, join(root, f), | 97 tests.extend(self.CreateTestCases(test_path, path, |
98 os.path.join(root, f), | |
88 mode, arch)) | 99 mode, arch)) |
89 atexit.register(lambda: self._cleanup(tests)) | 100 atexit.register(lambda: self._Cleanup(tests)) |
90 return tests | 101 return tests |
91 | 102 |
92 def IsTest(self, name): | 103 def IsTest(self, name): |
93 return name.endswith('Test.dart') or name.endswith("Test.app") | 104 """Returns True if the file name looks like a test file.""" |
ngeoffray
2011/10/13 08:03:38
looks like -> is?
zundel
2011/10/13 11:07:44
Done.
| |
105 return name.endswith('Test.dart') or name.endswith('Test.app') | |
94 | 106 |
95 def GetTestStatus(self, sections, defs): | 107 def GetTestStatus(self, sections, defs): |
96 status = join(self.root, basename(self.root) + '.status') | 108 """Populates the sections and defs parameters if the file exists.""" |
ngeoffray
2011/10/13 08:03:38
Change to """Reads the status file of the test sui
zundel
2011/10/13 11:07:44
Done.
| |
97 if exists(status): | 109 status = os.path.join(self.root, os.path.basename(self.root) + '.status') |
110 if os.path.exists(status): | |
98 test.ReadConfigurationInto(status, sections, defs) | 111 test.ReadConfigurationInto(status, sections, defs) |
99 | 112 |
100 def FindReferencedFiles(self, lines): | 113 def FindReferencedFiles(self, lines): |
114 """Scours the lines containing source code for include directives.""" | |
101 referenced_files = [] | 115 referenced_files = [] |
102 for line in lines: | 116 for line in lines: |
103 m = re.match("#(source|import)\(['\"](.*)['\"]\);", line) | 117 m = re.match("#(source|import)\(['\"](.*)['\"]\);", line) |
104 if m: | 118 if m: |
105 referenced_files.append(m.group(2)) | 119 referenced_files.append(m.group(2)) |
106 return referenced_files | 120 return referenced_files |
107 | 121 |
108 def SplitMultiTest(self, test_path, filename): | 122 def SplitMultiTest(self, test_path, filename): |
123 """Takes a file with multiple test case defined. | |
124 | |
125 Splits the file into multiple TestCase instances. | |
126 | |
127 Args: | |
128 test_path: temporary dir to write split test case data. | |
129 filename: name of the file to split. | |
130 | |
131 Returns: | |
132 sequence of test cases split from file. | |
133 | |
134 Raises: | |
135 TestConfigurationError: when a problem with the multi-test-case | |
136 syntax is encountered. | |
137 """ | |
109 (name, extension) = os.path.splitext(os.path.basename(filename)) | 138 (name, extension) = os.path.splitext(os.path.basename(filename)) |
110 with open(filename, 'r') as s: | 139 with open(filename, 'r') as s: |
111 source = s.read() | 140 source = s.read() |
112 lines = source.splitlines() | 141 lines = source.splitlines() |
113 tags = {} | 142 tags = {} |
114 for line in lines: | 143 for line in lines: |
115 (code, sep, info) = line.partition(' /// ') | 144 (unused_code, sep, info) = line.partition(' /// ') |
116 if sep: | 145 if sep: |
117 (tag, sep, kind) = info.partition(': ') | 146 (tag, sep, kind) = info.partition(': ') |
118 if tags.has_key(tag): | 147 if tag in tags: |
119 raise utils.Error('duplicated tag %s' % tag) | 148 raise TestConfigurationError('duplicated tag %s' % tag) |
120 if kind not in StandardTestConfiguration.LEGAL_KINDS: | 149 if kind not in StandardTestConfiguration.LEGAL_KINDS: |
121 raise utils.Error('unrecognized kind %s' % kind) | 150 raise TestConfigurationError('unrecognized kind %s' % kind) |
122 tags[tag] = kind | 151 tags[tag] = kind |
123 if not tags: | 152 if not tags: |
124 return {} | 153 return {} |
125 # Prepare directory for generated tests. | 154 # Prepare directory for generated tests. |
126 tests = {} | 155 tests = {} |
127 generated_test_dir = os.path.join(self.context.workspace, 'generated_tests') | 156 generated_test_dir = os.path.join(self.context.workspace, 'generated_tests') |
128 generated_test_dir = os.path.join(generated_test_dir, *test_path[:-1]) | 157 generated_test_dir = os.path.join(generated_test_dir, *test_path[:-1]) |
129 if not os.path.exists(generated_test_dir): | 158 if not os.path.exists(generated_test_dir): |
130 os.makedirs(generated_test_dir) | 159 os.makedirs(generated_test_dir) |
131 # Copy referenced files to generated tests directory. | 160 # Copy referenced files to generated tests directory. |
(...skipping 22 matching lines...) Expand all Loading... | |
154 '%s%s' % (name, extension)) | 183 '%s%s' % (name, extension)) |
155 with open(test_filename, 'w') as test_file: | 184 with open(test_filename, 'w') as test_file: |
156 for line in lines: | 185 for line in lines: |
157 if ' /// ' not in line: | 186 if ' /// ' not in line: |
158 print >> test_file, line | 187 print >> test_file, line |
159 else: | 188 else: |
160 print >> test_file, '//', line | 189 print >> test_file, '//', line |
161 tests['none'] = ('', test_filename) | 190 tests['none'] = ('', test_filename) |
162 return tests | 191 return tests |
163 | 192 |
164 class BrowserTestCase(test_case.StandardTestCase): | |
165 def __init__(self, context, path, filename, | |
166 fatal_static_type_errors, mode, arch): | |
167 super(test_case.BrowserTestCase, self).__init__(context, path, filename, mod e, arch) | |
168 self.fatal_static_type_errors = fatal_static_type_errors | |
169 | |
170 def IsBatchable(self): | |
171 return True | |
172 | |
173 def Run(self): | |
174 command = self.run_arch.GetCompileCommand(self.fatal_static_type_errors) | |
175 if command != None: | |
176 # We change the directory where dartc will be launched because | |
177 # it is not predictable on the location of the compiled file. In | |
178 # case the test is a web test, we make sure the app file is not | |
179 # in a subdirectory. | |
180 cwd = None | |
181 if self.run_arch.is_web_test: cwd = self.run_arch.temp_dir | |
182 command = command[:1] + self.context.flags + command[1:] | |
183 test_output = self.RunCommand(command, cwd=cwd) | |
184 | |
185 # If errors were found, fail fast and show compile errors: | |
186 if test_output.output.exit_code != 0: | |
187 if not self.context.keep_temporary_files: | |
188 self.run_arch.Cleanup() | |
189 return test_output | |
190 | |
191 command = self.run_arch.GetRunCommand(); | |
192 test_output = self.RunCommand(command) | |
193 # The return value of DumpRenderedTree does not indicate test failing, but | |
194 # the output does. | |
195 if self.run_arch.HasFailed(test_output.output.stdout): | |
196 test_output.output.exit_code = 1 | |
197 | |
198 # TODO(ngeoffray): We run out of space on the build bots for these tests if | |
199 # the temp directories are not removed right after running the test. | |
200 if not self.context.keep_temporary_files: | |
201 self.run_arch.Cleanup() | |
202 | |
203 return test_output | |
204 | |
205 | 193 |
206 class BrowserTestConfiguration(StandardTestConfiguration): | 194 class BrowserTestConfiguration(StandardTestConfiguration): |
195 """A configuration used to run tests inside a browser.""" | |
196 | |
207 def __init__(self, context, root, fatal_static_type_errors=False): | 197 def __init__(self, context, root, fatal_static_type_errors=False): |
208 super(BrowserTestConfiguration, self).__init__(context, root) | 198 super(BrowserTestConfiguration, self).__init__(context, root) |
209 self.fatal_static_type_errors = fatal_static_type_errors | 199 self.fatal_static_type_errors = fatal_static_type_errors |
210 | 200 |
211 def ListTests(self, current_path, path, mode, arch): | 201 def ListTests(self, current_path, path, mode, arch): |
202 """Searches for .dart files that qualify and returns list of TestCases.""" | |
ngeoffray
2011/10/13 08:03:38
*Test.dart
zundel
2011/10/13 11:07:44
Done.
| |
212 tests = [] | 203 tests = [] |
213 for root, dirs, files in os.walk(self.root): | 204 for root, unused_dirs, files in os.walk(self.root): |
214 for f in [x for x in files if self.IsTest(x)]: | 205 for f in [x for x in files if self.IsTest(x)]: |
215 relative = os.path.relpath(root, self.root).split(os.path.sep) | 206 relative = os.path.relpath(root, self.root).split(os.path.sep) |
216 test_path = current_path + relative + [os.path.splitext(f)[0]] | 207 test_path = current_path + relative + [os.path.splitext(f)[0]] |
217 if not self.Contains(path, test_path): | 208 if not self.Contains(path, test_path): |
218 continue | 209 continue |
219 tests.append(test_case.BrowserTestCase(self.context, | 210 tests.append(test_case.BrowserTestCase(self.context, |
220 test_path, join(root, f), self.fatal_static_type_errors, mode, | 211 test_path, |
221 arch)) | 212 os.path.join(root, f), |
222 atexit.register(lambda: self._cleanup(tests)) | 213 self.fatal_static_type_errors, |
214 mode, arch)) | |
215 atexit.register(lambda: self._Cleanup(tests)) | |
223 return tests | 216 return tests |
224 | 217 |
225 def IsTest(self, name): | 218 def IsTest(self, name): |
226 return name.endswith('_tests.dart') | 219 return name.endswith('_tests.dart') |
227 | 220 |
228 | 221 |
229 class CompilationTestConfiguration(test.TestConfiguration): | 222 class CompilationTestConfiguration(test.TestConfiguration): |
230 """ Configuration that searches specific directories for apps to compile | 223 """Configuration that searches specific directories for apps to compile. |
231 | 224 |
232 Expects a status file named dartc.status | 225 Expects a status file named dartc.status |
233 """ | 226 """ |
227 | |
234 def __init__(self, context, root): | 228 def __init__(self, context, root): |
235 super(CompilationTestConfiguration, self).__init__(context, root) | 229 super(CompilationTestConfiguration, self).__init__(context, root) |
236 | 230 |
237 def ListTests(self, current_path, path, mode, arch): | 231 def ListTests(self, current_path, path, mode, arch): |
232 """Searches for .dart files that qualify and returns list of TestCases.""" | |
ngeoffray
2011/10/13 08:03:38
*Test.dart
zundel
2011/10/13 11:07:44
Done.
| |
238 tests = [] | 233 tests = [] |
239 client_path = os.path.normpath(os.path.join(self.root, '..', '..')) | 234 client_path = os.path.normpath(os.path.join(self.root, '..', '..')) |
240 | 235 |
241 for src_dir in self.SourceDirs(): | 236 for src_dir in self.SourceDirs(): |
242 for root, dirs, files in os.walk(os.path.join(client_path, src_dir)): | 237 for root, dirs, files in os.walk(os.path.join(client_path, src_dir)): |
243 ignore_dirs = [d for d in dirs if d.startswith('.')] | 238 ignore_dirs = [d for d in dirs if d.startswith('.')] |
244 for d in ignore_dirs: | 239 for d in ignore_dirs: |
245 dirs.remove(d) | 240 dirs.remove(d) |
246 for f in files: | 241 for f in files: |
247 filename = [os.path.basename(client_path)] | 242 filename = [os.path.basename(client_path)] |
248 filename.extend(root[len(client_path) + 1:].split(os.path.sep)) | 243 filename.extend(root[len(client_path) + 1:].split(os.path.sep)) |
249 filename.append(f) # Remove .lib or .app suffix. | 244 filename.append(f) # Remove .lib or .app suffix. |
250 test_path = current_path + filename | 245 test_path = current_path + filename |
251 test_dart_file = os.path.join(root, f) | 246 test_dart_file = os.path.join(root, f) |
252 if ((not self.Contains(path, test_path)) | 247 if (not self.Contains(path, test_path) |
253 or (not self.IsTest(test_dart_file))): | 248 or not self.IsTest(test_dart_file)): |
254 continue | 249 continue |
255 tests.append(test_case.CompilationTestCase(test_path, | 250 tests.append(test_case.CompilationTestCase(test_path, |
256 self.context, | 251 self.context, |
257 test_dart_file, | 252 test_dart_file, |
258 mode, | 253 mode, |
259 arch)) | 254 arch)) |
260 atexit.register(lambda: self._cleanup(tests)) | 255 atexit.register(lambda: self._Cleanup(tests)) |
261 return tests | 256 return tests |
262 | 257 |
263 def SourceDirs(self): | 258 def SourceDirs(self): |
264 """ Returns a list of directories to scan for files to compile """ | 259 """Returns a list of directories to scan for files to compile.""" |
265 raise TestConfigurationError( | 260 raise TestConfigurationError( |
266 "Subclasses must implement SourceDirs()") | 261 'Subclasses must implement SourceDirs()') |
267 | 262 |
268 def IsTest(self, name): | 263 def IsTest(self, name): |
269 if (not name.endswith('.dart')): | 264 """Returns True if name looks like a test case to be compiled.""" |
ngeoffray
2011/10/13 08:03:38
looks like -> is
zundel
2011/10/13 11:07:44
Done.
| |
265 if not name.endswith('.dart'): | |
270 return False | 266 return False |
271 if (os.path.exists(name)): | 267 if os.path.exists(name): |
272 # TODO(dgrove): can we end reading the input early? | 268 # TODO(dgrove): can we end reading the input early? |
273 for line in fileinput.input(name): | 269 for line in fileinput.input(name): |
274 if (re.match('#', line)): | 270 if re.match('#', line): |
275 fileinput.close() | 271 fileinput.close() |
276 return True | 272 return True |
277 fileinput.close() | 273 fileinput.close() |
278 return False | 274 return False |
279 return False | 275 return False |
280 | 276 |
281 def GetTestStatus(self, sections, defs): | 277 def GetTestStatus(self, sections, defs): |
282 status = os.path.join(self.root, 'dartc.status') | 278 status = os.path.join(self.root, 'dartc.status') |
283 if os.path.exists(status): | 279 if os.path.exists(status): |
284 test.ReadConfigurationInto(status, sections, defs) | 280 test.ReadConfigurationInto(status, sections, defs) |
285 | 281 |
286 def _cleanup(self, tests): | 282 def _Cleanup(self, tests): |
287 if not utils.Daemonize(): return | 283 if not utils.Daemonize(): return |
288 os.execlp('rm', *(['rm', '-rf'] + [t.temp_dir for t in tests])) | 284 os.execlp('rm', *(['rm', '-rf'] + [t.temp_dir for t in tests])) |
289 raise | 285 raise |
OLD | NEW |