From 31c74fc960fdf708a8838be775af9047b320be32 Mon Sep 17 00:00:00 2001 From: Overlord Date: Thu, 6 Aug 2026 10:49:05 +0200 Subject: [PATCH] logger tests; verify buffering, flushing, and overflow behavior --- src/logging/log.zig | 87 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/logging/log.zig b/src/logging/log.zig index b8a27d5..d322728 100644 --- a/src/logging/log.zig +++ b/src/logging/log.zig @@ -147,3 +147,90 @@ pub const Logger = struct { try logger.writer.interface.flush(); } }; + +// + +extern fn mkdtemp(template: [*:0]u8) ?[*:0]u8; + +fn mktmpdir(buffer: *[64:0]u8, pattern: []const u8) ![]u8 +{ + if (pattern.len >= buffer.len) return error.PatternTooLong; + + @memcpy(buffer[0..pattern.len], pattern); + buffer[pattern.len] = 0; + + const result = mkdtemp(buffer) orelse return error.MkDtempFailed; + + return std.mem.span(result); +} + +test "filtering, buffering and automatic flushing" +{ + const io = std.testing.io; + const allocator = std.testing.allocator; + const fname = "logger.test"; + + var path_buf: [64:0]u8 = undefined; + var read_buf: [512]u8 = undefined; + + const path = try mktmpdir(&path_buf,"/tmp/zocket-test-XXXXXX"); + + const dir = try std.Io.Dir.openDirAbsolute(io, path, .{}); + defer + { + dir.deleteFile(io, fname) catch unreachable; + dir.close(io); + std.Io.Dir.deleteDirAbsolute(io, path) catch unreachable; + } + + const file = try dir.createFile(io, fname, .{ .lock = .exclusive }); + defer file.close(io); + + var log = try Logger.init(allocator, .{ + .io = io, .buffer = 256, .file = file + }); + defer log.deinit(); + + // + + // The file is expected to be empty, as this does not force the internal buffer to auto-flush. + log.info("info={d}", .{1}); + + { + const contents = try dir.readFile(io, fname, &read_buf); + try std.testing.expect(contents.len == 0); + } + + // The file should include 'info=1' after flushing to disk. + try log.flush(); + + { + const contents = try dir.readFile(io, fname, &read_buf); + try std.testing.expectEqualStrings("info=1", contents); + } + try file.setLength(io, 0); + try log.writer.seekTo(0); + @memset(read_buf[0..], 0); + + // The file should include 'warn=1' as warnings and errors automatically trigger a flush to disk. + log.warn("warn={d}", .{1}); + + { + const contents = try dir.readFile(io, fname, &read_buf); + try std.testing.expectEqualStrings("warn=1", contents); + } + try file.setLength(io, 0); + try log.writer.seekTo(0); + @memset(read_buf[0..], 0); + + // The file should include 'info=x...' as it's bigger than the allocated 256 buffer, forcing it to automatically drain on overflow. + log.info("info={s}", .{[_]u8{'x'} ** 300}); + + { + const contents = try dir.readFile(io, fname, &read_buf); + try std.testing.expectEqualStrings("info=" ++ ([_]u8{'x'} ** 300), contents); + } + try file.setLength(io, 0); + try log.writer.seekTo(0); + @memset(read_buf[0..], 0); +}