| ... | ... | @@ -27,15 +27,17 @@ pub var zig_exe_path: []const u8 = undefined; |
| 27 | 27 | |
| 28 | 28 | /// This function is intended to be used only in tests. It prints diagnostics to stderr |
| 29 | 29 | /// and then aborts when actual_error_union is not expected_error. |
| 30 | | pub fn expectError(expected_error: anyerror, actual_error_union: anytype) void { |
| 30 | pub fn expectError(expected_error: anyerror, actual_error_union: anytype) !void { |
| 31 | 31 | if (actual_error_union) |actual_payload| { |
| 32 | | std.debug.panic("expected error.{s}, found {any}", .{ @errorName(expected_error), actual_payload }); |
| 32 | std.debug.print("expected error.{s}, found {any}", .{ @errorName(expected_error), actual_payload }); |
| 33 | return error.TestUnexpectedError; |
| 33 | 34 | } else |actual_error| { |
| 34 | 35 | if (expected_error != actual_error) { |
| 35 | | std.debug.panic("expected error.{s}, found error.{s}", .{ |
| 36 | std.debug.print("expected error.{s}, found error.{s}", .{ |
| 36 | 37 | @errorName(expected_error), |
| 37 | 38 | @errorName(actual_error), |
| 38 | 39 | }); |
| 40 | return error.TestExpectedError; |
| 39 | 41 | } |
| 40 | 42 | } |
| 41 | 43 | } |
| ... | ... | @@ -44,7 +46,7 @@ pub fn expectError(expected_error: anyerror, actual_error_union: anytype) void { |
| 44 | 46 | /// equal, prints diagnostics to stderr to show exactly how they are not equal, |
| 45 | 47 | /// then aborts. |
| 46 | 48 | /// `actual` is casted to the type of `expected`. |
| 47 | | pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void { |
| 49 | pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) !void { |
| 48 | 50 | switch (@typeInfo(@TypeOf(actual))) { |
| 49 | 51 | .NoReturn, |
| 50 | 52 | .BoundFn, |
| ... | ... | @@ -60,7 +62,8 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void { |
| 60 | 62 | |
| 61 | 63 | .Type => { |
| 62 | 64 | if (actual != expected) { |
| 63 | | std.debug.panic("expected type {s}, found type {s}", .{ @typeName(expected), @typeName(actual) }); |
| 65 | std.debug.print("expected type {s}, found type {s}", .{ @typeName(expected), @typeName(actual) }); |
| 66 | return error.TestExpectedEqual; |
| 64 | 67 | } |
| 65 | 68 | }, |
| 66 | 69 | |
| ... | ... | @@ -75,7 +78,8 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void { |
| 75 | 78 | .ErrorSet, |
| 76 | 79 | => { |
| 77 | 80 | if (actual != expected) { |
| 78 | | std.debug.panic("expected {}, found {}", .{ expected, actual }); |
| 81 | std.debug.print("expected {}, found {}", .{ expected, actual }); |
| 82 | return error.TestExpectedEqual; |
| 79 | 83 | } |
| 80 | 84 | }, |
| 81 | 85 | |
| ... | ... | @@ -83,34 +87,38 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void { |
| 83 | 87 | switch (pointer.size) { |
| 84 | 88 | .One, .Many, .C => { |
| 85 | 89 | if (actual != expected) { |
| 86 | | std.debug.panic("expected {*}, found {*}", .{ expected, actual }); |
| 90 | std.debug.print("expected {*}, found {*}", .{ expected, actual }); |
| 91 | return error.TestExpectedEqual; |
| 87 | 92 | } |
| 88 | 93 | }, |
| 89 | 94 | .Slice => { |
| 90 | 95 | if (actual.ptr != expected.ptr) { |
| 91 | | std.debug.panic("expected slice ptr {*}, found {*}", .{ expected.ptr, actual.ptr }); |
| 96 | std.debug.print("expected slice ptr {*}, found {*}", .{ expected.ptr, actual.ptr }); |
| 97 | return error.TestExpectedEqual; |
| 92 | 98 | } |
| 93 | 99 | if (actual.len != expected.len) { |
| 94 | | std.debug.panic("expected slice len {}, found {}", .{ expected.len, actual.len }); |
| 100 | std.debug.print("expected slice len {}, found {}", .{ expected.len, actual.len }); |
| 101 | return error.TestExpectedEqual; |
| 95 | 102 | } |
| 96 | 103 | }, |
| 97 | 104 | } |
| 98 | 105 | }, |
| 99 | 106 | |
| 100 | | .Array => |array| expectEqualSlices(array.child, &expected, &actual), |
| 107 | .Array => |array| try expectEqualSlices(array.child, &expected, &actual), |
| 101 | 108 | |
| 102 | 109 | .Vector => |vectorType| { |
| 103 | 110 | var i: usize = 0; |
| 104 | 111 | while (i < vectorType.len) : (i += 1) { |
| 105 | 112 | if (!std.meta.eql(expected[i], actual[i])) { |
| 106 | | std.debug.panic("index {} incorrect. expected {}, found {}", .{ i, expected[i], actual[i] }); |
| 113 | std.debug.print("index {} incorrect. expected {}, found {}", .{ i, expected[i], actual[i] }); |
| 114 | return error.TestExpectedEqual; |
| 107 | 115 | } |
| 108 | 116 | } |
| 109 | 117 | }, |
| 110 | 118 | |
| 111 | 119 | .Struct => |structType| { |
| 112 | 120 | inline for (structType.fields) |field| { |
| 113 | | expectEqual(@field(expected, field.name), @field(actual, field.name)); |
| 121 | try expectEqual(@field(expected, field.name), @field(actual, field.name)); |
| 114 | 122 | } |
| 115 | 123 | }, |
| 116 | 124 | |
| ... | ... | @@ -124,12 +132,12 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void { |
| 124 | 132 | const expectedTag = @as(Tag, expected); |
| 125 | 133 | const actualTag = @as(Tag, actual); |
| 126 | 134 | |
| 127 | | expectEqual(expectedTag, actualTag); |
| 135 | try expectEqual(expectedTag, actualTag); |
| 128 | 136 | |
| 129 | 137 | // we only reach this loop if the tags are equal |
| 130 | 138 | inline for (std.meta.fields(@TypeOf(actual))) |fld| { |
| 131 | 139 | if (std.mem.eql(u8, fld.name, @tagName(actualTag))) { |
| 132 | | expectEqual(@field(expected, fld.name), @field(actual, fld.name)); |
| 140 | try expectEqual(@field(expected, fld.name), @field(actual, fld.name)); |
| 133 | 141 | return; |
| 134 | 142 | } |
| 135 | 143 | } |
| ... | ... | @@ -143,13 +151,15 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void { |
| 143 | 151 | .Optional => { |
| 144 | 152 | if (expected) |expected_payload| { |
| 145 | 153 | if (actual) |actual_payload| { |
| 146 | | expectEqual(expected_payload, actual_payload); |
| 154 | try expectEqual(expected_payload, actual_payload); |
| 147 | 155 | } else { |
| 148 | | std.debug.panic("expected {any}, found null", .{expected_payload}); |
| 156 | std.debug.print("expected {any}, found null", .{expected_payload}); |
| 157 | return error.TestExpectedEqual; |
| 149 | 158 | } |
| 150 | 159 | } else { |
| 151 | 160 | if (actual) |actual_payload| { |
| 152 | | std.debug.panic("expected null, found {any}", .{actual_payload}); |
| 161 | std.debug.print("expected null, found {any}", .{actual_payload}); |
| 162 | return error.TestExpectedEqual; |
| 153 | 163 | } |
| 154 | 164 | } |
| 155 | 165 | }, |
| ... | ... | @@ -157,15 +167,17 @@ pub fn expectEqual(expected: anytype, actual: @TypeOf(expected)) void { |
| 157 | 167 | .ErrorUnion => { |
| 158 | 168 | if (expected) |expected_payload| { |
| 159 | 169 | if (actual) |actual_payload| { |
| 160 | | expectEqual(expected_payload, actual_payload); |
| 170 | try expectEqual(expected_payload, actual_payload); |
| 161 | 171 | } else |actual_err| { |
| 162 | | std.debug.panic("expected {any}, found {}", .{ expected_payload, actual_err }); |
| 172 | std.debug.print("expected {any}, found {}", .{ expected_payload, actual_err }); |
| 173 | return error.TestExpectedEqual; |
| 163 | 174 | } |
| 164 | 175 | } else |expected_err| { |
| 165 | 176 | if (actual) |actual_payload| { |
| 166 | | std.debug.panic("expected {}, found {any}", .{ expected_err, actual_payload }); |
| 177 | std.debug.print("expected {}, found {any}", .{ expected_err, actual_payload }); |
| 178 | return error.TestExpectedEqual; |
| 167 | 179 | } else |actual_err| { |
| 168 | | expectEqual(expected_err, actual_err); |
| 180 | try expectEqual(expected_err, actual_err); |
| 169 | 181 | } |
| 170 | 182 | } |
| 171 | 183 | }, |
| ... | ... | @@ -181,7 +193,7 @@ test "expectEqual.union(enum)" { |
| 181 | 193 | const a10 = T{ .a = 10 }; |
| 182 | 194 | const a20 = T{ .a = 20 }; |
| 183 | 195 | |
| 184 | | expectEqual(a10, a10); |
| 196 | try expectEqual(a10, a10); |
| 185 | 197 | } |
| 186 | 198 | |
| 187 | 199 | /// This function is intended to be used only in tests. When the formatted result of the template |
| ... | ... | @@ -197,7 +209,7 @@ pub fn expectFmt(expected: []const u8, comptime template: []const u8, args: anyt |
| 197 | 209 | print("\n======== instead found this: =========\n", .{}); |
| 198 | 210 | print("{s}", .{result}); |
| 199 | 211 | print("\n======================================\n", .{}); |
| 200 | | return error.TestFailed; |
| 212 | return error.TestExpectedFmt; |
| 201 | 213 | } |
| 202 | 214 | |
| 203 | 215 | pub const expectWithinMargin = @compileError("expectWithinMargin is deprecated, use expectApproxEqAbs or expectApproxEqRel"); |
| ... | ... | @@ -208,12 +220,14 @@ pub const expectWithinEpsilon = @compileError("expectWithinEpsilon is deprecated |
| 208 | 220 | /// to show exactly how they are not equal, then aborts. |
| 209 | 221 | /// See `math.approxEqAbs` for more informations on the tolerance parameter. |
| 210 | 222 | /// The types must be floating point |
| 211 | | pub fn expectApproxEqAbs(expected: anytype, actual: @TypeOf(expected), tolerance: @TypeOf(expected)) void { |
| 223 | pub fn expectApproxEqAbs(expected: anytype, actual: @TypeOf(expected), tolerance: @TypeOf(expected)) !void { |
| 212 | 224 | const T = @TypeOf(expected); |
| 213 | 225 | |
| 214 | 226 | switch (@typeInfo(T)) { |
| 215 | | .Float => if (!math.approxEqAbs(T, expected, actual, tolerance)) |
| 216 | | std.debug.panic("actual {}, not within absolute tolerance {} of expected {}", .{ actual, tolerance, expected }), |
| 227 | .Float => if (!math.approxEqAbs(T, expected, actual, tolerance)) { |
| 228 | std.debug.print("actual {}, not within absolute tolerance {} of expected {}", .{ actual, tolerance, expected }); |
| 229 | return error.TestExpectedApproxEqAbs; |
| 230 | }, |
| 217 | 231 | |
| 218 | 232 | .ComptimeFloat => @compileError("Cannot approximately compare two comptime_float values"), |
| 219 | 233 | |
| ... | ... | @@ -228,8 +242,8 @@ test "expectApproxEqAbs" { |
| 228 | 242 | const neg_x: T = -12.0; |
| 229 | 243 | const neg_y: T = -12.06; |
| 230 | 244 | |
| 231 | | expectApproxEqAbs(pos_x, pos_y, 0.1); |
| 232 | | expectApproxEqAbs(neg_x, neg_y, 0.1); |
| 245 | try expectApproxEqAbs(pos_x, pos_y, 0.1); |
| 246 | try expectApproxEqAbs(neg_x, neg_y, 0.1); |
| 233 | 247 | } |
| 234 | 248 | } |
| 235 | 249 | |
| ... | ... | @@ -238,12 +252,14 @@ test "expectApproxEqAbs" { |
| 238 | 252 | /// to show exactly how they are not equal, then aborts. |
| 239 | 253 | /// See `math.approxEqRel` for more informations on the tolerance parameter. |
| 240 | 254 | /// The types must be floating point |
| 241 | | pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance: @TypeOf(expected)) void { |
| 255 | pub fn expectApproxEqRel(expected: anytype, actual: @TypeOf(expected), tolerance: @TypeOf(expected)) !void { |
| 242 | 256 | const T = @TypeOf(expected); |
| 243 | 257 | |
| 244 | 258 | switch (@typeInfo(T)) { |
| 245 | | .Float => if (!math.approxEqRel(T, expected, actual, tolerance)) |
| 246 | | std.debug.panic("actual {}, not within relative tolerance {} of expected {}", .{ actual, tolerance, expected }), |
| 259 | .Float => if (!math.approxEqRel(T, expected, actual, tolerance)) { |
| 260 | std.debug.print("actual {}, not within relative tolerance {} of expected {}", .{ actual, tolerance, expected }); |
| 261 | return error.TestExpectedApproxEqRel; |
| 262 | }, |
| 247 | 263 | |
| 248 | 264 | .ComptimeFloat => @compileError("Cannot approximately compare two comptime_float values"), |
| 249 | 265 | |
| ... | ... | @@ -261,8 +277,8 @@ test "expectApproxEqRel" { |
| 261 | 277 | const neg_x: T = -12.0; |
| 262 | 278 | const neg_y: T = neg_x - 2 * eps_value; |
| 263 | 279 | |
| 264 | | expectApproxEqRel(pos_x, pos_y, sqrt_eps_value); |
| 265 | | expectApproxEqRel(neg_x, neg_y, sqrt_eps_value); |
| 280 | try expectApproxEqRel(pos_x, pos_y, sqrt_eps_value); |
| 281 | try expectApproxEqRel(neg_x, neg_y, sqrt_eps_value); |
| 266 | 282 | } |
| 267 | 283 | } |
| 268 | 284 | |
| ... | ... | @@ -270,26 +286,28 @@ test "expectApproxEqRel" { |
| 270 | 286 | /// equal, prints diagnostics to stderr to show exactly how they are not equal, |
| 271 | 287 | /// then aborts. |
| 272 | 288 | /// If your inputs are UTF-8 encoded strings, consider calling `expectEqualStrings` instead. |
| 273 | | pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) void { |
| 289 | pub fn expectEqualSlices(comptime T: type, expected: []const T, actual: []const T) !void { |
| 274 | 290 | // TODO better printing of the difference |
| 275 | 291 | // If the arrays are small enough we could print the whole thing |
| 276 | 292 | // If the child type is u8 and no weird bytes, we could print it as strings |
| 277 | 293 | // Even for the length difference, it would be useful to see the values of the slices probably. |
| 278 | 294 | if (expected.len != actual.len) { |
| 279 | | std.debug.panic("slice lengths differ. expected {d}, found {d}", .{ expected.len, actual.len }); |
| 295 | std.debug.print("slice lengths differ. expected {d}, found {d}", .{ expected.len, actual.len }); |
| 296 | return error.TestExpectedEqual; |
| 280 | 297 | } |
| 281 | 298 | var i: usize = 0; |
| 282 | 299 | while (i < expected.len) : (i += 1) { |
| 283 | 300 | if (!std.meta.eql(expected[i], actual[i])) { |
| 284 | | std.debug.panic("index {} incorrect. expected {any}, found {any}", .{ i, expected[i], actual[i] }); |
| 301 | std.debug.print("index {} incorrect. expected {any}, found {any}", .{ i, expected[i], actual[i] }); |
| 302 | return error.TestExpectedEqual; |
| 285 | 303 | } |
| 286 | 304 | } |
| 287 | 305 | } |
| 288 | 306 | |
| 289 | 307 | /// This function is intended to be used only in tests. When `ok` is false, the test fails. |
| 290 | 308 | /// A message is printed to stderr and then abort is called. |
| 291 | | pub fn expect(ok: bool) void { |
| 292 | | if (!ok) @panic("test failure"); |
| 309 | pub fn expect(ok: bool) !void { |
| 310 | if (!ok) return error.TestUnexpectedResult; |
| 293 | 311 | } |
| 294 | 312 | |
| 295 | 313 | pub const TmpDir = struct { |
| ... | ... | @@ -356,17 +374,17 @@ test "expectEqual nested array" { |
| 356 | 374 | [_]f32{ 0.0, 1.0 }, |
| 357 | 375 | }; |
| 358 | 376 | |
| 359 | | expectEqual(a, b); |
| 377 | try expectEqual(a, b); |
| 360 | 378 | } |
| 361 | 379 | |
| 362 | 380 | test "expectEqual vector" { |
| 363 | 381 | var a = @splat(4, @as(u32, 4)); |
| 364 | 382 | var b = @splat(4, @as(u32, 4)); |
| 365 | 383 | |
| 366 | | expectEqual(a, b); |
| 384 | try expectEqual(a, b); |
| 367 | 385 | } |
| 368 | 386 | |
| 369 | | pub fn expectEqualStrings(expected: []const u8, actual: []const u8) void { |
| 387 | pub fn expectEqualStrings(expected: []const u8, actual: []const u8) !void { |
| 370 | 388 | if (std.mem.indexOfDiff(u8, actual, expected)) |diff_index| { |
| 371 | 389 | print("\n====== expected this output: =========\n", .{}); |
| 372 | 390 | printWithVisibleNewlines(expected); |
| ... | ... | @@ -386,11 +404,11 @@ pub fn expectEqualStrings(expected: []const u8, actual: []const u8) void { |
| 386 | 404 | print("found:\n", .{}); |
| 387 | 405 | printIndicatorLine(actual, diff_index); |
| 388 | 406 | |
| 389 | | @panic("test failure"); |
| 407 | return error.TestExpectedEqual; |
| 390 | 408 | } |
| 391 | 409 | } |
| 392 | 410 | |
| 393 | | pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) void { |
| 411 | pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) !void { |
| 394 | 412 | if (std.mem.endsWith(u8, actual, expected_ends_with)) |
| 395 | 413 | return; |
| 396 | 414 | |
| ... | ... | @@ -407,7 +425,7 @@ pub fn expectStringEndsWith(actual: []const u8, expected_ends_with: []const u8) |
| 407 | 425 | printWithVisibleNewlines(actual); |
| 408 | 426 | print("\n======================================\n", .{}); |
| 409 | 427 | |
| 410 | | @panic("test failure"); |
| 428 | return error.TestExpectedEndsWith; |
| 411 | 429 | } |
| 412 | 430 | |
| 413 | 431 | fn printIndicatorLine(source: []const u8, indicator_index: usize) void { |
| ... | ... | @@ -446,7 +464,7 @@ fn printLine(line: []const u8) void { |
| 446 | 464 | } |
| 447 | 465 | |
| 448 | 466 | test { |
| 449 | | expectEqualStrings("foo", "foo"); |
| 467 | try expectEqualStrings("foo", "foo"); |
| 450 | 468 | } |
| 451 | 469 | |
| 452 | 470 | /// Given a type, reference all the declarations inside, so that the semantic analyzer sees them. |