diff --git a/src/browser/console/console.zig b/src/browser/console/console.zig index 4078a416..3e3fd02b 100644 --- a/src/browser/console/console.zig +++ b/src/browser/console/console.zig @@ -22,8 +22,7 @@ const builtin = @import("builtin"); const JsObject = @import("../env.zig").Env.JsObject; const SessionState = @import("../env.zig").SessionState; -// const log = if (builtin.is_test) &test_capture else @import("../../log.zig"); -const log = @import("../../log.zig"); +const log = if (builtin.is_test) &test_capture else @import("../../log.zig"); pub const Console = struct { // TODO: configurable writer @@ -151,137 +150,137 @@ fn timestamp() u32 { return @intCast(ts.sec); } -// var test_capture = TestCapture{}; -// const testing = @import("../../testing.zig"); -// test "Browser.Console" { -// defer testing.reset(); +var test_capture = TestCapture{}; +const testing = @import("../../testing.zig"); +test "Browser.Console" { + defer testing.reset(); -// var runner = try testing.jsRunner(testing.tracking_allocator, .{}); -// defer runner.deinit(); + var runner = try testing.jsRunner(testing.tracking_allocator, .{}); + defer runner.deinit(); -// { -// try runner.testCases(&.{ -// .{ "console.log('a')", "undefined" }, -// .{ "console.warn('hello world', 23, true, new Object())", "undefined" }, -// }, .{}); + { + try runner.testCases(&.{ + .{ "console.log('a')", "undefined" }, + .{ "console.warn('hello world', 23, true, new Object())", "undefined" }, + }, .{}); -// const captured = test_capture.captured.items; -// try testing.expectEqual("[info] args=a", captured[0]); -// try testing.expectEqual("[warn] args=hello world 23 true [object Object]", captured[1]); -// } + const captured = test_capture.captured.items; + try testing.expectEqual("[info] args=a", captured[0]); + try testing.expectEqual("[warn] args=hello world 23 true [object Object]", captured[1]); + } -// { -// test_capture.reset(); -// try runner.testCases(&.{ -// .{ "console.countReset()", "undefined" }, -// .{ "console.count()", "undefined" }, -// .{ "console.count('teg')", "undefined" }, -// .{ "console.count('teg')", "undefined" }, -// .{ "console.count('teg')", "undefined" }, -// .{ "console.count()", "undefined" }, -// .{ "console.countReset('teg')", "undefined" }, -// .{ "console.countReset()", "undefined" }, -// .{ "console.count()", "undefined" }, -// }, .{}); + { + test_capture.reset(); + try runner.testCases(&.{ + .{ "console.countReset()", "undefined" }, + .{ "console.count()", "undefined" }, + .{ "console.count('teg')", "undefined" }, + .{ "console.count('teg')", "undefined" }, + .{ "console.count('teg')", "undefined" }, + .{ "console.count()", "undefined" }, + .{ "console.countReset('teg')", "undefined" }, + .{ "console.countReset()", "undefined" }, + .{ "console.count()", "undefined" }, + }, .{}); -// const captured = test_capture.captured.items; -// try testing.expectEqual("[invalid counter] label=default", captured[0]); -// try testing.expectEqual("[count] label=default count=1", captured[1]); -// try testing.expectEqual("[count] label=teg count=1", captured[2]); -// try testing.expectEqual("[count] label=teg count=2", captured[3]); -// try testing.expectEqual("[count] label=teg count=3", captured[4]); -// try testing.expectEqual("[count] label=default count=2", captured[5]); -// try testing.expectEqual("[count reset] label=teg count=3", captured[6]); -// try testing.expectEqual("[count reset] label=default count=2", captured[7]); -// try testing.expectEqual("[count] label=default count=1", captured[8]); -// } + const captured = test_capture.captured.items; + try testing.expectEqual("[invalid counter] label=default", captured[0]); + try testing.expectEqual("[count] label=default count=1", captured[1]); + try testing.expectEqual("[count] label=teg count=1", captured[2]); + try testing.expectEqual("[count] label=teg count=2", captured[3]); + try testing.expectEqual("[count] label=teg count=3", captured[4]); + try testing.expectEqual("[count] label=default count=2", captured[5]); + try testing.expectEqual("[count reset] label=teg count=3", captured[6]); + try testing.expectEqual("[count reset] label=default count=2", captured[7]); + try testing.expectEqual("[count] label=default count=1", captured[8]); + } -// { -// test_capture.reset(); -// try runner.testCases(&.{ -// .{ "console.assert(true)", "undefined" }, -// .{ "console.assert('a', 2, 3, 4)", "undefined" }, -// .{ "console.assert('')", "undefined" }, -// .{ "console.assert('', 'x', true)", "undefined" }, -// .{ "console.assert(false, 'x')", "undefined" }, -// }, .{}); + { + test_capture.reset(); + try runner.testCases(&.{ + .{ "console.assert(true)", "undefined" }, + .{ "console.assert('a', 2, 3, 4)", "undefined" }, + .{ "console.assert('')", "undefined" }, + .{ "console.assert('', 'x', true)", "undefined" }, + .{ "console.assert(false, 'x')", "undefined" }, + }, .{}); -// const captured = test_capture.captured.items; -// try testing.expectEqual("[assertion failed] values=", captured[0]); -// try testing.expectEqual("[assertion failed] values=x true", captured[1]); -// try testing.expectEqual("[assertion failed] values=x", captured[2]); -// } -// } -// const TestCapture = struct { -// captured: std.ArrayListUnmanaged([]const u8) = .{}, + const captured = test_capture.captured.items; + try testing.expectEqual("[assertion failed] values=", captured[0]); + try testing.expectEqual("[assertion failed] values=x true", captured[1]); + try testing.expectEqual("[assertion failed] values=x", captured[2]); + } +} +const TestCapture = struct { + captured: std.ArrayListUnmanaged([]const u8) = .{}, -// fn reset(self: *TestCapture) void { -// self.captured = .{}; -// } + fn reset(self: *TestCapture) void { + self.captured = .{}; + } -// fn debug( -// self: *TestCapture, -// comptime scope: @Type(.enum_literal), -// comptime msg: []const u8, -// args: anytype, -// ) void { -// self.capture(scope, msg, args); -// } + fn debug( + self: *TestCapture, + comptime scope: @Type(.enum_literal), + comptime msg: []const u8, + args: anytype, + ) void { + self.capture(scope, msg, args); + } -// fn info( -// self: *TestCapture, -// comptime scope: @Type(.enum_literal), -// comptime msg: []const u8, -// args: anytype, -// ) void { -// self.capture(scope, msg, args); -// } + fn info( + self: *TestCapture, + comptime scope: @Type(.enum_literal), + comptime msg: []const u8, + args: anytype, + ) void { + self.capture(scope, msg, args); + } -// fn warn( -// self: *TestCapture, -// comptime scope: @Type(.enum_literal), -// comptime msg: []const u8, -// args: anytype, -// ) void { -// self.capture(scope, msg, args); -// } + fn warn( + self: *TestCapture, + comptime scope: @Type(.enum_literal), + comptime msg: []const u8, + args: anytype, + ) void { + self.capture(scope, msg, args); + } -// fn err( -// self: *TestCapture, -// comptime scope: @Type(.enum_literal), -// comptime msg: []const u8, -// args: anytype, -// ) void { -// self.capture(scope, msg, args); -// } + fn err( + self: *TestCapture, + comptime scope: @Type(.enum_literal), + comptime msg: []const u8, + args: anytype, + ) void { + self.capture(scope, msg, args); + } -// fn capture( -// self: *TestCapture, -// comptime scope: @Type(.enum_literal), -// comptime msg: []const u8, -// args: anytype, -// ) void { -// self._capture(scope, msg, args) catch unreachable; -// } + fn capture( + self: *TestCapture, + comptime scope: @Type(.enum_literal), + comptime msg: []const u8, + args: anytype, + ) void { + self._capture(scope, msg, args) catch unreachable; + } -// fn _capture( -// self: *TestCapture, -// comptime scope: @Type(.enum_literal), -// comptime msg: []const u8, -// args: anytype, -// ) !void { -// std.debug.assert(scope == .console); + fn _capture( + self: *TestCapture, + comptime scope: @Type(.enum_literal), + comptime msg: []const u8, + args: anytype, + ) !void { + std.debug.assert(scope == .console); -// const allocator = testing.arena_allocator; -// var buf: std.ArrayListUnmanaged(u8) = .empty; -// try buf.appendSlice(allocator, "[" ++ msg ++ "] "); + const allocator = testing.arena_allocator; + var buf: std.ArrayListUnmanaged(u8) = .empty; + try buf.appendSlice(allocator, "[" ++ msg ++ "] "); -// inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |f| { -// try buf.appendSlice(allocator, f.name); -// try buf.append(allocator, '='); -// try @import("../../log.zig").writeValue(allocator, &buf, false, @field(args, f.name)); -// try buf.append(allocator, ' '); -// } -// self.captured.append(testing.arena_allocator, std.mem.trimRight(u8, buf.items, " ")) catch unreachable; -// } -// }; + inline for (@typeInfo(@TypeOf(args)).@"struct".fields) |f| { + try buf.appendSlice(allocator, f.name); + try buf.append(allocator, '='); + try @import("../../log.zig").writeValue(false, @field(args, f.name), buf.writer(allocator)); + try buf.append(allocator, ' '); + } + self.captured.append(testing.arena_allocator, std.mem.trimRight(u8, buf.items, " ")) catch unreachable; + } +}; diff --git a/src/log.zig b/src/log.zig index 6414d97c..51764ee9 100644 --- a/src/log.zig +++ b/src/log.zig @@ -81,12 +81,16 @@ pub fn log(comptime scope: @Type(.enum_literal), comptime level: Level, comptime if (comptime enabled(scope, level) == false) { return; } - tryLog(scope, level, msg, data) catch |log_err| { + + std.debug.lockStdErr(); + defer std.debug.unlockStdErr(); + + logTo(scope, level, msg, data, std.io.getStdErr().writer()) catch |log_err| { std.debug.print("$time={d} $level=fatal $scope={s} $msg=\"log err\" err={s} log_msg=\"{s}\"", .{ timestamp(), @errorName(log_err), @tagName(scope), msg }); }; } -fn tryLog(comptime scope: @Type(.enum_literal), comptime level: Level, comptime msg: []const u8, data: anytype) !void { +fn logTo(comptime scope: @Type(.enum_literal), comptime level: Level, comptime msg: []const u8, data: anytype, out: anytype) !void { comptime { if (msg.len > 30) { @compileError("log msg cannot be more than 30 characters: '" ++ msg ++ "'"); @@ -102,12 +106,7 @@ fn tryLog(comptime scope: @Type(.enum_literal), comptime level: Level, comptime } } - out_lock.lock(); - defer out_lock.unlock(); - - const stderr = std.io.getStdErr().writer(); - var bw = std.io.bufferedWriter(stderr); - + var bw = std.io.bufferedWriter(out); switch (format) { .logfmt => try logLogfmt(scope, level, msg, data, bw.writer()), .pretty => try logPretty(scope, level, msg, data, bw.writer()), @@ -292,64 +291,56 @@ fn elapsed() i64 { return now - previous; } -// const testing = @import("testing.zig"); -// test "log: data" { -// var buf: std.ArrayListUnmanaged(u8) = .{}; -// defer buf.deinit(testing.allocator); +const testing = @import("testing.zig"); +test "log: data" { + var buf: std.ArrayListUnmanaged(u8) = .{}; + defer buf.deinit(testing.allocator); -// var logger = try TestLogger.init(testing.allocator, .{ .format = .logfmt }, buf.writer(testing.allocator)); -// defer logger.deinit(); + { + try logTo(.t_scope, .err, "nope", .{}, buf.writer(testing.allocator)); + try testing.expectEqual("$time=1739795092929 $scope=t_scope $level=error $msg=nope\n", buf.items); + } -// { -// try logger.log(.t_scope, .err, "nope", .{}); -// try testing.expectEqual("$time=1739795092929 $scope=t_scope $level=error $msg=nope\n", buf.items); -// } + { + buf.clearRetainingCapacity(); + const string = try testing.allocator.dupe(u8, "spice_must_flow"); + defer testing.allocator.free(string); -// { -// buf.clearRetainingCapacity(); -// const string = try testing.allocator.dupe(u8, "spice_must_flow"); -// defer testing.allocator.free(string); + try logTo(.scope_2, .warn, "a msg", .{ + .cint = 5, + .cfloat = 3.43, + .int = @as(i16, -49), + .float = @as(f32, 0.0003232), + .bt = true, + .bf = false, + .nn = @as(?i32, 33), + .n = @as(?i32, null), + .lit = "over9000!", + .slice = string, + .err = error.Nope, + .level = Level.warn, + }, buf.writer(testing.allocator)); -// try logger.log(.scope_2, .warn, "a msg", .{ -// .cint = 5, -// .cfloat = 3.43, -// .int = @as(i16, -49), -// .float = @as(f32, 0.0003232), -// .bt = true, -// .bf = false, -// .nn = @as(?i32, 33), -// .n = @as(?i32, null), -// .lit = "over9000!", -// .slice = string, -// .err = error.Nope, -// .level = Level.warn, -// }); + try testing.expectEqual("$time=1739795092929 $scope=scope_2 $level=warn $msg=\"a msg\" " ++ + "cint=5 cfloat=3.43 int=-49 float=0.0003232 bt=true bf=false " ++ + "nn=33 n=null lit=over9000! slice=spice_must_flow " ++ + "err=Nope level=warn\n", buf.items); + } +} -// try testing.expectEqual("$time=1739795092929 $scope=scope_2 $level=warn $msg=\"a msg\" " ++ -// "cint=5 cfloat=3.43 int=-49 float=0.0003232 bt=true bf=false " ++ -// "nn=33 n=null lit=over9000! slice=spice_must_flow " ++ -// "err=Nope level=warn\n", buf.items); -// } -// } +test "log: string escape" { + var buf: std.ArrayListUnmanaged(u8) = .{}; + defer buf.deinit(testing.allocator); -// test "log: string escape" { -// var buf: std.ArrayListUnmanaged(u8) = .{}; -// defer buf.deinit(testing.allocator); + const prefix = "$time=1739795092929 $scope=scope $level=error $msg=test "; + { + try logTo(.scope, .err, "test", .{ .string = "hello world" }, buf.writer(testing.allocator)); + try testing.expectEqual(prefix ++ "string=\"hello world\"\n", buf.items); + } -// var logger = try TestLogger.init(testing.allocator, .{ .format = .logfmt }, buf.writer(testing.allocator)); -// defer logger.deinit(); - -// const prefix = "$time=1739795092929 $scope=scope $level=error $msg=test "; -// { -// try logger.log(.scope, .err, "test", .{ .string = "hello world" }); -// try testing.expectEqual(prefix ++ "string=\"hello world\"\n", buf.items); -// } - -// { -// buf.clearRetainingCapacity(); -// try logger.log(.scope, .err, "test", .{ .string = "\n \thi \" \" " }); -// try testing.expectEqual(prefix ++ "string=\"\\n \thi \\\" \\\" \"\n", buf.items); -// } -// } - -// const TestLogger = LogT(std.ArrayListUnmanaged(u8).Writer); + { + buf.clearRetainingCapacity(); + try logTo(.scope, .err, "test", .{ .string = "\n \thi \" \" " }, buf.writer(testing.allocator)); + try testing.expectEqual(prefix ++ "string=\"\\n \thi \\\" \\\" \"\n", buf.items); + } +}