|
1 #! /usr/bin/python |
|
2 |
|
3 """This script takes the file produced by DMD's test mode and checks its |
|
4 correctness. |
|
5 |
|
6 It produces the following output files: $TMP/test-{fixed,filtered,diff}.dmd. |
|
7 |
|
8 It runs the appropriate fix* script to get nice stack traces. It also |
|
9 filters out platform-specific details from the test output file. |
|
10 |
|
11 Note: you must run this from the same directory that you invoked DMD's test |
|
12 mode, otherwise the fix* script will not work properly, because some of the |
|
13 paths in the test output are relative. |
|
14 |
|
15 """ |
|
16 |
|
17 from __future__ import print_function |
|
18 |
|
19 import os |
|
20 import platform |
|
21 import re |
|
22 import subprocess |
|
23 import sys |
|
24 import tempfile |
|
25 |
|
26 |
|
27 def main(): |
|
28 |
|
29 # Arguments |
|
30 |
|
31 if (len(sys.argv) != 3): |
|
32 print("usage:", sys.argv[0], "<topsrcdir> <test.dmd>") |
|
33 sys.exit(1) |
|
34 |
|
35 srcdir = sys.argv[1] |
|
36 |
|
37 # Filenames |
|
38 |
|
39 tempdir = tempfile.gettempdir() |
|
40 in_name = sys.argv[2] |
|
41 fixed_name = tempdir + os.sep + "test-fixed.dmd" |
|
42 filtered_name = tempdir + os.sep + "test-filtered.dmd" |
|
43 diff_name = tempdir + os.sep + "test-diff.dmd" |
|
44 expected_name = srcdir + os.sep + \ |
|
45 "memory/replace/dmd/test-expected.dmd" |
|
46 |
|
47 # Fix stack traces |
|
48 |
|
49 print("fixing output to", fixed_name) |
|
50 |
|
51 sysname = platform.system() |
|
52 if sysname == "Linux": |
|
53 fix = srcdir + os.sep + "tools/rb/fix-linux-stack.pl" |
|
54 elif sysname == "Darwin": |
|
55 fix = srcdir + os.sep + "tools/rb/fix_macosx_stack.py" |
|
56 else: |
|
57 print("unhandled platform: " + sysname, file=sys.stderr) |
|
58 sys.exit(1) |
|
59 |
|
60 subprocess.call(fix, stdin=open(in_name, "r"), |
|
61 stdout=open(fixed_name, "w")) |
|
62 |
|
63 # Filter output |
|
64 |
|
65 # In stack trace records we filter out most stack frames. The only thing |
|
66 # we leave behind is a "DMD.cpp" entry if we see one or more frames that |
|
67 # have DMD.cpp in them. There is simply too much variation to do anything |
|
68 # better than that. |
|
69 # |
|
70 # As for stack frame records, alas, we filter them out entirely because |
|
71 # they have even more variation. |
|
72 |
|
73 print("filtering output to", filtered_name) |
|
74 |
|
75 with open(fixed_name, "r") as fin, \ |
|
76 open(filtered_name, "w") as fout: |
|
77 |
|
78 test_frame_re = re.compile(r".*(DMD.cpp)") |
|
79 |
|
80 for line in fin: |
|
81 if re.match(r" (Allocated at|Reported( again)? at)", line): |
|
82 # It's a stack trace record. |
|
83 print(line, end='', file=fout) |
|
84 |
|
85 # Filter the stack trace -- print a single line if we see one |
|
86 # or more frames involving DMD.cpp. |
|
87 seen_DMD_frame = False |
|
88 for frame in fin: |
|
89 if re.match(r" ", frame): |
|
90 m = test_frame_re.match(frame) |
|
91 if m: |
|
92 seen_DMD_frame = True |
|
93 else: |
|
94 # We're past the stack trace. |
|
95 if seen_DMD_frame: |
|
96 print(" ... DMD.cpp", file=fout) |
|
97 print(frame, end='', file=fout) |
|
98 break |
|
99 |
|
100 elif re.search("in stack frame record", line): |
|
101 # Stack frame record. Get the whole thing (we know how many |
|
102 # lines it has). |
|
103 line2 = fin.next() |
|
104 line3 = fin.next() |
|
105 line4 = fin.next() |
|
106 line5 = fin.next() |
|
107 line6 = fin.next() |
|
108 |
|
109 else: |
|
110 # A line that needs no special handling. Copy it through. |
|
111 print(line, end='', file=fout) |
|
112 |
|
113 # Compare with expected output |
|
114 |
|
115 print("diffing output to", diff_name) |
|
116 |
|
117 ret = subprocess.call(["diff", "-u", expected_name, filtered_name], |
|
118 stdout=open(diff_name, "w")) |
|
119 |
|
120 if ret == 0: |
|
121 print("test PASSED") |
|
122 else: |
|
123 print("test FAILED (did you remember to run this script and Firefox " |
|
124 "in the same directory?)") |
|
125 |
|
126 |
|
127 if __name__ == "__main__": |
|
128 main() |