diff options
-rw-r--r-- | .gitignore | 9 | ||||
-rw-r--r-- | src/test/fixtures/function-scope-bug.jsx | 28 | ||||
-rw-r--r-- | src/test/tester.zig | 159 |
3 files changed, 196 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore index d05822f8d..ec6caf6c7 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,12 @@ zig-cache *.o *.a profile.json + +/package.json +node_modules +.swcrc +yarn.lock +dist +*.log +*.out.js +/package-lock.json
\ No newline at end of file diff --git a/src/test/fixtures/function-scope-bug.jsx b/src/test/fixtures/function-scope-bug.jsx new file mode 100644 index 000000000..57c783d87 --- /dev/null +++ b/src/test/fixtures/function-scope-bug.jsx @@ -0,0 +1,28 @@ +var Button = () => { + return <div className="button">Button!</div>; +}; + +var Bar = () => { + return ( + <div prop={1}> + Plain text + <div> + ← A child div + <Button>Red</Button> + </div> + </div> + ); +}; + +// This is where it failed. +var Baz = () => { + return ( + <div prop={1}> + Plain text + <div> + ← A child div + <Button>Red</Button> + </div> + </div> + ); +}; diff --git a/src/test/tester.zig b/src/test/tester.zig new file mode 100644 index 000000000..6b3174eac --- /dev/null +++ b/src/test/tester.zig @@ -0,0 +1,159 @@ +const std = @import("std"); + +const string = []const u8; + +const RED = "\x1b[31;1m"; +const GREEN = "\x1b[32;1m"; +const CYAN = "\x1b[36;1m"; +const WHITE = "\x1b[37;1m"; +const DIM = "\x1b[2m"; +const RESET = "\x1b[0m"; + +pub const Tester = struct { + pass: std.ArrayList(Expectation), + fail: std.ArrayList(Expectation), + allocator: *std.mem.Allocator, + + pub fn t(allocator: *std.mem.Allocator) Tester { + return Tester{ + .allocator = allocator, + .pass = std.ArrayList(Expectation).init(allocator), + .fail = std.ArrayList(Expectation).init(allocator), + }; + } + + pub const Expectation = struct { + expected: string, + result: string, + source: std.builtin.SourceLocation, + + pub fn init(expected: string, result: string, src: std.builtin.SourceLocation) Expectation { + return Expectation{ + .expected = expected, + .result = result, + .source = src, + }; + } + const PADDING = 0; + pub fn print(self: *const @This()) void { + var pad = &([_]u8{' '} ** PADDING); + var stderr = std.io.getStdErr(); + + stderr.writeAll(RESET) catch unreachable; + stderr.writeAll(pad) catch unreachable; + stderr.writeAll(DIM) catch unreachable; + std.fmt.format(stderr.writer(), "{s}:{d}:{d}", .{ self.source.file, self.source.line, self.source.column }) catch unreachable; + stderr.writeAll(RESET) catch unreachable; + stderr.writeAll("\n") catch unreachable; + + stderr.writeAll(pad) catch unreachable; + stderr.writeAll("Expected: ") catch unreachable; + stderr.writeAll(RESET) catch unreachable; + stderr.writeAll(GREEN) catch unreachable; + std.fmt.format(stderr.writer(), "\"{s}\"", .{self.expected}) catch unreachable; + stderr.writeAll(GREEN) catch unreachable; + stderr.writeAll(RESET) catch unreachable; + + stderr.writeAll("\n") catch unreachable; + stderr.writeAll(pad) catch unreachable; + stderr.writeAll("Received: ") catch unreachable; + stderr.writeAll(RESET) catch unreachable; + stderr.writeAll(RED) catch unreachable; + std.fmt.format(stderr.writer(), "\"{s}\"", .{self.result}) catch unreachable; + stderr.writeAll(RED) catch unreachable; + stderr.writeAll(RESET) catch unreachable; + stderr.writeAll("\n") catch unreachable; + } + + pub fn evaluate_outcome(self: *const @This()) Outcome { + for (self.expected) |char, i| { + if (char != self.result[i]) { + return Outcome.fail; + } + } + + return Outcome.pass; + } + }; + + pub const Outcome = enum { + pass, + fail, + }; + + pub fn expect(tester: *Tester, expected: string, result: string, src: std.builtin.SourceLocation) callconv(.Inline) bool { + var expectation = Expectation.init(expected, result, src); + switch (expectation.evaluate_outcome()) { + .pass => { + tester.pass.append(expectation) catch unreachable; + return true; + }, + .fail => { + tester.fail.append(expectation) catch unreachable; + return false; + }, + } + } + + const ReportType = enum { + none, + pass, + fail, + some_fail, + + pub fn init(tester: *Tester) ReportType { + if (tester.fail.items.len == 0 and tester.pass.items.len == 0) { + return .none; + } else if (tester.fail.items.len == 0) { + return .pass; + } else if (tester.pass.items.len == 0) { + return .fail; + } else { + return .some_fail; + } + } + }; + + pub fn report(tester: *Tester, src: std.builtin.SourceLocation) void { + var stderr = std.io.getStdErr(); + + if (tester.fail.items.len > 0) { + std.fmt.format(stderr.writer(), "\n\n", .{}) catch unreachable; + } + + for (tester.fail.items) |item| { + item.print(); + std.fmt.format(stderr.writer(), "\n", .{}) catch unreachable; + } + + switch (ReportType.init(tester)) { + .none => { + std.log.info("No expectations.\n\n", .{}); + }, + .pass => { + std.fmt.format(stderr.writer(), "{s}All {d} expectations passed.{s}\n", .{ GREEN, tester.pass.items.len, GREEN }) catch unreachable; + std.fmt.format(stderr.writer(), RESET, .{}) catch unreachable; + std.testing.expect(true); + }, + .fail => { + std.fmt.format(stderr.writer(), "{s}All {d} expectations failed.{s}\n\n", .{ RED, tester.fail.items.len, RED }) catch unreachable; + std.fmt.format(stderr.writer(), RESET, .{}) catch unreachable; + std.testing.expect(false); + }, + .some_fail => { + std.fmt.format(stderr.writer(), "{s}{d} failed{s} and {s}{d} passed{s} of {d} expectations{s}\n\n", .{ + RED, + tester.fail.items.len, + RED ++ RESET, + GREEN, + tester.pass.items.len, + GREEN ++ RESET, + tester.fail.items.len + tester.pass.items.len, + RESET, + }) catch unreachable; + std.fmt.format(stderr.writer(), RESET, .{}) catch unreachable; + std.testing.expect(false); + }, + } + } +}; |