authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-19 14:41:59-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-19 14:41:59-04:00
log9b7f438882b4f283d252d8ca364607fae385cc1a
treebb0458781d3bd0f4bb1a4a991690022d900fb767
parentd1e01e43d3b2078bfb07defb693d819e99eaa6c5

convert debug safety tests to zig build system


4 files changed, 410 insertions(+), 331 deletions(-)

build.zig+1
......@@ -39,4 +39,5 @@ pub fn build(b: &Builder) {
3939 test_step.dependOn(tests.addBuildExampleTests(b, test_filter));
4040 test_step.dependOn(tests.addCompileErrorTests(b, test_filter));
4141 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter));
42 test_step.dependOn(tests.addDebugSafetyTests(b, test_filter));
4243}
test/debug_safety.zig created+234
......@@ -0,0 +1,234 @@
1const tests = @import("tests.zig");
2
3pub fn addCases(cases: &tests.CompareOutputContext) {
4 cases.addDebugSafety("calling panic",
5 \\pub fn panic(message: []const u8) -> noreturn {
6 \\ @breakpoint();
7 \\ while (true) {}
8 \\}
9 \\pub fn main() -> %void {
10 \\ @panic("oh no");
11 \\}
12 );
13
14 cases.addDebugSafety("out of bounds slice access",
15 \\pub fn panic(message: []const u8) -> noreturn {
16 \\ @breakpoint();
17 \\ while (true) {}
18 \\}
19 \\pub fn main() -> %void {
20 \\ const a = []i32{1, 2, 3, 4};
21 \\ baz(bar(a));
22 \\}
23 \\fn bar(a: []const i32) -> i32 {
24 \\ a[4]
25 \\}
26 \\fn baz(a: i32) { }
27 );
28
29 cases.addDebugSafety("integer addition overflow",
30 \\pub fn panic(message: []const u8) -> noreturn {
31 \\ @breakpoint();
32 \\ while (true) {}
33 \\}
34 \\error Whatever;
35 \\pub fn main() -> %void {
36 \\ const x = add(65530, 10);
37 \\ if (x == 0) return error.Whatever;
38 \\}
39 \\fn add(a: u16, b: u16) -> u16 {
40 \\ a + b
41 \\}
42 );
43
44 cases.addDebugSafety("integer subtraction overflow",
45 \\pub fn panic(message: []const u8) -> noreturn {
46 \\ @breakpoint();
47 \\ while (true) {}
48 \\}
49 \\error Whatever;
50 \\pub fn main() -> %void {
51 \\ const x = sub(10, 20);
52 \\ if (x == 0) return error.Whatever;
53 \\}
54 \\fn sub(a: u16, b: u16) -> u16 {
55 \\ a - b
56 \\}
57 );
58
59 cases.addDebugSafety("integer multiplication overflow",
60 \\pub fn panic(message: []const u8) -> noreturn {
61 \\ @breakpoint();
62 \\ while (true) {}
63 \\}
64 \\error Whatever;
65 \\pub fn main() -> %void {
66 \\ const x = mul(300, 6000);
67 \\ if (x == 0) return error.Whatever;
68 \\}
69 \\fn mul(a: u16, b: u16) -> u16 {
70 \\ a * b
71 \\}
72 );
73
74 cases.addDebugSafety("integer negation overflow",
75 \\pub fn panic(message: []const u8) -> noreturn {
76 \\ @breakpoint();
77 \\ while (true) {}
78 \\}
79 \\error Whatever;
80 \\pub fn main() -> %void {
81 \\ const x = neg(-32768);
82 \\ if (x == 32767) return error.Whatever;
83 \\}
84 \\fn neg(a: i16) -> i16 {
85 \\ -a
86 \\}
87 );
88
89 cases.addDebugSafety("signed integer division overflow",
90 \\pub fn panic(message: []const u8) -> noreturn {
91 \\ @breakpoint();
92 \\ while (true) {}
93 \\}
94 \\error Whatever;
95 \\pub fn main() -> %void {
96 \\ const x = div(-32768, -1);
97 \\ if (x == 32767) return error.Whatever;
98 \\}
99 \\fn div(a: i16, b: i16) -> i16 {
100 \\ a / b
101 \\}
102 );
103
104 cases.addDebugSafety("signed shift left overflow",
105 \\pub fn panic(message: []const u8) -> noreturn {
106 \\ @breakpoint();
107 \\ while (true) {}
108 \\}
109 \\error Whatever;
110 \\pub fn main() -> %void {
111 \\ const x = shl(-16385, 1);
112 \\ if (x == 0) return error.Whatever;
113 \\}
114 \\fn shl(a: i16, b: i16) -> i16 {
115 \\ a << b
116 \\}
117 );
118
119 cases.addDebugSafety("unsigned shift left overflow",
120 \\pub fn panic(message: []const u8) -> noreturn {
121 \\ @breakpoint();
122 \\ while (true) {}
123 \\}
124 \\error Whatever;
125 \\pub fn main() -> %void {
126 \\ const x = shl(0b0010111111111111, 3);
127 \\ if (x == 0) return error.Whatever;
128 \\}
129 \\fn shl(a: u16, b: u16) -> u16 {
130 \\ a << b
131 \\}
132 );
133
134 cases.addDebugSafety("integer division by zero",
135 \\pub fn panic(message: []const u8) -> noreturn {
136 \\ @breakpoint();
137 \\ while (true) {}
138 \\}
139 \\error Whatever;
140 \\pub fn main() -> %void {
141 \\ const x = div0(999, 0);
142 \\}
143 \\fn div0(a: i32, b: i32) -> i32 {
144 \\ a / b
145 \\}
146 );
147
148 cases.addDebugSafety("exact division failure",
149 \\pub fn panic(message: []const u8) -> noreturn {
150 \\ @breakpoint();
151 \\ while (true) {}
152 \\}
153 \\error Whatever;
154 \\pub fn main() -> %void {
155 \\ const x = divExact(10, 3);
156 \\ if (x == 0) return error.Whatever;
157 \\}
158 \\fn divExact(a: i32, b: i32) -> i32 {
159 \\ @divExact(a, b)
160 \\}
161 );
162
163 cases.addDebugSafety("cast []u8 to bigger slice of wrong size",
164 \\pub fn panic(message: []const u8) -> noreturn {
165 \\ @breakpoint();
166 \\ while (true) {}
167 \\}
168 \\error Whatever;
169 \\pub fn main() -> %void {
170 \\ const x = widenSlice([]u8{1, 2, 3, 4, 5});
171 \\ if (x.len == 0) return error.Whatever;
172 \\}
173 \\fn widenSlice(slice: []const u8) -> []const i32 {
174 \\ ([]const i32)(slice)
175 \\}
176 );
177
178 cases.addDebugSafety("value does not fit in shortening cast",
179 \\pub fn panic(message: []const u8) -> noreturn {
180 \\ @breakpoint();
181 \\ while (true) {}
182 \\}
183 \\error Whatever;
184 \\pub fn main() -> %void {
185 \\ const x = shorten_cast(200);
186 \\ if (x == 0) return error.Whatever;
187 \\}
188 \\fn shorten_cast(x: i32) -> i8 {
189 \\ i8(x)
190 \\}
191 );
192
193 cases.addDebugSafety("signed integer not fitting in cast to unsigned integer",
194 \\pub fn panic(message: []const u8) -> noreturn {
195 \\ @breakpoint();
196 \\ while (true) {}
197 \\}
198 \\error Whatever;
199 \\pub fn main() -> %void {
200 \\ const x = unsigned_cast(-10);
201 \\ if (x == 0) return error.Whatever;
202 \\}
203 \\fn unsigned_cast(x: i32) -> u32 {
204 \\ u32(x)
205 \\}
206 );
207
208 cases.addDebugSafety("unwrap error",
209 \\pub fn panic(message: []const u8) -> noreturn {
210 \\ @breakpoint();
211 \\ while (true) {}
212 \\}
213 \\error Whatever;
214 \\pub fn main() -> %void {
215 \\ %%bar();
216 \\}
217 \\fn bar() -> %void {
218 \\ return error.Whatever;
219 \\}
220 );
221
222 cases.addDebugSafety("cast integer to error and no code matches",
223 \\pub fn panic(message: []const u8) -> noreturn {
224 \\ @breakpoint();
225 \\ while (true) {}
226 \\}
227 \\pub fn main() -> %void {
228 \\ _ = bar(9999);
229 \\}
230 \\fn bar(x: u32) -> error {
231 \\ return error(x);
232 \\}
233 );
234}
test/run_tests.cpp+17-292
......@@ -40,7 +40,6 @@ struct TestCase {
4040 bool is_parseh;
4141 TestSpecial special;
4242 bool is_release_mode;
43 bool is_debug_safety;
4443 AllowWarnings allow_warnings;
4544};
4645
......@@ -58,26 +57,6 @@ static const char *zig_exe = "./zig";
5857#define NL "\n"
5958#endif
6059
61static void add_debug_safety_case(const char *case_name, const char *source) {
62 TestCase *test_case = allocate<TestCase>(1);
63 test_case->is_debug_safety = true;
64 test_case->case_name = buf_ptr(buf_sprintf("%s", case_name));
65 test_case->source_files.resize(1);
66 test_case->source_files.at(0).relative_path = tmp_source_path;
67 test_case->source_files.at(0).source_code = source;
68
69 test_case->compiler_args.append("build_exe");
70 test_case->compiler_args.append(tmp_source_path);
71
72 test_case->compiler_args.append("--name");
73 test_case->compiler_args.append("test");
74
75 test_case->compiler_args.append("--output");
76 test_case->compiler_args.append(tmp_exe_path);
77
78 test_cases.append(test_case);
79}
80
8160static TestCase *add_parseh_case(const char *case_name, AllowWarnings allow_warnings,
8261 const char *source, size_t count, ...)
8362{
......@@ -107,240 +86,6 @@ static TestCase *add_parseh_case(const char *case_name, AllowWarnings allow_warn
10786 va_end(ap);
10887 return test_case;
10988}
110//////////////////////////////////////////////////////////////////////////////
111
112static void add_debug_safety_test_cases(void) {
113 add_debug_safety_case("calling panic", R"SOURCE(
114pub fn panic(message: []const u8) -> noreturn {
115 @breakpoint();
116 while (true) {}
117}
118pub fn main() -> %void {
119 @panic("oh no");
120}
121 )SOURCE");
122
123 add_debug_safety_case("out of bounds slice access", R"SOURCE(
124pub fn panic(message: []const u8) -> noreturn {
125 @breakpoint();
126 while (true) {}
127}
128pub fn main() -> %void {
129 const a = []i32{1, 2, 3, 4};
130 baz(bar(a));
131}
132fn bar(a: []const i32) -> i32 {
133 a[4]
134}
135fn baz(a: i32) { }
136 )SOURCE");
137
138 add_debug_safety_case("integer addition overflow", R"SOURCE(
139pub fn panic(message: []const u8) -> noreturn {
140 @breakpoint();
141 while (true) {}
142}
143error Whatever;
144pub fn main() -> %void {
145 const x = add(65530, 10);
146 if (x == 0) return error.Whatever;
147}
148fn add(a: u16, b: u16) -> u16 {
149 a + b
150}
151 )SOURCE");
152
153 add_debug_safety_case("integer subtraction overflow", R"SOURCE(
154pub fn panic(message: []const u8) -> noreturn {
155 @breakpoint();
156 while (true) {}
157}
158error Whatever;
159pub fn main() -> %void {
160 const x = sub(10, 20);
161 if (x == 0) return error.Whatever;
162}
163fn sub(a: u16, b: u16) -> u16 {
164 a - b
165}
166 )SOURCE");
167
168 add_debug_safety_case("integer multiplication overflow", R"SOURCE(
169pub fn panic(message: []const u8) -> noreturn {
170 @breakpoint();
171 while (true) {}
172}
173error Whatever;
174pub fn main() -> %void {
175 const x = mul(300, 6000);
176 if (x == 0) return error.Whatever;
177}
178fn mul(a: u16, b: u16) -> u16 {
179 a * b
180}
181 )SOURCE");
182
183 add_debug_safety_case("integer negation overflow", R"SOURCE(
184pub fn panic(message: []const u8) -> noreturn {
185 @breakpoint();
186 while (true) {}
187}
188error Whatever;
189pub fn main() -> %void {
190 const x = neg(-32768);
191 if (x == 32767) return error.Whatever;
192}
193fn neg(a: i16) -> i16 {
194 -a
195}
196 )SOURCE");
197
198 add_debug_safety_case("signed integer division overflow", R"SOURCE(
199pub fn panic(message: []const u8) -> noreturn {
200 @breakpoint();
201 while (true) {}
202}
203error Whatever;
204pub fn main() -> %void {
205 const x = div(-32768, -1);
206 if (x == 32767) return error.Whatever;
207}
208fn div(a: i16, b: i16) -> i16 {
209 a / b
210}
211 )SOURCE");
212
213 add_debug_safety_case("signed shift left overflow", R"SOURCE(
214pub fn panic(message: []const u8) -> noreturn {
215 @breakpoint();
216 while (true) {}
217}
218error Whatever;
219pub fn main() -> %void {
220 const x = shl(-16385, 1);
221 if (x == 0) return error.Whatever;
222}
223fn shl(a: i16, b: i16) -> i16 {
224 a << b
225}
226 )SOURCE");
227
228 add_debug_safety_case("unsigned shift left overflow", R"SOURCE(
229pub fn panic(message: []const u8) -> noreturn {
230 @breakpoint();
231 while (true) {}
232}
233error Whatever;
234pub fn main() -> %void {
235 const x = shl(0b0010111111111111, 3);
236 if (x == 0) return error.Whatever;
237}
238fn shl(a: u16, b: u16) -> u16 {
239 a << b
240}
241 )SOURCE");
242
243 add_debug_safety_case("integer division by zero", R"SOURCE(
244pub fn panic(message: []const u8) -> noreturn {
245 @breakpoint();
246 while (true) {}
247}
248error Whatever;
249pub fn main() -> %void {
250 const x = div0(999, 0);
251}
252fn div0(a: i32, b: i32) -> i32 {
253 a / b
254}
255 )SOURCE");
256
257 add_debug_safety_case("exact division failure", R"SOURCE(
258pub fn panic(message: []const u8) -> noreturn {
259 @breakpoint();
260 while (true) {}
261}
262error Whatever;
263pub fn main() -> %void {
264 const x = divExact(10, 3);
265 if (x == 0) return error.Whatever;
266}
267fn divExact(a: i32, b: i32) -> i32 {
268 @divExact(a, b)
269}
270 )SOURCE");
271
272 add_debug_safety_case("cast []u8 to bigger slice of wrong size", R"SOURCE(
273pub fn panic(message: []const u8) -> noreturn {
274 @breakpoint();
275 while (true) {}
276}
277error Whatever;
278pub fn main() -> %void {
279 const x = widenSlice([]u8{1, 2, 3, 4, 5});
280 if (x.len == 0) return error.Whatever;
281}
282fn widenSlice(slice: []const u8) -> []const i32 {
283 ([]const i32)(slice)
284}
285 )SOURCE");
286
287 add_debug_safety_case("value does not fit in shortening cast", R"SOURCE(
288pub fn panic(message: []const u8) -> noreturn {
289 @breakpoint();
290 while (true) {}
291}
292error Whatever;
293pub fn main() -> %void {
294 const x = shorten_cast(200);
295 if (x == 0) return error.Whatever;
296}
297fn shorten_cast(x: i32) -> i8 {
298 i8(x)
299}
300 )SOURCE");
301
302 add_debug_safety_case("signed integer not fitting in cast to unsigned integer", R"SOURCE(
303pub fn panic(message: []const u8) -> noreturn {
304 @breakpoint();
305 while (true) {}
306}
307error Whatever;
308pub fn main() -> %void {
309 const x = unsigned_cast(-10);
310 if (x == 0) return error.Whatever;
311}
312fn unsigned_cast(x: i32) -> u32 {
313 u32(x)
314}
315 )SOURCE");
316
317 add_debug_safety_case("unwrap error", R"SOURCE(
318pub fn panic(message: []const u8) -> noreturn {
319 @breakpoint();
320 while (true) {}
321}
322error Whatever;
323pub fn main() -> %void {
324 %%bar();
325}
326fn bar() -> %void {
327 return error.Whatever;
328}
329 )SOURCE");
330
331 add_debug_safety_case("cast integer to error and no code matches", R"SOURCE(
332pub fn panic(message: []const u8) -> noreturn {
333 @breakpoint();
334 while (true) {}
335}
336pub fn main() -> %void {
337 _ = bar(9999);
338}
339fn bar(x: u32) -> error {
340 return error(x);
341}
342 )SOURCE");
343}
34489
34590//////////////////////////////////////////////////////////////////////////////
34691
......@@ -653,43 +398,24 @@ static void run_test(TestCase *test_case) {
653398 Buf program_stdout = BUF_INIT;
654399 os_exec_process(tmp_exe_path, test_case->program_args, &term, &program_stderr, &program_stdout);
655400
656 if (test_case->is_debug_safety) {
657 int debug_trap_signal = 5;
658 if (term.how != TerminationIdSignaled || term.code != debug_trap_signal) {
659 if (term.how == TerminationIdClean) {
660 printf("\nProgram expected to hit debug trap (signal %d) but exited with return code %d\n",
661 debug_trap_signal, term.code);
662 } else if (term.how == TerminationIdSignaled) {
663 printf("\nProgram expected to hit debug trap (signal %d) but signaled with code %d\n",
664 debug_trap_signal, term.code);
665 } else {
666 printf("\nProgram expected to hit debug trap (signal %d) exited in an unexpected way\n",
667 debug_trap_signal);
668 }
669 print_compiler_invocation(test_case);
670 print_exe_invocation(test_case);
671 exit(1);
672 }
673 } else {
674 if (term.how != TerminationIdClean || term.code != 0) {
675 printf("\nProgram exited with error\n");
676 print_compiler_invocation(test_case);
677 print_exe_invocation(test_case);
678 printf("%s\n", buf_ptr(&program_stderr));
679 exit(1);
680 }
401 if (term.how != TerminationIdClean || term.code != 0) {
402 printf("\nProgram exited with error\n");
403 print_compiler_invocation(test_case);
404 print_exe_invocation(test_case);
405 printf("%s\n", buf_ptr(&program_stderr));
406 exit(1);
407 }
681408
682 if (test_case->output != nullptr && !buf_eql_str(&program_stdout, test_case->output)) {
683 printf("\n");
684 print_compiler_invocation(test_case);
685 print_exe_invocation(test_case);
686 printf("==== Test failed. Expected output: ====\n");
687 printf("%s\n", test_case->output);
688 printf("========= Actual output: ==============\n");
689 printf("%s\n", buf_ptr(&program_stdout));
690 printf("=======================================\n");
691 exit(1);
692 }
409 if (test_case->output != nullptr && !buf_eql_str(&program_stdout, test_case->output)) {
410 printf("\n");
411 print_compiler_invocation(test_case);
412 print_exe_invocation(test_case);
413 printf("==== Test failed. Expected output: ====\n");
414 printf("%s\n", test_case->output);
415 printf("========= Actual output: ==============\n");
416 printf("%s\n", buf_ptr(&program_stdout));
417 printf("=======================================\n");
418 exit(1);
693419 }
694420 }
695421
......@@ -740,7 +466,6 @@ int main(int argc, char **argv) {
740466 }
741467 }
742468 }
743 add_debug_safety_test_cases();
744469 add_parseh_test_cases();
745470 run_all_tests(grep_text);
746471 cleanup();
test/tests.zig+158-39
......@@ -16,6 +16,7 @@ pub const compare_output = @import("compare_output.zig");
1616pub const build_examples = @import("build_examples.zig");
1717pub const compile_errors = @import("compile_errors.zig");
1818pub const assemble_and_link = @import("assemble_and_link.zig");
19pub const debug_safety = @import("debug_safety.zig");
1920
2021pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
2122 const cases = %%b.allocator.create(CompareOutputContext);
......@@ -31,6 +32,20 @@ pub fn addCompareOutputTests(b: &build.Builder, test_filter: ?[]const u8) -> &bu
3132 return cases.step;
3233}
3334
35pub fn addDebugSafetyTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
36 const cases = %%b.allocator.create(CompareOutputContext);
37 *cases = CompareOutputContext {
38 .b = b,
39 .step = b.step("test-debug-safety", "Run the debug safety tests"),
40 .test_index = 0,
41 .test_filter = test_filter,
42 };
43
44 debug_safety.addCases(cases);
45
46 return cases.step;
47}
48
3449pub fn addCompileErrorTests(b: &build.Builder, test_filter: ?[]const u8) -> &build.Step {
3550 const cases = %%b.allocator.create(CompileErrorContext);
3651 *cases = CompileErrorContext {
......@@ -79,12 +94,18 @@ pub const CompareOutputContext = struct {
7994 test_index: usize,
8095 test_filter: ?[]const u8,
8196
97 const Special = enum {
98 None,
99 Asm,
100 DebugSafety,
101 };
102
82103 const TestCase = struct {
83104 name: []const u8,
84105 sources: List(SourceFile),
85106 expected_output: []const u8,
86107 link_libc: bool,
87 is_asm: bool,
108 special: Special,
88109
89110 const SourceFile = struct {
90111 filename: []const u8,
......@@ -175,17 +196,83 @@ pub const CompareOutputContext = struct {
175196 }
176197 };
177198
199 const DebugSafetyRunStep = struct {
200 step: build.Step,
201 context: &CompareOutputContext,
202 exe_path: []const u8,
203 name: []const u8,
204 test_index: usize,
205
206 pub fn create(context: &CompareOutputContext, exe_path: []const u8,
207 name: []const u8) -> &DebugSafetyRunStep
208 {
209 const allocator = context.b.allocator;
210 const ptr = %%allocator.create(DebugSafetyRunStep);
211 *ptr = DebugSafetyRunStep {
212 .context = context,
213 .exe_path = exe_path,
214 .name = name,
215 .test_index = context.test_index,
216 .step = build.Step.init("DebugSafetyRun", allocator, make),
217 };
218 context.test_index += 1;
219 return ptr;
220 }
221
222 fn make(step: &build.Step) -> %void {
223 const self = @fieldParentPtr(DebugSafetyRunStep, "step", step);
224 const b = self.context.b;
225
226 const full_exe_path = b.pathFromRoot(self.exe_path);
227
228 %%io.stderr.printf("Test {}/{} {}...", self.test_index+1, self.context.test_index, self.name);
229
230 var child = os.ChildProcess.spawn(full_exe_path, [][]u8{}, &b.env_map,
231 StdIo.Ignore, StdIo.Pipe, StdIo.Pipe, b.allocator) %% |err|
232 {
233 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
234 };
235
236 const term = child.wait() %% |err| {
237 debug.panic("Unable to spawn {}: {}\n", full_exe_path, @errorName(err));
238 };
239
240 const debug_trap_signal: i32 = 5;
241 switch (term) {
242 Term.Clean => |code| {
243 %%io.stderr.printf("\nProgram expected to hit debug trap (signal {}) " ++
244 "but exited with return code {}\n", debug_trap_signal, code);
245 return error.TestFailed;
246 },
247 Term.Signal => |sig| {
248 if (sig != debug_trap_signal) {
249 %%io.stderr.printf("\nProgram expected to hit debug trap (signal {}) " ++
250 "but instead signaled {}\n", debug_trap_signal, sig);
251 return error.TestFailed;
252 }
253 },
254 else => {
255 %%io.stderr.printf("\nProgram expected to hit debug trap (signal {}) " ++
256 " but exited in an unexpected way\n", debug_trap_signal);
257 return error.TestFailed;
258 },
259 }
260
261 %%io.stderr.printf("OK\n");
262 }
263 };
264
178265 pub fn createExtra(self: &CompareOutputContext, name: []const u8, source: []const u8,
179 expected_output: []const u8, is_asm: bool) -> TestCase
266 expected_output: []const u8, special: Special) -> TestCase
180267 {
181268 var tc = TestCase {
182269 .name = name,
183270 .sources = List(TestCase.SourceFile).init(self.b.allocator),
184271 .expected_output = expected_output,
185272 .link_libc = false,
186 .is_asm = is_asm,
273 .special = special,
187274 };
188 const root_src_name = if (is_asm) "source.s" else "source.zig";
275 const root_src_name = if (special == Special.Asm) "source.s" else "source.zig";
189276 tc.addSourceFile(root_src_name, source);
190277 return tc;
191278 }
......@@ -193,7 +280,7 @@ pub const CompareOutputContext = struct {
193280 pub fn create(self: &CompareOutputContext, name: []const u8, source: []const u8,
194281 expected_output: []const u8) -> TestCase
195282 {
196 return createExtra(self, name, source, expected_output, false);
283 return createExtra(self, name, source, expected_output, Special.None);
197284 }
198285
199286 pub fn addC(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) {
......@@ -208,7 +295,12 @@ pub const CompareOutputContext = struct {
208295 }
209296
210297 pub fn addAsm(self: &CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) {
211 const tc = self.createExtra(name, source, expected_output, true);
298 const tc = self.createExtra(name, source, expected_output, Special.Asm);
299 self.addCase(tc);
300 }
301
302 pub fn addDebugSafety(self: &CompareOutputContext, name: []const u8, source: []const u8) {
303 const tc = self.createExtra(name, source, undefined, Special.DebugSafety);
212304 self.addCase(tc);
213305 }
214306
......@@ -218,45 +310,74 @@ pub const CompareOutputContext = struct {
218310 const root_src = %%os.path.join(b.allocator, "test_artifacts", case.sources.items[0].filename);
219311 const exe_path = %%os.path.join(b.allocator, "test_artifacts", "test");
220312
221 if (case.is_asm) {
222 const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o");
223 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "assemble-and-link {}", case.name);
224 if (const filter ?= self.test_filter) {
225 if (mem.indexOf(u8, annotated_case_name, filter) == null)
226 return;
227 }
313 switch (case.special) {
314 Special.Asm => {
315 const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o");
316 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "assemble-and-link {}", case.name);
317 if (const filter ?= self.test_filter) {
318 if (mem.indexOf(u8, annotated_case_name, filter) == null)
319 return;
320 }
228321
229 const obj = b.addAssemble("test", root_src);
230 obj.setOutputPath(obj_path);
322 const obj = b.addAssemble("test", root_src);
323 obj.setOutputPath(obj_path);
231324
232 for (case.sources.toSliceConst()) |src_file| {
233 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
234 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
235 obj.step.dependOn(&write_src.step);
236 }
325 for (case.sources.toSliceConst()) |src_file| {
326 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
327 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
328 obj.step.dependOn(&write_src.step);
329 }
237330
238 const exe = b.addLinkExecutable("test");
239 exe.step.dependOn(&obj.step);
240 exe.addObjectFile(obj_path);
241 exe.setOutputPath(exe_path);
331 const exe = b.addLinkExecutable("test");
332 exe.step.dependOn(&obj.step);
333 exe.addObjectFile(obj_path);
334 exe.setOutputPath(exe_path);
242335
243 const run_and_cmp_output = RunCompareOutputStep.create(self, exe_path, annotated_case_name,
244 case.expected_output);
245 run_and_cmp_output.step.dependOn(&exe.step);
336 const run_and_cmp_output = RunCompareOutputStep.create(self, exe_path, annotated_case_name,
337 case.expected_output);
338 run_and_cmp_output.step.dependOn(&exe.step);
339
340 self.step.dependOn(&run_and_cmp_output.step);
341 },
342 Special.None => {
343 for ([]bool{false, true}) |release| {
344 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} ({})",
345 case.name, if (release) "release" else "debug");
346 if (const filter ?= self.test_filter) {
347 if (mem.indexOf(u8, annotated_case_name, filter) == null)
348 continue;
349 }
246350
247 self.step.dependOn(&run_and_cmp_output.step);
248 } else {
249 for ([]bool{false, true}) |release| {
250 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "{} ({})",
251 case.name, if (release) "release" else "debug");
351 const exe = b.addExecutable("test", root_src);
352 exe.setOutputPath(exe_path);
353 exe.setRelease(release);
354 if (case.link_libc) {
355 exe.linkLibrary("c");
356 }
357
358 for (case.sources.toSliceConst()) |src_file| {
359 const expanded_src_path = %%os.path.join(b.allocator, "test_artifacts", src_file.filename);
360 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
361 exe.step.dependOn(&write_src.step);
362 }
363
364 const run_and_cmp_output = RunCompareOutputStep.create(self, exe_path, annotated_case_name,
365 case.expected_output);
366 run_and_cmp_output.step.dependOn(&exe.step);
367
368 self.step.dependOn(&run_and_cmp_output.step);
369 }
370 },
371 Special.DebugSafety => {
372 const obj_path = %%os.path.join(b.allocator, "test_artifacts", "test.o");
373 const annotated_case_name = %%fmt.allocPrint(self.b.allocator, "debug-safety {}", case.name);
252374 if (const filter ?= self.test_filter) {
253375 if (mem.indexOf(u8, annotated_case_name, filter) == null)
254 continue;
376 return;
255377 }
256378
257379 const exe = b.addExecutable("test", root_src);
258380 exe.setOutputPath(exe_path);
259 exe.setRelease(release);
260381 if (case.link_libc) {
261382 exe.linkLibrary("c");
262383 }
......@@ -267,14 +388,12 @@ pub const CompareOutputContext = struct {
267388 exe.step.dependOn(&write_src.step);
268389 }
269390
270 const run_and_cmp_output = RunCompareOutputStep.create(self, exe_path, annotated_case_name,
271 case.expected_output);
391 const run_and_cmp_output = DebugSafetyRunStep.create(self, exe_path, annotated_case_name);
272392 run_and_cmp_output.step.dependOn(&exe.step);
273393
274394 self.step.dependOn(&run_and_cmp_output.step);
275 }
276 };
277
395 },
396 }
278397 }
279398};
280399