Commit 8538053940

Noam Preil <noam@pixelhero.dev>
2020-11-19 02:51:42
Add header test harness
1 parent ac33b10
Changed files (2)
src
test
stage2
src/test.zig
@@ -96,6 +96,10 @@ pub const TestContext = struct {
             /// stdout against the expected results
             /// This is a slice containing the expected message.
             Execution: []const u8,
+            /// A header update compiles the input with the equivalent of
+            /// `-Demit_h=true` and tests the produced header against the
+            /// expected result
+            Header: []const u8,
         },
     };
 
@@ -138,6 +142,15 @@ pub const TestContext = struct {
             }) catch unreachable;
         }
 
+        /// Adds a subcase in which the module is updated with `src`, and a C
+        /// header is generated.
+        pub fn addHeader(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
+            self.updates.append(.{
+                .src = src,
+                .case = .{ .Header = result },
+            }) catch unreachable;
+        }
+
         /// Adds a subcase in which the module is updated with `src`, compiled,
         /// run, and the output is tested against `result`.
         pub fn addCompareOutput(self: *Case, src: [:0]const u8, result: []const u8) void {
@@ -269,6 +282,10 @@ pub const TestContext = struct {
         ctx.addC(name, target, .Zig).addTransform(src, cheader ++ out);
     }
 
+    pub fn h(ctx: *TestContext, name: []const u8, target: std.zig.CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {
+        ctx.addC(name, target, .Zig).addHeader(src, cheader ++ out);
+    }
+
     pub fn addCompareOutput(
         ctx: *TestContext,
         name: []const u8,
@@ -547,6 +564,10 @@ pub const TestContext = struct {
             .directory = emit_directory,
             .basename = bin_name,
         };
+        const emit_h: Compilation.EmitLoc = .{
+            .directory = emit_directory,
+            .basename = "test_case.h",
+        };
         const comp = try Compilation.create(allocator, .{
             .local_cache_directory = zig_cache_directory,
             .global_cache_directory = zig_cache_directory,
@@ -561,6 +582,7 @@ pub const TestContext = struct {
             // TODO: support testing optimizations
             .optimize_mode = .Debug,
             .emit_bin = emit_bin,
+            .emit_h = emit_h,
             .root_pkg = &root_pkg,
             .keep_source_files_loaded = true,
             .object_format = ofmt,
@@ -616,6 +638,22 @@ pub const TestContext = struct {
             }
 
             switch (update.case) {
+                .Header => |expected_output| {
+                    var file = try tmp.dir.openFile("test_case.h", .{ .read = true });
+                    defer file.close();
+                    var out = file.reader().readAllAlloc(arena, 1024 * 1024) catch @panic("Unable to read headeroutput!");
+
+                    if (expected_output.len != out.len) {
+                        std.debug.print("\nTransformed header length differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out });
+                        std.process.exit(1);
+                    }
+                    for (expected_output) |e, i| {
+                        if (out[i] != e) {
+                            std.debug.print("\nTransformed header differs:\n================\nExpected:\n================\n{}\n================\nFound:\n================\n{}\n================\nTest failed.\n", .{ expected_output, out });
+                            std.process.exit(1);
+                        }
+                    }
+                },
                 .Transformation => |expected_output| {
                     if (case.cbe) {
                         // The C file is always closed after an update, because we don't support
@@ -670,8 +708,8 @@ pub const TestContext = struct {
                     test_node.activate();
                     defer test_node.end();
                     var handled_errors = try arena.alloc(bool, e.len);
-                    for (handled_errors) |*h| {
-                        h.* = false;
+                    for (handled_errors) |*handled| {
+                        handled.* = false;
                     }
                     var all_errors = try comp.getAllErrorsAlloc();
                     defer all_errors.deinit(allocator);
@@ -709,8 +747,8 @@ pub const TestContext = struct {
                         }
                     }
 
-                    for (handled_errors) |h, i| {
-                        if (!h) {
+                    for (handled_errors) |handled, i| {
+                        if (!handled) {
                             const er = e[i];
                             std.debug.print(
                                 "{s}\nDid not receive error:\n================\n{}\n================\nTest failed.\n",
test/stage2/cbe.zig
@@ -19,6 +19,12 @@ pub fn addCases(ctx: *TestContext) !void {
         \\}
         \\
     );
+    ctx.h("Simple header", linux_x64,
+        \\export fn start() void{}
+    ,
+        \\void start(void);
+        \\
+    );
     ctx.c("less empty start function", linux_x64,
         \\fn main() noreturn {
         \\    unreachable;