zig/test/compare_output.zig
Andrew Kelley 62c25af802 add higher level arg-parsing API + misc. changes
* add @noInlineCall - see #640
   This fixes a crash in --release-safe and --release-fast modes
   where the optimizer inlines everything into _start and
   clobbers the command line argument data.
   If we were able to verify that the user's code never reads
   command line args, we could leave off this "no inline"
   attribute.
 * add i29 and u29 primitive types. u29 is the type of alignment,
   so it makes sense to be a primitive.
   probably in the future we'll make any `i` or `u` followed by
   digits into a primitive.
 * add `aligned` functions to Allocator interface
 * add `os.argsAlloc` and `os.argsFree` so that you can get
   a `[]const []u8`, do whatever arg parsing you want, and then free
   it. For now this uses the other API under the hood, but it could
   be reimplemented to do a single allocation.
 * add tests to make sure command line argument parsing works.
2017-12-06 18:12:05 -05:00

530 lines
18 KiB
Zig

const os = @import("std").os;
const tests = @import("tests.zig");
pub fn addCases(cases: &tests.CompareOutputContext) {
cases.addC("hello world with libc",
\\const c = @cImport(@cInclude("stdio.h"));
\\export fn main(argc: c_int, argv: &&u8) -> c_int {
\\ _ = c.puts(c"Hello, world!");
\\ return 0;
\\}
, "Hello, world!" ++ os.line_sep);
cases.addCase({
var tc = cases.create("multiple files with private function",
\\use @import("std").io;
\\use @import("foo.zig");
\\
\\pub fn main() -> %void {
\\ privateFunction();
\\ const stdout = &(FileOutStream.init(&%%getStdOut()).stream);
\\ %%stdout.print("OK 2\n");
\\}
\\
\\fn privateFunction() {
\\ printText();
\\}
, "OK 1\nOK 2\n");
tc.addSourceFile("foo.zig",
\\use @import("std").io;
\\
\\// purposefully conflicting function with main.zig
\\// but it's private so it should be OK
\\fn privateFunction() {
\\ const stdout = &(FileOutStream.init(&%%getStdOut()).stream);
\\ %%stdout.print("OK 1\n");
\\}
\\
\\pub fn printText() {
\\ privateFunction();
\\}
);
tc
});
cases.addCase({
var tc = cases.create("import segregation",
\\use @import("foo.zig");
\\use @import("bar.zig");
\\
\\pub fn main() -> %void {
\\ foo_function();
\\ bar_function();
\\}
, "OK\nOK\n");
tc.addSourceFile("foo.zig",
\\use @import("std").io;
\\pub fn foo_function() {
\\ const stdout = &(FileOutStream.init(&%%getStdOut()).stream);
\\ %%stdout.print("OK\n");
\\}
);
tc.addSourceFile("bar.zig",
\\use @import("other.zig");
\\use @import("std").io;
\\
\\pub fn bar_function() {
\\ if (foo_function()) {
\\ const stdout = &(FileOutStream.init(&%%getStdOut()).stream);
\\ %%stdout.print("OK\n");
\\ }
\\}
);
tc.addSourceFile("other.zig",
\\pub fn foo_function() -> bool {
\\ // this one conflicts with the one from foo
\\ return true;
\\}
);
tc
});
cases.addCase({
var tc = cases.create("two files use import each other",
\\use @import("a.zig");
\\
\\pub fn main() -> %void {
\\ ok();
\\}
, "OK\n");
tc.addSourceFile("a.zig",
\\use @import("b.zig");
\\const io = @import("std").io;
\\
\\pub const a_text = "OK\n";
\\
\\pub fn ok() {
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
\\ %%stdout.print(b_text);
\\}
);
tc.addSourceFile("b.zig",
\\use @import("a.zig");
\\
\\pub const b_text = a_text;
);
tc
});
cases.add("hello world without libc",
\\const io = @import("std").io;
\\
\\pub fn main() -> %void {
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
\\ %%stdout.print("Hello, world!\n{d4} {x3} {c}\n", u32(12), u16(0x12), u8('a'));
\\}
, "Hello, world!\n0012 012 a\n");
cases.addC("number literals",
\\const builtin = @import("builtin");
\\const is_windows = builtin.os == builtin.Os.windows;
\\const c = @cImport({
\\ if (is_windows) {
\\ // See https://github.com/zig-lang/zig/issues/515
\\ @cDefine("_NO_CRT_STDIO_INLINE", "1");
\\ @cInclude("io.h");
\\ @cInclude("fcntl.h");
\\ }
\\ @cInclude("stdio.h");
\\});
\\
\\export fn main(argc: c_int, argv: &&u8) -> c_int {
\\ if (is_windows) {
\\ // we want actual \n, not \r\n
\\ _ = c._setmode(1, c._O_BINARY);
\\ }
\\ _ = c.printf(c"0: %llu\n",
\\ u64(0));
\\ _ = c.printf(c"320402575052271: %llu\n",
\\ u64(320402575052271));
\\ _ = c.printf(c"0x01236789abcdef: %llu\n",
\\ u64(0x01236789abcdef));
\\ _ = c.printf(c"0xffffffffffffffff: %llu\n",
\\ u64(0xffffffffffffffff));
\\ _ = c.printf(c"0x000000ffffffffffffffff: %llu\n",
\\ u64(0x000000ffffffffffffffff));
\\ _ = c.printf(c"0o1777777777777777777777: %llu\n",
\\ u64(0o1777777777777777777777));
\\ _ = c.printf(c"0o0000001777777777777777777777: %llu\n",
\\ u64(0o0000001777777777777777777777));
\\ _ = c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
\\ u64(0b1111111111111111111111111111111111111111111111111111111111111111));
\\ _ = c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
\\ u64(0b0000001111111111111111111111111111111111111111111111111111111111111111));
\\
\\ _ = c.printf(c"\n");
\\
\\ _ = c.printf(c"0.0: %.013a\n",
\\ f64(0.0));
\\ _ = c.printf(c"0e0: %.013a\n",
\\ f64(0e0));
\\ _ = c.printf(c"0.0e0: %.013a\n",
\\ f64(0.0e0));
\\ _ = c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %.013a\n",
\\ f64(000000000000000000000000000000000000000000000000000000000.0e0));
\\ _ = c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %.013a\n",
\\ f64(0.000000000000000000000000000000000000000000000000000000000e0));
\\ _ = c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %.013a\n",
\\ f64(0.0e000000000000000000000000000000000000000000000000000000000));
\\ _ = c.printf(c"1.0: %.013a\n",
\\ f64(1.0));
\\ _ = c.printf(c"10.0: %.013a\n",
\\ f64(10.0));
\\ _ = c.printf(c"10.5: %.013a\n",
\\ f64(10.5));
\\ _ = c.printf(c"10.5e5: %.013a\n",
\\ f64(10.5e5));
\\ _ = c.printf(c"10.5e+5: %.013a\n",
\\ f64(10.5e+5));
\\ _ = c.printf(c"50.0e-2: %.013a\n",
\\ f64(50.0e-2));
\\ _ = c.printf(c"50e-2: %.013a\n",
\\ f64(50e-2));
\\
\\ _ = c.printf(c"\n");
\\
\\ _ = c.printf(c"0x1.0: %.013a\n",
\\ f64(0x1.0));
\\ _ = c.printf(c"0x10.0: %.013a\n",
\\ f64(0x10.0));
\\ _ = c.printf(c"0x100.0: %.013a\n",
\\ f64(0x100.0));
\\ _ = c.printf(c"0x103.0: %.013a\n",
\\ f64(0x103.0));
\\ _ = c.printf(c"0x103.7: %.013a\n",
\\ f64(0x103.7));
\\ _ = c.printf(c"0x103.70: %.013a\n",
\\ f64(0x103.70));
\\ _ = c.printf(c"0x103.70p4: %.013a\n",
\\ f64(0x103.70p4));
\\ _ = c.printf(c"0x103.70p5: %.013a\n",
\\ f64(0x103.70p5));
\\ _ = c.printf(c"0x103.70p+5: %.013a\n",
\\ f64(0x103.70p+5));
\\ _ = c.printf(c"0x103.70p-5: %.013a\n",
\\ f64(0x103.70p-5));
\\
\\ _ = c.printf(c"\n");
\\
\\ _ = c.printf(c"0b10100.00010e0: %.013a\n",
\\ f64(0b10100.00010e0));
\\ _ = c.printf(c"0o10700.00010e0: %.013a\n",
\\ f64(0o10700.00010e0));
\\
\\ 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
\\
\\0b10100.00010e0: 0x1.4100000000000p+4
\\0o10700.00010e0: 0x1.1c00010000000p+12
\\
);
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);
\\}
\\fn print_ok(val: @typeOf(x)) -> @typeOf(foo) {
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
\\ %%stdout.print("OK\n");
\\ 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 c_void, b: ?&const c_void) -> c_int {
\\ const a_int = @ptrCast(&align(1) i32, a ?? unreachable);
\\ const b_int = @ptrCast(&align(1) i32, b ?? unreachable);
\\ if (*a_int < *b_int) {
\\ -1
\\ } else if (*a_int > *b_int) {
\\ 1
\\ } else {
\\ c_int(0)
\\ }
\\}
\\
\\export fn main() -> c_int {
\\ var array = []u32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
\\
\\ c.qsort(@ptrCast(&c_void, &array[0]), c_ulong(array.len), @sizeOf(i32), compare_fn);
\\
\\ for (array) |item, i| {
\\ if (item != i) {
\\ c.abort();
\\ }
\\ }
\\
\\ return 0;
\\}
, "");
cases.addC("casting between float and integer types",
\\const builtin = @import("builtin");
\\const is_windows = builtin.os == builtin.Os.windows;
\\const c = @cImport({
\\ if (is_windows) {
\\ // See https://github.com/zig-lang/zig/issues/515
\\ @cDefine("_NO_CRT_STDIO_INLINE", "1");
\\ @cInclude("io.h");
\\ @cInclude("fcntl.h");
\\ }
\\ @cInclude("stdio.h");
\\});
\\
\\export fn main(argc: c_int, argv: &&u8) -> c_int {
\\ 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(x);
\\ const z = f64(y);
\\ _ = c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, 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 { true }
\\};
\\
\\const Bar = struct {
\\ field2: i32,
\\
\\ fn method(b: &const Bar) -> bool { true }
\\};
\\
\\pub fn main() -> %void {
\\ const bar = Bar {.field2 = 13,};
\\ const foo = Foo {.field1 = bar,};
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
\\ if (!foo.method()) {
\\ %%stdout.print("BAD\n");
\\ }
\\ if (!bar.method()) {
\\ %%stdout.print("BAD\n");
\\ }
\\ %%stdout.print("OK\n");
\\}
, "OK\n");
cases.add("defer with only fallthrough",
\\const io = @import("std").io;
\\pub fn main() -> %void {
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
\\ %%stdout.print("before\n");
\\ defer %%stdout.print("defer1\n");
\\ defer %%stdout.print("defer2\n");
\\ defer %%stdout.print("defer3\n");
\\ %%stdout.print("after\n");
\\}
, "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.FileOutStream.init(&%%io.getStdOut()).stream);
\\ %%stdout.print("before\n");
\\ defer %%stdout.print("defer1\n");
\\ defer %%stdout.print("defer2\n");
\\ var args_it = @import("std").os.args();
\\ if (args_it.skip() and !args_it.skip()) return;
\\ defer %%stdout.print("defer3\n");
\\ %%stdout.print("after\n");
\\}
, "before\ndefer2\ndefer1\n");
cases.add("%defer and it fails",
\\const io = @import("std").io;
\\pub fn main() -> %void {
\\ do_test() %% return;
\\}
\\fn do_test() -> %void {
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
\\ %%stdout.print("before\n");
\\ defer %%stdout.print("defer1\n");
\\ %defer %%stdout.print("deferErr\n");
\\ %return its_gonna_fail();
\\ defer %%stdout.print("defer3\n");
\\ %%stdout.print("after\n");
\\}
\\error IToldYouItWouldFail;
\\fn its_gonna_fail() -> %void {
\\ return error.IToldYouItWouldFail;
\\}
, "before\ndeferErr\ndefer1\n");
cases.add("%defer and it passes",
\\const io = @import("std").io;
\\pub fn main() -> %void {
\\ do_test() %% return;
\\}
\\fn do_test() -> %void {
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
\\ %%stdout.print("before\n");
\\ defer %%stdout.print("defer1\n");
\\ %defer %%stdout.print("deferErr\n");
\\ %return its_gonna_pass();
\\ defer %%stdout.print("defer3\n");
\\ %%stdout.print("after\n");
\\}
\\fn its_gonna_pass() -> %void { }
, "before\nafter\ndefer3\ndefer1\n");
cases.addCase({
var tc = cases.create("@embedFile",
\\const foo_txt = @embedFile("foo.txt");
\\const io = @import("std").io;
\\
\\pub fn main() -> %void {
\\ const stdout = &(io.FileOutStream.init(&%%io.getStdOut()).stream);
\\ %%stdout.print(foo_txt);
\\}
, "1234\nabcd\n");
tc.addSourceFile("foo.txt", "1234\nabcd\n");
tc
});
cases.addCase({
var tc = cases.create("parsing args",
\\const std = @import("std");
\\const io = std.io;
\\const os = std.os;
\\const allocator = std.debug.global_allocator;
\\
\\pub fn main() -> %void {
\\ var args_it = os.args();
\\ var stdout_file = %return io.getStdOut();
\\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
\\ const stdout = &stdout_adapter.stream;
\\ var index: usize = 0;
\\ _ = args_it.skip();
\\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) {
\\ const arg = %return arg_or_err;
\\ %return stdout.print("{}: {}\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",
});
tc
});
cases.addCase({
var tc = cases.create("parsing args new API",
\\const std = @import("std");
\\const io = std.io;
\\const os = std.os;
\\const allocator = std.debug.global_allocator;
\\
\\pub fn main() -> %void {
\\ var args_it = os.args();
\\ var stdout_file = %return io.getStdOut();
\\ var stdout_adapter = io.FileOutStream.init(&stdout_file);
\\ const stdout = &stdout_adapter.stream;
\\ var index: usize = 0;
\\ _ = args_it.skip();
\\ while (args_it.next(allocator)) |arg_or_err| : (index += 1) {
\\ const arg = %return arg_or_err;
\\ %return stdout.print("{}: {}\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",
});
tc
});
}