authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-28 20:01:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-28 20:01:17-07:00
log7561fca4352e18f03fd4950591341150b9839fda
treebd2a9d9d5147f129359000b620141c92b2870242
parent7ca9f3bc7ba1a413ea7f8b88dfafba3d0f842f6e

stage2: improve test harness to support executing generated C code


2 files changed, 138 insertions(+), 92 deletions(-)

src/test.zig+115-92
...@@ -11,8 +11,9 @@ const enable_wine: bool = build_options.enable_wine;...@@ -11,8 +11,9 @@ const enable_wine: bool = build_options.enable_wine;
11const enable_wasmtime: bool = build_options.enable_wasmtime;11const enable_wasmtime: bool = build_options.enable_wasmtime;
12const glibc_multi_install_dir: ?[]const u8 = build_options.glibc_multi_install_dir;12const glibc_multi_install_dir: ?[]const u8 = build_options.glibc_multi_install_dir;
13const ThreadPool = @import("ThreadPool.zig");13const ThreadPool = @import("ThreadPool.zig");
14const CrossTarget = std.zig.CrossTarget;
1415
15const cheader = @embedFile("link/cbe.h");16const c_header = @embedFile("link/cbe.h");
1617
17test "self-hosted" {18test "self-hosted" {
18 var ctx = TestContext.init();19 var ctx = TestContext.init();
...@@ -88,6 +89,9 @@ pub const TestContext = struct {...@@ -88,6 +89,9 @@ pub const TestContext = struct {
88 /// A transformation update transforms the input and tests against89 /// A transformation update transforms the input and tests against
89 /// the expected output ZIR.90 /// the expected output ZIR.
90 Transformation: [:0]const u8,91 Transformation: [:0]const u8,
92 /// Check the main binary output file against an expected set of bytes.
93 /// This is most useful with, for example, `-ofmt=c`.
94 CompareObjectFile: []const u8,
91 /// An error update attempts to compile bad code, and ensures that it95 /// An error update attempts to compile bad code, and ensures that it
92 /// fails to compile, and for the expected reasons.96 /// fails to compile, and for the expected reasons.
93 /// A slice containing the expected errors *in sequential order*.97 /// A slice containing the expected errors *in sequential order*.
...@@ -109,12 +113,12 @@ pub const TestContext = struct {...@@ -109,12 +113,12 @@ pub const TestContext = struct {
109 path: []const u8,113 path: []const u8,
110 };114 };
111115
112 pub const TestType = enum {116 pub const Extension = enum {
113 Zig,117 Zig,
114 ZIR,118 ZIR,
115 };119 };
116120
117 /// A Case consists of a set of *updates*. The same Compilation is used for each121 /// A `Case` consists of a list of `Update`. The same `Compilation` is used for each
118 /// update, so each update's source is treated as a single file being122 /// update, so each update's source is treated as a single file being
119 /// updated by the test harness and incrementally compiled.123 /// updated by the test harness and incrementally compiled.
120 pub const Case = struct {124 pub const Case = struct {
...@@ -123,13 +127,14 @@ pub const TestContext = struct {...@@ -123,13 +127,14 @@ pub const TestContext = struct {
123 name: []const u8,127 name: []const u8,
124 /// The platform the test targets. For non-native platforms, an emulator128 /// The platform the test targets. For non-native platforms, an emulator
125 /// such as QEMU is required for tests to complete.129 /// such as QEMU is required for tests to complete.
126 target: std.zig.CrossTarget,130 target: CrossTarget,
127 /// In order to be able to run e.g. Execution updates, this must be set131 /// In order to be able to run e.g. Execution updates, this must be set
128 /// to Executable.132 /// to Executable.
129 output_mode: std.builtin.OutputMode,133 output_mode: std.builtin.OutputMode,
130 updates: std.ArrayList(Update),134 updates: std.ArrayList(Update),
131 extension: TestType,135 extension: Extension,
132 cbe: bool = false,136 object_format: ?std.builtin.ObjectFormat = null,
137 emit_h: bool = false,
133138
134 files: std.ArrayList(File),139 files: std.ArrayList(File),
135140
...@@ -145,6 +150,7 @@ pub const TestContext = struct {...@@ -145,6 +150,7 @@ pub const TestContext = struct {
145 /// Adds a subcase in which the module is updated with `src`, and a C150 /// Adds a subcase in which the module is updated with `src`, and a C
146 /// header is generated.151 /// header is generated.
147 pub fn addHeader(self: *Case, src: [:0]const u8, result: [:0]const u8) void {152 pub fn addHeader(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
153 self.emit_h = true;
148 self.updates.append(.{154 self.updates.append(.{
149 .src = src,155 .src = src,
150 .case = .{ .Header = result },156 .case = .{ .Header = result },
...@@ -160,6 +166,15 @@ pub const TestContext = struct {...@@ -160,6 +166,15 @@ pub const TestContext = struct {
160 }) catch unreachable;166 }) catch unreachable;
161 }167 }
162168
169 /// Adds a subcase in which the module is updated with `src`, compiled,
170 /// and the object file data is compared against `result`.
171 pub fn addCompareObjectFile(self: *Case, src: [:0]const u8, result: []const u8) void {
172 self.updates.append(.{
173 .src = src,
174 .case = .{ .CompareObjectFile = result },
175 }) catch unreachable;
176 }
177
163 /// Adds a subcase in which the module is updated with `src`, which178 /// Adds a subcase in which the module is updated with `src`, which
164 /// should contain invalid input, and ensures that compilation fails179 /// should contain invalid input, and ensures that compilation fails
165 /// for the expected reasons, given in sequential order in `errors` in180 /// for the expected reasons, given in sequential order in `errors` in
...@@ -214,86 +229,100 @@ pub const TestContext = struct {...@@ -214,86 +229,100 @@ pub const TestContext = struct {
214 pub fn addExe(229 pub fn addExe(
215 ctx: *TestContext,230 ctx: *TestContext,
216 name: []const u8,231 name: []const u8,
217 target: std.zig.CrossTarget,232 target: CrossTarget,
218 T: TestType,233 extension: Extension,
219 ) *Case {234 ) *Case {
220 ctx.cases.append(Case{235 ctx.cases.append(Case{
221 .name = name,236 .name = name,
222 .target = target,237 .target = target,
223 .updates = std.ArrayList(Update).init(ctx.cases.allocator),238 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
224 .output_mode = .Exe,239 .output_mode = .Exe,
225 .extension = T,240 .extension = extension,
226 .files = std.ArrayList(File).init(ctx.cases.allocator),241 .files = std.ArrayList(File).init(ctx.cases.allocator),
227 }) catch unreachable;242 }) catch unreachable;
228 return &ctx.cases.items[ctx.cases.items.len - 1];243 return &ctx.cases.items[ctx.cases.items.len - 1];
229 }244 }
230245
231 /// Adds a test case for Zig input, producing an executable246 /// Adds a test case for Zig input, producing an executable
232 pub fn exe(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget) *Case {247 pub fn exe(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
233 return ctx.addExe(name, target, .Zig);248 return ctx.addExe(name, target, .Zig);
234 }249 }
235250
236 /// Adds a test case for ZIR input, producing an executable251 /// Adds a test case for ZIR input, producing an executable
237 pub fn exeZIR(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget) *Case {252 pub fn exeZIR(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
238 return ctx.addExe(name, target, .ZIR);253 return ctx.addExe(name, target, .ZIR);
239 }254 }
240255
256 pub fn exeFromCompiledC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
257 ctx.cases.append(Case{
258 .name = name,
259 .target = target,
260 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
261 .output_mode = .Exe,
262 .extension = .Zig,
263 .object_format = .c,
264 .files = std.ArrayList(File).init(ctx.cases.allocator),
265 }) catch unreachable;
266 return &ctx.cases.items[ctx.cases.items.len - 1];
267 }
268
241 pub fn addObj(269 pub fn addObj(
242 ctx: *TestContext,270 ctx: *TestContext,
243 name: []const u8,271 name: []const u8,
244 target: std.zig.CrossTarget,272 target: CrossTarget,
245 T: TestType,273 extension: Extension,
246 ) *Case {274 ) *Case {
247 ctx.cases.append(Case{275 ctx.cases.append(Case{
248 .name = name,276 .name = name,
249 .target = target,277 .target = target,
250 .updates = std.ArrayList(Update).init(ctx.cases.allocator),278 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
251 .output_mode = .Obj,279 .output_mode = .Obj,
252 .extension = T,280 .extension = extension,
253 .files = std.ArrayList(File).init(ctx.cases.allocator),281 .files = std.ArrayList(File).init(ctx.cases.allocator),
254 }) catch unreachable;282 }) catch unreachable;
255 return &ctx.cases.items[ctx.cases.items.len - 1];283 return &ctx.cases.items[ctx.cases.items.len - 1];
256 }284 }
257285
258 /// Adds a test case for Zig input, producing an object file286 /// Adds a test case for Zig input, producing an object file.
259 pub fn obj(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget) *Case {287 pub fn obj(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
260 return ctx.addObj(name, target, .Zig);288 return ctx.addObj(name, target, .Zig);
261 }289 }
262290
263 /// Adds a test case for ZIR input, producing an object file291 /// Adds a test case for ZIR input, producing an object file.
264 pub fn objZIR(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget) *Case {292 pub fn objZIR(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
265 return ctx.addObj(name, target, .ZIR);293 return ctx.addObj(name, target, .ZIR);
266 }294 }
267295
268 pub fn addC(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, T: TestType) *Case {296 /// Adds a test case for Zig or ZIR input, producing C code.
297 pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget, ext: Extension) *Case {
269 ctx.cases.append(Case{298 ctx.cases.append(Case{
270 .name = name,299 .name = name,
271 .target = target,300 .target = target,
272 .updates = std.ArrayList(Update).init(ctx.cases.allocator),301 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
273 .output_mode = .Obj,302 .output_mode = .Obj,
274 .extension = T,303 .extension = ext,
275 .cbe = true,304 .object_format = .c,
276 .files = std.ArrayList(File).init(ctx.cases.allocator),305 .files = std.ArrayList(File).init(ctx.cases.allocator),
277 }) catch unreachable;306 }) catch unreachable;
278 return &ctx.cases.items[ctx.cases.items.len - 1];307 return &ctx.cases.items[ctx.cases.items.len - 1];
279 }308 }
280309
281 pub fn c(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {310 pub fn c(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {
282 ctx.addC(name, target, .Zig).addTransform(src, cheader ++ out);311 ctx.addC(name, target, .Zig).addCompareObjectFile(src, c_header ++ out);
283 }312 }
284313
285 pub fn h(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {314 pub fn h(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {
286 ctx.addC(name, target, .Zig).addHeader(src, cheader ++ out);315 ctx.addC(name, target, .Zig).addHeader(src, c_header ++ out);
287 }316 }
288317
289 pub fn addCompareOutput(318 pub fn addCompareOutput(
290 ctx: *TestContext,319 ctx: *TestContext,
291 name: []const u8,320 name: []const u8,
292 T: TestType,321 extension: Extension,
293 src: [:0]const u8,322 src: [:0]const u8,
294 expected_stdout: []const u8,323 expected_stdout: []const u8,
295 ) void {324 ) void {
296 ctx.addExe(name, .{}, T).addCompareOutput(src, expected_stdout);325 ctx.addExe(name, .{}, extension).addCompareOutput(src, expected_stdout);
297 }326 }
298327
299 /// Adds a test case that compiles the Zig source given in `src`, executes328 /// Adds a test case that compiles the Zig source given in `src`, executes
...@@ -321,12 +350,12 @@ pub const TestContext = struct {...@@ -321,12 +350,12 @@ pub const TestContext = struct {
321 pub fn addTransform(350 pub fn addTransform(
322 ctx: *TestContext,351 ctx: *TestContext,
323 name: []const u8,352 name: []const u8,
324 target: std.zig.CrossTarget,353 target: CrossTarget,
325 T: TestType,354 extension: Extension,
326 src: [:0]const u8,355 src: [:0]const u8,
327 result: [:0]const u8,356 result: [:0]const u8,
328 ) void {357 ) void {
329 ctx.addObj(name, target, T).addTransform(src, result);358 ctx.addObj(name, target, extension).addTransform(src, result);
330 }359 }
331360
332 /// Adds a test case that compiles the Zig given in `src` to ZIR and tests361 /// Adds a test case that compiles the Zig given in `src` to ZIR and tests
...@@ -334,7 +363,7 @@ pub const TestContext = struct {...@@ -334,7 +363,7 @@ pub const TestContext = struct {
334 pub fn transform(363 pub fn transform(
335 ctx: *TestContext,364 ctx: *TestContext,
336 name: []const u8,365 name: []const u8,
337 target: std.zig.CrossTarget,366 target: CrossTarget,
338 src: [:0]const u8,367 src: [:0]const u8,
339 result: [:0]const u8,368 result: [:0]const u8,
340 ) void {369 ) void {
...@@ -346,7 +375,7 @@ pub const TestContext = struct {...@@ -346,7 +375,7 @@ pub const TestContext = struct {
346 pub fn transformZIR(375 pub fn transformZIR(
347 ctx: *TestContext,376 ctx: *TestContext,
348 name: []const u8,377 name: []const u8,
349 target: std.zig.CrossTarget,378 target: CrossTarget,
350 src: [:0]const u8,379 src: [:0]const u8,
351 result: [:0]const u8,380 result: [:0]const u8,
352 ) void {381 ) void {
...@@ -356,12 +385,12 @@ pub const TestContext = struct {...@@ -356,12 +385,12 @@ pub const TestContext = struct {
356 pub fn addError(385 pub fn addError(
357 ctx: *TestContext,386 ctx: *TestContext,
358 name: []const u8,387 name: []const u8,
359 target: std.zig.CrossTarget,388 target: CrossTarget,
360 T: TestType,389 extension: Extension,
361 src: [:0]const u8,390 src: [:0]const u8,
362 expected_errors: []const []const u8,391 expected_errors: []const []const u8,
363 ) void {392 ) void {
364 ctx.addObj(name, target, T).addError(src, expected_errors);393 ctx.addObj(name, target, extension).addError(src, expected_errors);
365 }394 }
366395
367 /// Adds a test case that ensures that the Zig given in `src` fails to396 /// Adds a test case that ensures that the Zig given in `src` fails to
...@@ -370,7 +399,7 @@ pub const TestContext = struct {...@@ -370,7 +399,7 @@ pub const TestContext = struct {
370 pub fn compileError(399 pub fn compileError(
371 ctx: *TestContext,400 ctx: *TestContext,
372 name: []const u8,401 name: []const u8,
373 target: std.zig.CrossTarget,402 target: CrossTarget,
374 src: [:0]const u8,403 src: [:0]const u8,
375 expected_errors: []const []const u8,404 expected_errors: []const []const u8,
376 ) void {405 ) void {
...@@ -383,7 +412,7 @@ pub const TestContext = struct {...@@ -383,7 +412,7 @@ pub const TestContext = struct {
383 pub fn compileErrorZIR(412 pub fn compileErrorZIR(
384 ctx: *TestContext,413 ctx: *TestContext,
385 name: []const u8,414 name: []const u8,
386 target: std.zig.CrossTarget,415 target: CrossTarget,
387 src: [:0]const u8,416 src: [:0]const u8,
388 expected_errors: []const []const u8,417 expected_errors: []const []const u8,
389 ) void {418 ) void {
...@@ -393,11 +422,11 @@ pub const TestContext = struct {...@@ -393,11 +422,11 @@ pub const TestContext = struct {
393 pub fn addCompiles(422 pub fn addCompiles(
394 ctx: *TestContext,423 ctx: *TestContext,
395 name: []const u8,424 name: []const u8,
396 target: std.zig.CrossTarget,425 target: CrossTarget,
397 T: TestType,426 extension: Extension,
398 src: [:0]const u8,427 src: [:0]const u8,
399 ) void {428 ) void {
400 ctx.addObj(name, target, T).compiles(src);429 ctx.addObj(name, target, extension).compiles(src);
401 }430 }
402431
403 /// Adds a test case that asserts that the Zig given in `src` compiles432 /// Adds a test case that asserts that the Zig given in `src` compiles
...@@ -405,7 +434,7 @@ pub const TestContext = struct {...@@ -405,7 +434,7 @@ pub const TestContext = struct {
405 pub fn compiles(434 pub fn compiles(
406 ctx: *TestContext,435 ctx: *TestContext,
407 name: []const u8,436 name: []const u8,
408 target: std.zig.CrossTarget,437 target: CrossTarget,
409 src: [:0]const u8,438 src: [:0]const u8,
410 ) void {439 ) void {
411 ctx.addCompiles(name, target, .Zig, src);440 ctx.addCompiles(name, target, .Zig, src);
...@@ -416,7 +445,7 @@ pub const TestContext = struct {...@@ -416,7 +445,7 @@ pub const TestContext = struct {
416 pub fn compilesZIR(445 pub fn compilesZIR(
417 ctx: *TestContext,446 ctx: *TestContext,
418 name: []const u8,447 name: []const u8,
419 target: std.zig.CrossTarget,448 target: CrossTarget,
420 src: [:0]const u8,449 src: [:0]const u8,
421 ) void {450 ) void {
422 ctx.addCompiles(name, target, .ZIR, src);451 ctx.addCompiles(name, target, .ZIR, src);
...@@ -430,7 +459,7 @@ pub const TestContext = struct {...@@ -430,7 +459,7 @@ pub const TestContext = struct {
430 pub fn incrementalFailure(459 pub fn incrementalFailure(
431 ctx: *TestContext,460 ctx: *TestContext,
432 name: []const u8,461 name: []const u8,
433 target: std.zig.CrossTarget,462 target: CrossTarget,
434 src: [:0]const u8,463 src: [:0]const u8,
435 expected_errors: []const []const u8,464 expected_errors: []const []const u8,
436 fixed_src: [:0]const u8,465 fixed_src: [:0]const u8,
...@@ -448,7 +477,7 @@ pub const TestContext = struct {...@@ -448,7 +477,7 @@ pub const TestContext = struct {
448 pub fn incrementalFailureZIR(477 pub fn incrementalFailureZIR(
449 ctx: *TestContext,478 ctx: *TestContext,
450 name: []const u8,479 name: []const u8,
451 target: std.zig.CrossTarget,480 target: CrossTarget,
452 src: [:0]const u8,481 src: [:0]const u8,
453 expected_errors: []const []const u8,482 expected_errors: []const []const u8,
454 fixed_src: [:0]const u8,483 fixed_src: [:0]const u8,
...@@ -548,12 +577,11 @@ pub const TestContext = struct {...@@ -548,12 +577,11 @@ pub const TestContext = struct {
548 .root_src_path = tmp_src_path,577 .root_src_path = tmp_src_path,
549 };578 };
550579
551 const ofmt: ?std.builtin.ObjectFormat = if (case.cbe) .c else null;
552 const bin_name = try std.zig.binNameAlloc(arena, .{580 const bin_name = try std.zig.binNameAlloc(arena, .{
553 .root_name = "test_case",581 .root_name = "test_case",
554 .target = target,582 .target = target,
555 .output_mode = case.output_mode,583 .output_mode = case.output_mode,
556 .object_format = ofmt,584 .object_format = case.object_format,
557 });585 });
558586
559 const emit_directory: Compilation.Directory = .{587 const emit_directory: Compilation.Directory = .{
...@@ -564,7 +592,7 @@ pub const TestContext = struct {...@@ -564,7 +592,7 @@ pub const TestContext = struct {
564 .directory = emit_directory,592 .directory = emit_directory,
565 .basename = bin_name,593 .basename = bin_name,
566 };594 };
567 const emit_h: ?Compilation.EmitLoc = if (case.cbe)595 const emit_h: ?Compilation.EmitLoc = if (case.emit_h)
568 .{596 .{
569 .directory = emit_directory,597 .directory = emit_directory,
570 .basename = "test_case.h",598 .basename = "test_case.h",
...@@ -588,7 +616,7 @@ pub const TestContext = struct {...@@ -588,7 +616,7 @@ pub const TestContext = struct {
588 .emit_h = emit_h,616 .emit_h = emit_h,
589 .root_pkg = &root_pkg,617 .root_pkg = &root_pkg,
590 .keep_source_files_loaded = true,618 .keep_source_files_loaded = true,
591 .object_format = ofmt,619 .object_format = case.object_format,
592 .is_native_os = case.target.isNativeOs(),620 .is_native_os = case.target.isNativeOs(),
593 .is_native_abi = case.target.isNativeAbi(),621 .is_native_abi = case.target.isNativeAbi(),
594 });622 });
...@@ -631,9 +659,10 @@ pub const TestContext = struct {...@@ -631,9 +659,10 @@ pub const TestContext = struct {
631 },659 },
632 }660 }
633 }661 }
634 if (case.cbe) {662 if (comp.bin_file.cast(link.File.C)) |c_file| {
635 const C = comp.bin_file.cast(link.File.C).?;663 std.debug.print("Generated C: \n===============\n{}\n\n===========\n\n", .{
636 std.debug.print("Generated C: \n===============\n{}\n\n===========\n\n", .{C.main.items});664 c_file.main.items,
665 });
637 }666 }
638 std.debug.print("Test failed.\n", .{});667 std.debug.print("Test failed.\n", .{});
639 std.process.exit(1);668 std.process.exit(1);
...@@ -644,39 +673,37 @@ pub const TestContext = struct {...@@ -644,39 +673,37 @@ pub const TestContext = struct {
644 .Header => |expected_output| {673 .Header => |expected_output| {
645 var file = try tmp.dir.openFile("test_case.h", .{ .read = true });674 var file = try tmp.dir.openFile("test_case.h", .{ .read = true });
646 defer file.close();675 defer file.close();
647 var out = file.reader().readAllAlloc(arena, 1024 * 1024) catch @panic("Unable to read headeroutput!");676 const out = try file.reader().readAllAlloc(arena, 5 * 1024 * 1024);
677
678 std.testing.expectEqualStrings(expected_output, out);
679 },
680 .CompareObjectFile => |expected_output| {
681 var file = try tmp.dir.openFile(bin_name, .{ .read = true });
682 defer file.close();
683 const out = try file.reader().readAllAlloc(arena, 5 * 1024 * 1024);
648684
649 std.testing.expectEqualStrings(expected_output, out);685 std.testing.expectEqualStrings(expected_output, out);
650 },686 },
651 .Transformation => |expected_output| {687 .Transformation => |expected_output| {
652 if (case.cbe) {688 update_node.setEstimatedTotalItems(5);
653 // The C file is always closed after an update, because we don't support689 var emit_node = update_node.start("emit", 0);
654 // incremental updates.690 emit_node.activate();
655 var file = try tmp.dir.openFile(bin_name, .{ .read = true });691 var new_zir_module = try zir.emit(allocator, comp.bin_file.options.module.?);
656 defer file.close();692 defer new_zir_module.deinit(allocator);
657 var out = file.reader().readAllAlloc(arena, 1024 * 1024) catch @panic("Unable to read C output!");693 emit_node.end();
658 std.testing.expectEqualStrings(expected_output, out);694
659 } else {695 var write_node = update_node.start("write", 0);
660 update_node.setEstimatedTotalItems(5);696 write_node.activate();
661 var emit_node = update_node.start("emit", 0);697 var out_zir = std.ArrayList(u8).init(allocator);
662 emit_node.activate();698 defer out_zir.deinit();
663 var new_zir_module = try zir.emit(allocator, comp.bin_file.options.module.?);699 try new_zir_module.writeToStream(allocator, out_zir.outStream());
664 defer new_zir_module.deinit(allocator);700 write_node.end();
665 emit_node.end();701
666702 var test_node = update_node.start("assert", 0);
667 var write_node = update_node.start("write", 0);703 test_node.activate();
668 write_node.activate();704 defer test_node.end();
669 var out_zir = std.ArrayList(u8).init(allocator);705
670 defer out_zir.deinit();706 std.testing.expectEqualStrings(expected_output, out_zir.items);
671 try new_zir_module.writeToStream(allocator, out_zir.outStream());
672 write_node.end();
673
674 var test_node = update_node.start("assert", 0);
675 test_node.activate();
676 defer test_node.end();
677
678 std.testing.expectEqualStrings(expected_output, out_zir.items);
679 }
680 },707 },
681 .Error => |e| {708 .Error => |e| {
682 var test_node = update_node.start("assert", 0);709 var test_node = update_node.start("assert", 0);
...@@ -734,8 +761,6 @@ pub const TestContext = struct {...@@ -734,8 +761,6 @@ pub const TestContext = struct {
734 }761 }
735 },762 },
736 .Execution => |expected_stdout| {763 .Execution => |expected_stdout| {
737 std.debug.assert(!case.cbe);
738
739 update_node.setEstimatedTotalItems(4);764 update_node.setEstimatedTotalItems(4);
740 var exec_result = x: {765 var exec_result = x: {
741 var exec_node = update_node.start("execute", 0);766 var exec_node = update_node.start("execute", 0);
...@@ -745,9 +770,12 @@ pub const TestContext = struct {...@@ -745,9 +770,12 @@ pub const TestContext = struct {
745 var argv = std.ArrayList([]const u8).init(allocator);770 var argv = std.ArrayList([]const u8).init(allocator);
746 defer argv.deinit();771 defer argv.deinit();
747772
748 const exe_path = try std.fmt.allocPrint(arena, "." ++ std.fs.path.sep_str ++ "{}", .{bin_name});773 const exe_path = try std.fmt.allocPrint(arena, "." ++ std.fs.path.sep_str ++ "{s}", .{bin_name});
749774 if (case.object_format != null and case.object_format.? == .c) {
750 switch (case.target.getExternalExecutor()) {775 try argv.appendSlice(&[_][]const u8{
776 std.testing.zig_exe_path, "run", exe_path, "-lc",
777 });
778 } else switch (case.target.getExternalExecutor()) {
751 .native => try argv.append(exe_path),779 .native => try argv.append(exe_path),
752 .unavailable => {780 .unavailable => {
753 try self.runInterpreterIfAvailable(allocator, &exec_node, case, tmp.dir, bin_name);781 try self.runInterpreterIfAvailable(allocator, &exec_node, case, tmp.dir, bin_name);
...@@ -809,18 +837,13 @@ pub const TestContext = struct {...@@ -809,18 +837,13 @@ pub const TestContext = struct {
809 switch (exec_result.term) {837 switch (exec_result.term) {
810 .Exited => |code| {838 .Exited => |code| {
811 if (code != 0) {839 if (code != 0) {
812 std.debug.print("elf file exited with code {}\n", .{code});840 std.debug.print("execution exited with code {}\n", .{code});
813 return error.BinaryBadExitCode;841 return error.BinaryBadExitCode;
814 }842 }
815 },843 },
816 else => return error.BinaryCrashed,844 else => return error.BinaryCrashed,
817 }845 }
818 if (!std.mem.eql(u8, expected_stdout, exec_result.stdout)) {846 std.testing.expectEqualStrings(expected_stdout, exec_result.stdout);
819 std.debug.panic(
820 "update index {}, mismatched stdout\n====Expected (len={}):====\n{}\n====Actual (len={}):====\n{}\n========\n",
821 .{ update_index, expected_stdout.len, expected_stdout, exec_result.stdout.len, exec_result.stdout },
822 );
823 }
824 },847 },
825 }848 }
826 }849 }
test/stage2/cbe.zig+23
...@@ -9,6 +9,29 @@ const linux_x64 = std.zig.CrossTarget{...@@ -9,6 +9,29 @@ const linux_x64 = std.zig.CrossTarget{
9};9};
1010
11pub fn addCases(ctx: *TestContext) !void {11pub fn addCases(ctx: *TestContext) !void {
12 {
13 var case = ctx.exeFromCompiledC("hello world with updates", .{});
14
15 // Regular old hello world
16 case.addCompareOutput(
17 \\extern fn puts(s: [*:0]const u8) c_int;
18 \\export fn main() c_int {
19 \\ _ = puts("hello world!");
20 \\ return 0;
21 \\}
22 , "hello world!" ++ std.cstr.line_sep);
23
24 // Now change the message only
25 // TODO fix C backend not supporting updates
26 //case.addCompareOutput(
27 // \\extern fn puts(s: [*:0]const u8) c_int;
28 // \\export fn main() c_int {
29 // \\ _ = puts("yo");
30 // \\ return 0;
31 // \\}
32 //, "yo" ++ std.cstr.line_sep);
33 }
34
12 ctx.c("empty start function", linux_x64,35 ctx.c("empty start function", linux_x64,
13 \\export fn _start() noreturn {36 \\export fn _start() noreturn {
14 \\ unreachable;37 \\ unreachable;