expectEqualDeepInner
Function parameters
Parameters
- T:type
- expected:T
- actual:T
Type definitions in this namespace
Types
- Reader
- A `std.Io.Reader` that writes a predetermined list of buffers during `stream`.
- ReaderIndirect
- A `std.Io.Reader` that gets its data from another `std.Io.Reader`, and always
This function is intended to be used only in tests.
Functions
- expectError
- This function is intended to be used only in tests.
- expectEqual
- This function is intended to be used only in tests.
- expectFmt
- This function is intended to be used only in tests.
- expectApproxEqAbs
- This function is intended to be used only in tests.
- expectApproxEqRel
- This function is intended to be used only in tests.
- expectEqualSlices
- This function is intended to be used only in tests.
- expectEqualSentinel
- This function is intended to be used only in tests.
- expect
- This function is intended to be used only in tests.
- expectEqualDeep
- This function is intended to be used only in tests.
- checkAllAllocationFailures
- Exhaustively check that allocation failures within `test_fn` are handled without
- refAllDecls
- Given a type, references all the declarations inside, so that the semantic analyzer sees them.
- refAllDeclsRecursive
- Given a type, recursively references all the declarations inside, so that the semantic analyzer sees them.
- fuzz
- Inline to avoid coverage instrumentation.
Provides deterministic randomness in unit tests.
Values
- random_seed
- Provides deterministic randomness in unit tests.
- failing_allocator
- = failing_allocator_instance.allocator()
- allocator
- This should only be used in temporary test programs.
- log_level
- TODO https://github.com/ziglang/zig/issues/5738
- backend_can_print
- = switch (builtin.zig_backend) { .stage2_aarch64, .stage2_powerpc, .stage2_riscv64, .stage2_spirv, => false, else => true, }
Source
Implementation
fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpectedEqual}!void {
switch (@typeInfo(@TypeOf(actual))) {
.noreturn,
.@"opaque",
.frame,
.@"anyframe",
=> @compileError("value of type " ++ @typeName(@TypeOf(actual)) ++ " encountered"),
.undefined,
.null,
.void,
=> return,
.type => {
if (actual != expected) {
print("expected type {s}, found type {s}\n", .{ @typeName(expected), @typeName(actual) });
return error.TestExpectedEqual;
}
},
.bool,
.int,
.float,
.comptime_float,
.comptime_int,
.enum_literal,
.@"enum",
.@"fn",
.error_set,
=> {
if (actual != expected) {
print("expected {}, found {}\n", .{ expected, actual });
return error.TestExpectedEqual;
}
},
.pointer => |pointer| {
switch (pointer.size) {
// We have no idea what is behind those pointers, so the best we can do is `==` check.
.c, .many => {
if (actual != expected) {
print("expected {*}, found {*}\n", .{ expected, actual });
return error.TestExpectedEqual;
}
},
.one => {
// Length of those pointers are runtime value, so the best we can do is `==` check.
switch (@typeInfo(pointer.child)) {
.@"fn", .@"opaque" => {
if (actual != expected) {
print("expected {*}, found {*}\n", .{ expected, actual });
return error.TestExpectedEqual;
}
},
else => try expectEqualDeep(expected.*, actual.*),
}
},
.slice => {
if (expected.len != actual.len) {
print("Slice len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });
return error.TestExpectedEqual;
}
var i: usize = 0;
while (i < expected.len) : (i += 1) {
expectEqualDeep(expected[i], actual[i]) catch |e| {
print("index {d} incorrect. expected {any}, found {any}\n", .{
i, expected[i], actual[i],
});
return e;
};
}
},
}
},
.array => |_| {
if (expected.len != actual.len) {
print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len });
return error.TestExpectedEqual;
}
var i: usize = 0;
while (i < expected.len) : (i += 1) {
expectEqualDeep(expected[i], actual[i]) catch |e| {
print("index {d} incorrect. expected {any}, found {any}\n", .{
i, expected[i], actual[i],
});
return e;
};
}
},
.vector => |info| {
if (info.len != @typeInfo(@TypeOf(actual)).vector.len) {
print("Vector len not the same, expected {d}, found {d}\n", .{ info.len, @typeInfo(@TypeOf(actual)).vector.len });
return error.TestExpectedEqual;
}
var i: usize = 0;
while (i < info.len) : (i += 1) {
expectEqualDeep(expected[i], actual[i]) catch |e| {
print("index {d} incorrect. expected {any}, found {any}\n", .{
i, expected[i], actual[i],
});
return e;
};
}
},
.@"struct" => |structType| {
inline for (structType.fields) |field| {
expectEqualDeep(@field(expected, field.name), @field(actual, field.name)) catch |e| {
print("Field {s} incorrect. expected {any}, found {any}\n", .{ field.name, @field(expected, field.name), @field(actual, field.name) });
return e;
};
}
},
.@"union" => |union_info| {
if (union_info.tag_type == null) {
@compileError("Unable to compare untagged union values for type " ++ @typeName(@TypeOf(actual)));
}
const Tag = std.meta.Tag(@TypeOf(expected));
const expectedTag = @as(Tag, expected);
const actualTag = @as(Tag, actual);
try expectEqual(expectedTag, actualTag);
// we only reach this switch if the tags are equal
switch (expected) {
inline else => |val, tag| {
try expectEqualDeep(val, @field(actual, @tagName(tag)));
},
}
},
.optional => {
if (expected) |expected_payload| {
if (actual) |actual_payload| {
try expectEqualDeep(expected_payload, actual_payload);
} else {
print("expected {any}, found null\n", .{expected_payload});
return error.TestExpectedEqual;
}
} else {
if (actual) |actual_payload| {
print("expected null, found {any}\n", .{actual_payload});
return error.TestExpectedEqual;
}
}
},
.error_union => {
if (expected) |expected_payload| {
if (actual) |actual_payload| {
try expectEqualDeep(expected_payload, actual_payload);
} else |actual_err| {
print("expected {any}, found {any}\n", .{ expected_payload, actual_err });
return error.TestExpectedEqual;
}
} else |expected_err| {
if (actual) |actual_payload| {
print("expected {any}, found {any}\n", .{ expected_err, actual_payload });
return error.TestExpectedEqual;
} else |actual_err| {
try expectEqualDeep(expected_err, actual_err);
}
}
},
}
}