1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 from dejagnu_test import DejaGNUTest
21 import fnmatch
22 import os
23 from qm.test.result import Result
24 from qm.fields import BooleanField
25 import re
26
27
28
29
30
32 """A 'DGTest' is a test using the DejaGNU 'dg' driver.
33
34 This test class emulates the 'dg.exp' source file in the DejaGNU
35 distribution."""
36
38 """The exception class raised by 'DGTest'.
39
40 When a 'DGTest' method detects an error situation, it raises
41 an exception of this type."""
42
43 pass
44
45
46
47 __dg_command_regexp \
48 = re.compile(r"{[ \t]+dg-([-a-z]+)[ \t]+(.*)[ \t]+}[^}]*$")
49 """A regular expression matching commands embedded in the source file."""
50
51
52
53 KIND_PREPROCESS = "preprocess"
54 KIND_COMPILE = "compile"
55 KIND_ASSEMBLE = "assemble"
56 KIND_LINK = "link"
57 KIND_RUN = "run"
58
59 keep_output = BooleanField(default_value=False,
60 description="""True if the output file should be retained
61 after the test is complete. Otherwise, it is removed.""")
62
63 _default_kind = KIND_COMPILE
64 """The default test kind.
65
66 This value can be overridden by a 'dg-do' command in the test file."""
67
68 __test_kinds = (
69 KIND_PREPROCESS,
70 KIND_COMPILE,
71 KIND_ASSEMBLE,
72 KIND_LINK,
73 KIND_RUN
74 )
75 """The kinds of tests supported by 'dg.exp'."""
76
77 __DIAG_BOGUS = "bogus"
78 __DIAG_ERROR = "error"
79 __DIAG_WARNING = "warning"
80
81 __diagnostic_descriptions = {
82 __DIAG_ERROR : "errors",
83 __DIAG_WARNING : "warnings",
84 __DIAG_BOGUS : "bogus messages",
85 "build" : "build failure",
86 }
87 """A map from dg diagnostic kinds to descriptive strings."""
88
89 - def _RunDGTest(self, tool_flags, default_options, context, result,
90 path = None,
91 default_kind = None,
92 keep_output = None):
93 """Run a 'dg' test.
94
95 'tool_flags' -- A list of strings giving a set of options to be
96 provided to the tool being tested.
97
98 'default_options' -- A list of strings giving a default set of
99 options to be provided to the tool being tested. These options
100 can be overridden by an embedded 'dg-options' command in the
101 test itself.
102
103 'context' -- The 'Context' in which this test is running.
104
105 'result' -- The 'Result' of the test execution.
106
107 'path' -- The path to the test file. If 'None', the main test
108 file path is used.
109
110 'default_kind' -- The kind of test to perform. If this value
111 is 'None', then 'self._default_kind' is used.
112
113 'keep_output' -- True if the output file should be retained
114 after the test is complete. Otherwise, it is removed.
115
116 This function emulates 'dg-test'."""
117
118
119 if default_kind is None:
120 default_kind = self._default_kind
121 self._kind = default_kind
122 self._selected = None
123 self._expectation = None
124 self._options = list(default_options)
125 self._diagnostics = []
126 self._excess_errors_expected = False
127 self._final_commands = []
128
129 line_num = 0
130 if not path:
131 path = self._GetSourcePath()
132 root = self.GetDatabase().GetRoot()
133 if path.startswith(root):
134 self._name = path[len(root) + 1:]
135 else:
136
137 self._name = os.path.join(".", os.path.basename(path))
138 for l in open(path).xreadlines():
139 line_num += 1
140 m = self.__dg_command_regexp.search(l)
141 if m:
142 f = getattr(self, "_DG" + m.group(1).replace("-", "_"))
143 args = self._ParseTclWords(m.group(2),
144 { "srcdir" : root })
145 f(line_num, args, context)
146
147
148 if self._selected == 0:
149 self._RecordDejaGNUOutcome(result,
150 self.UNSUPPORTED,
151 self._name)
152 return
153
154
155 file = self._RunDGToolPortion(path, tool_flags, context, result)
156
157
158 self._RunDGExecutePortion(file, context, result)
159
160
161 for c, a in self._final_commands:
162 self._ExecuteFinalCommand(c, a, context, result)
163
164
165
166 do_keep_output = keep_output is None and self.keep_output or keep_output
167
168 if not do_keep_output:
169 try:
170 os.remove(file)
171 except:
172 pass
173
240
241
260
261
263 """Run a command specified with 'dg-final'.
264
265 'command' -- A string giving the name of the command.
266
267 'args' -- A list of strings giving the arguments (if any) to
268 that command.
269
270 'context' -- The 'Context' in which this test is running.
271
272 'result' -- The 'Result' of this test."""
273
274 raise self.DGException, \
275 'dg-final command \"%s\" is not implemented' % command
276
277
279 """Remove unintersting messages from 'output'.
280
281 'output' -- A string giving the output from the tool being
282 tested.
283
284 returns -- A modified version of 'output'. This modified
285 version does not contain tool output messages that are
286 irrelevant for testing purposes."""
287
288 raise NotImplementedError
289
290
310
311
312 - def _DGdo(self, line_num, args, context):
313 """Emulate the 'dg-do' command.
314
315 'line_num' -- The line number at which the command was found.
316
317 'args' -- The arguments to the command, as a list of
318 strings.
319
320 'context' -- The 'Context' in which the test is running."""
321
322 if len(args) > 2:
323 self._Error("dg-do: too many arguments")
324
325 if len(args) >= 2:
326 code = self._ParseTargetSelector(args[1], context)
327 if code == "S":
328 self._selected = 1
329 elif code == "N":
330 if self._selected != 1:
331 self._selected = 0
332 elif code == "F":
333 self._expectation = Result.FAIL
334 else:
335 self._selected = 1
336 self._expectation = Result.PASS
337
338 kind = args[0]
339 if kind not in self.__test_kinds:
340 self._Error("dg-do: syntax error")
341
342 self._kind = kind
343
344
345 - def _DGfinal(self, line_num, args, context):
346 """Emulate the 'dg-final' command.
347
348 'line_num' -- The line number at which the command was found.
349
350 'args' -- The arguments to the command, as a list of
351 strings.
352
353 'context' -- The 'Context' in which the test is running."""
354
355 if len(args) > 1:
356 self._Error("dg-final: too many arguments")
357
358 words = self._ParseTclWords(args[0])
359 self._final_commands.append((words[0], words[1:]))
360
361
363 """Emulate the 'dg-options' command.
364
365 'line_num' -- The line number at which the command was found.
366
367 'args' -- The arguments to the command, as a list of
368 strings.
369
370 'context' -- The 'Context' in which the test is running."""
371
372 if len(args) > 2:
373 self._Error("'dg-options': too many arguments")
374
375 if len(args) >= 2:
376 code = self._ParseTargetSelector(args[1], context)
377 if code == "S":
378 self._options = self._ParseTclWords(args[0])
379 elif code != "N":
380 self._Error("'dg-options': 'xfail' not allowed here")
381 else:
382 self._options = self._ParseTclWords(args[0])
383
384
385 - def _DGbogus(self, line_num, args, context):
386 """Emulate the 'dg-bogus' command.
387
388 'line_num' -- The number at which the command was found.
389
390 'args' -- The arguments to the command, as a list of
391 strings.
392
393 'context' -- The 'Context' in which the test is running."""
394
395 self.__ExpectDiagnostic(self.__DIAG_BOGUS, line_num, args, context)
396
397
399 """Emulate the 'dg-warning' command.
400
401 'line_num' -- The number at which the command was found.
402
403 'args' -- The arguments to the command, as a list of
404 strings.
405
406 'context' -- The 'Context' in which the test is running."""
407
408 self.__ExpectDiagnostic(self.__DIAG_WARNING, line_num, args, context)
409
410
411 - def _DGerror(self, line_num, args, context):
412 """Emulate the 'dg-error' command.
413
414 'line_num' -- The number at which the command was found.
415
416 'args' -- The arguments to the command, as a list of
417 strings.
418
419 'context' -- The 'Context' in which the test is running."""
420
421 self.__ExpectDiagnostic(self.__DIAG_ERROR, line_num, args, context)
422
423
425 """Emulate the 'dg-excess-errors' command.
426
427 'line_num' -- The line number at which the command was found.
428
429 'args' -- The arguments to the command, as a list of
430 strings.
431
432 'context' -- The 'Context' in which the test is running."""
433
434 if len(args) > 2:
435 self._Error("'dg-excess-errors': too many arguments")
436
437 if len(args) >= 2:
438 code = self._ParseTargetSelector(args[1], context)
439 if code in ("F", "S"):
440 self._excess_errors_expected = True
441 else:
442 self._excess_errors_expected = True
443
444
446 """Register an expected diagnostic.
447
448 'kind' -- The kind of diagnostic expected.
449
450 'line_num' -- The number at which the command was found.
451
452 'args' -- The arguments to the command, as a list of
453 strings.
454
455 'context' -- The 'Context' in which the test is running."""
456
457 if len(args) > 4:
458 self._Error("'dg-" + kind + "': too many arguments")
459
460 if len(args) >= 4:
461 l = args[3]
462 if l == "0":
463 line_num = None
464 elif l != ".":
465 line_num = int(args[3])
466
467
468 expectation = self.PASS
469 if len(args) >= 3:
470 code = self._ParseTargetSelector(args[2], context)
471 if code == "N":
472 return
473 if code == "F":
474 expectation = self.FAIL
475
476 if len(args) >= 2:
477 comment = args[1]
478 else:
479 comment = ""
480
481 self._diagnostics.append((line_num, kind, expectation,
482 args[0], comment))
483
484
486 """Parse the target 'selector'.
487
488 'selector' -- A target selector.
489
490 'context' -- The 'Context' in which the test is running.
491
492 returns -- For a 'target' selector, 'S' if this test should be
493 run, or 'N' if it should not. For an 'xfail' selector, 'F' if
494 the test is expected to fail; 'P' if if not.
495
496 This function emulates dg-process-target."""
497
498
499
500
501 words = selector.split()
502
503 if words[0] != "target" and words[0] != "xfail":
504 raise QMException, "Invalid selector."
505
506
507
508 target = self._GetTarget(context)
509 match = 0
510 for p in words[1:]:
511 if (p == "native" and self._IsNative(context)
512 or fnmatch.fnmatch(target, p)):
513 match = 1
514 break
515
516 if words[0] == "target":
517 if match:
518 return "S"
519 else:
520 return "N"
521 else:
522 if match:
523 return "F"
524 else:
525 return "P"
526