diff --git a/src/util/lib.zig b/src/util/lib.zig index 9a66dc8..acc29f3 100644 --- a/src/util/lib.zig +++ b/src/util/lib.zig @@ -194,3 +194,44 @@ pub fn seedThreadPrng() !void { prng = std.rand.DefaultPrng.init(@bitCast(u64, buf)); } + +pub const testing = struct { + pub fn expectDeepEqual(expected: anytype, actual: @TypeOf(expected)) !void { + const T = @TypeOf(expected); + switch (@typeInfo(T)) { + .Null, .Void => return, + .Int, .Float, .Bool, .Enum => try std.testing.expectEqual(expected, actual), + .Struct => { + inline for (comptime std.meta.fieldNames(T)) |f| { + try expectDeepEqual(@field(expected, f), @field(actual, f)); + } + }, + .Union => { + inline for (comptime std.meta.fieldNames(T)) |f| { + if (std.meta.isTag(expected, f)) { + try std.testing.expect(std.std.meta.isTag(actual, f)); + try expectDeepEqual(@field(expected, f), @field(actual, f)); + } + } + }, + .Pointer, .Array => { + if (comptime std.meta.trait.isIndexable(T)) { + try std.testing.expectEqual(expected.len, actual.len); + for (expected) |_, i| { + try expectDeepEqual(expected[i], actual[i]); + } + } else if (comptime std.meta.trait.isSingleItemPtr(T)) { + try expectDeepEqual(expected.*, actual.*); + } + }, + .Optional => { + if (expected) |e| { + try expectDeepEqual(e, actual orelse return error.TestExpectedEqual); + } else { + try std.testing.expect(actual == null); + } + }, + else => @compileError("Unsupported Type " ++ @typeName(T)), + } + } +};