Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ pub fn build(b: *std.Build) void {
.root_source_file = b.path("src/stdx/mod.zig"),
.target = target,
.optimize = optimize,
// stdx wraps libc directly (std.c sockets, fcntl, file IO), so it needs
// the link wherever it is rooted. Consumers set this on their own root
// module, which covers stdx as a dependency but not the test artifact
// rooted at stdx itself — that one fails to compile without it on
// targets where libc is not linked implicitly.
.link_libc = true,
});

// ── Version (git describe) ──
Expand Down Expand Up @@ -105,6 +111,15 @@ pub fn build(b: *std.Build) void {

const run_unit_tests = b.addRunArtifact(unit_tests);

// stdx is its own module, and module dependencies contribute no tests to
// a test root — everything in stdx (PRNG, log, helpers) was invisible to
// the src test runner and had never run. Compile stdx as its own root.
const stdx_tests = b.addTest(.{
.root_module = stdx_module,
.filters = if (test_filter) |f| &.{f} else &.{},
});
const run_stdx_tests = b.addRunArtifact(stdx_tests);

// ── E2E Tests ──

const e2e_tests = b.addTest(.{
Expand Down Expand Up @@ -144,9 +159,11 @@ pub fn build(b: *std.Build) void {

const test_step = b.step("test", "Run all tests");
test_step.dependOn(&run_unit_tests.step);
test_step.dependOn(&run_stdx_tests.step);

const unit_test_step = b.step("test-unit", "Run unit tests only");
unit_test_step.dependOn(&run_unit_tests.step);
unit_test_step.dependOn(&run_stdx_tests.step);

const e2e_test_step = b.step("test-e2e", "Run end-to-end tests");
e2e_test_step.dependOn(&run_e2e_tests.step);
Expand Down
17 changes: 10 additions & 7 deletions src/stdx/log.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

const std = @import("std");
const builtin = @import("builtin");
const time = @import("time.zig");

// Re-exports
pub const Field = @import("log/field.zig").Field;
Expand Down Expand Up @@ -411,7 +412,7 @@ fn writeFmtEntry(
var fbs: std.Io.Writer = .fixed(&buf);
const writer = &fbs;

const timestamp = @import("time.zig").nanoTimestamp();
const timestamp = time.nanoTimestamp();

const caller: ?format.Caller = if (global.show_caller)
.{ .file = src.file, .line = src.line, .fn_name = src.fn_name }
Expand Down Expand Up @@ -446,7 +447,7 @@ fn writeEntry(
var fbs: std.Io.Writer = .fixed(&buf);
const writer = &fbs;

const timestamp = @import("time.zig").nanoTimestamp();
const timestamp = time.nanoTimestamp();

// Build caller info if enabled
const caller: ?format.Caller = if (global.show_caller)
Expand Down Expand Up @@ -759,7 +760,7 @@ pub fn stdLogFn(
var fbs: std.Io.Writer = .fixed(&buf);
const writer = &fbs;

const timestamp = @import("time.zig").nanoTimestamp();
const timestamp = time.nanoTimestamp();
const colors = global.use_colors;

// Simple text format for std.log bridge
Expand Down Expand Up @@ -805,7 +806,7 @@ pub const TestLogger = struct {
allocator: std.mem.Allocator,

pub fn init(allocator: std.mem.Allocator) TestLogger {
return .{ .buffer = .{}, .allocator = allocator };
return .{ .buffer = .empty, .allocator = allocator };
}

pub fn deinit(self: *TestLogger) void {
Expand All @@ -822,8 +823,10 @@ pub const TestLogger = struct {

/// Log to this buffer instead of stdout.
pub fn logTo(self: *TestLogger, level: Level, comptime msg: []const u8, fields: anytype) void {
const w = self.buffer.writer(self.allocator);
formatTextEntry(w, level, msg, @import("time.zig").nanoTimestamp(), null, fields);
var aw: std.Io.Writer.Allocating = .init(self.allocator);
defer aw.deinit();
formatTextEntry(&aw.writer, level, msg, time.nanoTimestamp(), null, fields);
self.buffer.appendSlice(self.allocator, aw.written()) catch {};
}
};

Expand Down Expand Up @@ -901,7 +904,7 @@ test "test logger buffer" {
Field.str("key", "value"),
});

const output = test_log.buffered();
const output = test_log.getWritten();
try std.testing.expect(std.mem.indexOf(u8, output, "test message") != null);
try std.testing.expect(std.mem.indexOf(u8, output, "key=") != null);
}
28 changes: 6 additions & 22 deletions src/stdx/mod.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ pub const process = @import("process.zig");
pub const Mutex = sync.Mutex;

pub const testing = @import("testing/e2e/mod.zig");

test {
// The deterministic PRNG's tests live only here; without this
// reference they are never collected.
_ = @import("testing/prng.zig");
}
/// Copy memory from source to destination.
/// Asserts that the slices do not overlap.
pub fn copy_disjoint(
Expand All @@ -46,11 +52,6 @@ pub fn copy_disjoint(
}
}

/// Check if a struct has no padding.
pub fn no_padding(comptime T: type) bool {
return @sizeOf(T) == @bitSizeOf(T) / 8;
}

/// Maybe assertion - only asserts in debug mode.
pub fn maybe(condition: bool) void {
if (std.debug.runtime_safety) {
Expand Down Expand Up @@ -99,23 +100,6 @@ test "copy_disjoint: inexact" {
try std.testing.expectEqualSlices(u8, &[_]u8{ 1, 2, 0, 0 }, &dest);
}

test "no_padding: struct without padding" {
const NoPadding = struct {
a: u32,
b: u32,
};
try std.testing.expect(no_padding(NoPadding));
}

test "no_padding: struct with padding" {
const WithPadding = struct {
a: u8,
// 3 bytes padding here
b: u32,
};
try std.testing.expect(!no_padding(WithPadding));
}

test "nullIfEmpty: non-empty string" {
const str = "hello";
const result = nullIfEmpty(u8, str);
Expand Down
Loading