diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-01-02 22:45:48 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-01-03 00:26:12 -0500 |
| commit | 695c8f756b7ef12c4e8993720503b9c6d2242689 (patch) | |
| tree | 477bd6c3482558abbd26a4844500067af9b3d317 /test | |
| parent | f83411b0b1b857c7f8679e3b90d2093ba60621d4 (diff) | |
| download | zig-695c8f756b7ef12c4e8993720503b9c6d2242689.tar.gz zig-695c8f756b7ef12c4e8993720503b9c6d2242689.zip | |
add test harness for "run translated C" tests
Diffstat (limited to 'test')
| -rw-r--r-- | test/run_translated_c.zig | 24 | ||||
| -rw-r--r-- | test/src/run_translated_c.zig | 180 | ||||
| -rw-r--r-- | test/tests.zig | 19 |
3 files changed, 223 insertions, 0 deletions
diff --git a/test/run_translated_c.zig b/test/run_translated_c.zig new file mode 100644 index 0000000000..4bfe22d366 --- /dev/null +++ b/test/run_translated_c.zig @@ -0,0 +1,24 @@ +const tests = @import("tests.zig"); + +pub fn addCases(cases: *tests.RunTranslatedCContext) void { + cases.add("hello world", + \\#define _NO_CRT_STDIO_INLINE 1 + \\#include <stdio.h> + \\int main(int argc, char **argv) { + \\ printf("hello, world!\n"); + \\ return 0; + \\} + , "hello, world!\n"); + + cases.add("anon struct init", + \\#include <stdlib.h> + \\struct {int a; int b;} x = {1, 2}; + \\int main(int argc, char **argv) { + \\ x.a += 2; + \\ x.b += 1; + \\ if (x.a != 3) abort(); + \\ if (x.b != 3) abort(); + \\ return 0; + \\} + , ""); +} diff --git a/test/src/run_translated_c.zig b/test/src/run_translated_c.zig new file mode 100644 index 0000000000..ae09e32dbc --- /dev/null +++ b/test/src/run_translated_c.zig @@ -0,0 +1,180 @@ +// This is the implementation of the test harness for running translated +// C code. For the actual test cases, see test/run_translated_c.zig. +const std = @import("std"); +const build = std.build; +const ArrayList = std.ArrayList; +const fmt = std.fmt; +const mem = std.mem; +const fs = std.fs; +const warn = std.debug.warn; + +pub const RunTranslatedCContext = struct { + b: *build.Builder, + step: *build.Step, + test_index: usize, + test_filter: ?[]const u8, + + const TestCase = struct { + name: []const u8, + sources: ArrayList(SourceFile), + expected_stdout: []const u8, + allow_warnings: bool, + + const SourceFile = struct { + filename: []const u8, + source: []const u8, + }; + + pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void { + self.sources.append(SourceFile{ + .filename = filename, + .source = source, + }) catch unreachable; + } + }; + + const DoEverythingStep = struct { + step: build.Step, + context: *RunTranslatedCContext, + name: []const u8, + case: *const TestCase, + test_index: usize, + + pub fn create( + context: *RunTranslatedCContext, + name: []const u8, + case: *const TestCase, + ) *DoEverythingStep { + const allocator = context.b.allocator; + const ptr = allocator.create(DoEverythingStep) catch unreachable; + ptr.* = DoEverythingStep{ + .context = context, + .name = name, + .case = case, + .test_index = context.test_index, + .step = build.Step.init("RunTranslatedC", allocator, make), + }; + context.test_index += 1; + return ptr; + } + + fn make(step: *build.Step) !void { + const self = @fieldParentPtr(DoEverythingStep, "step", step); + const b = self.context.b; + + warn("Test {}/{} {}...", .{ self.test_index + 1, self.context.test_index, self.name }); + // translate from c to zig + const translated_c_code = blk: { + var zig_args = ArrayList([]const u8).init(b.allocator); + defer zig_args.deinit(); + + const rel_c_filename = try fs.path.join(b.allocator, &[_][]const u8{ + b.cache_root, + self.case.sources.toSliceConst()[0].filename, + }); + + try zig_args.append(b.zig_exe); + try zig_args.append("translate-c"); + try zig_args.append("-lc"); + try zig_args.append(b.pathFromRoot(rel_c_filename)); + + break :blk try b.exec(zig_args.toSliceConst()); + }; + + // write stdout to a file + + const translated_c_path = try fs.path.join(b.allocator, + &[_][]const u8{ b.cache_root, "translated_c.zig" }); + try fs.cwd().writeFile(translated_c_path, translated_c_code); + + // zig run the result + const run_stdout = blk: { + var zig_args = ArrayList([]const u8).init(b.allocator); + defer zig_args.deinit(); + + try zig_args.append(b.zig_exe); + try zig_args.append("-lc"); + try zig_args.append("run"); + try zig_args.append(translated_c_path); + + break :blk try b.exec(zig_args.toSliceConst()); + }; + // compare stdout + if (!mem.eql(u8, self.case.expected_stdout, run_stdout)) { + warn( + \\ + \\========= Expected this output: ========= + \\{} + \\========= But found: ==================== + \\{} + \\ + , .{ self.case.expected_stdout, run_stdout }); + return error.TestFailed; + } + + warn("OK\n", .{}); + } + }; + + pub fn create( + self: *RunTranslatedCContext, + allow_warnings: bool, + filename: []const u8, + name: []const u8, + source: []const u8, + expected_stdout: []const u8, + ) *TestCase { + const tc = self.b.allocator.create(TestCase) catch unreachable; + tc.* = TestCase{ + .name = name, + .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), + .expected_stdout = expected_stdout, + .allow_warnings = allow_warnings, + }; + + tc.addSourceFile(filename, source); + return tc; + } + + pub fn add( + self: *RunTranslatedCContext, + name: []const u8, + source: []const u8, + expected_stdout: []const u8, + ) void { + const tc = self.create(false, "source.c", name, source, expected_stdout); + self.addCase(tc); + } + + pub fn addAllowWarnings( + self: *RunTranslatedCContext, + name: []const u8, + source: []const u8, + expected_stdout: []const u8, + ) void { + const tc = self.create(true, "source.c", name, source, expected_stdout); + self.addCase(tc); + } + + pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void { + const b = self.b; + + const annotated_case_name = fmt.allocPrint(self.b.allocator, "run-translated-c {}", .{ case.name }) catch unreachable; + if (self.test_filter) |filter| { + if (mem.indexOf(u8, annotated_case_name, filter) == null) return; + } + + const do_everything_step = DoEverythingStep.create(self, annotated_case_name, case); + self.step.dependOn(&do_everything_step.step); + + for (case.sources.toSliceConst()) |src_file| { + const expanded_src_path = fs.path.join( + b.allocator, + &[_][]const u8{ b.cache_root, src_file.filename }, + ) catch unreachable; + const write_src = b.addWriteFile(expanded_src_path, src_file.source); + do_everything_step.step.dependOn(&write_src.step); + } + } +}; + diff --git a/test/tests.zig b/test/tests.zig index 4672359802..4636eb8132 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -14,6 +14,7 @@ const builtin = @import("builtin"); const Mode = builtin.Mode; const LibExeObjStep = build.LibExeObjStep; +// Cases const compare_output = @import("compare_output.zig"); const standalone = @import("standalone.zig"); const stack_traces = @import("stack_traces.zig"); @@ -21,8 +22,12 @@ const compile_errors = @import("compile_errors.zig"); const assemble_and_link = @import("assemble_and_link.zig"); const runtime_safety = @import("runtime_safety.zig"); const translate_c = @import("translate_c.zig"); +const run_translated_c = @import("run_translated_c.zig"); const gen_h = @import("gen_h.zig"); +// Implementations +pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTranslatedCContext; + const TestTarget = struct { target: Target = .Native, mode: builtin.Mode = .Debug, @@ -383,6 +388,20 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St return cases.step; } +pub fn addRunTranslatedCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { + const cases = b.allocator.create(RunTranslatedCContext) catch unreachable; + cases.* = .{ + .b = b, + .step = b.step("test-run-translated-c", "Run the Run-Translated-C tests"), + .test_index = 0, + .test_filter = test_filter, + }; + + run_translated_c.addCases(cases); + + return cases.step; +} + pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step { const cases = b.allocator.create(GenHContext) catch unreachable; cases.* = GenHContext{ |
