authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-02 22:45:48-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-03 00:26:12-05:00
log695c8f756b7ef12c4e8993720503b9c6d2242689
tree477bd6c3482558abbd26a4844500067af9b3d317
parentf83411b0b1b857c7f8679e3b90d2093ba60621d4
signature Commit is signed but in an unrecognized format.

add test harness for "run translated C" tests


5 files changed, 224 insertions(+), 1 deletions(-)

build.zig+1
...@@ -137,6 +137,7 @@ pub fn build(b: *Builder) !void {...@@ -137,6 +137,7 @@ pub fn build(b: *Builder) !void {
137 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));137 test_step.dependOn(tests.addAssembleAndLinkTests(b, test_filter, modes));
138 test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));138 test_step.dependOn(tests.addRuntimeSafetyTests(b, test_filter, modes));
139 test_step.dependOn(tests.addTranslateCTests(b, test_filter));139 test_step.dependOn(tests.addTranslateCTests(b, test_filter));
140 test_step.dependOn(tests.addRunTranslatedCTests(b, test_filter));
140 test_step.dependOn(tests.addGenHTests(b, test_filter));141 test_step.dependOn(tests.addGenHTests(b, test_filter));
141 test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));142 test_step.dependOn(tests.addCompileErrorTests(b, test_filter, modes));
142 test_step.dependOn(docs_step);143 test_step.dependOn(docs_step);
src/main.cpp-1
...@@ -43,7 +43,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -43,7 +43,6 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
43 " libc [paths_file] Display native libc paths file or validate one\n"43 " libc [paths_file] Display native libc paths file or validate one\n"
44 " run [source] [-- [args]] create executable and run immediately\n"44 " run [source] [-- [args]] create executable and run immediately\n"
45 " translate-c [source] convert c code to zig code\n"45 " translate-c [source] convert c code to zig code\n"
46 " translate-c-2 [source] experimental self-hosted translate-c\n"
47 " targets list available compilation targets\n"46 " targets list available compilation targets\n"
48 " test [source] create and run a test build\n"47 " test [source] create and run a test build\n"
49 " version print version number and exit\n"48 " version print version number and exit\n"
test/run_translated_c.zig created+24
...@@ -0,0 +1,24 @@
1const tests = @import("tests.zig");
2
3pub fn addCases(cases: *tests.RunTranslatedCContext) void {
4 cases.add("hello world",
5 \\#define _NO_CRT_STDIO_INLINE 1
6 \\#include <stdio.h>
7 \\int main(int argc, char **argv) {
8 \\ printf("hello, world!\n");
9 \\ return 0;
10 \\}
11 , "hello, world!\n");
12
13 cases.add("anon struct init",
14 \\#include <stdlib.h>
15 \\struct {int a; int b;} x = {1, 2};
16 \\int main(int argc, char **argv) {
17 \\ x.a += 2;
18 \\ x.b += 1;
19 \\ if (x.a != 3) abort();
20 \\ if (x.b != 3) abort();
21 \\ return 0;
22 \\}
23 , "");
24}
test/src/run_translated_c.zig created+180
...@@ -0,0 +1,180 @@
1// This is the implementation of the test harness for running translated
2// C code. For the actual test cases, see test/run_translated_c.zig.
3const std = @import("std");
4const build = std.build;
5const ArrayList = std.ArrayList;
6const fmt = std.fmt;
7const mem = std.mem;
8const fs = std.fs;
9const warn = std.debug.warn;
10
11pub const RunTranslatedCContext = struct {
12 b: *build.Builder,
13 step: *build.Step,
14 test_index: usize,
15 test_filter: ?[]const u8,
16
17 const TestCase = struct {
18 name: []const u8,
19 sources: ArrayList(SourceFile),
20 expected_stdout: []const u8,
21 allow_warnings: bool,
22
23 const SourceFile = struct {
24 filename: []const u8,
25 source: []const u8,
26 };
27
28 pub fn addSourceFile(self: *TestCase, filename: []const u8, source: []const u8) void {
29 self.sources.append(SourceFile{
30 .filename = filename,
31 .source = source,
32 }) catch unreachable;
33 }
34 };
35
36 const DoEverythingStep = struct {
37 step: build.Step,
38 context: *RunTranslatedCContext,
39 name: []const u8,
40 case: *const TestCase,
41 test_index: usize,
42
43 pub fn create(
44 context: *RunTranslatedCContext,
45 name: []const u8,
46 case: *const TestCase,
47 ) *DoEverythingStep {
48 const allocator = context.b.allocator;
49 const ptr = allocator.create(DoEverythingStep) catch unreachable;
50 ptr.* = DoEverythingStep{
51 .context = context,
52 .name = name,
53 .case = case,
54 .test_index = context.test_index,
55 .step = build.Step.init("RunTranslatedC", allocator, make),
56 };
57 context.test_index += 1;
58 return ptr;
59 }
60
61 fn make(step: *build.Step) !void {
62 const self = @fieldParentPtr(DoEverythingStep, "step", step);
63 const b = self.context.b;
64
65 warn("Test {}/{} {}...", .{ self.test_index + 1, self.context.test_index, self.name });
66 // translate from c to zig
67 const translated_c_code = blk: {
68 var zig_args = ArrayList([]const u8).init(b.allocator);
69 defer zig_args.deinit();
70
71 const rel_c_filename = try fs.path.join(b.allocator, &[_][]const u8{
72 b.cache_root,
73 self.case.sources.toSliceConst()[0].filename,
74 });
75
76 try zig_args.append(b.zig_exe);
77 try zig_args.append("translate-c");
78 try zig_args.append("-lc");
79 try zig_args.append(b.pathFromRoot(rel_c_filename));
80
81 break :blk try b.exec(zig_args.toSliceConst());
82 };
83
84 // write stdout to a file
85
86 const translated_c_path = try fs.path.join(b.allocator,
87 &[_][]const u8{ b.cache_root, "translated_c.zig" });
88 try fs.cwd().writeFile(translated_c_path, translated_c_code);
89
90 // zig run the result
91 const run_stdout = blk: {
92 var zig_args = ArrayList([]const u8).init(b.allocator);
93 defer zig_args.deinit();
94
95 try zig_args.append(b.zig_exe);
96 try zig_args.append("-lc");
97 try zig_args.append("run");
98 try zig_args.append(translated_c_path);
99
100 break :blk try b.exec(zig_args.toSliceConst());
101 };
102 // compare stdout
103 if (!mem.eql(u8, self.case.expected_stdout, run_stdout)) {
104 warn(
105 \\
106 \\========= Expected this output: =========
107 \\{}
108 \\========= But found: ====================
109 \\{}
110 \\
111 , .{ self.case.expected_stdout, run_stdout });
112 return error.TestFailed;
113 }
114
115 warn("OK\n", .{});
116 }
117 };
118
119 pub fn create(
120 self: *RunTranslatedCContext,
121 allow_warnings: bool,
122 filename: []const u8,
123 name: []const u8,
124 source: []const u8,
125 expected_stdout: []const u8,
126 ) *TestCase {
127 const tc = self.b.allocator.create(TestCase) catch unreachable;
128 tc.* = TestCase{
129 .name = name,
130 .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator),
131 .expected_stdout = expected_stdout,
132 .allow_warnings = allow_warnings,
133 };
134
135 tc.addSourceFile(filename, source);
136 return tc;
137 }
138
139 pub fn add(
140 self: *RunTranslatedCContext,
141 name: []const u8,
142 source: []const u8,
143 expected_stdout: []const u8,
144 ) void {
145 const tc = self.create(false, "source.c", name, source, expected_stdout);
146 self.addCase(tc);
147 }
148
149 pub fn addAllowWarnings(
150 self: *RunTranslatedCContext,
151 name: []const u8,
152 source: []const u8,
153 expected_stdout: []const u8,
154 ) void {
155 const tc = self.create(true, "source.c", name, source, expected_stdout);
156 self.addCase(tc);
157 }
158
159 pub fn addCase(self: *RunTranslatedCContext, case: *const TestCase) void {
160 const b = self.b;
161
162 const annotated_case_name = fmt.allocPrint(self.b.allocator, "run-translated-c {}", .{ case.name }) catch unreachable;
163 if (self.test_filter) |filter| {
164 if (mem.indexOf(u8, annotated_case_name, filter) == null) return;
165 }
166
167 const do_everything_step = DoEverythingStep.create(self, annotated_case_name, case);
168 self.step.dependOn(&do_everything_step.step);
169
170 for (case.sources.toSliceConst()) |src_file| {
171 const expanded_src_path = fs.path.join(
172 b.allocator,
173 &[_][]const u8{ b.cache_root, src_file.filename },
174 ) catch unreachable;
175 const write_src = b.addWriteFile(expanded_src_path, src_file.source);
176 do_everything_step.step.dependOn(&write_src.step);
177 }
178 }
179};
180
test/tests.zig+19
...@@ -14,6 +14,7 @@ const builtin = @import("builtin");...@@ -14,6 +14,7 @@ const builtin = @import("builtin");
14const Mode = builtin.Mode;14const Mode = builtin.Mode;
15const LibExeObjStep = build.LibExeObjStep;15const LibExeObjStep = build.LibExeObjStep;
1616
17// Cases
17const compare_output = @import("compare_output.zig");18const compare_output = @import("compare_output.zig");
18const standalone = @import("standalone.zig");19const standalone = @import("standalone.zig");
19const stack_traces = @import("stack_traces.zig");20const stack_traces = @import("stack_traces.zig");
...@@ -21,8 +22,12 @@ const compile_errors = @import("compile_errors.zig");...@@ -21,8 +22,12 @@ const compile_errors = @import("compile_errors.zig");
21const assemble_and_link = @import("assemble_and_link.zig");22const assemble_and_link = @import("assemble_and_link.zig");
22const runtime_safety = @import("runtime_safety.zig");23const runtime_safety = @import("runtime_safety.zig");
23const translate_c = @import("translate_c.zig");24const translate_c = @import("translate_c.zig");
25const run_translated_c = @import("run_translated_c.zig");
24const gen_h = @import("gen_h.zig");26const gen_h = @import("gen_h.zig");
2527
28// Implementations
29pub const RunTranslatedCContext = @import("src/run_translated_c.zig").RunTranslatedCContext;
30
26const TestTarget = struct {31const TestTarget = struct {
27 target: Target = .Native,32 target: Target = .Native,
28 mode: builtin.Mode = .Debug,33 mode: builtin.Mode = .Debug,
...@@ -383,6 +388,20 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St...@@ -383,6 +388,20 @@ pub fn addTranslateCTests(b: *build.Builder, test_filter: ?[]const u8) *build.St
383 return cases.step;388 return cases.step;
384}389}
385390
391pub fn addRunTranslatedCTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
392 const cases = b.allocator.create(RunTranslatedCContext) catch unreachable;
393 cases.* = .{
394 .b = b,
395 .step = b.step("test-run-translated-c", "Run the Run-Translated-C tests"),
396 .test_index = 0,
397 .test_filter = test_filter,
398 };
399
400 run_translated_c.addCases(cases);
401
402 return cases.step;
403}
404
386pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {405pub fn addGenHTests(b: *build.Builder, test_filter: ?[]const u8) *build.Step {
387 const cases = b.allocator.create(GenHContext) catch unreachable;406 const cases = b.allocator.create(GenHContext) catch unreachable;
388 cases.* = GenHContext{407 cases.* = GenHContext{