diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-01-05 02:01:28 -0500 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-01-05 02:19:22 -0500 |
| commit | a690a5085ddbfb540cf07db146645a9f8a4e92f6 (patch) | |
| tree | 267f1c2908cd0125178d85adc41c7c81109d608e /test/src/compare_output.zig | |
| parent | 14fcfe29817c03c3cac023b045433ea7abe4bd47 (diff) | |
| download | zig-a690a5085ddbfb540cf07db146645a9f8a4e92f6.tar.gz zig-a690a5085ddbfb540cf07db146645a9f8a4e92f6.zip | |
rework and improve some of the zig build steps
* `RunStep` moved to lib/std/build/run.zig and gains ability to compare
output and exit code against expected values. Multiple redundant
locations in the test harness code are replaced to use `RunStep`.
* `WriteFileStep` moved to lib/std/build/write_file.zig and gains
ability to write more than one file into the cache directory, for
when the files need to be relative to each other. This makes
usage of `WriteFileStep` no longer problematic when parallelizing
zig build.
* Added `CheckFileStep`, which can be used to validate that the output
of another step produced a valid file. Multiple redundant locations
in the test harness code are replaced to use `CheckFileStep`.
* Added `TranslateCStep`. This exposes `zig translate-c` to the build
system, which is likely to be rarely useful by most Zig users;
however Zig's own test suite uses it both for translate-c tests and
for run-translated-c tests.
* Refactored ad-hoc code to handle source files coming from multiple
kinds of sources, into `std.build.FileSource`.
* Added `std.build.Builder.addExecutableFromWriteFileStep`.
* Added `std.build.Builder.addExecutableSource`.
* Added `std.build.Builder.addWriteFiles`.
* Added `std.build.Builder.addTranslateC`.
* Added `std.build.LibExeObjStep.addCSourceFileSource`.
* Added `std.build.LibExeObjStep.addAssemblyFileFromWriteFileStep`.
* Added `std.build.LibExeObjStep.addAssemblyFileSource`.
* Exposed `std.fs.base64_encoder`.
Diffstat (limited to 'test/src/compare_output.zig')
| -rw-r--r-- | test/src/compare_output.zig | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/test/src/compare_output.zig b/test/src/compare_output.zig new file mode 100644 index 0000000000..ae994a0697 --- /dev/null +++ b/test/src/compare_output.zig @@ -0,0 +1,165 @@ +// This is the implementation of the test harness. +// For the actual test cases, see test/compare_output.zig. +const std = @import("std"); +const builtin = std.builtin; +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; +const Mode = builtin.Mode; + +pub const CompareOutputContext = struct { + b: *build.Builder, + step: *build.Step, + test_index: usize, + test_filter: ?[]const u8, + modes: []const Mode, + + const Special = enum { + None, + Asm, + RuntimeSafety, + }; + + const TestCase = struct { + name: []const u8, + sources: ArrayList(SourceFile), + expected_output: []const u8, + link_libc: bool, + special: Special, + cli_args: []const []const u8, + + 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; + } + + pub fn setCommandLineArgs(self: *TestCase, args: []const []const u8) void { + self.cli_args = args; + } + }; + + pub fn createExtra(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8, special: Special) TestCase { + var tc = TestCase{ + .name = name, + .sources = ArrayList(TestCase.SourceFile).init(self.b.allocator), + .expected_output = expected_output, + .link_libc = false, + .special = special, + .cli_args = &[_][]const u8{}, + }; + const root_src_name = if (special == Special.Asm) "source.s" else "source.zig"; + tc.addSourceFile(root_src_name, source); + return tc; + } + + pub fn create(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) TestCase { + return createExtra(self, name, source, expected_output, Special.None); + } + + pub fn addC(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) void { + var tc = self.create(name, source, expected_output); + tc.link_libc = true; + self.addCase(tc); + } + + pub fn add(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) void { + const tc = self.create(name, source, expected_output); + self.addCase(tc); + } + + pub fn addAsm(self: *CompareOutputContext, name: []const u8, source: []const u8, expected_output: []const u8) void { + const tc = self.createExtra(name, source, expected_output, Special.Asm); + self.addCase(tc); + } + + pub fn addRuntimeSafety(self: *CompareOutputContext, name: []const u8, source: []const u8) void { + const tc = self.createExtra(name, source, undefined, Special.RuntimeSafety); + self.addCase(tc); + } + + pub fn addCase(self: *CompareOutputContext, case: TestCase) void { + const b = self.b; + + const write_src = b.addWriteFiles(); + for (case.sources.toSliceConst()) |src_file| { + write_src.add(src_file.filename, src_file.source); + } + + switch (case.special) { + Special.Asm => { + const annotated_case_name = fmt.allocPrint(self.b.allocator, "assemble-and-link {}", .{ + case.name, + }) catch unreachable; + if (self.test_filter) |filter| { + if (mem.indexOf(u8, annotated_case_name, filter) == null) return; + } + + const exe = b.addExecutable("test", null); + exe.addAssemblyFileFromWriteFileStep(write_src, case.sources.toSliceConst()[0].filename); + + const run = exe.run(); + run.addArgs(case.cli_args); + run.expectStdErrEqual(""); + run.expectStdOutEqual(case.expected_output); + + self.step.dependOn(&run.step); + }, + Special.None => { + for (self.modes) |mode| { + const annotated_case_name = fmt.allocPrint(self.b.allocator, "{} {} ({})", .{ + "compare-output", + case.name, + @tagName(mode), + }) catch unreachable; + if (self.test_filter) |filter| { + if (mem.indexOf(u8, annotated_case_name, filter) == null) continue; + } + + const basename = case.sources.toSliceConst()[0].filename; + const exe = b.addExecutableFromWriteFileStep("test", write_src, basename); + exe.setBuildMode(mode); + if (case.link_libc) { + exe.linkSystemLibrary("c"); + } + + const run = exe.run(); + run.addArgs(case.cli_args); + run.expectStdErrEqual(""); + run.expectStdOutEqual(case.expected_output); + + self.step.dependOn(&run.step); + } + }, + Special.RuntimeSafety => { + const annotated_case_name = fmt.allocPrint(self.b.allocator, "safety {}", .{case.name}) catch unreachable; + if (self.test_filter) |filter| { + if (mem.indexOf(u8, annotated_case_name, filter) == null) return; + } + + const basename = case.sources.toSliceConst()[0].filename; + const exe = b.addExecutableFromWriteFileStep("test", write_src, basename); + if (case.link_libc) { + exe.linkSystemLibrary("c"); + } + + const run = exe.run(); + run.addArgs(case.cli_args); + run.stderr_action = .ignore; + run.stdout_action = .ignore; + run.expected_exit_code = 126; + + self.step.dependOn(&run.step); + }, + } + } +}; |
