Commit ddd39b994b

Paul Espinosa <mrpaul@aestheticwisdom.com>
2020-07-11 04:27:26
Use std.testing.expect in language reference samples
In this commit, the code samples in the language reference have been changed to use `std.testing.expect` rather than `std.debug.assert` when they are written in `test` code. This will teach Zig learners best practices when they write their own test code. Not all uses of `std.debug.assert` have been replaced. There are examples where using `assert` fits the context of the sample. Using `std.debug.assert` in test code can lead to errors if running tests in ReleaseFast mode. In ReleaseFast mode, the `unreachable` in `assert` is undefined behavior. It is possible that `assert` always causes `zig test` to pass thus possibly leading to incorrect test code outcomes. The goal is to prevent incorrect code from passing test cases. Closes #5836
1 parent 1e13e8e
Changed files (1)
doc/langref.html.in
@@ -344,16 +344,16 @@ pub fn main() void {
       {#header_close#}
       {#header_open|Comments#}
       {#code_begin|test|comments#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "comments" {
     // Comments in Zig start with "//" and end at the next LF byte (end of line).
     // The below line is a comment, and won't be executed.
 
-    //assert(false);
+    //expect(false);
 
     const x = true;  // another comment
-    assert(x);
+    expect(x);
 }
       {#code_end#}
       <p>
@@ -695,19 +695,19 @@ pub fn main() void {
       and character literals.
       </p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 const mem = @import("std").mem;
 
 test "string literals" {
     const bytes = "hello";
-    assert(@TypeOf(bytes) == *const [5:0]u8);
-    assert(bytes.len == 5);
-    assert(bytes[1] == 'e');
-    assert(bytes[5] == 0);
-    assert('e' == '\x65');
-    assert('\u{1f4a9}' == 128169);
-    assert('💯' == 128175);
-    assert(mem.eql(u8, "hello", "h\x65llo"));
+    expect(@TypeOf(bytes) == *const [5:0]u8);
+    expect(bytes.len == 5);
+    expect(bytes[1] == 'e');
+    expect(bytes[5] == 0);
+    expect('e' == '\x65');
+    expect('\u{1f4a9}' == 128169);
+    expect('💯' == 128175);
+    expect(mem.eql(u8, "hello", "h\x65llo"));
 }
       {#code_end#}
       {#see_also|Arrays|Zig Test|Source Encoding#}
@@ -800,14 +800,14 @@ test "assignment" {
       <p>{#syntax#}const{#endsyntax#} applies to all of the bytes that the identifier immediately addresses. {#link|Pointers#} have their own const-ness.</p>
       <p>If you need a variable that you can modify, use the {#syntax#}var{#endsyntax#} keyword:</p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "var" {
     var y: i32 = 5678;
 
     y += 1;
 
-    assert(y == 5679);
+    expect(y == 5679);
 }
       {#code_end#}
       <p>Variables must be initialized:</p>
@@ -821,12 +821,12 @@ test "initialization" {
       {#header_open|undefined#}
       <p>Use {#syntax#}undefined{#endsyntax#} to leave variables uninitialized:</p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "init with undefined" {
     var x: i32 = undefined;
     x = 1;
-    assert(x == 1);
+    expect(x == 1);
 }
       {#code_end#}
       <p>
@@ -868,8 +868,8 @@ var y: i32 = add(10, x);
 const x: i32 = add(12, 34);
 
 test "global variables" {
-    assert(x == 46);
-    assert(y == 56);
+    expect(x == 46);
+    expect(y == 56);
 }
 
 fn add(a: i32, b: i32) i32 {
@@ -877,18 +877,18 @@ fn add(a: i32, b: i32) i32 {
 }
 
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
       {#code_end#}
       <p>
       Global variables may be declared inside a {#link|struct#}, {#link|union#}, or {#link|enum#}:
       </p>
       {#code_begin|test|namespaced_global#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "namespaced global variable" {
-    assert(foo() == 1235);
-    assert(foo() == 1236);
+    expect(foo() == 1235);
+    expect(foo() == 1236);
 }
 
 fn foo() i32 {
@@ -957,7 +957,7 @@ fn testTls(context: void) void {
       </p>
       {#code_begin|test|comptime_vars#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "comptime vars" {
     var x: i32 = 1;
@@ -966,8 +966,8 @@ test "comptime vars" {
     x += 1;
     y += 1;
 
-    assert(x == 2);
-    assert(y == 2);
+    expect(x == 2);
+    expect(y == 2);
 
     if (y != 2) {
         // This compile error never triggers because y is a comptime variable,
@@ -1757,7 +1757,7 @@ orelse catch
       {#header_close#}
       {#header_open|Arrays#}
       {#code_begin|test|arrays#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 const mem = @import("std").mem;
 
 // array literal
@@ -1765,14 +1765,14 @@ const message = [_]u8{ 'h', 'e', 'l', 'l', 'o' };
 
 // get the size of an array
 comptime {
-    assert(message.len == 5);
+    expect(message.len == 5);
 }
 
 // A string literal is a pointer to an array literal.
 const same_message = "hello";
 
 comptime {
-    assert(mem.eql(u8, &message, same_message));
+    expect(mem.eql(u8, &message, same_message));
 }
 
 test "iterate over an array" {
@@ -1780,7 +1780,7 @@ test "iterate over an array" {
     for (message) |byte| {
         sum += byte;
     }
-    assert(sum == 'h' + 'e' + 'l' * 2 + 'o');
+    expect(sum == 'h' + 'e' + 'l' * 2 + 'o');
 }
 
 // modifiable array
@@ -1790,8 +1790,8 @@ test "modify an array" {
     for (some_integers) |*item, i| {
         item.* = @intCast(i32, i);
     }
-    assert(some_integers[10] == 10);
-    assert(some_integers[99] == 99);
+    expect(some_integers[10] == 10);
+    expect(some_integers[99] == 99);
 }
 
 // array concatenation works if the values are known
@@ -1800,7 +1800,7 @@ const part_one = [_]i32{ 1, 2, 3, 4 };
 const part_two = [_]i32{ 5, 6, 7, 8 };
 const all_of_it = part_one ++ part_two;
 comptime {
-    assert(mem.eql(i32, &all_of_it, &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }));
+    expect(mem.eql(i32, &all_of_it, &[_]i32{ 1, 2, 3, 4, 5, 6, 7, 8 }));
 }
 
 // remember that string literals are arrays
@@ -1808,21 +1808,21 @@ const hello = "hello";
 const world = "world";
 const hello_world = hello ++ " " ++ world;
 comptime {
-    assert(mem.eql(u8, hello_world, "hello world"));
+    expect(mem.eql(u8, hello_world, "hello world"));
 }
 
 // ** does repeating patterns
 const pattern = "ab" ** 3;
 comptime {
-    assert(mem.eql(u8, pattern, "ababab"));
+    expect(mem.eql(u8, pattern, "ababab"));
 }
 
 // initialize an array to zero
 const all_zero = [_]u16{0} ** 10;
 
 comptime {
-    assert(all_zero.len == 10);
-    assert(all_zero[5] == 0);
+    expect(all_zero.len == 10);
+    expect(all_zero[5] == 0);
 }
 
 // use compile-time code to initialize an array
@@ -1842,8 +1842,8 @@ const Point = struct {
 };
 
 test "compile-time array initialization" {
-    assert(fancy_array[4].x == 4);
-    assert(fancy_array[4].y == 8);
+    expect(fancy_array[4].x == 4);
+    expect(fancy_array[4].y == 8);
 }
 
 // call a function to initialize an array
@@ -1855,9 +1855,9 @@ fn makePoint(x: i32) Point {
     };
 }
 test "array initialization with function calls" {
-    assert(more_points[4].x == 3);
-    assert(more_points[4].y == 6);
-    assert(more_points.len == 10);
+    expect(more_points[4].x == 3);
+    expect(more_points[4].y == 6);
+    expect(more_points.len == 10);
 }
       {#code_end#}
       {#see_also|for|Slices#}
@@ -1867,14 +1867,14 @@ test "array initialization with function calls" {
       the type can be omitted from array literals:</p>
       {#code_begin|test|anon_list#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "anonymous list literal syntax" {
     var array: [4]u8 = .{11, 22, 33, 44};
-    assert(array[0] == 11);
-    assert(array[1] == 22);
-    assert(array[2] == 33);
-    assert(array[3] == 44);
+    expect(array[0] == 11);
+    expect(array[1] == 22);
+    expect(array[2] == 33);
+    expect(array[3] == 44);
 }
       {#code_end#}
       <p>
@@ -1883,18 +1883,18 @@ test "anonymous list literal syntax" {
       </p>
       {#code_begin|test|infer_list_literal#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "fully anonymous list literal" {
     dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi"});
 }
 
 fn dump(args: anytype) void {
-    assert(args.@"0" == 1234);
-    assert(args.@"1" == 12.34);
-    assert(args.@"2");
-    assert(args.@"3"[0] == 'h');
-    assert(args.@"3"[1] == 'i');
+    expect(args.@"0" == 1234);
+    expect(args.@"1" == 12.34);
+    expect(args.@"2");
+    expect(args.@"3"[0] == 'h');
+    expect(args.@"3"[1] == 'i');
 }
       {#code_end#}
       {#header_close#}
@@ -1905,7 +1905,7 @@ fn dump(args: anytype) void {
       </p>
       {#code_begin|test|multidimensional#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const mat4x4 = [4][4]f32{
     [_]f32{ 1.0, 0.0, 0.0, 0.0 },
@@ -1915,13 +1915,13 @@ const mat4x4 = [4][4]f32{
 };
 test "multidimensional arrays" {
     // Access the 2D array by indexing the outer array, and then the inner array.
-    assert(mat4x4[1][1] == 1.0);
+    expect(mat4x4[1][1] == 1.0);
 
     // Here we iterate with for loops.
     for (mat4x4) |row, row_index| {
         for (row) |cell, column_index| {
             if (row_index == column_index) {
-                assert(cell == 1.0);
+                expect(cell == 1.0);
             }
         }
     }
@@ -1936,14 +1936,14 @@ test "multidimensional arrays" {
       </p>
       {#code_begin|test|null_terminated_array#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "null terminated array" {
     const array = [_:0]u8 {1, 2, 3, 4};
 
-    assert(@TypeOf(array) == [4:0]u8);
-    assert(array.len == 4);
-    assert(array[4] == 0);
+    expect(@TypeOf(array) == [4:0]u8);
+    expect(array.len == 4);
+    expect(array[4] == 0);
 }
       {#code_end#}
       {#see_also|Sentinel-Terminated Pointers|Sentinel-Terminated Slices#}
@@ -2013,7 +2013,7 @@ test "null terminated array" {
         </ul>
         <p>Use {#syntax#}&x{#endsyntax#} to obtain a single-item pointer:</p>
         {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "address of syntax" {
     // Get the address of a variable:
@@ -2021,17 +2021,17 @@ test "address of syntax" {
     const x_ptr = &x;
 
     // Dereference a pointer:
-    assert(x_ptr.* == 1234);
+    expect(x_ptr.* == 1234);
 
     // When you get the address of a const variable, you get a const pointer to a single item.
-    assert(@TypeOf(x_ptr) == *const i32);
+    expect(@TypeOf(x_ptr) == *const i32);
 
     // If you want to mutate the value, you'd need an address of a mutable variable:
     var y: i32 = 5678;
     const y_ptr = &y;
-    assert(@TypeOf(y_ptr) == *i32);
+    expect(@TypeOf(y_ptr) == *i32);
     y_ptr.* += 1;
-    assert(y_ptr.* == 5679);
+    expect(y_ptr.* == 5679);
 }
 
 test "pointer array access" {
@@ -2040,11 +2040,11 @@ test "pointer array access" {
     // does not support pointer arithmetic.
     var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
     const ptr = &array[2];
-    assert(@TypeOf(ptr) == *u8);
+    expect(@TypeOf(ptr) == *u8);
 
-    assert(array[2] == 3);
+    expect(array[2] == 3);
     ptr.* += 1;
-    assert(array[2] == 4);
+    expect(array[2] == 4);
 }
       {#code_end#}
       <p>
@@ -2057,22 +2057,22 @@ test "pointer array access" {
         we prefer slices to pointers.
       </p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "pointer slicing" {
     var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
     const slice = array[2..4];
-    assert(slice.len == 2);
+    expect(slice.len == 2);
 
-    assert(array[3] == 4);
+    expect(array[3] == 4);
     slice[1] += 1;
-    assert(array[3] == 5);
+    expect(array[3] == 5);
 }
       {#code_end#}
       <p>Pointers work at compile-time too, as long as the code does not depend on
       an undefined memory layout:</p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "comptime pointers" {
     comptime {
@@ -2080,26 +2080,26 @@ test "comptime pointers" {
         const ptr = &x;
         ptr.* += 1;
         x += 1;
-        assert(ptr.* == 3);
+        expect(ptr.* == 3);
     }
 }
       {#code_end#}
       <p>To convert an integer address into a pointer, use {#syntax#}@intToPtr{#endsyntax#}.
       To convert a pointer to an integer, use {#syntax#}@ptrToInt{#endsyntax#}:</p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "@ptrToInt and @intToPtr" {
     const ptr = @intToPtr(*i32, 0xdeadbee0);
     const addr = @ptrToInt(ptr);
-    assert(@TypeOf(addr) == usize);
-    assert(addr == 0xdeadbee0);
+    expect(@TypeOf(addr) == usize);
+    expect(addr == 0xdeadbee0);
 }
       {#code_end#}
       <p>Zig is able to preserve memory addresses in comptime code, as long as
       the pointer is never dereferenced:</p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "comptime @intToPtr" {
     comptime {
@@ -2107,8 +2107,8 @@ test "comptime @intToPtr" {
         // ptr is never dereferenced.
         const ptr = @intToPtr(*i32, 0xdeadbee0);
         const addr = @ptrToInt(ptr);
-        assert(@TypeOf(addr) == usize);
-        assert(addr == 0xdeadbee0);
+        expect(@TypeOf(addr) == usize);
+        expect(addr == 0xdeadbee0);
     }
 }
       {#code_end#}
@@ -2119,11 +2119,11 @@ test "comptime @intToPtr" {
       In the following code, loads and stores with {#syntax#}mmio_ptr{#endsyntax#} are guaranteed to all happen
       and in the same order as in source code:</p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "volatile" {
     const mmio_ptr = @intToPtr(*volatile u8, 0x12345678);
-    assert(@TypeOf(mmio_ptr) == *volatile u8);
+    expect(@TypeOf(mmio_ptr) == *volatile u8);
 }
       {#code_end#}
       <p>
@@ -2139,25 +2139,25 @@ test "volatile" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "pointer casting" {
     const bytes align(@alignOf(u32)) = [_]u8{ 0x12, 0x12, 0x12, 0x12 };
     const u32_ptr = @ptrCast(*const u32, &bytes);
-    assert(u32_ptr.* == 0x12121212);
+    expect(u32_ptr.* == 0x12121212);
 
     // Even this example is contrived - there are better ways to do the above than
     // pointer casting. For example, using a slice narrowing cast:
     const u32_value = std.mem.bytesAsSlice(u32, bytes[0..])[0];
-    assert(u32_value == 0x12121212);
+    expect(u32_value == 0x12121212);
 
     // And even another way, the most straightforward way to do it:
-    assert(@bitCast(u32, bytes) == 0x12121212);
+    expect(@bitCast(u32, bytes) == 0x12121212);
 }
 
 test "pointer child type" {
     // pointer types have a `child` field which tells you the type they point to.
-    assert(@typeInfo(*u32).Pointer.child == u32);
+    expect(@typeInfo(*u32).Pointer.child == u32);
 }
       {#code_end#}
       {#header_open|Alignment#}
@@ -2177,15 +2177,15 @@ test "pointer child type" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "variable alignment" {
     var x: i32 = 1234;
     const align_of_i32 = @alignOf(@TypeOf(x));
-    assert(@TypeOf(&x) == *i32);
-    assert(*i32 == *align(align_of_i32) i32);
+    expect(@TypeOf(&x) == *i32);
+    expect(*i32 == *align(align_of_i32) i32);
     if (std.Target.current.cpu.arch == .x86_64) {
-        assert(@typeInfo(*i32).Pointer.alignment == 4);
+        expect(@typeInfo(*i32).Pointer.alignment == 4);
     }
 }
       {#code_end#}
@@ -2198,16 +2198,16 @@ test "variable alignment" {
       pointers to them get the specified alignment:
       </p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 var foo: u8 align(4) = 100;
 
 test "global variable alignment" {
-    assert(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
-    assert(@TypeOf(&foo) == *align(4) u8);
+    expect(@typeInfo(@TypeOf(&foo)).Pointer.alignment == 4);
+    expect(@TypeOf(&foo) == *align(4) u8);
     const as_pointer_to_array: *[1]u8 = &foo;
     const as_slice: []u8 = as_pointer_to_array;
-    assert(@TypeOf(as_slice) == []align(4) u8);
+    expect(@TypeOf(as_slice) == []align(4) u8);
 }
 
 fn derp() align(@sizeOf(usize) * 2) i32 { return 1234; }
@@ -2215,9 +2215,9 @@ fn noop1() align(1) void {}
 fn noop4() align(4) void {}
 
 test "function alignment" {
-    assert(derp() == 1234);
-    assert(@TypeOf(noop1) == fn() align(1) void);
-    assert(@TypeOf(noop4) == fn() align(4) void);
+    expect(derp() == 1234);
+    expect(@TypeOf(noop1) == fn() align(1) void);
+    expect(@TypeOf(noop4) == fn() align(4) void);
     noop1();
     noop4();
 }
@@ -2234,7 +2234,7 @@ const std = @import("std");
 test "pointer alignment safety" {
     var array align(4) = [_]u32{ 0x11111111, 0x11111111 };
     const bytes = std.mem.sliceAsBytes(array[0..]);
-    std.debug.assert(foo(bytes) == 0x11111111);
+    std.testing.expect(foo(bytes) == 0x11111111);
 }
 fn foo(bytes: []u8) u32 {
     const slice4 = bytes[1..5];
@@ -2255,12 +2255,12 @@ fn foo(bytes: []u8) u32 {
       </p>
       {#code_begin|test|allowzero#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "allowzero" {
     var zero: usize = 0;
     var ptr = @intToPtr(*allowzero i32, zero);
-    assert(@ptrToInt(ptr) == 0);
+    expect(@ptrToInt(ptr) == 0);
 }
       {#code_end#}
       {#header_close#}
@@ -2292,7 +2292,7 @@ pub fn main() anyerror!void {
 
       {#header_open|Slices#}
       {#code_begin|test_safety|index out of bounds#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "basic slices" {
     var array = [_]i32{ 1, 2, 3, 4 };
@@ -2302,14 +2302,14 @@ test "basic slices" {
     // Both can be accessed with the `len` field.
     var known_at_runtime_zero: usize = 0;
     const slice = array[known_at_runtime_zero..array.len];
-    assert(&slice[0] == &array[0]);
-    assert(slice.len == array.len);
+    expect(&slice[0] == &array[0]);
+    expect(slice.len == array.len);
 
     // Using the address-of operator on a slice gives a pointer to a single
     // item, while using the `ptr` field gives an unknown length pointer.
-    assert(@TypeOf(slice.ptr) == [*]i32);
-    assert(@TypeOf(&slice[0]) == *i32);
-    assert(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0]));
+    expect(@TypeOf(slice.ptr) == [*]i32);
+    expect(@TypeOf(&slice[0]) == *i32);
+    expect(@ptrToInt(slice.ptr) == @ptrToInt(&slice[0]));
 
     // Slices have array bounds checking. If you try to access something out
     // of bounds, you'll get a safety check failure:
@@ -2322,7 +2322,7 @@ test "basic slices" {
       <p>This is one reason we prefer slices to pointers.</p>
       {#code_begin|test|slices#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 const mem = std.mem;
 const fmt = std.fmt;
 
@@ -2343,7 +2343,7 @@ test "using slices for strings" {
     // Generally, you can use UTF-8 and not worry about whether something is a
     // string. If you don't need to deal with individual characters, no need
     // to decode.
-    assert(mem.eql(u8, hello_world, "hello 世界"));
+    expect(mem.eql(u8, hello_world, "hello 世界"));
 }
 
 test "slice pointer" {
@@ -2353,16 +2353,16 @@ test "slice pointer" {
     // You can use slicing syntax to convert a pointer into a slice:
     const slice = ptr[0..5];
     slice[2] = 3;
-    assert(slice[2] == 3);
+    expect(slice[2] == 3);
     // The slice is mutable because we sliced a mutable pointer.
     // Furthermore, it is actually a pointer to an array, since the start
     // and end indexes were both comptime-known.
-    assert(@TypeOf(slice) == *[5]u8);
+    expect(@TypeOf(slice) == *[5]u8);
 
     // You can also slice a slice:
     const slice2 = slice[2..3];
-    assert(slice2.len == 1);
-    assert(slice2[0] == 3);
+    expect(slice2.len == 1);
+    expect(slice2[0] == 3);
 }
       {#code_end#}
       {#see_also|Pointers|for|Arrays#}
@@ -2376,13 +2376,13 @@ test "slice pointer" {
       </p>
       {#code_begin|test|null_terminated_slice#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "null terminated slice" {
     const slice: [:0]const u8 = "hello";
 
-    assert(slice.len == 5);
-    assert(slice[5] == 0);
+    expect(slice.len == 5);
+    expect(slice[5] == 0);
 }
       {#code_end#}
       {#see_also|Sentinel-Terminated Pointers|Sentinel-Terminated Arrays#}
@@ -2440,16 +2440,16 @@ const Vec3 = struct {
     }
 };
 
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 test "dot product" {
     const v1 = Vec3.init(1.0, 0.0, 0.0);
     const v2 = Vec3.init(0.0, 1.0, 0.0);
-    assert(v1.dot(v2) == 0.0);
+    expect(v1.dot(v2) == 0.0);
 
     // Other than being available to call with dot syntax, struct methods are
     // not special. You can reference them as any other declaration inside
     // the struct:
-    assert(Vec3.dot(v1, v2) == 0.0);
+    expect(Vec3.dot(v1, v2) == 0.0);
 }
 
 // Structs can have global declarations.
@@ -2458,8 +2458,8 @@ const Empty = struct {
     pub const PI = 3.14;
 };
 test "struct namespaced variable" {
-    assert(Empty.PI == 3.14);
-    assert(@sizeOf(Empty) == 0);
+    expect(Empty.PI == 3.14);
+    expect(@sizeOf(Empty) == 0);
 
     // you can still instantiate an empty struct
     const does_nothing = Empty {};
@@ -2477,7 +2477,7 @@ test "field parent pointer" {
         .y = 0.5678,
     };
     setYBasedOnX(&point.x, 0.9);
-    assert(point.y == 0.9);
+    expect(point.y == 0.9);
 }
 
 // You can return a struct from a function. This is how we do generics
@@ -2499,19 +2499,19 @@ fn LinkedList(comptime T: type) type {
 test "linked list" {
     // Functions called at compile-time are memoized. This means you can
     // do this:
-    assert(LinkedList(i32) == LinkedList(i32));
+    expect(LinkedList(i32) == LinkedList(i32));
 
     var list = LinkedList(i32) {
         .first = null,
         .last = null,
         .len = 0,
     };
-    assert(list.len == 0);
+    expect(list.len == 0);
 
     // Since types are first class values you can instantiate the type
     // by assigning it to a variable:
     const ListOfInts = LinkedList(i32);
-    assert(ListOfInts == LinkedList(i32));
+    expect(ListOfInts == LinkedList(i32));
 
     var node = ListOfInts.Node {
         .prev = null,
@@ -2523,7 +2523,7 @@ test "linked list" {
         .last = &node,
         .len = 1,
     };
-    assert(list2.first.?.data == 1234);
+    expect(list2.first.?.data == 1234);
 }
       {#code_end#}
 
@@ -2584,7 +2584,7 @@ test "default struct initialization fields" {
       {#code_begin|test#}
 const std = @import("std");
 const builtin = std.builtin;
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Full = packed struct {
     number: u16,
@@ -2601,20 +2601,20 @@ test "@bitCast between packed structs" {
 }
 
 fn doTheTest() void {
-    assert(@sizeOf(Full) == 2);
-    assert(@sizeOf(Divided) == 2);
+    expect(@sizeOf(Full) == 2);
+    expect(@sizeOf(Divided) == 2);
     var full = Full{ .number = 0x1234 };
     var divided = @bitCast(Divided, full);
     switch (builtin.endian) {
         .Big => {
-            assert(divided.half1 == 0x12);
-            assert(divided.quarter3 == 0x3);
-            assert(divided.quarter4 == 0x4);
+            expect(divided.half1 == 0x12);
+            expect(divided.quarter3 == 0x3);
+            expect(divided.quarter4 == 0x4);
         },
         .Little => {
-            assert(divided.half1 == 0x34);
-            assert(divided.quarter3 == 0x2);
-            assert(divided.quarter4 == 0x1);
+            expect(divided.half1 == 0x34);
+            expect(divided.quarter3 == 0x2);
+            expect(divided.quarter4 == 0x1);
         },
     }
 }
@@ -2624,7 +2624,7 @@ fn doTheTest() void {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const BitField = packed struct {
     a: u3,
@@ -2640,7 +2640,7 @@ var foo = BitField{
 
 test "pointer to non-byte-aligned field" {
     const ptr = &foo.b;
-    assert(ptr.* == 2);
+    expect(ptr.* == 2);
 }
       {#code_end#}
       <p>
@@ -2649,7 +2649,7 @@ test "pointer to non-byte-aligned field" {
       </p>
       {#code_begin|test_err|expected type#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const BitField = packed struct {
     a: u3,
@@ -2664,7 +2664,7 @@ var bit_field = BitField{
 };
 
 test "pointer to non-bit-aligned field" {
-    assert(bar(&bit_field.b) == 2);
+    expect(bar(&bit_field.b) == 2);
 }
 
 fn bar(x: *const u3) u3 {
@@ -2680,7 +2680,7 @@ fn bar(x: *const u3) u3 {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const BitField = packed struct {
     a: u3,
@@ -2695,8 +2695,8 @@ var bit_field = BitField{
 };
 
 test "pointer to non-bit-aligned field" {
-    assert(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.b));
-    assert(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.c));
+    expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.b));
+    expect(@ptrToInt(&bit_field.a) == @ptrToInt(&bit_field.c));
 }
       {#code_end#}
       <p>
@@ -2704,7 +2704,7 @@ test "pointer to non-bit-aligned field" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const BitField = packed struct {
     a: u3,
@@ -2714,13 +2714,13 @@ const BitField = packed struct {
 
 test "pointer to non-bit-aligned field" {
     comptime {
-        assert(@bitOffsetOf(BitField, "a") == 0);
-        assert(@bitOffsetOf(BitField, "b") == 3);
-        assert(@bitOffsetOf(BitField, "c") == 6);
+        expect(@bitOffsetOf(BitField, "a") == 0);
+        expect(@bitOffsetOf(BitField, "b") == 3);
+        expect(@bitOffsetOf(BitField, "c") == 6);
 
-        assert(@byteOffsetOf(BitField, "a") == 0);
-        assert(@byteOffsetOf(BitField, "b") == 0);
-        assert(@byteOffsetOf(BitField, "c") == 0);
+        expect(@byteOffsetOf(BitField, "a") == 0);
+        expect(@byteOffsetOf(BitField, "b") == 0);
+        expect(@byteOffsetOf(BitField, "c") == 0);
     }
 }
       {#code_end#}
@@ -2791,7 +2791,7 @@ fn List(comptime T: type) type {
       </p>
       {#code_begin|test|struct_result#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Point = struct {x: i32, y: i32};
 
@@ -2800,8 +2800,8 @@ test "anonymous struct literal" {
         .x = 13,
         .y = 67,
     };
-    assert(pt.x == 13);
-    assert(pt.y == 67);
+    expect(pt.x == 13);
+    expect(pt.y == 67);
 }
       {#code_end#}
       <p>
@@ -2810,7 +2810,7 @@ test "anonymous struct literal" {
       </p>
       {#code_begin|test|struct_anon#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "fully anonymous struct" {
     dump(.{
@@ -2822,11 +2822,11 @@ test "fully anonymous struct" {
 }
 
 fn dump(args: anytype) void {
-    assert(args.int == 1234);
-    assert(args.float == 12.34);
-    assert(args.b);
-    assert(args.s[0] == 'h');
-    assert(args.s[1] == 'i');
+    expect(args.int == 1234);
+    expect(args.float == 12.34);
+    expect(args.b);
+    expect(args.s[0] == 'h');
+    expect(args.s[1] == 'i');
 }
       {#code_end#}
       {#header_close#}
@@ -2834,7 +2834,7 @@ fn dump(args: anytype) void {
       {#header_close#}
       {#header_open|enum#}
       {#code_begin|test|enums#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 const mem = @import("std").mem;
 
 // Declare an enum.
@@ -2857,9 +2857,9 @@ const Value = enum(u2) {
 // Now you can cast between u2 and Value.
 // The ordinal value starts from 0, counting up for each member.
 test "enum ordinal value" {
-    assert(@enumToInt(Value.zero) == 0);
-    assert(@enumToInt(Value.one) == 1);
-    assert(@enumToInt(Value.two) == 2);
+    expect(@enumToInt(Value.zero) == 0);
+    expect(@enumToInt(Value.one) == 1);
+    expect(@enumToInt(Value.two) == 2);
 }
 
 // You can override the ordinal value for an enum.
@@ -2869,9 +2869,9 @@ const Value2 = enum(u32) {
     million = 1000000,
 };
 test "set enum ordinal value" {
-    assert(@enumToInt(Value2.hundred) == 100);
-    assert(@enumToInt(Value2.thousand) == 1000);
-    assert(@enumToInt(Value2.million) == 1000000);
+    expect(@enumToInt(Value2.hundred) == 100);
+    expect(@enumToInt(Value2.thousand) == 1000);
+    expect(@enumToInt(Value2.million) == 1000000);
 }
 
 // Enums can have methods, the same as structs and unions.
@@ -2889,7 +2889,7 @@ const Suit = enum {
 };
 test "enum method" {
     const p = Suit.spades;
-    assert(!p.isClubs());
+    expect(!p.isClubs());
 }
 
 // An enum variant of different types can be switched upon.
@@ -2905,7 +2905,7 @@ test "enum variant switch" {
         Foo.number => "this is a number",
         Foo.none => "this is a none",
     };
-    assert(mem.eql(u8, what_is_it, "this is a number"));
+    expect(mem.eql(u8, what_is_it, "this is a number"));
 }
 
 // @TagType can be used to access the integer tag type of an enum.
@@ -2916,18 +2916,18 @@ const Small = enum {
     four,
 };
 test "@TagType" {
-    assert(@TagType(Small) == u2);
+    expect(@TagType(Small) == u2);
 }
 
 // @typeInfo tells us the field count and the fields names:
 test "@typeInfo" {
-    assert(@typeInfo(Small).Enum.fields.len == 4);
-    assert(mem.eql(u8, @typeInfo(Small).Enum.fields[1].name, "two"));
+    expect(@typeInfo(Small).Enum.fields.len == 4);
+    expect(mem.eql(u8, @typeInfo(Small).Enum.fields[1].name, "two"));
 }
 
 // @tagName gives a []const u8 representation of an enum value:
 test "@tagName" {
-    assert(mem.eql(u8, @tagName(Small.three), "three"));
+    expect(mem.eql(u8, @tagName(Small.three), "three"));
 }
       {#code_end#}
       {#see_also|@typeInfo|@tagName|@sizeOf#}
@@ -2962,7 +2962,7 @@ test "packed enum" {
         two,
         three,
     };
-    std.debug.assert(@sizeOf(Number) == @sizeOf(u8));
+    std.testing.expect(@sizeOf(Number) == @sizeOf(u8));
 }
       {#code_end#}
       <p>This makes the enum eligible to be in a {#link|packed struct#}.</p>
@@ -2974,7 +2974,7 @@ test "packed enum" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Color = enum {
     auto,
@@ -2985,7 +2985,7 @@ const Color = enum {
 test "enum literals" {
     const color1: Color = .auto;
     const color2 = Color.auto;
-    assert(color1 == color2);
+    expect(color1 == color2);
 }
 
 test "switch using enum literals" {
@@ -2995,7 +2995,7 @@ test "switch using enum literals" {
         .on => true,
         .off => false,
     };
-    assert(result);
+    expect(result);
 }
       {#code_end#}
       {#header_close#}
@@ -3014,7 +3014,7 @@ test "switch using enum literals" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Number = enum(u8) {
     one,
@@ -3031,12 +3031,12 @@ test "switch on non-exhaustive enum" {
         .three => false,
         _ => false,
     };
-    assert(result);
+    expect(result);
     const is_one = switch (number) {
         .one => true,
         else => false,
     };
-    assert(is_one);
+    expect(is_one);
 }
       {#code_end#}
       {#header_close#}
@@ -3067,7 +3067,7 @@ test "simple union" {
       <p>You can activate another field by assigning the entire union:</p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Payload = union {
     int: i64,
@@ -3076,9 +3076,9 @@ const Payload = union {
 };
 test "simple union" {
     var payload = Payload{ .int = 1234 };
-    assert(payload.int == 1234);
+    expect(payload.int == 1234);
     payload = Payload{ .float = 12.34 };
-    assert(payload.float == 12.34);
+    expect(payload.float == 12.34);
 }
       {#code_end#}
       <p>
@@ -3097,7 +3097,7 @@ test "simple union" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const ComplexTypeTag = enum {
     ok,
@@ -3110,24 +3110,24 @@ const ComplexType = union(ComplexTypeTag) {
 
 test "switch on tagged union" {
     const c = ComplexType{ .ok = 42 };
-    assert(@as(ComplexTypeTag, c) == ComplexTypeTag.ok);
+    expect(@as(ComplexTypeTag, c) == ComplexTypeTag.ok);
 
     switch (c) {
-        ComplexTypeTag.ok => |value| assert(value == 42),
+        ComplexTypeTag.ok => |value| expect(value == 42),
         ComplexTypeTag.not_ok => unreachable,
     }
 }
 
 test "@TagType" {
-    assert(@TagType(ComplexType) == ComplexTypeTag);
+    expect(@TagType(ComplexType) == ComplexTypeTag);
 }
 
 test "coerce to enum" {
     const c1 = ComplexType{ .ok = 42 };
     const c2 = ComplexType.not_ok;
 
-    assert(c1 == .ok);
-    assert(c2 == .not_ok);
+    expect(c1 == .ok);
+    expect(c2 == .not_ok);
 }
       {#code_end#}
       <p>In order to modify the payload of a tagged union in a switch expression,
@@ -3135,7 +3135,7 @@ test "coerce to enum" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const ComplexTypeTag = enum {
     ok,
@@ -3148,14 +3148,14 @@ const ComplexType = union(ComplexTypeTag) {
 
 test "modify tagged union in switch" {
     var c = ComplexType{ .ok = 42 };
-    assert(@as(ComplexTypeTag, c) == ComplexTypeTag.ok);
+    expect(@as(ComplexTypeTag, c) == ComplexTypeTag.ok);
 
     switch (c) {
         ComplexTypeTag.ok => |*value| value.* += 1,
         ComplexTypeTag.not_ok => unreachable,
     }
 
-    assert(c.ok == 43);
+    expect(c.ok == 43);
 }
       {#code_end#}
       <p>
@@ -3164,7 +3164,7 @@ test "modify tagged union in switch" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Variant = union(enum) {
     int: i32,
@@ -3186,8 +3186,8 @@ test "union method" {
     var v1 = Variant{ .int = 1 };
     var v2 = Variant{ .boolean = false };
 
-    assert(v1.truthy());
-    assert(!v2.truthy());
+    expect(v1.truthy());
+    expect(!v2.truthy());
 }
       {#code_end#}
       <p>
@@ -3196,7 +3196,7 @@ test "union method" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Small2 = union(enum) {
     a: i32,
@@ -3204,7 +3204,7 @@ const Small2 = union(enum) {
     c: u8,
 };
 test "@tagName" {
-    assert(std.mem.eql(u8, @tagName(Small2.a), "a"));
+    expect(std.mem.eql(u8, @tagName(Small2.a), "a"));
 }
       {#code_end#}
       {#header_close#}
@@ -3227,7 +3227,7 @@ test "@tagName" {
       the type:</p>
       {#code_begin|test|anon_union#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Number = union {
     int: i32,
@@ -3237,8 +3237,8 @@ const Number = union {
 test "anonymous union literal syntax" {
     var i: Number = .{.int = 42};
     var f = makeNumber();
-    assert(i.int == 42);
-    assert(f.float == 12.34);
+    expect(i.int == 42);
+    expect(f.float == 12.34);
 }
 
 fn makeNumber() Number {
@@ -3291,7 +3291,7 @@ test "access variable after block scope" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "labeled break from labeled block expression" {
     var y: i32 = 123;
@@ -3300,8 +3300,8 @@ test "labeled break from labeled block expression" {
         y += 1;
         break :blk y;
     };
-    assert(x == 124);
-    assert(y == 124);
+    expect(x == 124);
+    expect(y == 124);
 }
       {#code_end#}
       <p>Here, {#syntax#}blk{#endsyntax#} can be any name.</p>
@@ -3339,7 +3339,7 @@ test "separate scopes" {
       {#header_open|switch#}
       {#code_begin|test|switch#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "switch simple" {
     const a: u64 = 10;
@@ -3379,7 +3379,7 @@ test "switch simple" {
         else => 9,
     };
 
-    assert(b == 1);
+    expect(b == 1);
 }
 
 // Switch expressions can be used outside a function:
@@ -3409,7 +3409,7 @@ test "switch inside function" {
       turning it into a pointer.
       </p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "switch on tagged union" {
     const Point = struct {
@@ -3442,8 +3442,8 @@ test "switch on tagged union" {
         Item.d => 8,
     };
 
-    assert(b == 6);
-    assert(a.c.x == 2);
+    expect(b == 6);
+    expect(a.c.x == 2);
 }
       {#code_end#}
       {#see_also|comptime|enum|@compileError|Compile Variables#}
@@ -3477,7 +3477,7 @@ test "exhaustive switching" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Color = enum {
     auto,
@@ -3492,7 +3492,7 @@ test "enum literals with switch" {
         .on => false,
         .off => true,
     };
-    assert(result);
+    expect(result);
 }
       {#code_end#}
       {#header_close#}
@@ -3504,21 +3504,21 @@ test "enum literals with switch" {
       some condition is no longer true.
       </p>
       {#code_begin|test|while#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "while basic" {
     var i: usize = 0;
     while (i < 10) {
         i += 1;
     }
-    assert(i == 10);
+    expect(i == 10);
 }
       {#code_end#}
       <p>
       Use {#syntax#}break{#endsyntax#} to exit a while loop early.
       </p>
       {#code_begin|test|while#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "while break" {
     var i: usize = 0;
@@ -3527,14 +3527,14 @@ test "while break" {
             break;
         i += 1;
     }
-    assert(i == 10);
+    expect(i == 10);
 }
       {#code_end#}
       <p>
       Use {#syntax#}continue{#endsyntax#} to jump back to the beginning of the loop.
       </p>
       {#code_begin|test|while#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "while continue" {
     var i: usize = 0;
@@ -3544,7 +3544,7 @@ test "while continue" {
             continue;
         break;
     }
-    assert(i == 10);
+    expect(i == 10);
 }
       {#code_end#}
       <p>
@@ -3552,12 +3552,12 @@ test "while continue" {
       is continued. The {#syntax#}continue{#endsyntax#} keyword respects this expression.
       </p>
       {#code_begin|test|while#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "while loop continue expression" {
     var i: usize = 0;
     while (i < 10) : (i += 1) {}
-    assert(i == 10);
+    expect(i == 10);
 }
 
 test "while loop continue expression, more complicated" {
@@ -3565,7 +3565,7 @@ test "while loop continue expression, more complicated" {
     var j: usize = 1;
     while (i * j < 2000) : ({ i *= 2; j *= 3; }) {
         const my_ij = i * j;
-        assert(my_ij < 2000);
+        expect(my_ij < 2000);
     }
 }
       {#code_end#}
@@ -3581,11 +3581,11 @@ test "while loop continue expression, more complicated" {
       evaluated.
       </p>
       {#code_begin|test|while#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "while else" {
-    assert(rangeHasNumber(0, 10, 5));
-    assert(!rangeHasNumber(0, 10, 15));
+    expect(rangeHasNumber(0, 10, 5));
+    expect(!rangeHasNumber(0, 10, 15));
 }
 
 fn rangeHasNumber(begin: usize, end: usize, number: usize) bool {
@@ -3634,7 +3634,7 @@ test "nested continue" {
       be executed on the first null value encountered.
       </p>
       {#code_begin|test|while#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "while null capture" {
     var sum1: u32 = 0;
@@ -3642,14 +3642,14 @@ test "while null capture" {
     while (eventuallyNullSequence()) |value| {
         sum1 += value;
     }
-    assert(sum1 == 3);
+    expect(sum1 == 3);
 
     var sum2: u32 = 0;
     numbers_left = 3;
     while (eventuallyNullSequence()) |value| {
         sum2 += value;
     } else {
-        assert(sum2 == 3);
+        expect(sum2 == 3);
     }
 }
 
@@ -3676,7 +3676,7 @@ fn eventuallyNullSequence() ?u32 {
       the while condition must have an {#link|Error Union Type#}.
       </p>
       {#code_begin|test|while#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "while error union capture" {
     var sum1: u32 = 0;
@@ -3684,7 +3684,7 @@ test "while error union capture" {
     while (eventuallyErrorSequence()) |value| {
         sum1 += value;
     } else |err| {
-        assert(err == error.ReachedZero);
+        expect(err == error.ReachedZero);
     }
 }
 
@@ -3706,7 +3706,7 @@ fn eventuallyErrorSequence() anyerror!u32 {
       such as use types as first class values.
       </p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "inline while loop" {
     comptime var i = 0;
@@ -3720,7 +3720,7 @@ test "inline while loop" {
         };
         sum += typeNameLength(T);
     }
-    assert(sum == 9);
+    expect(sum == 9);
 }
 
 fn typeNameLength(comptime T: type) usize {
@@ -3741,7 +3741,7 @@ fn typeNameLength(comptime T: type) usize {
       {#header_close#}
       {#header_open|for#}
       {#code_begin|test|for#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "for basics" {
     const items = [_]i32 { 4, 5, 3, 4, 0 };
@@ -3755,22 +3755,22 @@ test "for basics" {
         }
         sum += value;
     }
-    assert(sum == 16);
+    expect(sum == 16);
 
     // To iterate over a portion of a slice, reslice.
     for (items[0..1]) |value| {
         sum += value;
     }
-    assert(sum == 20);
+    expect(sum == 20);
 
     // To access the index of iteration, specify a second capture value.
     // This is zero-indexed.
     var sum2: i32 = 0;
     for (items) |value, i| {
-        assert(@TypeOf(i) == usize);
+        expect(@TypeOf(i) == usize);
         sum2 += @intCast(i32, i);
     }
-    assert(sum2 == 10);
+    expect(sum2 == 10);
 }
 
 test "for reference" {
@@ -3782,9 +3782,9 @@ test "for reference" {
         value.* += 1;
     }
 
-    assert(items[0] == 4);
-    assert(items[1] == 5);
-    assert(items[2] == 3);
+    expect(items[0] == 4);
+    expect(items[1] == 5);
+    expect(items[2] == 3);
 }
 
 test "for else" {
@@ -3799,10 +3799,10 @@ test "for else" {
             sum += value.?;
         }
     } else blk: {
-        assert(sum == 12);
+        expect(sum == 12);
         break :blk sum;
     };
-    assert(result == 12);
+    expect(result == 12);
 }
       {#code_end#}
       {#header_open|Labeled for#}
@@ -3810,7 +3810,7 @@ test "for else" {
               or {#syntax#}continue{#endsyntax#} from within a nested loop:</p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "nested break" {
     var count: usize = 0;
@@ -3820,7 +3820,7 @@ test "nested break" {
             break :outer;
         }
     }
-    assert(count == 1);
+    expect(count == 1);
 }
 
 test "nested continue" {
@@ -3832,7 +3832,7 @@ test "nested continue" {
         }
     }
 
-    assert(count == 8);
+    expect(count == 8);
 }
       {#code_end#}
       {#header_close#}
@@ -3845,7 +3845,7 @@ test "nested continue" {
       compile-time known.
       </p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "inline for loop" {
     const nums = [_]i32{2, 4, 6};
@@ -3859,7 +3859,7 @@ test "inline for loop" {
         };
         sum += typeNameLength(T);
     }
-    assert(sum == 9);
+    expect(sum == 9);
 }
 
 fn typeNameLength(comptime T: type) usize {
@@ -3885,14 +3885,14 @@ fn typeNameLength(comptime T: type) usize {
 // * ?T
 // * anyerror!T
 
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "if expression" {
     // If expressions are used instead of a ternary expression.
     const a: u32 = 5;
     const b: u32 = 4;
     const result = if (a != b) 47 else 3089;
-    assert(result == 47);
+    expect(result == 47);
 }
 
 test "if boolean" {
@@ -3900,7 +3900,7 @@ test "if boolean" {
     const a: u32 = 5;
     const b: u32 = 4;
     if (a != b) {
-        assert(true);
+        expect(true);
     } else if (a == 9) {
         unreachable;
     } else {
@@ -3913,7 +3913,7 @@ test "if optional" {
 
     const a: ?u32 = 0;
     if (a) |value| {
-        assert(value == 0);
+        expect(value == 0);
     } else {
         unreachable;
     }
@@ -3922,17 +3922,17 @@ test "if optional" {
     if (b) |value| {
         unreachable;
     } else {
-        assert(true);
+        expect(true);
     }
 
     // The else is not required.
     if (a) |value| {
-        assert(value == 0);
+        expect(value == 0);
     }
 
     // To test against null only, use the binary equality operator.
     if (b == null) {
-        assert(true);
+        expect(true);
     }
 
     // Access the value by reference using a pointer capture.
@@ -3942,7 +3942,7 @@ test "if optional" {
     }
 
     if (c) |value| {
-        assert(value == 2);
+        expect(value == 2);
     } else {
         unreachable;
     }
@@ -3954,7 +3954,7 @@ test "if error union" {
 
     const a: anyerror!u32 = 0;
     if (a) |value| {
-        assert(value == 0);
+        expect(value == 0);
     } else |err| {
         unreachable;
     }
@@ -3963,17 +3963,17 @@ test "if error union" {
     if (b) |value| {
         unreachable;
     } else |err| {
-        assert(err == error.BadValue);
+        expect(err == error.BadValue);
     }
 
     // The else and |err| capture is strictly required.
     if (a) |value| {
-        assert(value == 0);
+        expect(value == 0);
     } else |_| {}
 
     // To check only the error value, use an empty block expression.
     if (b) |_| {} else |err| {
-        assert(err == error.BadValue);
+        expect(err == error.BadValue);
     }
 
     // Access the value by reference using a pointer capture.
@@ -3985,7 +3985,7 @@ test "if error union" {
     }
 
     if (c) |value| {
-        assert(value == 9);
+        expect(value == 9);
     } else |err| {
         unreachable;
     }
@@ -3997,14 +3997,14 @@ test "if error union with optional" {
 
     const a: anyerror!?u32 = 0;
     if (a) |optional_value| {
-        assert(optional_value.? == 0);
+        expect(optional_value.? == 0);
     } else |err| {
         unreachable;
     }
 
     const b: anyerror!?u32 = null;
     if (b) |optional_value| {
-        assert(optional_value == null);
+        expect(optional_value == null);
     } else |err| {
         unreachable;
     }
@@ -4013,7 +4013,7 @@ test "if error union with optional" {
     if (c) |optional_value| {
         unreachable;
     } else |err| {
-        assert(err == error.BadValue);
+        expect(err == error.BadValue);
     }
 
     // Access the value by reference by using a pointer capture each time.
@@ -4027,7 +4027,7 @@ test "if error union with optional" {
     }
 
     if (d) |optional_value| {
-        assert(optional_value.? == 9);
+        expect(optional_value.? == 9);
     } else |err| {
         unreachable;
     }
@@ -4038,7 +4038,7 @@ test "if error union with optional" {
       {#header_open|defer#}
       {#code_begin|test|defer#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 const print = std.debug.print;
 
 // defer will execute an expression at the end of the current scope.
@@ -4049,14 +4049,14 @@ fn deferExample() usize {
         defer a = 2;
         a = 1;
     }
-    assert(a == 2);
+    expect(a == 2);
 
     a = 5;
     return a;
 }
 
 test "defer basics" {
-    assert(deferExample() == 5);
+    expect(deferExample() == 5);
 }
 
 // If multiple defer statements are specified, they will be executed in
@@ -4133,8 +4133,9 @@ test "basic math" {
     }
 }
       {#code_end#}
-      <p>In fact, this is how assert is implemented:</p>
+      <p>In fact, this is how {#syntax#}std.debug.assert{#endsyntax#} is implemented:</p>
       {#code_begin|test_err#}
+// This is how std.debug.assert is implemented
 fn assert(ok: bool) void {
     if (!ok) unreachable; // assertion failure
 }
@@ -4193,19 +4194,19 @@ pub extern "kernel32" fn ExitProcess(exit_code: c_uint) callconv(.Stdcall) noret
 
 test "foo" {
     const value = bar() catch ExitProcess(1);
-    assert(value == 1234);
+    expect(value == 1234);
 }
 
 fn bar() anyerror!u32 {
     return 1234;
 }
 
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
       {#code_end#}
       {#header_close#}
       {#header_open|Functions#}
       {#code_begin|test|functions#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 // Functions are declared like this
 fn add(a: i8, b: i8) i8 {
@@ -4256,17 +4257,17 @@ fn do_op(fn_call: call2_op, op1: i8, op2: i8) i8 {
 }
 
 test "function" {
-    assert(do_op(add, 5, 6) == 11);
-    assert(do_op(sub2, 5, 6) == -1);
+    expect(do_op(add, 5, 6) == 11);
+    expect(do_op(sub2, 5, 6) == -1);
 }
       {#code_end#}
       <p>Function values are like pointers:</p>
       {#code_begin|obj#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 comptime {
-    assert(@TypeOf(foo) == fn()void);
-    assert(@sizeOf(fn()void) == @sizeOf(?fn()void));
+    expect(@TypeOf(foo) == fn()void);
+    expect(@sizeOf(fn()void) == @sizeOf(?fn()void));
 }
 
 fn foo() void { }
@@ -4298,10 +4299,10 @@ fn foo(point: Point) i32 {
     return point.x + point.y;
 }
 
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "pass struct to function" {
-    assert(foo(Point{ .x = 1, .y = 2 }) == 3);
+    expect(foo(Point{ .x = 1, .y = 2 }) == 3);
 }
       {#code_end#}
       <p>
@@ -4315,29 +4316,29 @@ test "pass struct to function" {
       Use {#link|@TypeOf#} and {#link|@typeInfo#} to get information about the inferred type.
       </p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 fn addFortyTwo(x: anytype) @TypeOf(x) {
     return x + 42;
 }
 
 test "fn type inference" {
-    assert(addFortyTwo(1) == 43);
-    assert(@TypeOf(addFortyTwo(1)) == comptime_int);
+    expect(addFortyTwo(1) == 43);
+    expect(@TypeOf(addFortyTwo(1)) == comptime_int);
     var y: i64 = 2;
-    assert(addFortyTwo(y) == 44);
-    assert(@TypeOf(addFortyTwo(y)) == i64);
+    expect(addFortyTwo(y) == 44);
+    expect(@TypeOf(addFortyTwo(y)) == i64);
 }
       {#code_end#}
 
       {#header_close#}
       {#header_open|Function Reflection#}
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "fn reflection" {
-    assert(@typeInfo(@TypeOf(assert)).Fn.return_type.? == void);
-    assert(@typeInfo(@TypeOf(assert)).Fn.is_var_args == false);
+    expect(@typeInfo(@TypeOf(expect)).Fn.return_type.? == void);
+    expect(@typeInfo(@TypeOf(expect)).Fn.is_var_args == false);
 }
       {#code_end#}
       {#header_close#}
@@ -4372,7 +4373,7 @@ const AllocationError = error {
 
 test "coerce subset to superset" {
     const err = foo(AllocationError.OutOfMemory);
-    std.debug.assert(err == FileOpenError.OutOfMemory);
+    std.testing.expect(err == FileOpenError.OutOfMemory);
 }
 
 fn foo(err: AllocationError) FileOpenError {
@@ -4480,7 +4481,7 @@ fn charToDigit(c: u8) u8 {
 
 test "parse u64" {
     const result = try parseU64("1234", 10);
-    std.debug.assert(result == 1234);
+    std.testing.expect(result == 1234);
 }
       {#code_end#}
       <p>
@@ -4625,7 +4626,7 @@ fn createFoo(param: i32) !Foo {
       <p>An error union is created with the {#syntax#}!{#endsyntax#} binary operator.
       You can use compile-time reflection to access the child type of an error union:</p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "error union" {
     var foo: anyerror!i32 = undefined;
@@ -4637,10 +4638,10 @@ test "error union" {
     foo = error.SomeError;
 
     // Use compile-time reflection to access the payload type of an error union:
-    comptime assert(@typeInfo(@TypeOf(foo)).ErrorUnion.payload == i32);
+    comptime expect(@typeInfo(@TypeOf(foo)).ErrorUnion.payload == i32);
 
     // Use compile-time reflection to access the error set type of an error union:
-    comptime assert(@typeInfo(@TypeOf(foo)).ErrorUnion.error_set == anyerror);
+    comptime expect(@typeInfo(@TypeOf(foo)).ErrorUnion.error_set == anyerror);
 }
       {#code_end#}
       {#header_open|Merging Error Sets#}
@@ -5007,7 +5008,7 @@ fn doAThing(optional_foo: ?*Foo) void {
       <p>An optional is created by putting {#syntax#}?{#endsyntax#} in front of a type. You can use compile-time
       reflection to access the child type of an optional:</p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "optional type" {
     // Declare an optional and coerce from null:
@@ -5017,7 +5018,7 @@ test "optional type" {
     foo = 1234;
 
     // Use compile-time reflection to access the child type of the optional:
-    comptime assert(@typeInfo(@TypeOf(foo)).Optional.child == i32);
+    comptime expect(@typeInfo(@TypeOf(foo)).Optional.child == i32);
 }
       {#code_end#}
       {#header_close#}
@@ -5034,7 +5035,7 @@ const optional_value: ?i32 = null;
       <p>An optional pointer is guaranteed to be the same size as a pointer. The {#syntax#}null{#endsyntax#} of
       the optional is guaranteed to be address 0.</p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "optional pointers" {
     // Pointers cannot be null. If you want a null pointer, use the optional
@@ -5044,11 +5045,11 @@ test "optional pointers" {
     var x: i32 = 1;
     ptr = &x;
 
-    assert(ptr.?.* == 1);
+    expect(ptr.?.* == 1);
 
     // Optional pointers are the same size as normal pointers, because pointer
     // value 0 is used as the null value.
-    assert(@sizeOf(?*i32) == @sizeOf(*i32));
+    expect(@sizeOf(?*i32) == @sizeOf(*i32));
 }
       {#code_end#}
       {#header_close#}
@@ -5115,13 +5116,13 @@ fn foo(a: *const i32) void {}
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 const mem = std.mem;
 
 test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
     const window_name = [1][*]const u8{"window name"};
     const x: [*]const ?[*]const u8 = &window_name;
-    assert(mem.eql(u8, std.mem.spanZ(@ptrCast([*:0]const u8, x[0].?)), "window name"));
+    expect(mem.eql(u8, std.mem.spanZ(@ptrCast([*:0]const u8, x[0].?)), "window name"));
 }
       {#code_end#}
       {#header_close#}
@@ -5132,7 +5133,7 @@ test "cast *[1][*]const u8 to [*]const ?[*]const u8" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 const mem = std.mem;
 
 test "integer widening" {
@@ -5142,13 +5143,13 @@ test "integer widening" {
     var d: u64 = c;
     var e: u64 = d;
     var f: u128 = e;
-    assert(f == a);
+    expect(f == a);
 }
 
 test "implicit unsigned integer to signed integer" {
     var a: u8 = 250;
     var b: i16 = a;
-    assert(b == 250);
+    expect(b == 250);
 }
 
 test "float widening" {
@@ -5160,7 +5161,7 @@ test "float widening" {
     var b: f32 = a;
     var c: f64 = b;
     var d: f128 = c;
-    assert(d == a);
+    expect(d == a);
 }
       {#code_end#}
       {#header_close#}
@@ -5183,7 +5184,7 @@ test "implicit cast to comptime_int" {
       {#header_open|Type Coercion: Arrays and Pointers#}
       {#code_begin|test|coerce_arrays_and_ptrs#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 // This cast exists primarily so that string literals can be
 // passed to functions that accept const slices. However
@@ -5192,41 +5193,41 @@ const assert = std.debug.assert;
 test "[N]T to []const T" {
     var x1: []const u8 = "hello";
     var x2: []const u8 = &[5]u8{ 'h', 'e', 'l', 'l', 111 };
-    assert(std.mem.eql(u8, x1, x2));
+    expect(std.mem.eql(u8, x1, x2));
 
     var y: []const f32 = &[2]f32{ 1.2, 3.4 };
-    assert(y[0] == 1.2);
+    expect(y[0] == 1.2);
 }
 
 // Likewise, it works when the destination type is an error union.
 test "[N]T to E![]const T" {
     var x1: anyerror![]const u8 = "hello";
     var x2: anyerror![]const u8 = &[5]u8{ 'h', 'e', 'l', 'l', 111 };
-    assert(std.mem.eql(u8, try x1, try x2));
+    expect(std.mem.eql(u8, try x1, try x2));
 
     var y: anyerror![]const f32 = &[2]f32{ 1.2, 3.4 };
-    assert((try y)[0] == 1.2);
+    expect((try y)[0] == 1.2);
 }
 
 // Likewise, it works when the destination type is an optional.
 test "[N]T to ?[]const T" {
     var x1: ?[]const u8 = "hello";
     var x2: ?[]const u8 = &[5]u8{ 'h', 'e', 'l', 'l', 111 };
-    assert(std.mem.eql(u8, x1.?, x2.?));
+    expect(std.mem.eql(u8, x1.?, x2.?));
 
     var y: ?[]const f32 = &[2]f32{ 1.2, 3.4 };
-    assert(y.?[0] == 1.2);
+    expect(y.?[0] == 1.2);
 }
 
 // In this cast, the array length becomes the slice length.
 test "*[N]T to []T" {
     var buf: [5]u8 = "hello".*;
     const x: []u8 = &buf;
-    assert(std.mem.eql(u8, x, "hello"));
+    expect(std.mem.eql(u8, x, "hello"));
 
     const buf2 = [2]f32{ 1.2, 3.4 };
     const x2: []const f32 = &buf2;
-    assert(std.mem.eql(f32, x2, &[2]f32{ 1.2, 3.4 }));
+    expect(std.mem.eql(f32, x2, &[2]f32{ 1.2, 3.4 }));
 }
 
 // Single-item pointers to arrays can be coerced to
@@ -5234,7 +5235,7 @@ test "*[N]T to []T" {
 test "*[N]T to [*]T" {
     var buf: [5]u8 = "hello".*;
     const x: [*]u8 = &buf;
-    assert(x[4] == 'o');
+    expect(x[4] == 'o');
     // x[5] would be an uncaught out of bounds pointer dereference!
 }
 
@@ -5242,7 +5243,7 @@ test "*[N]T to [*]T" {
 test "*[N]T to ?[*]T" {
     var buf: [5]u8 = "hello".*;
     const x: ?[*]u8 = &buf;
-    assert(x.?[4] == 'o');
+    expect(x.?[4] == 'o');
 }
 
 // Single-item pointers can be cast to len-1 single-item arrays.
@@ -5250,7 +5251,7 @@ test "*T to *[1]T" {
     var x: i32 = 1234;
     const y: *[1]i32 = &x;
     const z: [*]i32 = y;
-    assert(z[0] == 1234);
+    expect(z[0] == 1234);
 }
       {#code_end#}
       {#see_also|C Pointers#}
@@ -5261,27 +5262,27 @@ test "*T to *[1]T" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "coerce to optionals" {
     const x: ?i32 = 1234;
     const y: ?i32 = null;
 
-    assert(x.? == 1234);
-    assert(y == null);
+    expect(x.? == 1234);
+    expect(y == null);
 }
       {#code_end#}
       <p>It works nested inside the {#link|Error Union Type#}, too:</p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "coerce to optionals wrapped in error union" {
     const x: anyerror!?i32 = 1234;
     const y: anyerror!?i32 = null;
 
-    assert((try x).? == 1234);
-    assert((try y) == null);
+    expect((try x).? == 1234);
+    expect((try y) == null);
 }
       {#code_end#}
       {#header_close#}
@@ -5291,13 +5292,13 @@ test "coerce to optionals wrapped in error union" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "coercion to error unions" {
     const x: anyerror!i32 = 1234;
     const y: anyerror!i32 = error.Failure;
 
-    assert((try x) == 1234);
+    expect((try x) == 1234);
     std.testing.expectError(error.Failure, y);
 }
       {#code_end#}
@@ -5308,12 +5309,12 @@ test "coercion to error unions" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "coercing large integer type to smaller one when value is comptime known to fit" {
     const x: u64 = 255;
     const y: u8 = x;
-    assert(y == 255);
+    expect(y == 255);
 }
       {#code_end#}
       {#header_close#}
@@ -5324,7 +5325,7 @@ test "coercing large integer type to smaller one when value is comptime known to
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const E = enum {
     one,
@@ -5341,11 +5342,11 @@ const U = union(E) {
 test "coercion between unions and enums" {
     var u = U{ .two = 12.34 };
     var e: E = u;
-    assert(e == E.two);
+    expect(e == E.two);
 
     const three = E.three;
     var another_u: U = three;
-    assert(another_u == E.three);
+    expect(another_u == E.three);
 }
       {#code_end#}
       {#see_also|union|enum#}
@@ -5411,22 +5412,22 @@ test "coercion of zero bit types" {
       </p>
       {#code_begin|test|peer_type_resolution#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 const mem = std.mem;
 
 test "peer resolve int widening" {
     var a: i8 = 12;
     var b: i16 = 34;
     var c = a + b;
-    assert(c == 46);
-    assert(@TypeOf(c) == i16);
+    expect(c == 46);
+    expect(@TypeOf(c) == i16);
 }
 
 test "peer resolve arrays of different size to const slice" {
-    assert(mem.eql(u8, boolToStr(true), "true"));
-    assert(mem.eql(u8, boolToStr(false), "false"));
-    comptime assert(mem.eql(u8, boolToStr(true), "true"));
-    comptime assert(mem.eql(u8, boolToStr(false), "false"));
+    expect(mem.eql(u8, boolToStr(true), "true"));
+    expect(mem.eql(u8, boolToStr(false), "false"));
+    comptime expect(mem.eql(u8, boolToStr(true), "true"));
+    comptime expect(mem.eql(u8, boolToStr(false), "false"));
 }
 fn boolToStr(b: bool) []const u8 {
     return if (b) "true" else "false";
@@ -5439,16 +5440,16 @@ test "peer resolve array and const slice" {
 fn testPeerResolveArrayConstSlice(b: bool) void {
     const value1 = if (b) "aoeu" else @as([]const u8, "zz");
     const value2 = if (b) @as([]const u8, "zz") else "aoeu";
-    assert(mem.eql(u8, value1, "aoeu"));
-    assert(mem.eql(u8, value2, "zz"));
+    expect(mem.eql(u8, value1, "aoeu"));
+    expect(mem.eql(u8, value2, "zz"));
 }
 
 test "peer type resolution: ?T and T" {
-    assert(peerTypeTAndOptionalT(true, false).? == 0);
-    assert(peerTypeTAndOptionalT(false, false).? == 3);
+    expect(peerTypeTAndOptionalT(true, false).? == 0);
+    expect(peerTypeTAndOptionalT(false, false).? == 3);
     comptime {
-        assert(peerTypeTAndOptionalT(true, false).? == 0);
-        assert(peerTypeTAndOptionalT(false, false).? == 3);
+        expect(peerTypeTAndOptionalT(true, false).? == 0);
+        expect(peerTypeTAndOptionalT(false, false).? == 3);
     }
 }
 fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
@@ -5460,11 +5461,11 @@ fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize {
 }
 
 test "peer type resolution: *[0]u8 and []const u8" {
-    assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
-    assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
+    expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
+    expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
     comptime {
-        assert(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
-        assert(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
+        expect(peerTypeEmptyArrayAndSlice(true, "hi").len == 0);
+        expect(peerTypeEmptyArrayAndSlice(false, "hi").len == 1);
     }
 }
 fn peerTypeEmptyArrayAndSlice(a: bool, slice: []const u8) []const u8 {
@@ -5478,14 +5479,14 @@ test "peer type resolution: *[0]u8, []const u8, and anyerror![]u8" {
     {
         var data = "hi".*;
         const slice = data[0..];
-        assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
-        assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+        expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+        expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
     }
     comptime {
         var data = "hi".*;
         const slice = data[0..];
-        assert((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
-        assert((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
+        expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0);
+        expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1);
     }
 }
 fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
@@ -5499,8 +5500,8 @@ fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 {
 test "peer type resolution: *const T and ?*T" {
     const a = @intToPtr(*const usize, 0x123456780);
     const b = @intToPtr(?*usize, 0x123456780);
-    assert(a == b);
-    assert(b == a);
+    expect(a == b);
+    expect(b == a);
 }
       {#code_end#}
       {#header_close#}
@@ -5547,7 +5548,7 @@ export fn entry() void {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "turn HashMap into a set with void" {
     var map = std.AutoHashMap(i32, void).init(std.testing.allocator);
@@ -5556,11 +5557,11 @@ test "turn HashMap into a set with void" {
     try map.put(1, {});
     try map.put(2, {});
 
-    assert(map.contains(2));
-    assert(!map.contains(3));
+    expect(map.contains(2));
+    expect(!map.contains(3));
 
     _ = map.remove(2);
-    assert(!map.contains(2));
+    expect(!map.contains(2));
 }
       {#code_end#}
       <p>Note that this is different from using a dummy value for the hash map value.
@@ -5607,7 +5608,7 @@ fn foo() i32 {
       <p>Pointers to zero bit types also have zero bits. They always compare equal to each other:</p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "pointer to empty struct" {
     const Empty = struct {};
@@ -5615,7 +5616,7 @@ test "pointer to empty struct" {
     var b = Empty{};
     var ptr_a = &a;
     var ptr_b = &b;
-    comptime assert(ptr_a == ptr_b);
+    comptime expect(ptr_a == ptr_b);
 }
       {#code_end#}
       <p>The type being pointed to can only ever be one value; therefore loads and stores are
@@ -5650,7 +5651,7 @@ test "@intToPtr for pointer to zero bit type" {
 usingnamespace @import("std");
 
 test "using std namespace" {
-    debug.assert(true);
+    testing.expect(true);
 }
       {#code_end#}
       <p>
@@ -5762,7 +5763,7 @@ fn max(comptime T: type, a: T, b: T) T {
     }
 }
 test "try to compare bools" {
-    @import("std").debug.assert(max(bool, false, true) == true);
+    @import("std").testing.expect(max(bool, false, true) == true);
 }
       {#code_end#}
       <p>
@@ -5802,7 +5803,7 @@ fn max(a: bool, b: bool) bool {
       For example:
       </p>
       {#code_begin|test|comptime_vars#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 const CmdFn = struct {
     name: []const u8,
@@ -5830,9 +5831,9 @@ fn performFn(comptime prefix_char: u8, start_value: i32) i32 {
 }
 
 test "perform fn" {
-    assert(performFn('t', 1) == 6);
-    assert(performFn('o', 0) == 1);
-    assert(performFn('w', 99) == 99);
+    expect(performFn('t', 1) == 6);
+    expect(performFn('o', 0) == 1);
+    expect(performFn('w', 99) == 99);
 }
       {#code_end#}
       <p>
@@ -5843,7 +5844,7 @@ test "perform fn" {
       </p>
       {#code_begin|syntax#}
 // From the line:
-// assert(performFn('t', 1) == 6);
+// expect(performFn('t', 1) == 6);
 fn performFn(start_value: i32) i32 {
     var result: i32 = start_value;
     result = two(result);
@@ -5853,7 +5854,7 @@ fn performFn(start_value: i32) i32 {
       {#code_end#}
       {#code_begin|syntax#}
 // From the line:
-// assert(performFn('o', 0) == 1);
+// expect(performFn('o', 0) == 1);
 fn performFn(start_value: i32) i32 {
     var result: i32 = start_value;
     result = one(result);
@@ -5862,7 +5863,7 @@ fn performFn(start_value: i32) i32 {
       {#code_end#}
       {#code_begin|syntax#}
 // From the line:
-// assert(performFn('w', 99) == 99);
+// expect(performFn('w', 99) == 99);
 fn performFn(start_value: i32) i32 {
     var result: i32 = start_value;
     return result;
@@ -5915,7 +5916,7 @@ test "foo" {
       Let's look at an example:
       </p>
       {#code_begin|test#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 fn fibonacci(index: u32) u32 {
     if (index < 2) return index;
@@ -5924,11 +5925,11 @@ fn fibonacci(index: u32) u32 {
 
 test "fibonacci" {
     // test fibonacci at run-time
-    assert(fibonacci(7) == 13);
+    expect(fibonacci(7) == 13);
 
     // test fibonacci at compile-time
     comptime {
-        assert(fibonacci(7) == 13);
+        expect(fibonacci(7) == 13);
     }
 }
       {#code_end#}
@@ -5936,7 +5937,7 @@ test "fibonacci" {
       Imagine if we had forgotten the base case of the recursive function and tried to run the tests:
       </p>
       {#code_begin|test_err|operation caused overflow#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 fn fibonacci(index: u32) u32 {
     //if (index < 2) return index;
@@ -5945,7 +5946,7 @@ fn fibonacci(index: u32) u32 {
 
 test "fibonacci" {
     comptime {
-        assert(fibonacci(7) == 13);
+        expect(fibonacci(7) == 13);
     }
 }
       {#code_end#}
@@ -5959,7 +5960,7 @@ test "fibonacci" {
       But what would have happened if we used a signed integer?
       </p>
       {#code_begin|test_err|evaluation exceeded 1000 backwards branches#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 fn fibonacci(index: i32) i32 {
     //if (index < 2) return index;
@@ -5968,7 +5969,7 @@ fn fibonacci(index: i32) i32 {
 
 test "fibonacci" {
     comptime {
-        assert(fibonacci(7) == 13);
+        expect(fibonacci(7) == 13);
     }
 }
       {#code_end#}
@@ -5979,10 +5980,10 @@ test "fibonacci" {
       {#link|@setEvalBranchQuota#} to change the default number 1000 to something else.
       </p>
       <p>
-      What if we fix the base case, but put the wrong value in the {#syntax#}assert{#endsyntax#} line?
+      What if we fix the base case, but put the wrong value in the {#syntax#}expect{#endsyntax#} line?
       </p>
-      {#code_begin|test_err|unable to evaluate constant expression#}
-const assert = @import("std").debug.assert;
+      {#code_begin|test_err|encountered @panic at compile-time#}
+const expect = @import("std").testing.expect;
 
 fn fibonacci(index: i32) i32 {
     if (index < 2) return index;
@@ -5991,16 +5992,15 @@ fn fibonacci(index: i32) i32 {
 
 test "fibonacci" {
     comptime {
-        assert(fibonacci(7) == 99999);
+        expect(fibonacci(7) == 99999);
     }
 }
       {#code_end#}
       <p>
-      What happened is Zig started interpreting the {#syntax#}assert{#endsyntax#} function with the
+      What happened is Zig started interpreting the {#syntax#}expect{#endsyntax#} function with the
           parameter {#syntax#}ok{#endsyntax#} set to {#syntax#}false{#endsyntax#}. When the interpreter hit
-                  {#syntax#}unreachable{#endsyntax#} it emitted a compile error, because reaching unreachable
-      code is undefined behavior, and undefined behavior causes a compile error if it is detected
-      at compile-time.
+                  {#syntax#}@panic{#endsyntax#} it emitted a compile error because a panic during compile
+      causes a compile error if it is detected at compile-time.
       </p>
 
       <p>
@@ -6042,7 +6042,7 @@ fn sum(numbers: []const i32) i32 {
 }
 
 test "variable values" {
-    @import("std").debug.assert(sum_of_first_25_primes == 1060);
+    @import("std").testing.expect(sum_of_first_25_primes == 1060);
 }
       {#code_end#}
       <p>
@@ -6435,7 +6435,7 @@ volatile (
       {#code_begin|test|global-asm#}
       {#target_linux_x86_64#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 comptime {
     asm (
@@ -6450,7 +6450,7 @@ comptime {
 extern fn my_func(a: i32, b: i32) i32;
 
 test "global assembly" {
-    assert(my_func(12, 34) == 46);
+    expect(my_func(12, 34) == 46);
 }
       {#code_end#}
       {#header_close#}
@@ -6485,13 +6485,13 @@ test "global assembly" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 var x: i32 = 1;
 
 test "suspend with no resume" {
     var frame = async func();
-    assert(x == 2);
+    expect(x == 2);
 }
 
 fn func() void {
@@ -6511,21 +6511,21 @@ fn func() void {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 var the_frame: anyframe = undefined;
 var result = false;
 
 test "async function suspend with block" {
     _ = async testSuspendBlock();
-    assert(!result);
+    expect(!result);
     resume the_frame;
-    assert(result);
+    expect(result);
 }
 
 fn testSuspendBlock() void {
     suspend {
-        comptime assert(@TypeOf(@frame()) == *@Frame(testSuspendBlock));
+        comptime expect(@TypeOf(@frame()) == *@Frame(testSuspendBlock));
         the_frame = @frame();
     }
     result = true;
@@ -6549,12 +6549,12 @@ fn testSuspendBlock() void {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "resume from suspend" {
     var my_result: i32 = 1;
     _ = async testResumeFromSuspend(&my_result);
-    std.debug.assert(my_result == 2);
+    std.testing.expect(my_result == 2);
 }
 fn testResumeFromSuspend(my_result: *i32) void {
     suspend {
@@ -6578,7 +6578,7 @@ fn testResumeFromSuspend(my_result: *i32) void {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "async and await" {
     // Here we have an exception where we do not match an async
@@ -6592,7 +6592,7 @@ test "async and await" {
 
 fn amain() void {
     var frame = async func();
-    comptime assert(@TypeOf(frame) == @Frame(func));
+    comptime expect(@TypeOf(frame) == @Frame(func));
 
     const ptr: anyframe->void = &frame;
     const any_ptr: anyframe = ptr;
@@ -6622,7 +6622,7 @@ fn func() void {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 var the_frame: anyframe = undefined;
 var final_result: i32 = 0;
@@ -6633,8 +6633,8 @@ test "async function await" {
     seq('f');
     resume the_frame;
     seq('i');
-    assert(final_result == 1234);
-    assert(std.mem.eql(u8, &seq_points, "abcdefghi"));
+    expect(final_result == 1234);
+    expect(std.mem.eql(u8, &seq_points, "abcdefghi"));
 }
 fn amain() void {
     seq('b');
@@ -6848,9 +6848,9 @@ fn readFile(allocator: *Allocator, filename: []const u8) ![]u8 {
       for the current target to match the C ABI. When the child type of a pointer has
       this alignment, the alignment can be omitted from the type.
       </p>
-      <pre>{#syntax#}const assert = @import("std").debug.assert;
+      <pre>{#syntax#}const expect = @import("std").testing.expect;
 comptime {
-    assert(*u32 == *align(@alignOf(u32)) u32);
+    expect(*u32 == *align(@alignOf(u32)) u32);
 }{#endsyntax#}</pre>
       <p>
       The result is a target-specific compile time constant. It is guaranteed to be
@@ -6886,7 +6886,7 @@ comptime {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "async fn pointer in a struct field" {
     var data: i32 = 1;
@@ -6896,9 +6896,9 @@ test "async fn pointer in a struct field" {
     var foo = Foo{ .bar = func };
     var bytes: [64]u8 align(@alignOf(@Frame(func))) = undefined;
     const f = @asyncCall(&bytes, {}, foo.bar, .{&data});
-    assert(data == 2);
+    expect(data == 2);
     resume f;
-    assert(data == 4);
+    expect(data == 4);
 }
 
 fn func(y: *i32) void {
@@ -7082,10 +7082,10 @@ fn func(y: *i32) void {
       Calls a function, in the same way that invoking an expression with parentheses does:
       </p>
       {#code_begin|test|call#}
-const assert = @import("std").debug.assert;
+const expect = @import("std").testing.expect;
 
 test "noinline function call" {
-    assert(@call(.{}, add, .{3, 9}) == 12);
+    expect(@call(.{}, add, .{3, 9}) == 12);
 }
 
 fn add(a: i32, b: i32) i32 {
@@ -7544,14 +7544,14 @@ const Point = struct {
 };
 
 test "field access by string" {
-    const assert = std.debug.assert;
+    const expect = std.testing.expect;
     var p = Point {.x = 0, .y = 0};
 
     @field(p, "x") = 4;
     @field(p, "y") = @field(p, "x") + 1;
 
-    assert(@field(p, "x") == 4);
-    assert(@field(p, "y") == 5);
+    expect(@field(p, "x") == 4);
+    expect(@field(p, "y") == 5);
 }
       {#code_end#}
 
@@ -7657,7 +7657,7 @@ fn func() void {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 const Foo = struct {
     nope: i32,
@@ -7667,16 +7667,16 @@ const Foo = struct {
 };
 
 test "@hasDecl" {
-    assert(@hasDecl(Foo, "blah"));
+    expect(@hasDecl(Foo, "blah"));
 
     // Even though `hi` is private, @hasDecl returns true because this test is
     // in the same file scope as Foo. It would return false if Foo was declared
     // in a different file.
-    assert(@hasDecl(Foo, "hi"));
+    expect(@hasDecl(Foo, "hi"));
 
     // @hasDecl is for declarations; not fields.
-    assert(!@hasDecl(Foo, "nope"));
-    assert(!@hasDecl(Foo, "nope1234"));
+    expect(!@hasDecl(Foo, "nope"));
+    expect(!@hasDecl(Foo, "nope1234"));
 }
       {#code_end#}
       {#see_also|@hasField#}
@@ -7851,14 +7851,14 @@ mem.set(u8, dest, c);{#endsyntax#}</pre>
       {#code_begin|test#}
 const std = @import("std");
 const builtin = @import("builtin");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "@wasmMemoryGrow" {
     if (builtin.arch != .wasm32) return error.SkipZigTest;
 
     var prev = @wasmMemorySize(0);
-    assert(prev == @wasmMemoryGrow(0, 1));
-    assert(prev + 1 == @wasmMemorySize(0));
+    expect(prev == @wasmMemoryGrow(0, 1));
+    expect(prev + 1 == @wasmMemorySize(0));
 }
       {#code_end#}
       {#see_also|@wasmMemorySize#}
@@ -8194,13 +8194,13 @@ test "@setRuntimeSafety" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "vector @splat" {
     const scalar: u32 = 5;
     const result = @splat(4, scalar);
-    comptime assert(@TypeOf(result) == std.meta.Vector(4, u32));
-    assert(std.mem.eql(u32, &@as([4]u32, result), &[_]u32{ 5, 5, 5, 5 }));
+    comptime expect(@TypeOf(result) == std.meta.Vector(4, u32));
+    expect(std.mem.eql(u32, &@as([4]u32, result), &[_]u32{ 5, 5, 5, 5 }));
 }
       {#code_end#}
       <p>
@@ -8410,12 +8410,12 @@ fn doTheTest() void {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "@This()" {
     var items = [_]i32{ 1, 2, 3, 4 };
     const list = List(i32){ .items = items[0..] };
-    assert(list.length() == 4);
+    expect(list.length() == 4);
 }
 
 fn List(comptime T: type) type {
@@ -8456,12 +8456,12 @@ test "integer cast panic" {
       </p>
       {#code_begin|test|truncate#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "integer truncation" {
     var a: u16 = 0xabcd;
     var b: u8 = @truncate(u8, a);
-    assert(b == 0xcd);
+    expect(b == 0xcd);
 }
       {#code_end#}
       <p>
@@ -8544,13 +8544,13 @@ test "integer truncation" {
       </p>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "no runtime side effects" {
     var data: i32 = 0;
     const T = @TypeOf(foo(i32, &data));
-    comptime assert(T == i32);
-    assert(data == 0);
+    comptime expect(T == i32);
+    expect(data == 0);
 }
 
 fn foo(comptime T: type, ptr: *T) T {
@@ -8853,16 +8853,16 @@ pub fn main() void {
       </ul>
       {#code_begin|test#}
 const std = @import("std");
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 const minInt = std.math.minInt;
 const maxInt = std.math.maxInt;
 
 test "wraparound addition and subtraction" {
     const x: i32 = maxInt(i32);
     const min_val = x +% 1;
-    assert(min_val == minInt(i32));
+    expect(min_val == minInt(i32));
     const max_val = min_val -% 1;
-    assert(max_val == maxInt(i32));
+    expect(max_val == maxInt(i32));
 }
       {#code_end#}
       {#header_close#}
@@ -9287,13 +9287,13 @@ pub fn main() void {
       {#code_begin|test|allocator#}
 const std = @import("std");
 const Allocator = std.mem.Allocator;
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "using an allocator" {
     var buffer: [100]u8 = undefined;
     const allocator = &std.heap.FixedBufferAllocator.init(&buffer).allocator;
     const result = try concat(allocator, "foo", "bar");
-    assert(std.mem.eql(u8, "foobar", result));
+    expect(std.mem.eql(u8, "foobar", result));
 }
 
 fn concat(allocator: *Allocator, a: []const u8, b: []const u8) ![]u8 {
@@ -9560,10 +9560,10 @@ const separator = if (builtin.os == builtin.Os.windows) '\\' else '/';
       {#code_begin|test|detect_test#}
 const std = @import("std");
 const builtin = std.builtin;
-const assert = std.debug.assert;
+const expect = std.testing.expect;
 
 test "builtin.is_test" {
-    assert(builtin.is_test);
+    expect(builtin.is_test);
 }
       {#code_end#}
       <p>
@@ -9613,7 +9613,7 @@ test "assert in release fast mode" {
 const std = @import("std");
 const expect = std.testing.expect;
 
-test "assert in release fast mode" {
+test "expect in release fast mode" {
     expect(false);
 }
       {#code_end#}