| ... | ... | @@ -793,28 +793,37 @@ fn writeEscaped(out: anytype, input: []const u8) !void { |
| 793 | 793 | } |
| 794 | 794 | } |
| 795 | 795 | |
| 796 | | //#define VT_RED "\x1b[31;1m" |
| 797 | | //#define VT_GREEN "\x1b[32;1m" |
| 798 | | //#define VT_CYAN "\x1b[36;1m" |
| 799 | | //#define VT_WHITE "\x1b[37;1m" |
| 800 | | //#define VT_BOLD "\x1b[0;1m" |
| 801 | | //#define VT_RESET "\x1b[0m" |
| 802 | | |
| 803 | | test "term color" { |
| 804 | | const input_bytes = "A\x1b[32;1mgreen\x1b[0mB"; |
| 805 | | const result = try termColor(std.testing.allocator, input_bytes); |
| 806 | | defer std.testing.allocator.free(result); |
| 807 | | try testing.expectEqualSlices(u8, "A<span class=\"t32_1\">green</span>B", result); |
| 796 | // Returns true if number is in slice. |
| 797 | fn in(slice: []const u8, number: u8) bool { |
| 798 | for (slice) |n| { |
| 799 | if (number == n) return true; |
| 800 | } |
| 801 | return false; |
| 808 | 802 | } |
| 809 | 803 | |
| 810 | 804 | fn termColor(allocator: Allocator, input: []const u8) ![]u8 { |
| 805 | // The SRG sequences generates by the Zig compiler are in the format: |
| 806 | // ESC [ <foreground-color> ; <n> m |
| 807 | // or |
| 808 | // ESC [ <n> m |
| 809 | // |
| 810 | // where |
| 811 | // foreground-color is 31 (red), 32 (green), 36 (cyan) |
| 812 | // n is 0 (reset), 1 (bold), 2 (dim) |
| 813 | // |
| 814 | // Note that 37 (white) is currently not used by the compiler. |
| 815 | // |
| 816 | // See std.debug.TTY.Color. |
| 817 | const supported_sgr_colors = [_]u8{ 31, 32, 36 }; |
| 818 | const supported_sgr_numbers = [_]u8{ 0, 1, 2 }; |
| 819 | |
| 811 | 820 | var buf = std.ArrayList(u8).init(allocator); |
| 812 | 821 | defer buf.deinit(); |
| 813 | 822 | |
| 814 | 823 | var out = buf.writer(); |
| 815 | | var number_start_index: usize = undefined; |
| 816 | | var first_number: usize = undefined; |
| 817 | | var second_number: usize = undefined; |
| 824 | var sgr_param_start_index: usize = undefined; |
| 825 | var sgr_num: u8 = undefined; |
| 826 | var sgr_color: u8 = undefined; |
| 818 | 827 | var i: usize = 0; |
| 819 | 828 | var state: enum { |
| 820 | 829 | start, |
| ... | ... | @@ -845,7 +854,7 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { |
| 845 | 854 | }, |
| 846 | 855 | .lbracket => switch (c) { |
| 847 | 856 | '0'...'9' => { |
| 848 | | number_start_index = i; |
| 857 | sgr_param_start_index = i; |
| 849 | 858 | state = .number; |
| 850 | 859 | }, |
| 851 | 860 | else => return error.UnsupportedEscape, |
| ... | ... | @@ -853,13 +862,12 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { |
| 853 | 862 | .number => switch (c) { |
| 854 | 863 | '0'...'9' => {}, |
| 855 | 864 | else => { |
| 856 | | first_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable; |
| 857 | | second_number = 0; |
| 865 | sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); |
| 866 | sgr_color = 0; |
| 858 | 867 | state = .after_number; |
| 859 | 868 | i -= 1; |
| 860 | 869 | }, |
| 861 | 870 | }, |
| 862 | | |
| 863 | 871 | .after_number => switch (c) { |
| 864 | 872 | ';' => state = .arg, |
| 865 | 873 | 'D' => state = .start, |
| ... | ... | @@ -874,7 +882,7 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { |
| 874 | 882 | }, |
| 875 | 883 | .arg => switch (c) { |
| 876 | 884 | '0'...'9' => { |
| 877 | | number_start_index = i; |
| 885 | sgr_param_start_index = i; |
| 878 | 886 | state = .arg_number; |
| 879 | 887 | }, |
| 880 | 888 | else => return error.UnsupportedEscape, |
| ... | ... | @@ -882,7 +890,15 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { |
| 882 | 890 | .arg_number => switch (c) { |
| 883 | 891 | '0'...'9' => {}, |
| 884 | 892 | else => { |
| 885 | | second_number = std.fmt.parseInt(usize, input[number_start_index..i], 10) catch unreachable; |
| 893 | // Keep the sequence consistent, foreground color first. |
| 894 | // 32;1m is equivalent to 1;32m, but the latter will |
| 895 | // generate an incorrect HTML class without notice. |
| 896 | sgr_color = sgr_num; |
| 897 | if (!in(&supported_sgr_colors, sgr_color)) return error.UnsupportedForegroundColor; |
| 898 | |
| 899 | sgr_num = try std.fmt.parseInt(u8, input[sgr_param_start_index..i], 10); |
| 900 | if (!in(&supported_sgr_numbers, sgr_num)) return error.UnsupportedNumber; |
| 901 | |
| 886 | 902 | state = .expect_end; |
| 887 | 903 | i -= 1; |
| 888 | 904 | }, |
| ... | ... | @@ -893,10 +909,16 @@ fn termColor(allocator: Allocator, input: []const u8) ![]u8 { |
| 893 | 909 | while (open_span_count != 0) : (open_span_count -= 1) { |
| 894 | 910 | try out.writeAll("</span>"); |
| 895 | 911 | } |
| 896 | | if (first_number != 0 or second_number != 0) { |
| 897 | | try out.print("<span class=\"t{d}_{d}\">", .{ first_number, second_number }); |
| 898 | | open_span_count += 1; |
| 912 | if (sgr_num == 0) { |
| 913 | if (sgr_color != 0) return error.UnsupportedColor; |
| 914 | continue; |
| 915 | } |
| 916 | if (sgr_color != 0) { |
| 917 | try out.print("<span class=\"sgr-{d}_{d}m\">", .{ sgr_color, sgr_num }); |
| 918 | } else { |
| 919 | try out.print("<span class=\"sgr-{d}m\">", .{sgr_num}); |
| 899 | 920 | } |
| 921 | open_span_count += 1; |
| 900 | 922 | }, |
| 901 | 923 | else => return error.UnsupportedEscape, |
| 902 | 924 | }, |
| ... | ... | @@ -1874,7 +1896,193 @@ fn dumpArgs(args: []const []const u8) void { |
| 1874 | 1896 | print("\n", .{}); |
| 1875 | 1897 | } |
| 1876 | 1898 | |
| 1877 | | test "shell parsed" { |
| 1899 | test "term supported colors" { |
| 1900 | const test_allocator = testing.allocator; |
| 1901 | |
| 1902 | { |
| 1903 | const input = "A\x1b[31;1mred\x1b[0mB"; |
| 1904 | const expect = "A<span class=\"sgr-31_1m\">red</span>B"; |
| 1905 | |
| 1906 | const result = try termColor(test_allocator, input); |
| 1907 | defer test_allocator.free(result); |
| 1908 | try testing.expectEqualSlices(u8, expect, result); |
| 1909 | } |
| 1910 | |
| 1911 | { |
| 1912 | const input = "A\x1b[32;1mgreen\x1b[0mB"; |
| 1913 | const expect = "A<span class=\"sgr-32_1m\">green</span>B"; |
| 1914 | |
| 1915 | const result = try termColor(test_allocator, input); |
| 1916 | defer test_allocator.free(result); |
| 1917 | try testing.expectEqualSlices(u8, expect, result); |
| 1918 | } |
| 1919 | |
| 1920 | { |
| 1921 | const input = "A\x1b[36;1mcyan\x1b[0mB"; |
| 1922 | const expect = "A<span class=\"sgr-36_1m\">cyan</span>B"; |
| 1923 | |
| 1924 | const result = try termColor(test_allocator, input); |
| 1925 | defer test_allocator.free(result); |
| 1926 | try testing.expectEqualSlices(u8, expect, result); |
| 1927 | } |
| 1928 | |
| 1929 | { |
| 1930 | const input = "A\x1b[1mbold\x1b[0mB"; |
| 1931 | const expect = "A<span class=\"sgr-1m\">bold</span>B"; |
| 1932 | |
| 1933 | const result = try termColor(test_allocator, input); |
| 1934 | defer test_allocator.free(result); |
| 1935 | try testing.expectEqualSlices(u8, expect, result); |
| 1936 | } |
| 1937 | |
| 1938 | { |
| 1939 | const input = "A\x1b[2mdim\x1b[0mB"; |
| 1940 | const expect = "A<span class=\"sgr-2m\">dim</span>B"; |
| 1941 | |
| 1942 | const result = try termColor(test_allocator, input); |
| 1943 | defer test_allocator.free(result); |
| 1944 | try testing.expectEqualSlices(u8, expect, result); |
| 1945 | } |
| 1946 | } |
| 1947 | |
| 1948 | test "term output from zig" { |
| 1949 | // Use data generated by https://github.com/perillo/zig-tty-test-data, |
| 1950 | // with zig version 0.11.0-dev.1898+36d47dd19. |
| 1951 | const test_allocator = testing.allocator; |
| 1952 | |
| 1953 | { |
| 1954 | // 1.1-with-build-progress.out |
| 1955 | const input = "Semantic Analysis [1324] \x1b[25D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLVM Emit Object... \x1b[20D\x1b[0KLLD Link... \x1b[12D\x1b[0K"; |
| 1956 | const expect = ""; |
| 1957 | |
| 1958 | const result = try termColor(test_allocator, input); |
| 1959 | defer test_allocator.free(result); |
| 1960 | try testing.expectEqualSlices(u8, expect, result); |
| 1961 | } |
| 1962 | |
| 1963 | { |
| 1964 | // 2.1-with-reference-traces.out |
| 1965 | const input = "\x1b[1msrc/2.1-with-reference-traces.zig:3:7: \x1b[31;1merror: \x1b[0m\x1b[1mcannot assign to constant\n\x1b[0m x += 1;\n \x1b[32;1m~~^~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.1-with-reference-traces.zig:7:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; |
| 1966 | const expect = |
| 1967 | \\<span class="sgr-1m">src/2.1-with-reference-traces.zig:3:7: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">cannot assign to constant |
| 1968 | \\</span> x += 1; |
| 1969 | \\ <span class="sgr-32_1m">~~^~~~ |
| 1970 | \\</span><span class="sgr-2m">referenced by: |
| 1971 | \\ main: src/2.1-with-reference-traces.zig:7:5 |
| 1972 | \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 |
| 1973 | \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces |
| 1974 | \\ |
| 1975 | \\</span> |
| 1976 | ; |
| 1977 | |
| 1978 | const result = try termColor(test_allocator, input); |
| 1979 | defer test_allocator.free(result); |
| 1980 | try testing.expectEqualSlices(u8, expect, result); |
| 1981 | } |
| 1982 | |
| 1983 | { |
| 1984 | // 2.2-without-reference-traces.out |
| 1985 | const input = "\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: \x1b[31;1merror: \x1b[0m\x1b[1minvalid type given to fixedBufferStream\n\x1b[0m else => @compileError(\"invalid type given to fixedBufferStream\"),\n \x1b[32;1m^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\x1b[0m\x1b[1m/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: \x1b[36;1mnote: \x1b[0m\x1b[1mcalled from here\n\x1b[0mpub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) {\n; \x1b[32;1m~~~~~^~~~~~~~~~~~~~~~~\n\x1b[0m"; |
| 1986 | const expect = |
| 1987 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:128:29: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">invalid type given to fixedBufferStream |
| 1988 | \\</span> else => @compileError("invalid type given to fixedBufferStream"), |
| 1989 | \\ <span class="sgr-32_1m">^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 1990 | \\</span><span class="sgr-1m">/usr/local/lib/zig/lib/std/io/fixed_buffer_stream.zig:116:66: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">called from here |
| 1991 | \\</span>pub fn fixedBufferStream(buffer: anytype) FixedBufferStream(Slice(@TypeOf(buffer))) { |
| 1992 | \\; <span class="sgr-32_1m">~~~~~^~~~~~~~~~~~~~~~~ |
| 1993 | \\</span> |
| 1994 | ; |
| 1995 | |
| 1996 | const result = try termColor(test_allocator, input); |
| 1997 | defer test_allocator.free(result); |
| 1998 | try testing.expectEqualSlices(u8, expect, result); |
| 1999 | } |
| 2000 | |
| 2001 | { |
| 2002 | // 2.3-with-notes.out |
| 2003 | const input = "\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[31;1merror: \x1b[0m\x1b[1mexpected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat'\n\x1b[0m bar(w);\n \x1b[32;1m^\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:6:9: \x1b[36;1mnote: \x1b[0m\x1b[1mpointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp'\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:2:13: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Wat = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:1:14: \x1b[36;1mnote: \x1b[0m\x1b[1mopaque declared here\n\x1b[0mconst Derp = opaque {};\n \x1b[32;1m^~~~~~~~~\n\x1b[0m\x1b[1msrc/2.3-with-notes.zig:4:18: \x1b[36;1mnote: \x1b[0m\x1b[1mparameter type declared here\n\x1b[0mextern fn bar(d: *Derp) void;\n \x1b[32;1m^~~~~\n\x1b[0m\x1b[0m\x1b[2mreferenced by:\n main: src/2.3-with-notes.zig:10:5\n callMain: /usr/local/lib/zig/lib/std/start.zig:607:17\n remaining reference traces hidden; use '-freference-trace' to see all reference traces\n\n\x1b[0m"; |
| 2004 | const expect = |
| 2005 | \\<span class="sgr-1m">src/2.3-with-notes.zig:6:9: </span><span class="sgr-31_1m">error: </span><span class="sgr-1m">expected type '*2.3-with-notes.Derp', found '*2.3-with-notes.Wat' |
| 2006 | \\</span> bar(w); |
| 2007 | \\ <span class="sgr-32_1m">^ |
| 2008 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:6:9: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">pointer type child '2.3-with-notes.Wat' cannot cast into pointer type child '2.3-with-notes.Derp' |
| 2009 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:2:13: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">opaque declared here |
| 2010 | \\</span>const Wat = opaque {}; |
| 2011 | \\ <span class="sgr-32_1m">^~~~~~~~~ |
| 2012 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:1:14: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">opaque declared here |
| 2013 | \\</span>const Derp = opaque {}; |
| 2014 | \\ <span class="sgr-32_1m">^~~~~~~~~ |
| 2015 | \\</span><span class="sgr-1m">src/2.3-with-notes.zig:4:18: </span><span class="sgr-36_1m">note: </span><span class="sgr-1m">parameter type declared here |
| 2016 | \\</span>extern fn bar(d: *Derp) void; |
| 2017 | \\ <span class="sgr-32_1m">^~~~~ |
| 2018 | \\</span><span class="sgr-2m">referenced by: |
| 2019 | \\ main: src/2.3-with-notes.zig:10:5 |
| 2020 | \\ callMain: /usr/local/lib/zig/lib/std/start.zig:607:17 |
| 2021 | \\ remaining reference traces hidden; use '-freference-trace' to see all reference traces |
| 2022 | \\ |
| 2023 | \\</span> |
| 2024 | ; |
| 2025 | |
| 2026 | const result = try termColor(test_allocator, input); |
| 2027 | defer test_allocator.free(result); |
| 2028 | try testing.expectEqualSlices(u8, expect, result); |
| 2029 | } |
| 2030 | |
| 2031 | { |
| 2032 | // 3.1-with-error-return-traces.out |
| 2033 | |
| 2034 | const input = "error: Error\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:5:5\x1b[0m: \x1b[2m0x20b008 in callee (3.1-with-error-return-traces)\x1b[0m\n return error.Error;\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:9:5\x1b[0m: \x1b[2m0x20b113 in caller (3.1-with-error-return-traces)\x1b[0m\n try callee();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.1-with-error-return-traces.zig:13:5\x1b[0m: \x1b[2m0x20b153 in main (3.1-with-error-return-traces)\x1b[0m\n try caller();\n \x1b[32;1m^\x1b[0m\n"; |
| 2035 | const expect = |
| 2036 | \\error: Error |
| 2037 | \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:5:5</span>: <span class="sgr-2m">0x20b008 in callee (3.1-with-error-return-traces)</span> |
| 2038 | \\ return error.Error; |
| 2039 | \\ <span class="sgr-32_1m">^</span> |
| 2040 | \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:9:5</span>: <span class="sgr-2m">0x20b113 in caller (3.1-with-error-return-traces)</span> |
| 2041 | \\ try callee(); |
| 2042 | \\ <span class="sgr-32_1m">^</span> |
| 2043 | \\<span class="sgr-1m">/home/zig/src/3.1-with-error-return-traces.zig:13:5</span>: <span class="sgr-2m">0x20b153 in main (3.1-with-error-return-traces)</span> |
| 2044 | \\ try caller(); |
| 2045 | \\ <span class="sgr-32_1m">^</span> |
| 2046 | \\ |
| 2047 | ; |
| 2048 | |
| 2049 | const result = try termColor(test_allocator, input); |
| 2050 | defer test_allocator.free(result); |
| 2051 | try testing.expectEqualSlices(u8, expect, result); |
| 2052 | } |
| 2053 | |
| 2054 | { |
| 2055 | // 3.2-with-stack-trace.out |
| 2056 | const input = "\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:561:19\x1b[0m: \x1b[2m0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace)\x1b[0m\n while (it.next()) |return_address| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/debug.zig:157:80\x1b[0m: \x1b[2m0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace)\x1b[0m\n writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| {\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:5:36\x1b[0m: \x1b[2m0x20d3b2 in foo (3.2-with-stack-trace)\x1b[0m\n std.debug.dumpCurrentStackTrace(null);\n \x1b[32;1m^\x1b[0m\n\x1b[1m/home/zig/src/3.2-with-stack-trace.zig:9:8\x1b[0m: \x1b[2m0x20b458 in main (3.2-with-stack-trace)\x1b[0m\n foo();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:607:22\x1b[0m: \x1b[2m0x20a965 in posixCallMainAndExit (3.2-with-stack-trace)\x1b[0m\n root.main();\n \x1b[32;1m^\x1b[0m\n\x1b[1m/usr/local/lib/zig/lib/std/start.zig:376:5\x1b[0m: \x1b[2m0x20a411 in _start (3.2-with-stack-trace)\x1b[0m\n @call(.never_inline, posixCallMainAndExit, .{});\n \x1b[32;1m^\x1b[0m\n"; |
| 2057 | const expect = |
| 2058 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/debug.zig:561:19</span>: <span class="sgr-2m">0x22a107 in writeCurrentStackTrace__anon_5898 (3.2-with-stack-trace)</span> |
| 2059 | \\ while (it.next()) |return_address| { |
| 2060 | \\ <span class="sgr-32_1m">^</span> |
| 2061 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/debug.zig:157:80</span>: <span class="sgr-2m">0x20bb23 in dumpCurrentStackTrace (3.2-with-stack-trace)</span> |
| 2062 | \\ writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(io.getStdErr()), start_addr) catch |err| { |
| 2063 | \\ <span class="sgr-32_1m">^</span> |
| 2064 | \\<span class="sgr-1m">/home/zig/src/3.2-with-stack-trace.zig:5:36</span>: <span class="sgr-2m">0x20d3b2 in foo (3.2-with-stack-trace)</span> |
| 2065 | \\ std.debug.dumpCurrentStackTrace(null); |
| 2066 | \\ <span class="sgr-32_1m">^</span> |
| 2067 | \\<span class="sgr-1m">/home/zig/src/3.2-with-stack-trace.zig:9:8</span>: <span class="sgr-2m">0x20b458 in main (3.2-with-stack-trace)</span> |
| 2068 | \\ foo(); |
| 2069 | \\ <span class="sgr-32_1m">^</span> |
| 2070 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/start.zig:607:22</span>: <span class="sgr-2m">0x20a965 in posixCallMainAndExit (3.2-with-stack-trace)</span> |
| 2071 | \\ root.main(); |
| 2072 | \\ <span class="sgr-32_1m">^</span> |
| 2073 | \\<span class="sgr-1m">/usr/local/lib/zig/lib/std/start.zig:376:5</span>: <span class="sgr-2m">0x20a411 in _start (3.2-with-stack-trace)</span> |
| 2074 | \\ @call(.never_inline, posixCallMainAndExit, .{}); |
| 2075 | \\ <span class="sgr-32_1m">^</span> |
| 2076 | \\ |
| 2077 | ; |
| 2078 | |
| 2079 | const result = try termColor(test_allocator, input); |
| 2080 | defer test_allocator.free(result); |
| 2081 | try testing.expectEqualSlices(u8, expect, result); |
| 2082 | } |
| 2083 | } |
| 2084 | |
| 2085 | test "printShell" { |
| 1878 | 2086 | const test_allocator = std.testing.allocator; |
| 1879 | 2087 | |
| 1880 | 2088 | { |