aboutsummaryrefslogtreecommitdiff
path: root/src-self-hosted/test.zig
diff options
context:
space:
mode:
authorAndrew Kelley <superjoe30@gmail.com>2018-07-10 20:18:43 -0400
committerAndrew Kelley <superjoe30@gmail.com>2018-07-10 20:18:43 -0400
commit574e31f0a046aa6e6fad73fff2cbbb3617fe1bae (patch)
treeb83f2dfec8821055929b82b18c87ea6b4e8da78a /src-self-hosted/test.zig
parent8fba0a6ae862993afa2aeca774347adc399b3605 (diff)
downloadzig-574e31f0a046aa6e6fad73fff2cbbb3617fe1bae.tar.gz
zig-574e31f0a046aa6e6fad73fff2cbbb3617fe1bae.zip
self-hosted: first passing test
* introduce std.atomic.Int * add src-self-hosted/test.zig which is tested by the main test suite - it fully utilizes the multithreaded async/await event loop so the tests should Go Fast * `stage2/bin/zig build-obj test.zig` is able to spit out an error if 2 exported functions collide * ability for `zig test` to accept `--object` and `--assembly` arguments * std.build: TestStep supports addLibPath and addObjectFile
Diffstat (limited to 'src-self-hosted/test.zig')
-rw-r--r--src-self-hosted/test.zig176
1 files changed, 176 insertions, 0 deletions
diff --git a/src-self-hosted/test.zig b/src-self-hosted/test.zig
new file mode 100644
index 0000000000..7ce7cf6ee3
--- /dev/null
+++ b/src-self-hosted/test.zig
@@ -0,0 +1,176 @@
+const std = @import("std");
+const mem = std.mem;
+const builtin = @import("builtin");
+const Target = @import("target.zig").Target;
+const Module = @import("module.zig").Module;
+const introspect = @import("introspect.zig");
+const assertOrPanic = std.debug.assertOrPanic;
+const errmsg = @import("errmsg.zig");
+
+test "compile errors" {
+ var ctx: TestContext = undefined;
+ try ctx.init();
+ defer ctx.deinit();
+
+ try ctx.testCompileError(
+ \\export fn entry() void {}
+ \\export fn entry() void {}
+ , file1, 2, 8, "exported symbol collision: 'entry'");
+
+ try ctx.run();
+}
+
+const file1 = "1.zig";
+
+const TestContext = struct {
+ loop: std.event.Loop,
+ zig_lib_dir: []u8,
+ direct_allocator: std.heap.DirectAllocator,
+ arena: std.heap.ArenaAllocator,
+ zig_cache_dir: []u8,
+ file_index: std.atomic.Int(usize),
+ group: std.event.Group(error!void),
+ any_err: error!void,
+
+ const tmp_dir_name = "stage2_test_tmp";
+
+ fn init(self: *TestContext) !void {
+ self.* = TestContext{
+ .any_err = {},
+ .direct_allocator = undefined,
+ .arena = undefined,
+ .loop = undefined,
+ .zig_lib_dir = undefined,
+ .zig_cache_dir = undefined,
+ .group = undefined,
+ .file_index = std.atomic.Int(usize).init(0),
+ };
+
+ self.direct_allocator = std.heap.DirectAllocator.init();
+ errdefer self.direct_allocator.deinit();
+
+ self.arena = std.heap.ArenaAllocator.init(&self.direct_allocator.allocator);
+ errdefer self.arena.deinit();
+
+ // TODO faster allocator for coroutines that is thread-safe/lock-free
+ try self.loop.initMultiThreaded(&self.direct_allocator.allocator);
+ errdefer self.loop.deinit();
+
+ self.group = std.event.Group(error!void).init(&self.loop);
+ errdefer self.group.cancelAll();
+
+ self.zig_lib_dir = try introspect.resolveZigLibDir(&self.arena.allocator);
+ errdefer self.arena.allocator.free(self.zig_lib_dir);
+
+ self.zig_cache_dir = try introspect.resolveZigCacheDir(&self.arena.allocator);
+ errdefer self.arena.allocator.free(self.zig_cache_dir);
+
+ try std.os.makePath(&self.arena.allocator, tmp_dir_name);
+ errdefer std.os.deleteTree(&self.arena.allocator, tmp_dir_name) catch {};
+ }
+
+ fn deinit(self: *TestContext) void {
+ std.os.deleteTree(&self.arena.allocator, tmp_dir_name) catch {};
+ self.arena.allocator.free(self.zig_cache_dir);
+ self.arena.allocator.free(self.zig_lib_dir);
+ self.loop.deinit();
+ self.arena.deinit();
+ self.direct_allocator.deinit();
+ }
+
+ fn run(self: *TestContext) !void {
+ const handle = try self.loop.call(waitForGroup, self);
+ defer cancel handle;
+ self.loop.run();
+ return self.any_err;
+ }
+
+ async fn waitForGroup(self: *TestContext) void {
+ self.any_err = await (async self.group.wait() catch unreachable);
+ }
+
+ fn testCompileError(
+ self: *TestContext,
+ source: []const u8,
+ path: []const u8,
+ line: usize,
+ column: usize,
+ msg: []const u8,
+ ) !void {
+ var file_index_buf: [20]u8 = undefined;
+ const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.next());
+ const file1_path = try std.os.path.join(&self.arena.allocator, tmp_dir_name, file_index, file1);
+
+ if (std.os.path.dirname(file1_path)) |dirname| {
+ try std.os.makePath(&self.arena.allocator, dirname);
+ }
+
+ // TODO async I/O
+ try std.io.writeFile(&self.arena.allocator, file1_path, source);
+
+ var module = try Module.create(
+ &self.loop,
+ "test",
+ file1_path,
+ Target.Native,
+ Module.Kind.Obj,
+ builtin.Mode.Debug,
+ self.zig_lib_dir,
+ self.zig_cache_dir,
+ );
+ errdefer module.destroy();
+
+ try module.build();
+
+ try self.group.call(getModuleEvent, module, source, path, line, column, msg);
+ }
+
+ async fn getModuleEvent(
+ module: *Module,
+ source: []const u8,
+ path: []const u8,
+ line: usize,
+ column: usize,
+ text: []const u8,
+ ) !void {
+ defer module.destroy();
+ const build_event = await (async module.events.get() catch unreachable);
+
+ switch (build_event) {
+ Module.Event.Ok => {
+ @panic("build incorrectly succeeded");
+ },
+ Module.Event.Error => |err| {
+ @panic("build incorrectly failed");
+ },
+ Module.Event.Fail => |msgs| {
+ assertOrPanic(msgs.len != 0);
+ for (msgs) |msg| {
+ if (mem.endsWith(u8, msg.path, path) and mem.eql(u8, msg.text, text)) {
+ const first_token = msg.tree.tokens.at(msg.span.first);
+ const last_token = msg.tree.tokens.at(msg.span.first);
+ const start_loc = msg.tree.tokenLocationPtr(0, first_token);
+ if (start_loc.line + 1 == line and start_loc.column + 1 == column) {
+ return;
+ }
+ }
+ }
+ std.debug.warn(
+ "\n=====source:=======\n{}\n====expected:========\n{}:{}:{}: error: {}\n",
+ source,
+ path,
+ line,
+ column,
+ text,
+ );
+ std.debug.warn("\n====found:========\n");
+ var stderr = try std.io.getStdErr();
+ for (msgs) |msg| {
+ try errmsg.printToFile(&stderr, msg, errmsg.Color.Auto);
+ }
+ std.debug.warn("============\n");
+ return error.TestFailed;
+ },
+ }
+ }
+};