aboutsummaryrefslogtreecommitdiff
path: root/lib/std/testing.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/testing.zig')
-rw-r--r--lib/std/testing.zig150
1 files changed, 150 insertions, 0 deletions
diff --git a/lib/std/testing.zig b/lib/std/testing.zig
new file mode 100644
index 0000000000..7f347b0c24
--- /dev/null
+++ b/lib/std/testing.zig
@@ -0,0 +1,150 @@
+const builtin = @import("builtin");
+const TypeId = builtin.TypeId;
+const std = @import("std.zig");
+
+/// This function is intended to be used only in tests. It prints diagnostics to stderr
+/// and then aborts when actual_error_union is not expected_error.
+pub fn expectError(expected_error: anyerror, actual_error_union: var) void {
+ if (actual_error_union) |actual_payload| {
+ // TODO remove workaround here for https://github.com/ziglang/zig/issues/557
+ if (@sizeOf(@typeOf(actual_payload)) == 0) {
+ std.debug.panic("expected error.{}, found {} value", @errorName(expected_error), @typeName(@typeOf(actual_payload)));
+ } else {
+ std.debug.panic("expected error.{}, found {}", @errorName(expected_error), actual_payload);
+ }
+ } else |actual_error| {
+ if (expected_error != actual_error) {
+ std.debug.panic("expected error.{}, found error.{}", @errorName(expected_error), @errorName(actual_error));
+ }
+ }
+}
+
+/// This function is intended to be used only in tests. When the two values are not
+/// equal, prints diagnostics to stderr to show exactly how they are not equal,
+/// then aborts.
+/// The types must match exactly.
+pub fn expectEqual(expected: var, actual: @typeOf(expected)) void {
+ switch (@typeInfo(@typeOf(actual))) {
+ .NoReturn,
+ .BoundFn,
+ .ArgTuple,
+ .Opaque,
+ .Frame,
+ .AnyFrame,
+ => @compileError("value of type " ++ @typeName(@typeOf(actual)) ++ " encountered"),
+
+ .Undefined,
+ .Null,
+ .Void,
+ => return,
+
+ .Type,
+ .Bool,
+ .Int,
+ .Float,
+ .ComptimeFloat,
+ .ComptimeInt,
+ .EnumLiteral,
+ .Enum,
+ .Fn,
+ .Vector,
+ .ErrorSet,
+ => {
+ if (actual != expected) {
+ std.debug.panic("expected {}, found {}", expected, actual);
+ }
+ },
+
+ .Pointer => |pointer| {
+ switch (pointer.size) {
+ builtin.TypeInfo.Pointer.Size.One,
+ builtin.TypeInfo.Pointer.Size.Many,
+ builtin.TypeInfo.Pointer.Size.C,
+ => {
+ if (actual != expected) {
+ std.debug.panic("expected {}, found {}", expected, actual);
+ }
+ },
+
+ builtin.TypeInfo.Pointer.Size.Slice => {
+ if (actual.ptr != expected.ptr) {
+ std.debug.panic("expected slice ptr {}, found {}", expected.ptr, actual.ptr);
+ }
+ if (actual.len != expected.len) {
+ std.debug.panic("expected slice len {}, found {}", expected.len, actual.len);
+ }
+ },
+ }
+ },
+
+ .Array => |array| expectEqualSlices(array.child, &expected, &actual),
+
+ .Struct => |structType| {
+ inline for (structType.fields) |field| {
+ expectEqual(@field(expected, field.name), @field(actual, field.name));
+ }
+ },
+
+ .Union => |union_info| {
+ if (union_info.tag_type == null) {
+ @compileError("Unable to compare untagged union values");
+ }
+ @compileError("TODO implement testing.expectEqual for tagged unions");
+ },
+
+ .Optional => {
+ if (expected) |expected_payload| {
+ if (actual) |actual_payload| {
+ expectEqual(expected_payload, actual_payload);
+ } else {
+ std.debug.panic("expected {}, found null", expected_payload);
+ }
+ } else {
+ if (actual) |actual_payload| {
+ std.debug.panic("expected null, found {}", actual_payload);
+ }
+ }
+ },
+
+ .ErrorUnion => {
+ if (expected) |expected_payload| {
+ if (actual) |actual_payload| {
+ expectEqual(expected_payload, actual_payload);
+ } else |actual_err| {
+ std.debug.panic("expected {}, found {}", expected_payload, actual_err);
+ }
+ } else |expected_err| {
+ if (actual) |actual_payload| {
+ std.debug.panic("expected {}, found {}", expected_err, actual_payload);
+ } else |actual_err| {
+ expectEqual(expected_err, actual_err);
+ }
+ }
+ },
+ }
+}
+
+/// This function is intended to be used only in tests. When the two slices are not
+/// equal, prints diagnostics to stderr to show exactly how they are not equal,
+/// then aborts.
+pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) void {
+ // TODO better printing of the difference
+ // If the arrays are small enough we could print the whole thing
+ // If the child type is u8 and no weird bytes, we could print it as strings
+ // Even for the length difference, it would be useful to see the values of the slices probably.
+ if (expected.len != actual.len) {
+ std.debug.panic("slice lengths differ. expected {}, found {}", expected.len, actual.len);
+ }
+ var i: usize = 0;
+ while (i < expected.len) : (i += 1) {
+ if (expected[i] != actual[i]) {
+ std.debug.panic("index {} incorrect. expected {}, found {}", i, expected[i], actual[i]);
+ }
+ }
+}
+
+/// This function is intended to be used only in tests. When `ok` is false, the test fails.
+/// A message is printed to stderr and then abort is called.
+pub fn expect(ok: bool) void {
+ if (!ok) @panic("test failure");
+}