zig/test/compare_output.zig
Andrew Kelley f1717777a2 std.heap: delete LoggingAllocator and friends
I don't think these belong in std, at least not in their current form.

If someone wants to add these back I'd like to review the patch before
it lands.

Reverts 629e2e784495dd8ac91493fa7bb11e1772698e42
2025-02-06 14:23:23 -08:00

505 lines
19 KiB
Zig

const std = @import("std");
const os = std.os;
const tests = @import("tests.zig");
pub fn addCases(cases: *tests.CompareOutputContext) void {
cases.addC("hello world with libc",
\\const c = @cImport({
\\ // See https://github.com/ziglang/zig/issues/515
\\ @cDefine("_NO_CRT_STDIO_INLINE", "1");
\\ @cInclude("stdio.h");
\\});
\\pub export fn main(argc: c_int, argv: [*][*]u8) c_int {
\\ _ = argc;
\\ _ = argv;
\\ _ = c.puts("Hello, world!");
\\ return 0;
\\}
, "Hello, world!" ++ if (@import("builtin").os.tag == .windows) "\r\n" else "\n");
cases.add("hello world without libc",
\\const io = @import("std").io;
\\
\\pub fn main() void {
\\ const stdout = io.getStdOut().writer();
\\ stdout.print("Hello, world!\n{d:4} {x:3} {c}\n", .{@as(u32, 12), @as(u16, 0x12), @as(u8, 'a')}) catch unreachable;
\\}
, "Hello, world!\n 12 12 a\n");
cases.addC("number literals",
\\const std = @import("std");
\\const builtin = @import("builtin");
\\const is_windows = builtin.os.tag == .windows;
\\const c = @cImport({
\\ if (is_windows) {
\\ // See https://github.com/ziglang/zig/issues/515
\\ @cDefine("_NO_CRT_STDIO_INLINE", "1");
\\ @cInclude("io.h");
\\ @cInclude("fcntl.h");
\\ }
\\ @cInclude("stdio.h");
\\});
\\
\\pub export fn main(argc: c_int, argv: [*][*]u8) c_int {
\\ _ = argc;
\\ _ = argv;
\\ if (is_windows) {
\\ // we want actual \n, not \r\n
\\ _ = c._setmode(1, c._O_BINARY);
\\ }
\\ _ = c.printf("0: %llu\n",
\\ @as(u64, 0));
\\ _ = c.printf("320402575052271: %llu\n",
\\ @as(u64, 320402575052271));
\\ _ = c.printf("0x01236789abcdef: %llu\n",
\\ @as(u64, 0x01236789abcdef));
\\ _ = c.printf("0xffffffffffffffff: %llu\n",
\\ @as(u64, 0xffffffffffffffff));
\\ _ = c.printf("0x000000ffffffffffffffff: %llu\n",
\\ @as(u64, 0x000000ffffffffffffffff));
\\ _ = c.printf("0o1777777777777777777777: %llu\n",
\\ @as(u64, 0o1777777777777777777777));
\\ _ = c.printf("0o0000001777777777777777777777: %llu\n",
\\ @as(u64, 0o0000001777777777777777777777));
\\ _ = c.printf("0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
\\ @as(u64, 0b1111111111111111111111111111111111111111111111111111111111111111));
\\ _ = c.printf("0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
\\ @as(u64, 0b0000001111111111111111111111111111111111111111111111111111111111111111));
\\
\\ _ = c.printf("\n");
\\
\\ _ = c.printf("0.0: %.013a\n",
\\ @as(f64, 0.0));
\\ _ = c.printf("0e0: %.013a\n",
\\ @as(f64, 0e0));
\\ _ = c.printf("0.0e0: %.013a\n",
\\ @as(f64, 0.0e0));
\\ _ = c.printf("000000000000000000000000000000000000000000000000000000000.0e0: %.013a\n",
\\ @as(f64, 0.0e0));
\\ _ = c.printf("0.000000000000000000000000000000000000000000000000000000000e0: %.013a\n",
\\ @as(f64, 0.000000000000000000000000000000000000000000000000000000000e0));
\\ _ = c.printf("0.0e000000000000000000000000000000000000000000000000000000000: %.013a\n",
\\ @as(f64, 0.0e000000000000000000000000000000000000000000000000000000000));
\\ _ = c.printf("1.0: %.013a\n",
\\ @as(f64, 1.0));
\\ _ = c.printf("10.0: %.013a\n",
\\ @as(f64, 10.0));
\\ _ = c.printf("10.5: %.013a\n",
\\ @as(f64, 10.5));
\\ _ = c.printf("10.5e5: %.013a\n",
\\ @as(f64, 10.5e5));
\\ _ = c.printf("10.5e+5: %.013a\n",
\\ @as(f64, 10.5e+5));
\\ _ = c.printf("50.0e-2: %.013a\n",
\\ @as(f64, 50.0e-2));
\\ _ = c.printf("50e-2: %.013a\n",
\\ @as(f64, 50e-2));
\\
\\ _ = c.printf("\n");
\\
\\ _ = c.printf("0x1.0: %.013a\n",
\\ @as(f64, 0x1.0));
\\ _ = c.printf("0x10.0: %.013a\n",
\\ @as(f64, 0x10.0));
\\ _ = c.printf("0x100.0: %.013a\n",
\\ @as(f64, 0x100.0));
\\ _ = c.printf("0x103.0: %.013a\n",
\\ @as(f64, 0x103.0));
\\ _ = c.printf("0x103.7: %.013a\n",
\\ @as(f64, 0x103.7));
\\ _ = c.printf("0x103.70: %.013a\n",
\\ @as(f64, 0x103.70));
\\ _ = c.printf("0x103.70p4: %.013a\n",
\\ @as(f64, 0x103.70p4));
\\ _ = c.printf("0x103.70p5: %.013a\n",
\\ @as(f64, 0x103.70p5));
\\ _ = c.printf("0x103.70p+5: %.013a\n",
\\ @as(f64, 0x103.70p+5));
\\ _ = c.printf("0x103.70p-5: %.013a\n",
\\ @as(f64, 0x103.70p-5));
\\
\\ return 0;
\\}
,
\\0: 0
\\320402575052271: 320402575052271
\\0x01236789abcdef: 320402575052271
\\0xffffffffffffffff: 18446744073709551615
\\0x000000ffffffffffffffff: 18446744073709551615
\\0o1777777777777777777777: 18446744073709551615
\\0o0000001777777777777777777777: 18446744073709551615
\\0b1111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615
\\0b0000001111111111111111111111111111111111111111111111111111111111111111: 18446744073709551615
\\
\\0.0: 0x0.0000000000000p+0
\\0e0: 0x0.0000000000000p+0
\\0.0e0: 0x0.0000000000000p+0
\\000000000000000000000000000000000000000000000000000000000.0e0: 0x0.0000000000000p+0
\\0.000000000000000000000000000000000000000000000000000000000e0: 0x0.0000000000000p+0
\\0.0e000000000000000000000000000000000000000000000000000000000: 0x0.0000000000000p+0
\\1.0: 0x1.0000000000000p+0
\\10.0: 0x1.4000000000000p+3
\\10.5: 0x1.5000000000000p+3
\\10.5e5: 0x1.0059000000000p+20
\\10.5e+5: 0x1.0059000000000p+20
\\50.0e-2: 0x1.0000000000000p-1
\\50e-2: 0x1.0000000000000p-1
\\
\\0x1.0: 0x1.0000000000000p+0
\\0x10.0: 0x1.0000000000000p+4
\\0x100.0: 0x1.0000000000000p+8
\\0x103.0: 0x1.0300000000000p+8
\\0x103.7: 0x1.0370000000000p+8
\\0x103.70: 0x1.0370000000000p+8
\\0x103.70p4: 0x1.0370000000000p+12
\\0x103.70p5: 0x1.0370000000000p+13
\\0x103.70p+5: 0x1.0370000000000p+13
\\0x103.70p-5: 0x1.0370000000000p+3
\\
);
cases.add("order-independent declarations",
\\const io = @import("std").io;
\\const z = io.stdin_fileno;
\\const x : @TypeOf(y) = 1234;
\\const y : u16 = 5678;
\\pub fn main() void {
\\ var x_local : i32 = print_ok(x);
\\ _ = &x_local;
\\}
\\fn print_ok(val: @TypeOf(x)) @TypeOf(foo) {
\\ _ = val;
\\ const stdout = io.getStdOut().writer();
\\ stdout.print("OK\n", .{}) catch unreachable;
\\ return 0;
\\}
\\const foo : i32 = 0;
, "OK\n");
cases.addC("expose function pointer to C land",
\\const c = @cImport(@cInclude("stdlib.h"));
\\
\\export fn compare_fn(a: ?*const anyopaque, b: ?*const anyopaque) c_int {
\\ const a_int: *const i32 = @ptrCast(@alignCast(a));
\\ const b_int: *const i32 = @ptrCast(@alignCast(b));
\\ if (a_int.* < b_int.*) {
\\ return -1;
\\ } else if (a_int.* > b_int.*) {
\\ return 1;
\\ } else {
\\ return 0;
\\ }
\\}
\\
\\pub export fn main() c_int {
\\ var array = [_]u32{ 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
\\
\\ c.qsort(@ptrCast(&array), @intCast(array.len), @sizeOf(i32), compare_fn);
\\
\\ for (array, 0..) |item, i| {
\\ if (item != i) {
\\ c.abort();
\\ }
\\ }
\\
\\ return 0;
\\}
, "");
cases.addC("casting between float and integer types",
\\const std = @import("std");
\\const builtin = @import("builtin");
\\const is_windows = builtin.os.tag == .windows;
\\const c = @cImport({
\\ if (is_windows) {
\\ // See https://github.com/ziglang/zig/issues/515
\\ @cDefine("_NO_CRT_STDIO_INLINE", "1");
\\ @cInclude("io.h");
\\ @cInclude("fcntl.h");
\\ }
\\ @cInclude("stdio.h");
\\});
\\
\\pub export fn main(argc: c_int, argv: [*][*]u8) c_int {
\\ _ = argc;
\\ _ = argv;
\\ if (is_windows) {
\\ // we want actual \n, not \r\n
\\ _ = c._setmode(1, c._O_BINARY);
\\ }
\\ const small: f32 = 3.25;
\\ const x: f64 = small;
\\ const y: i32 = @intFromFloat(x);
\\ const z: f64 = @floatFromInt(y);
\\ _ = c.printf("%.2f\n%d\n%.2f\n%.2f\n", x, y, z, @as(f64, -0.4));
\\ return 0;
\\}
, "3.25\n3\n3.00\n-0.40\n");
cases.add("same named methods in incomplete struct",
\\const io = @import("std").io;
\\
\\const Foo = struct {
\\ field1: Bar,
\\
\\ fn method(a: *const Foo) bool {
\\ _ = a;
\\ return true;
\\ }
\\};
\\
\\const Bar = struct {
\\ field2: i32,
\\
\\ fn method(b: *const Bar) bool {
\\ _ = b;
\\ return true;
\\ }
\\};
\\
\\pub fn main() void {
\\ const bar = Bar {.field2 = 13,};
\\ const foo = Foo {.field1 = bar,};
\\ const stdout = io.getStdOut().writer();
\\ if (!foo.method()) {
\\ stdout.print("BAD\n", .{}) catch unreachable;
\\ }
\\ if (!bar.method()) {
\\ stdout.print("BAD\n", .{}) catch unreachable;
\\ }
\\ stdout.print("OK\n", .{}) catch unreachable;
\\}
, "OK\n");
cases.add("defer with only fallthrough",
\\const io = @import("std").io;
\\pub fn main() void {
\\ const stdout = io.getStdOut().writer();
\\ stdout.print("before\n", .{}) catch unreachable;
\\ defer stdout.print("defer1\n", .{}) catch unreachable;
\\ defer stdout.print("defer2\n", .{}) catch unreachable;
\\ defer stdout.print("defer3\n", .{}) catch unreachable;
\\ stdout.print("after\n", .{}) catch unreachable;
\\}
, "before\nafter\ndefer3\ndefer2\ndefer1\n");
cases.add("defer with return",
\\const io = @import("std").io;
\\const os = @import("std").os;
\\pub fn main() void {
\\ const stdout = io.getStdOut().writer();
\\ stdout.print("before\n", .{}) catch unreachable;
\\ defer stdout.print("defer1\n", .{}) catch unreachable;
\\ defer stdout.print("defer2\n", .{}) catch unreachable;
\\ var gpa: @import("std").heap.GeneralPurposeAllocator(.{}) = .init;
\\ defer _ = gpa.deinit();
\\ var arena = @import("std").heap.ArenaAllocator.init(gpa.allocator());
\\ defer arena.deinit();
\\ var args_it = @import("std").process.argsWithAllocator(arena.allocator()) catch unreachable;
\\ if (args_it.skip() and !args_it.skip()) return;
\\ defer stdout.print("defer3\n", .{}) catch unreachable;
\\ stdout.print("after\n", .{}) catch unreachable;
\\}
, "before\ndefer2\ndefer1\n");
cases.add("errdefer and it fails",
\\const io = @import("std").io;
\\pub fn main() void {
\\ do_test() catch return;
\\}
\\fn do_test() !void {
\\ const stdout = io.getStdOut().writer();
\\ stdout.print("before\n", .{}) catch unreachable;
\\ defer stdout.print("defer1\n", .{}) catch unreachable;
\\ errdefer stdout.print("deferErr\n", .{}) catch unreachable;
\\ try its_gonna_fail();
\\ defer stdout.print("defer3\n", .{}) catch unreachable;
\\ stdout.print("after\n", .{}) catch unreachable;
\\}
\\fn its_gonna_fail() !void {
\\ return error.IToldYouItWouldFail;
\\}
, "before\ndeferErr\ndefer1\n");
cases.add("errdefer and it passes",
\\const io = @import("std").io;
\\pub fn main() void {
\\ do_test() catch return;
\\}
\\fn do_test() !void {
\\ const stdout = io.getStdOut().writer();
\\ stdout.print("before\n", .{}) catch unreachable;
\\ defer stdout.print("defer1\n", .{}) catch unreachable;
\\ errdefer stdout.print("deferErr\n", .{}) catch unreachable;
\\ try its_gonna_pass();
\\ defer stdout.print("defer3\n", .{}) catch unreachable;
\\ stdout.print("after\n", .{}) catch unreachable;
\\}
\\fn its_gonna_pass() anyerror!void { }
, "before\nafter\ndefer3\ndefer1\n");
cases.addCase(x: {
var tc = cases.create("@embedFile",
\\const foo_txt = @embedFile("foo.txt");
\\const io = @import("std").io;
\\
\\pub fn main() void {
\\ const stdout = io.getStdOut().writer();
\\ stdout.print(foo_txt, .{}) catch unreachable;
\\}
, "1234\nabcd\n");
tc.addSourceFile("foo.txt", "1234\nabcd\n");
break :x tc;
});
cases.addCase(x: {
var tc = cases.create("parsing args",
\\const std = @import("std");
\\const io = std.io;
\\const os = std.os;
\\
\\pub fn main() !void {
\\ var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
\\ defer _ = gpa.deinit();
\\ var arena = std.heap.ArenaAllocator.init(gpa.allocator());
\\ defer arena.deinit();
\\ var args_it = try std.process.argsWithAllocator(arena.allocator());
\\ const stdout = io.getStdOut().writer();
\\ var index: usize = 0;
\\ _ = args_it.skip();
\\ while (args_it.next()) |arg| : (index += 1) {
\\ try stdout.print("{}: {s}\n", .{index, arg});
\\ }
\\}
,
\\0: first arg
\\1: 'a' 'b' \
\\2: bare
\\3: ba""re
\\4: "
\\5: last arg
\\
);
tc.setCommandLineArgs(&[_][]const u8{
"first arg",
"'a' 'b' \\",
"bare",
"ba\"\"re",
"\"",
"last arg",
});
break :x tc;
});
cases.addCase(x: {
var tc = cases.create("parsing args new API",
\\const std = @import("std");
\\const io = std.io;
\\const os = std.os;
\\
\\pub fn main() !void {
\\ var gpa: std.heap.GeneralPurposeAllocator(.{}) = .init;
\\ defer _ = gpa.deinit();
\\ var arena = std.heap.ArenaAllocator.init(gpa.allocator());
\\ defer arena.deinit();
\\ var args_it = try std.process.argsWithAllocator(arena.allocator());
\\ const stdout = io.getStdOut().writer();
\\ var index: usize = 0;
\\ _ = args_it.skip();
\\ while (args_it.next()) |arg| : (index += 1) {
\\ try stdout.print("{}: {s}\n", .{index, arg});
\\ }
\\}
,
\\0: first arg
\\1: 'a' 'b' \
\\2: bare
\\3: ba""re
\\4: "
\\5: last arg
\\
);
tc.setCommandLineArgs(&[_][]const u8{
"first arg",
"'a' 'b' \\",
"bare",
"ba\"\"re",
"\"",
"last arg",
});
break :x tc;
});
// It is required to override the log function in order to print to stdout instead of stderr
cases.add("std.log per scope log level override",
\\const std = @import("std");
\\
\\pub const std_options: std.Options = .{
\\ .log_level = .debug,
\\
\\ .log_scope_levels = &.{
\\ .{ .scope = .a, .level = .warn },
\\ .{ .scope = .c, .level = .err },
\\ },
\\ .logFn = log,
\\};
\\
\\const loga = std.log.scoped(.a);
\\const logb = std.log.scoped(.b);
\\const logc = std.log.scoped(.c);
\\
\\pub fn main() !void {
\\ loga.debug("", .{});
\\ logb.debug("", .{});
\\ logc.debug("", .{});
\\
\\ loga.info("", .{});
\\ logb.info("", .{});
\\ logc.info("", .{});
\\
\\ loga.warn("", .{});
\\ logb.warn("", .{});
\\ logc.warn("", .{});
\\
\\ loga.err("", .{});
\\ logb.err("", .{});
\\ logc.err("", .{});
\\}
\\pub fn log(
\\ comptime level: std.log.Level,
\\ comptime scope: @TypeOf(.EnumLiteral),
\\ comptime format: []const u8,
\\ args: anytype,
\\) void {
\\ const level_txt = comptime level.asText();
\\ const prefix2 = if (scope == .default) ": " else "(" ++ @tagName(scope) ++ "):";
\\ const stdout = std.io.getStdOut().writer();
\\ nosuspend stdout.print(level_txt ++ prefix2 ++ format ++ "\n", args) catch return;
\\}
,
\\debug(b):
\\info(b):
\\warning(a):
\\warning(b):
\\error(a):
\\error(b):
\\error(c):
\\
);
cases.add("valid carriage return example", "const io = @import(\"std\").io;\r\n" ++ // Testing CRLF line endings are valid
"\r\n" ++
"pub \r fn main() void {\r\n" ++ // Testing isolated carriage return as whitespace is valid
" const stdout = io.getStdOut().writer();\r\n" ++
" stdout.print(\\\\A Multiline\r\n" ++ // testing CRLF at end of multiline string line is valid and normalises to \n in the output
" \\\\String\r\n" ++
" , .{}) catch unreachable;\r\n" ++
"}\r\n", "A Multiline\nString");
}