From 9cd4be047219d4b7364d502ebc3828953ab2d933 Mon Sep 17 00:00:00 2001 From: Drew Nutter Date: Fri, 22 Dec 2023 11:05:27 -0500 Subject: [PATCH] test(sync): add unit tests for OnceCell --- src/sync/once_cell.zig | 104 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/src/sync/once_cell.zig b/src/sync/once_cell.zig index e8e5f9ac3..f8610fa7c 100644 --- a/src/sync/once_cell.zig +++ b/src/sync/once_cell.zig @@ -35,7 +35,7 @@ pub fn OnceCell(comptime T: type) type { /// Tries to initialize the inner value and returns pointer to it, or return error if it fails. /// Returns error if it was already initialized. /// Blocks while other threads are in the process of initialization. - pub fn tryInitialize(self: *Self, initLogic: anytype, init_args: anytype) !*T { + pub fn tryInit(self: *Self, initLogic: anytype, init_args: anytype) !*T { if (!self.acquire()) return error.AlreadyInitialized; errdefer self.started.store(false, .Release); self.value = try @call(.auto, initLogic, init_args); @@ -96,3 +96,105 @@ pub fn OnceCell(comptime T: type) type { } }; } + +test "sync.once_cell: init returns correctly" { + var oc = OnceCell(u64).init(); + const x = try oc.initialize(returns(10), .{}); + try std.testing.expect(10 == x.*); +} + +test "sync.once_cell: cannot get uninitialized" { + var oc = OnceCell(u64).init(); + if (oc.get()) |_| { + try std.testing.expect(false); + } else |_| {} +} + +test "sync.once_cell: can get initialized" { + var oc = OnceCell(u64).init(); + _ = try oc.initialize(returns(10), .{}); + const x = try oc.get(); + try std.testing.expect(10 == x.*); +} + +test "sync.once_cell: tryInit returns error on failure" { + var oc = OnceCell(u64).init(); + const err = oc.tryInit(returnErr, .{}); + try std.testing.expectError(error.TestErr, err); +} + +test "sync.once_cell: tryInit works on success" { + var oc = OnceCell(u64).init(); + const x1 = try oc.tryInit(returnNotErr(10), .{}); + const x2 = try oc.get(); + try std.testing.expect(10 == x1.*); + try std.testing.expect(10 == x2.*); +} + +test "sync.once_cell: tryInit returns error if initialized" { + var oc = OnceCell(u64).init(); + const x1 = try oc.tryInit(returnNotErr(10), .{}); + const err = oc.tryInit(returnNotErr(11), .{}); + const x2 = try oc.get(); + try std.testing.expect(10 == x1.*); + try std.testing.expectError(error.AlreadyInitialized, err); + try std.testing.expect(10 == x2.*); +} + +test "sync.once_cell: getOrInit can initialize when needed" { + var oc = OnceCell(u64).init(); + const x1 = oc.getOrInit(returns(10), .{}); + const x2 = try oc.get(); + try std.testing.expect(10 == x1.*); + try std.testing.expect(10 == x2.*); +} + +test "sync.once_cell: getOrInit uses already initialized value" { + var oc = OnceCell(u64).init(); + const x1 = oc.getOrInit(returns(10), .{}); + const x2 = oc.getOrInit(returns(11), .{}); + try std.testing.expect(10 == x1.*); + try std.testing.expect(10 == x2.*); +} + +test "sync.once_cell: getOrTryInit returns error on failure" { + var oc = OnceCell(u64).init(); + const err = oc.getOrTryInit(returnErr, .{}); + try std.testing.expectError(error.TestErr, err); +} + +test "sync.once_cell: getOrTryInit works on success" { + var oc = OnceCell(u64).init(); + const x1 = try oc.getOrTryInit(returnNotErr(10), .{}); + const x2 = try oc.get(); + try std.testing.expect(10 == x1.*); + try std.testing.expect(10 == x2.*); +} + +test "sync.once_cell: getOrTryInit uses already initialized value" { + var oc = OnceCell(u64).init(); + const x1 = try oc.getOrTryInit(returnNotErr(10), .{}); + const x2 = try oc.getOrTryInit(returnNotErr(11), .{}); + try std.testing.expect(10 == x1.*); + try std.testing.expect(10 == x2.*); +} + +fn returns(comptime x: u64) fn () u64 { + return struct { + fn get() u64 { + return x; + } + }.get; +} + +fn returnNotErr(comptime x: u64) fn () error{}!u64 { + return struct { + fn get() !u64 { + return x; + } + }.get; +} + +fn returnErr() !u64 { + return error.TestErr; +}