// SPDX-License-Identifier: MIT // Copyright (c) 2015-2020 Zig Contributors // This file is part of [zig](https://ziglang.org/), which is MIT licensed. // The MIT license requires this copyright notice to be included in all copies // and substantial portions of the software. test "zig fmt: convert var to anytype" { // TODO remove in next release cycle try testTransform( \\pub fn main( \\ a: var, \\ bar: var, \\) void {} , \\pub fn main( \\ a: anytype, \\ bar: anytype, \\) void {} \\ ); } test "zig fmt: noasync to nosuspend" { // TODO: remove this try testTransform( \\pub fn main() void { \\ noasync call(); \\} , \\pub fn main() void { \\ nosuspend call(); \\} \\ ); } test "recovery: top level" { try testError( \\test "" {inline} \\test "" {inline} , &[_]Error{ .ExpectedInlinable, .ExpectedInlinable, }); } test "recovery: block statements" { try testError( \\test "" { \\ foo + +; \\ inline; \\} , &[_]Error{ .InvalidToken, .ExpectedInlinable, }); } test "recovery: missing comma" { try testError( \\test "" { \\ switch (foo) { \\ 2 => {} \\ 3 => {} \\ else => { \\ foo && bar +; \\ } \\ } \\} , &[_]Error{ .ExpectedToken, .ExpectedToken, .InvalidAnd, .InvalidToken, }); } test "recovery: extra qualifier" { try testError( \\const a: *const const u8; \\test "" , &[_]Error{ .ExtraConstQualifier, .ExpectedLBrace, }); } test "recovery: missing return type" { try testError( \\fn foo() { \\ a && b; \\} \\test "" , &[_]Error{ .ExpectedReturnType, .InvalidAnd, .ExpectedLBrace, }); } test "recovery: continue after invalid decl" { try testError( \\fn foo { \\ inline; \\} \\pub test "" { \\ async a && b; \\} , &[_]Error{ .ExpectedToken, .ExpectedPubItem, .ExpectedParamList, .InvalidAnd, }); try testError( \\threadlocal test "" { \\ @a && b; \\} , &[_]Error{ .ExpectedVarDecl, .ExpectedParamList, .InvalidAnd, }); } test "recovery: invalid extern/inline" { try testError( \\inline test "" { a && b; } , &[_]Error{ .ExpectedFn, .InvalidAnd, }); try testError( \\extern "" test "" { a && b; } , &[_]Error{ .ExpectedVarDeclOrFn, .InvalidAnd, }); } test "recovery: missing semicolon" { try testError( \\test "" { \\ comptime a && b \\ c && d \\ @foo \\} , &[_]Error{ .InvalidAnd, .ExpectedToken, .InvalidAnd, .ExpectedToken, .ExpectedParamList, .ExpectedToken, }); } test "recovery: invalid container members" { try testError( \\usingnamespace; \\foo+ \\bar@, \\while (a == 2) { test "" {}} \\test "" { \\ a && b \\} , &[_]Error{ .ExpectedExpr, .ExpectedToken, .ExpectedToken, .ExpectedContainerMembers, .InvalidAnd, .ExpectedToken, }); } test "recovery: invalid parameter" { try testError( \\fn main() void { \\ a(comptime T: type) \\} , &[_]Error{ .ExpectedToken, }); } test "recovery: extra '}' at top level" { try testError( \\}}} \\test "" { \\ a && b; \\} , &[_]Error{ .ExpectedContainerMembers, .ExpectedContainerMembers, .ExpectedContainerMembers, .InvalidAnd, }); } test "recovery: mismatched bracket at top level" { try testError( \\const S = struct { \\ arr: 128]?G \\}; , &[_]Error{ .ExpectedToken, }); } test "recovery: invalid global error set access" { try testError( \\test "" { \\ error && foo; \\} , &[_]Error{ .ExpectedToken, .ExpectedIdentifier, .InvalidAnd, }); } test "recovery: missing semicolon after if, for, while stmt" { try testError( \\test "" { \\ if (foo) bar \\ for (foo) |a| bar \\ while (foo) bar \\ a && b; \\} , &[_]Error{ .ExpectedSemiOrElse, .ExpectedSemiOrElse, .ExpectedSemiOrElse, .InvalidAnd, }); } test "recovery: invalid comptime" { try testError( \\comptime , &[_]Error{ .ExpectedBlockOrField, }); } test "recovery: missing block after for/while loops" { try testError( \\test "" { while (foo) } , &[_]Error{ .ExpectedBlockOrAssignment, }); try testError( \\test "" { for (foo) |bar| } , &[_]Error{ .ExpectedBlockOrAssignment, }); } test "zig fmt: empty file" { try testCanonical( \\ ); } test "zig fmt: if statment" { try testCanonical( \\test "" { \\ if (optional()) |some| \\ bar = some.foo(); \\} \\ ); } test "zig fmt: top-level fields" { try testCanonical( \\a: did_you_know, \\b: all_files_are, \\structs: ?x, \\ ); } test "zig fmt: decl between fields" { try testError( \\const S = struct { \\ const foo = 2; \\ const bar = 2; \\ const baz = 2; \\ a: usize, \\ const foo1 = 2; \\ const bar1 = 2; \\ const baz1 = 2; \\ b: usize, \\}; , &[_]Error{ .DeclBetweenFields, }); } test "zig fmt: eof after missing comma" { try testError( \\foo() , &[_]Error{ .ExpectedToken, }); } test "zig fmt: errdefer with payload" { try testCanonical( \\pub fn main() anyerror!void { \\ errdefer |a| x += 1; \\ errdefer |a| {} \\ errdefer |a| { \\ x += 1; \\ } \\} \\ ); } test "zig fmt: nosuspend block" { try testCanonical( \\pub fn main() anyerror!void { \\ nosuspend { \\ var foo: Foo = .{ .bar = 42 }; \\ } \\} \\ ); } test "zig fmt: nosuspend await" { try testCanonical( \\fn foo() void { \\ x = nosuspend await y; \\} \\ ); } test "zig fmt: trailing comma in container declaration" { try testCanonical( \\const X = struct { foo: i32 }; \\const X = struct { foo: i32, bar: i32 }; \\const X = struct { foo: i32 = 1, bar: i32 = 2 }; \\const X = struct { foo: i32 align(4), bar: i32 align(4) }; \\const X = struct { foo: i32 align(4) = 1, bar: i32 align(4) = 2 }; \\ ); try testCanonical( \\test "" { \\ comptime { \\ const X = struct { \\ x: i32 \\ }; \\ } \\} \\ ); try testTransform( \\const X = struct { \\ foo: i32, bar: i8 }; , \\const X = struct { \\ foo: i32, bar: i8 \\}; \\ ); } test "zig fmt: trailing comma in fn parameter list" { try testCanonical( \\pub fn f( \\ a: i32, \\ b: i32, \\) i32 {} \\pub fn f( \\ a: i32, \\ b: i32, \\) align(8) i32 {} \\pub fn f( \\ a: i32, \\ b: i32, \\) linksection(".text") i32 {} \\pub fn f( \\ a: i32, \\ b: i32, \\) callconv(.C) i32 {} \\pub fn f( \\ a: i32, \\ b: i32, \\) align(8) linksection(".text") i32 {} \\pub fn f( \\ a: i32, \\ b: i32, \\) align(8) callconv(.C) i32 {} \\pub fn f( \\ a: i32, \\ b: i32, \\) align(8) linksection(".text") callconv(.C) i32 {} \\pub fn f( \\ a: i32, \\ b: i32, \\) linksection(".text") callconv(.C) i32 {} \\ ); } test "zig fmt: comptime struct field" { try testCanonical( \\const Foo = struct { \\ a: i32, \\ comptime b: i32 = 1234, \\}; \\ ); } test "zig fmt: c pointer type" { try testCanonical( \\pub extern fn repro() [*c]const u8; \\ ); } test "zig fmt: builtin call with trailing comma" { try testCanonical( \\pub fn main() void { \\ @breakpoint(); \\ _ = @boolToInt(a); \\ _ = @call( \\ a, \\ b, \\ c, \\ ); \\} \\ ); } test "zig fmt: asm expression with comptime content" { try testCanonical( \\comptime { \\ asm ("foo" ++ "bar"); \\} \\pub fn main() void { \\ asm volatile ("foo" ++ "bar"); \\ asm volatile ("foo" ++ "bar" \\ : [_] "" (x) \\ ); \\ asm volatile ("foo" ++ "bar" \\ : [_] "" (x) \\ : [_] "" (y) \\ ); \\ asm volatile ("foo" ++ "bar" \\ : [_] "" (x) \\ : [_] "" (y) \\ : "h", "e", "l", "l", "o" \\ ); \\} \\ ); } test "zig fmt: anytype struct field" { try testCanonical( \\pub const Pointer = struct { \\ sentinel: anytype, \\}; \\ ); } test "zig fmt: sentinel-terminated array type" { try testCanonical( \\pub fn cStrToPrefixedFileW(s: [*:0]const u8) ![PATH_MAX_WIDE:0]u16 { \\ return sliceToPrefixedFileW(mem.toSliceConst(u8, s)); \\} \\ ); } test "zig fmt: sentinel-terminated slice type" { try testCanonical( \\pub fn toSlice(self: Buffer) [:0]u8 { \\ return self.list.toSlice()[0..self.len()]; \\} \\ ); } test "zig fmt: anon literal in array" { try testCanonical( \\var arr: [2]Foo = .{ \\ .{ .a = 2 }, \\ .{ .b = 3 }, \\}; \\ ); } test "zig fmt: anon struct literal syntax" { try testCanonical( \\const x = .{ \\ .a = b, \\ .c = d, \\}; \\ ); } test "zig fmt: anon list literal syntax" { try testCanonical( \\const x = .{ a, b, c }; \\ ); } test "zig fmt: async function" { try testCanonical( \\pub const Server = struct { \\ handleRequestFn: fn (*Server, *const std.net.Address, File) callconv(.Async) void, \\}; \\test "hi" { \\ var ptr = @ptrCast(fn (i32) callconv(.Async) void, other); \\} \\ ); } test "zig fmt: whitespace fixes" { try testTransform("test \"\" {\r\n\tconst hi = x;\r\n}\n// zig fmt: off\ntest \"\"{\r\n\tconst a = b;}\r\n", \\test "" { \\ const hi = x; \\} \\// zig fmt: off \\test ""{ \\ const a = b;} \\ ); } test "zig fmt: while else err prong with no block" { try testCanonical( \\test "" { \\ const result = while (returnError()) |value| { \\ break value; \\ } else |err| @as(i32, 2); \\ expect(result == 2); \\} \\ ); } test "zig fmt: tagged union with enum values" { try testCanonical( \\const MultipleChoice2 = union(enum(u32)) { \\ Unspecified1: i32, \\ A: f32 = 20, \\ Unspecified2: void, \\ B: bool = 40, \\ Unspecified3: i32, \\ C: i8 = 60, \\ Unspecified4: void, \\ D: void = 1000, \\ Unspecified5: i32, \\}; \\ ); } test "zig fmt: allowzero pointer" { try testCanonical( \\const T = [*]allowzero const u8; \\ ); } test "zig fmt: enum literal" { try testCanonical( \\const x = .hi; \\ ); } test "zig fmt: enum literal inside array literal" { try testCanonical( \\test "enums in arrays" { \\ var colors = []Color{.Green}; \\ colors = []Colors{ .Green, .Cyan }; \\ colors = []Colors{ \\ .Grey, \\ .Green, \\ .Cyan, \\ }; \\} \\ ); } test "zig fmt: character literal larger than u8" { try testCanonical( \\const x = '\u{01f4a9}'; \\ ); } test "zig fmt: infix operator and then multiline string literal" { try testCanonical( \\const x = "" ++ \\ \\ hi \\; \\ ); } test "zig fmt: infix operator and then multiline string literal" { try testCanonical( \\const x = "" ++ \\ \\ hi0 \\ \\ hi1 \\ \\ hi2 \\; \\ ); } test "zig fmt: C pointers" { try testCanonical( \\const Ptr = [*c]i32; \\ ); } test "zig fmt: threadlocal" { try testCanonical( \\threadlocal var x: i32 = 1234; \\ ); } test "zig fmt: linksection" { try testCanonical( \\export var aoeu: u64 linksection(".text.derp") = 1234; \\export fn _start() linksection(".text.boot") callconv(.Naked) noreturn {} \\ ); } test "zig fmt: correctly move doc comments on struct fields" { try testTransform( \\pub const section_64 = extern struct { \\ sectname: [16]u8, /// name of this section \\ segname: [16]u8, /// segment this section goes in \\}; , \\pub const section_64 = extern struct { \\ /// name of this section \\ sectname: [16]u8, \\ /// segment this section goes in \\ segname: [16]u8, \\}; \\ ); } test "zig fmt: correctly space struct fields with doc comments" { try testTransform( \\pub const S = struct { \\ /// A \\ a: u8, \\ /// B \\ /// B (cont) \\ b: u8, \\ \\ \\ /// C \\ c: u8, \\}; \\ , \\pub const S = struct { \\ /// A \\ a: u8, \\ /// B \\ /// B (cont) \\ b: u8, \\ \\ /// C \\ c: u8, \\}; \\ ); } test "zig fmt: doc comments on param decl" { try testCanonical( \\pub const Allocator = struct { \\ shrinkFn: fn ( \\ self: *Allocator, \\ /// Guaranteed to be the same as what was returned from most recent call to \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. \\ old_mem: []u8, \\ /// Guaranteed to be the same as what was returned from most recent call to \\ /// `allocFn`, `reallocFn`, or `shrinkFn`. \\ old_alignment: u29, \\ /// Guaranteed to be less than or equal to `old_mem.len`. \\ new_byte_count: usize, \\ /// Guaranteed to be less than or equal to `old_alignment`. \\ new_alignment: u29, \\ ) []u8, \\}; \\ ); } test "zig fmt: aligned struct field" { try testCanonical( \\pub const S = struct { \\ f: i32 align(32), \\}; \\ ); try testCanonical( \\pub const S = struct { \\ f: i32 align(32) = 1, \\}; \\ ); } test "zig fmt: comment to disable/enable zig fmt first" { try testCanonical( \\// Test trailing comma syntax \\// zig fmt: off \\ \\const struct_trailing_comma = struct { x: i32, y: i32, }; ); } test "zig fmt: comment to disable/enable zig fmt" { try testTransform( \\const a = b; \\// zig fmt: off \\const c = d; \\// zig fmt: on \\const e = f; , \\const a = b; \\// zig fmt: off \\const c = d; \\// zig fmt: on \\const e = f; \\ ); } test "zig fmt: line comment following 'zig fmt: off'" { try testCanonical( \\// zig fmt: off \\// Test \\const e = f; ); } test "zig fmt: doc comment following 'zig fmt: off'" { try testCanonical( \\// zig fmt: off \\/// test \\const e = f; ); } test "zig fmt: line and doc comment following 'zig fmt: off'" { try testCanonical( \\// zig fmt: off \\// test 1 \\/// test 2 \\const e = f; ); } test "zig fmt: doc and line comment following 'zig fmt: off'" { try testCanonical( \\// zig fmt: off \\/// test 1 \\// test 2 \\const e = f; ); } test "zig fmt: alternating 'zig fmt: off' and 'zig fmt: on'" { try testCanonical( \\// zig fmt: off \\// zig fmt: on \\// zig fmt: off \\const e = f; \\// zig fmt: off \\// zig fmt: on \\// zig fmt: off \\const a = b; \\// zig fmt: on \\const c = d; \\// zig fmt: on \\ ); } test "zig fmt: line comment following 'zig fmt: on'" { try testCanonical( \\// zig fmt: off \\const e = f; \\// zig fmt: on \\// test \\const e = f; \\ ); } test "zig fmt: doc comment following 'zig fmt: on'" { try testCanonical( \\// zig fmt: off \\const e = f; \\// zig fmt: on \\/// test \\const e = f; \\ ); } test "zig fmt: line and doc comment following 'zig fmt: on'" { try testCanonical( \\// zig fmt: off \\const e = f; \\// zig fmt: on \\// test1 \\/// test2 \\const e = f; \\ ); } test "zig fmt: doc and line comment following 'zig fmt: on'" { try testCanonical( \\// zig fmt: off \\const e = f; \\// zig fmt: on \\/// test1 \\// test2 \\const e = f; \\ ); } test "zig fmt: pointer of unknown length" { try testCanonical( \\fn foo(ptr: [*]u8) void {} \\ ); } test "zig fmt: spaces around slice operator" { try testCanonical( \\var a = b[c..d]; \\var a = b[c..d :0]; \\var a = b[c + 1 .. d]; \\var a = b[c + 1 ..]; \\var a = b[c .. d + 1]; \\var a = b[c .. d + 1 :0]; \\var a = b[c.a..d.e]; \\var a = b[c.a..d.e :0]; \\ ); } test "zig fmt: async call in if condition" { try testCanonical( \\comptime { \\ if (async b()) { \\ a(); \\ } \\} \\ ); } test "zig fmt: 2nd arg multiline string" { try testCanonical( \\comptime { \\ cases.addAsm("hello world linux x86_64", \\ \\.text \\ , "Hello, world!\n"); \\} \\ ); } test "zig fmt: 2nd arg multiline string many args" { try testCanonical( \\comptime { \\ cases.addAsm("hello world linux x86_64", \\ \\.text \\ , "Hello, world!\n", "Hello, world!\n"); \\} \\ ); } test "zig fmt: final arg multiline string" { try testCanonical( \\comptime { \\ cases.addAsm("hello world linux x86_64", "Hello, world!\n", \\ \\.text \\ ); \\} \\ ); } test "zig fmt: if condition wraps" { try testTransform( \\comptime { \\ if (cond and \\ cond) { \\ return x; \\ } \\ while (cond and \\ cond) { \\ return x; \\ } \\ if (a == b and \\ c) { \\ a = b; \\ } \\ while (a == b and \\ c) { \\ a = b; \\ } \\ if ((cond and \\ cond)) { \\ return x; \\ } \\ while ((cond and \\ cond)) { \\ return x; \\ } \\ var a = if (a) |*f| x: { \\ break :x &a.b; \\ } else |err| err; \\ var a = if (cond and \\ cond) |*f| \\ x: { \\ break :x &a.b; \\ } else |err| err; \\} , \\comptime { \\ if (cond and \\ cond) \\ { \\ return x; \\ } \\ while (cond and \\ cond) \\ { \\ return x; \\ } \\ if (a == b and \\ c) \\ { \\ a = b; \\ } \\ while (a == b and \\ c) \\ { \\ a = b; \\ } \\ if ((cond and \\ cond)) \\ { \\ return x; \\ } \\ while ((cond and \\ cond)) \\ { \\ return x; \\ } \\ var a = if (a) |*f| x: { \\ break :x &a.b; \\ } else |err| err; \\ var a = if (cond and \\ cond) |*f| \\ x: { \\ break :x &a.b; \\ } else |err| err; \\} \\ ); } test "zig fmt: if condition has line break but must not wrap" { try testCanonical( \\comptime { \\ if (self.user_input_options.put( \\ name, \\ UserInputOption{ \\ .name = name, \\ .used = false, \\ }, \\ ) catch unreachable) |*prev_value| { \\ foo(); \\ bar(); \\ } \\ if (put( \\ a, \\ b, \\ )) { \\ foo(); \\ } \\} \\ ); } test "zig fmt: if condition has line break but must not wrap" { try testCanonical( \\comptime { \\ if (self.user_input_options.put(name, UserInputOption{ \\ .name = name, \\ .used = false, \\ }) catch unreachable) |*prev_value| { \\ foo(); \\ bar(); \\ } \\ if (put( \\ a, \\ b, \\ )) { \\ foo(); \\ } \\} \\ ); } test "zig fmt: function call with multiline argument" { try testCanonical( \\comptime { \\ self.user_input_options.put(name, UserInputOption{ \\ .name = name, \\ .used = false, \\ }); \\} \\ ); } test "zig fmt: same-line doc comment on variable declaration" { try testTransform( \\pub const MAP_ANONYMOUS = 0x1000; /// allocated from memory, swap space \\pub const MAP_FILE = 0x0000; /// map from file (default) \\ \\pub const EMEDIUMTYPE = 124; /// Wrong medium type \\ \\// nameserver query return codes \\pub const ENSROK = 0; /// DNS server returned answer with no data , \\/// allocated from memory, swap space \\pub const MAP_ANONYMOUS = 0x1000; \\/// map from file (default) \\pub const MAP_FILE = 0x0000; \\ \\/// Wrong medium type \\pub const EMEDIUMTYPE = 124; \\ \\// nameserver query return codes \\/// DNS server returned answer with no data \\pub const ENSROK = 0; \\ ); } test "zig fmt: if-else with comment before else" { try testCanonical( \\comptime { \\ // cexp(finite|nan +- i inf|nan) = nan + i nan \\ if ((hx & 0x7fffffff) != 0x7f800000) { \\ return Complex(f32).new(y - y, y - y); \\ } // cexp(-inf +- i inf|nan) = 0 + i0 \\ else if (hx & 0x80000000 != 0) { \\ return Complex(f32).new(0, 0); \\ } // cexp(+inf +- i inf|nan) = inf + i nan \\ else { \\ return Complex(f32).new(x, y - y); \\ } \\} \\ ); } test "zig fmt: if nested" { try testCanonical( \\pub fn foo() void { \\ return if ((aInt & bInt) >= 0) \\ if (aInt < bInt) \\ GE_LESS \\ else if (aInt == bInt) \\ GE_EQUAL \\ else \\ GE_GREATER \\ else if (aInt > bInt) \\ GE_LESS \\ else if (aInt == bInt) \\ GE_EQUAL \\ else \\ GE_GREATER; \\} \\ ); } test "zig fmt: respect line breaks in if-else" { try testCanonical( \\comptime { \\ return if (cond) a else b; \\ return if (cond) \\ a \\ else \\ b; \\ return if (cond) \\ a \\ else if (cond) \\ b \\ else \\ c; \\} \\ ); } test "zig fmt: respect line breaks after infix operators" { try testCanonical( \\comptime { \\ self.crc = \\ lookup_tables[0][p[7]] ^ \\ lookup_tables[1][p[6]] ^ \\ lookup_tables[2][p[5]] ^ \\ lookup_tables[3][p[4]] ^ \\ lookup_tables[4][@truncate(u8, self.crc >> 24)] ^ \\ lookup_tables[5][@truncate(u8, self.crc >> 16)] ^ \\ lookup_tables[6][@truncate(u8, self.crc >> 8)] ^ \\ lookup_tables[7][@truncate(u8, self.crc >> 0)]; \\} \\ ); } test "zig fmt: fn decl with trailing comma" { try testTransform( \\fn foo(a: i32, b: i32,) void {} , \\fn foo( \\ a: i32, \\ b: i32, \\) void {} \\ ); } test "zig fmt: enum decl with no trailing comma" { try testTransform( \\const StrLitKind = enum {Normal, C}; , \\const StrLitKind = enum { Normal, C }; \\ ); } test "zig fmt: switch comment before prong" { try testCanonical( \\comptime { \\ switch (a) { \\ // hi \\ 0 => {}, \\ } \\} \\ ); } test "zig fmt: struct literal no trailing comma" { try testTransform( \\const a = foo{ .x = 1, .y = 2 }; \\const a = foo{ .x = 1, \\ .y = 2 }; , \\const a = foo{ .x = 1, .y = 2 }; \\const a = foo{ \\ .x = 1, \\ .y = 2, \\}; \\ ); } test "zig fmt: struct literal containing a multiline expression" { try testTransform( \\const a = A{ .x = if (f1()) 10 else 20 }; \\const a = A{ .x = if (f1()) 10 else 20, }; \\const a = A{ .x = if (f1()) \\ 10 else 20 }; \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 }; \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100, }; \\const a = A{ .x = if (f1()) \\ 10 else 20}; \\const a = A{ .x = switch(g) {0 => "ok", else => "no"} }; \\ , \\const a = A{ .x = if (f1()) 10 else 20 }; \\const a = A{ \\ .x = if (f1()) 10 else 20, \\}; \\const a = A{ \\ .x = if (f1()) \\ 10 \\ else \\ 20, \\}; \\const a = A{ .x = if (f1()) 10 else 20, .y = f2() + 100 }; \\const a = A{ \\ .x = if (f1()) 10 else 20, \\ .y = f2() + 100, \\}; \\const a = A{ \\ .x = if (f1()) \\ 10 \\ else \\ 20, \\}; \\const a = A{ \\ .x = switch (g) { \\ 0 => "ok", \\ else => "no", \\ }, \\}; \\ ); } test "zig fmt: array literal with hint" { try testTransform( \\const a = []u8{ \\ 1, 2, // \\ 3, \\ 4, \\ 5, \\ 6, \\ 7 }; \\const a = []u8{ \\ 1, 2, // \\ 3, \\ 4, \\ 5, \\ 6, \\ 7, 8 }; \\const a = []u8{ \\ 1, 2, // \\ 3, \\ 4, \\ 5, \\ 6, // blah \\ 7, 8 }; \\const a = []u8{ \\ 1, 2, // \\ 3, // \\ 4, \\ 5, \\ 6, \\ 7 }; \\const a = []u8{ \\ 1, \\ 2, \\ 3, 4, // \\ 5, 6, // \\ 7, 8, // \\}; , \\const a = []u8{ \\ 1, 2, \\ 3, 4, \\ 5, 6, \\ 7, \\}; \\const a = []u8{ \\ 1, 2, \\ 3, 4, \\ 5, 6, \\ 7, 8, \\}; \\const a = []u8{ \\ 1, 2, \\ 3, 4, \\ 5, 6, // blah \\ 7, 8, \\}; \\const a = []u8{ \\ 1, 2, \\ 3, // \\ 4, \\ 5, 6, \\ 7, \\}; \\const a = []u8{ \\ 1, \\ 2, \\ 3, \\ 4, \\ 5, \\ 6, \\ 7, \\ 8, \\}; \\ ); } test "zig fmt: array literal veritical column alignment" { try testTransform( \\const a = []u8{ \\ 1000, 200, \\ 30, 4, \\ 50000, 60 \\}; \\const a = []u8{0, 1, 2, 3, 40, \\ 4,5,600,7, \\ 80, \\ 9, 10, 11, 0, 13, 14, 15}; \\ , \\const a = []u8{ \\ 1000, 200, \\ 30, 4, \\ 50000, 60, \\}; \\const a = []u8{ \\ 0, 1, 2, 3, 40, \\ 4, 5, 600, 7, 80, \\ 9, 10, 11, 0, 13, \\ 14, 15, \\}; \\ ); } test "zig fmt: multiline string with backslash at end of line" { try testCanonical( \\comptime { \\ err( \\ \\\ \\ ); \\} \\ ); } test "zig fmt: multiline string parameter in fn call with trailing comma" { try testCanonical( \\fn foo() void { \\ try stdout.print( \\ \\ZIG_CMAKE_BINARY_DIR {} \\ \\ZIG_C_HEADER_FILES {} \\ \\ZIG_DIA_GUIDS_LIB {} \\ \\ \\ , \\ std.cstr.toSliceConst(c.ZIG_CMAKE_BINARY_DIR), \\ std.cstr.toSliceConst(c.ZIG_CXX_COMPILER), \\ std.cstr.toSliceConst(c.ZIG_DIA_GUIDS_LIB), \\ ); \\} \\ ); } test "zig fmt: trailing comma on fn call" { try testCanonical( \\comptime { \\ var module = try Module.create( \\ allocator, \\ zig_lib_dir, \\ full_cache_dir, \\ ); \\} \\ ); } test "zig fmt: multi line arguments without last comma" { try testTransform( \\pub fn foo( \\ a: usize, \\ b: usize, \\ c: usize, \\ d: usize \\) usize { \\ return a + b + c + d; \\} \\ , \\pub fn foo(a: usize, b: usize, c: usize, d: usize) usize { \\ return a + b + c + d; \\} \\ ); } test "zig fmt: empty block with only comment" { try testCanonical( \\comptime { \\ { \\ // comment \\ } \\} \\ ); } test "zig fmt: no trailing comma on struct decl" { try testCanonical( \\const RoundParam = struct { \\ k: usize, s: u32, t: u32 \\}; \\ ); } test "zig fmt: extra newlines at the end" { try testTransform( \\const a = b; \\ \\ \\ , \\const a = b; \\ ); } test "zig fmt: simple asm" { try testTransform( \\comptime { \\ asm volatile ( \\ \\.globl aoeu; \\ \\.type aoeu, @function; \\ \\.set aoeu, derp; \\ ); \\ \\ asm ("not real assembly" \\ :[a] "x" (x),); \\ asm ("not real assembly" \\ :[a] "x" (->i32),:[a] "x" (1),); \\ asm ("still not real assembly" \\ :::"a","b",); \\} , \\comptime { \\ asm volatile ( \\ \\.globl aoeu; \\ \\.type aoeu, @function; \\ \\.set aoeu, derp; \\ ); \\ \\ asm ("not real assembly" \\ : [a] "x" (x) \\ ); \\ asm ("not real assembly" \\ : [a] "x" (-> i32) \\ : [a] "x" (1) \\ ); \\ asm ("still not real assembly" \\ : \\ : \\ : "a", "b" \\ ); \\} \\ ); } test "zig fmt: nested struct literal with one item" { try testCanonical( \\const a = foo{ \\ .item = bar{ .a = b }, \\}; \\ ); } test "zig fmt: switch cases trailing comma" { try testTransform( \\fn switch_cases(x: i32) void { \\ switch (x) { \\ 1,2,3 => {}, \\ 4,5, => {}, \\ 6... 8, => {}, \\ else => {}, \\ } \\} , \\fn switch_cases(x: i32) void { \\ switch (x) { \\ 1, 2, 3 => {}, \\ 4, \\ 5, \\ => {}, \\ 6...8 => {}, \\ else => {}, \\ } \\} \\ ); } test "zig fmt: slice align" { try testCanonical( \\const A = struct { \\ items: []align(A) T, \\}; \\ ); } test "zig fmt: add trailing comma to array literal" { try testTransform( \\comptime { \\ return []u16{'m', 's', 'y', 's', '-' // hi \\ }; \\ return []u16{'m', 's', 'y', 's', \\ '-'}; \\ return []u16{'m', 's', 'y', 's', '-'}; \\} , \\comptime { \\ return []u16{ \\ 'm', 's', 'y', 's', '-', // hi \\ }; \\ return []u16{ \\ 'm', 's', 'y', 's', \\ '-', \\ }; \\ return []u16{ 'm', 's', 'y', 's', '-' }; \\} \\ ); } test "zig fmt: first thing in file is line comment" { try testCanonical( \\// Introspection and determination of system libraries needed by zig. \\ \\// Introspection and determination of system libraries needed by zig. \\ \\const std = @import("std"); \\ ); } test "zig fmt: line comment after doc comment" { try testCanonical( \\/// doc comment \\// line comment \\fn foo() void {} \\ ); } test "zig fmt: float literal with exponent" { try testCanonical( \\test "bit field alignment" { \\ assert(@TypeOf(&blah.b) == *align(1:3:6) const u3); \\} \\ ); } test "zig fmt: float literal with exponent" { try testCanonical( \\test "aoeu" { \\ switch (state) { \\ TermState.Start => switch (c) { \\ '\x1b' => state = TermState.Escape, \\ else => try out.writeByte(c), \\ }, \\ } \\} \\ ); } test "zig fmt: float literal with exponent" { try testCanonical( \\pub const f64_true_min = 4.94065645841246544177e-324; \\const threshold = 0x1.a827999fcef32p+1022; \\ ); } test "zig fmt: if-else end of comptime" { try testCanonical( \\comptime { \\ if (a) { \\ b(); \\ } else { \\ b(); \\ } \\} \\ ); } test "zig fmt: nested blocks" { try testCanonical( \\comptime { \\ { \\ { \\ { \\ a(); \\ } \\ } \\ } \\} \\ ); } test "zig fmt: block with same line comment after end brace" { try testCanonical( \\comptime { \\ { \\ b(); \\ } // comment \\} \\ ); } test "zig fmt: statements with comment between" { try testCanonical( \\comptime { \\ a = b; \\ // comment \\ a = b; \\} \\ ); } test "zig fmt: statements with empty line between" { try testCanonical( \\comptime { \\ a = b; \\ \\ a = b; \\} \\ ); } test "zig fmt: ptr deref operator and unwrap optional operator" { try testCanonical( \\const a = b.*; \\const a = b.?; \\ ); } test "zig fmt: comment after if before another if" { try testCanonical( \\test "aoeu" { \\ // comment \\ if (x) { \\ bar(); \\ } \\} \\ \\test "aoeu" { \\ if (x) { \\ foo(); \\ } \\ // comment \\ if (x) { \\ bar(); \\ } \\} \\ ); } test "zig fmt: line comment between if block and else keyword" { try testCanonical( \\test "aoeu" { \\ // cexp(finite|nan +- i inf|nan) = nan + i nan \\ if ((hx & 0x7fffffff) != 0x7f800000) { \\ return Complex(f32).new(y - y, y - y); \\ } \\ // cexp(-inf +- i inf|nan) = 0 + i0 \\ else if (hx & 0x80000000 != 0) { \\ return Complex(f32).new(0, 0); \\ } \\ // cexp(+inf +- i inf|nan) = inf + i nan \\ // another comment \\ else { \\ return Complex(f32).new(x, y - y); \\ } \\} \\ ); } test "zig fmt: same line comments in expression" { try testCanonical( \\test "aoeu" { \\ const x = ( // a \\ 0 // b \\ ); // c \\} \\ ); } test "zig fmt: add comma on last switch prong" { try testTransform( \\test "aoeu" { \\switch (self.init_arg_expr) { \\ InitArg.Type => |t| { }, \\ InitArg.None, \\ InitArg.Enum => { } \\} \\ switch (self.init_arg_expr) { \\ InitArg.Type => |t| { }, \\ InitArg.None, \\ InitArg.Enum => { }//line comment \\ } \\} , \\test "aoeu" { \\ switch (self.init_arg_expr) { \\ InitArg.Type => |t| {}, \\ InitArg.None, InitArg.Enum => {}, \\ } \\ switch (self.init_arg_expr) { \\ InitArg.Type => |t| {}, \\ InitArg.None, InitArg.Enum => {}, //line comment \\ } \\} \\ ); } test "zig fmt: same-line comment after a statement" { try testCanonical( \\test "" { \\ a = b; \\ debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption \\ a = b; \\} \\ ); } test "zig fmt: same-line comment after var decl in struct" { try testCanonical( \\pub const vfs_cap_data = extern struct { \\ const Data = struct {}; // when on disk. \\}; \\ ); } test "zig fmt: same-line comment after field decl" { try testCanonical( \\pub const dirent = extern struct { \\ d_name: u8, \\ d_name: u8, // comment 1 \\ d_name: u8, \\ d_name: u8, // comment 2 \\ d_name: u8, \\}; \\ ); } test "zig fmt: same-line comment after switch prong" { try testCanonical( \\test "" { \\ switch (err) { \\ error.PathAlreadyExists => {}, // comment 2 \\ else => return err, // comment 1 \\ } \\} \\ ); } test "zig fmt: same-line comment after non-block if expression" { try testCanonical( \\comptime { \\ if (sr > n_uword_bits - 1) // d > r \\ return 0; \\} \\ ); } test "zig fmt: same-line comment on comptime expression" { try testCanonical( \\test "" { \\ comptime assert(@typeInfo(T) == .Int); // must pass an integer to absInt \\} \\ ); } test "zig fmt: switch with empty body" { try testCanonical( \\test "" { \\ foo() catch |err| switch (err) {}; \\} \\ ); } test "zig fmt: line comments in struct initializer" { try testCanonical( \\fn foo() void { \\ return Self{ \\ .a = b, \\ \\ // Initialize these two fields to buffer_size so that \\ // in `readFn` we treat the state as being able to read \\ .start_index = buffer_size, \\ .end_index = buffer_size, \\ \\ // middle \\ \\ .a = b, \\ \\ // end \\ }; \\} \\ ); } test "zig fmt: first line comment in struct initializer" { try testCanonical( \\pub fn acquire(self: *Self) HeldLock { \\ return HeldLock{ \\ // guaranteed allocation elision \\ .held = self.lock.acquire(), \\ .value = &self.private_data, \\ }; \\} \\ ); } test "zig fmt: doc comments before struct field" { try testCanonical( \\pub const Allocator = struct { \\ /// Allocate byte_count bytes and return them in a slice, with the \\ /// slice's pointer aligned at least to alignment bytes. \\ allocFn: fn () void, \\}; \\ ); } test "zig fmt: error set declaration" { try testCanonical( \\const E = error{ \\ A, \\ B, \\ \\ C, \\}; \\ \\const Error = error{ \\ /// no more memory \\ OutOfMemory, \\}; \\ \\const Error = error{ \\ /// no more memory \\ OutOfMemory, \\ \\ /// another \\ Another, \\ \\ // end \\}; \\ \\const Error = error{OutOfMemory}; \\const Error = error{}; \\ \\const Error = error{ OutOfMemory, OutOfTime }; \\ ); } test "zig fmt: union(enum(u32)) with assigned enum values" { try testCanonical( \\const MultipleChoice = union(enum(u32)) { \\ A = 20, \\ B = 40, \\ C = 60, \\ D = 1000, \\}; \\ ); } test "zig fmt: resume from suspend block" { try testCanonical( \\fn foo() void { \\ suspend { \\ resume @frame(); \\ } \\} \\ ); } test "zig fmt: comments before error set decl" { try testCanonical( \\const UnexpectedError = error{ \\ /// The Operating System returned an undocumented error code. \\ Unexpected, \\ // another \\ Another, \\ \\ // in between \\ \\ // at end \\}; \\ ); } test "zig fmt: comments before switch prong" { try testCanonical( \\test "" { \\ switch (err) { \\ error.PathAlreadyExists => continue, \\ \\ // comment 1 \\ \\ // comment 2 \\ else => return err, \\ // at end \\ } \\} \\ ); } test "zig fmt: comments before var decl in struct" { try testCanonical( \\pub const vfs_cap_data = extern struct { \\ // All of these are mandated as little endian \\ // when on disk. \\ const Data = struct { \\ permitted: u32, \\ inheritable: u32, \\ }; \\ \\ // in between \\ \\ /// All of these are mandated as little endian \\ /// when on disk. \\ const Data = struct { \\ permitted: u32, \\ inheritable: u32, \\ }; \\ \\ // at end \\}; \\ ); } test "zig fmt: array literal with 1 item on 1 line" { try testCanonical( \\var s = []const u64{0} ** 25; \\ ); } test "zig fmt: comments before global variables" { try testCanonical( \\/// Foo copies keys and values before they go into the map, and \\/// frees them when they get removed. \\pub const Foo = struct {}; \\ ); } test "zig fmt: comments in statements" { try testCanonical( \\test "std" { \\ // statement comment \\ _ = @import("foo/bar.zig"); \\ \\ // middle \\ // middle2 \\ \\ // end \\} \\ ); } test "zig fmt: comments before test decl" { try testCanonical( \\/// top level doc comment \\test "hi" {} \\ \\// top level normal comment \\test "hi" {} \\ \\// middle \\ \\// end \\ ); } test "zig fmt: preserve spacing" { try testCanonical( \\const std = @import("std"); \\ \\pub fn main() !void { \\ var stdout_file = std.io.getStdOut; \\ var stdout_file = std.io.getStdOut; \\ \\ var stdout_file = std.io.getStdOut; \\ var stdout_file = std.io.getStdOut; \\} \\ ); } test "zig fmt: return types" { try testCanonical( \\pub fn main() !void {} \\pub fn main() anytype {} \\pub fn main() i32 {} \\ ); } test "zig fmt: imports" { try testCanonical( \\const std = @import("std"); \\const std = @import(); \\ ); } test "zig fmt: global declarations" { try testCanonical( \\const a = b; \\pub const a = b; \\var a = b; \\pub var a = b; \\const a: i32 = b; \\pub const a: i32 = b; \\var a: i32 = b; \\pub var a: i32 = b; \\extern const a: i32 = b; \\pub extern const a: i32 = b; \\extern var a: i32 = b; \\pub extern var a: i32 = b; \\extern "a" const a: i32 = b; \\pub extern "a" const a: i32 = b; \\extern "a" var a: i32 = b; \\pub extern "a" var a: i32 = b; \\ ); } test "zig fmt: extern declaration" { try testCanonical( \\extern var foo: c_int; \\ ); } test "zig fmt: alignment" { try testCanonical( \\var foo: c_int align(1); \\ ); } test "zig fmt: C main" { try testCanonical( \\fn main(argc: c_int, argv: **u8) c_int { \\ const a = b; \\} \\ ); } test "zig fmt: return" { try testCanonical( \\fn foo(argc: c_int, argv: **u8) c_int { \\ return 0; \\} \\ \\fn bar() void { \\ return; \\} \\ ); } test "zig fmt: pointer attributes" { try testCanonical( \\extern fn f1(s: *align(*u8) u8) c_int; \\extern fn f2(s: **align(1) *const *volatile u8) c_int; \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int; \\extern fn f4(s: *align(1) const volatile u8) c_int; \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int; \\ ); } test "zig fmt: slice attributes" { try testCanonical( \\extern fn f1(s: *align(*u8) u8) c_int; \\extern fn f2(s: **align(1) *const *volatile u8) c_int; \\extern fn f3(s: *align(1) const *align(1) volatile *const volatile u8) c_int; \\extern fn f4(s: *align(1) const volatile u8) c_int; \\extern fn f5(s: [*:0]align(1) const volatile u8) c_int; \\ ); } test "zig fmt: test declaration" { try testCanonical( \\test "test name" { \\ const a = 1; \\ var b = 1; \\} \\ ); } test "zig fmt: infix operators" { try testCanonical( \\test "infix operators" { \\ var i = undefined; \\ i = 2; \\ i *= 2; \\ i |= 2; \\ i ^= 2; \\ i <<= 2; \\ i >>= 2; \\ i &= 2; \\ i *= 2; \\ i *%= 2; \\ i -= 2; \\ i -%= 2; \\ i += 2; \\ i +%= 2; \\ i /= 2; \\ i %= 2; \\ _ = i == i; \\ _ = i != i; \\ _ = i != i; \\ _ = i.i; \\ _ = i || i; \\ _ = i!i; \\ _ = i ** i; \\ _ = i ++ i; \\ _ = i orelse i; \\ _ = i % i; \\ _ = i / i; \\ _ = i *% i; \\ _ = i * i; \\ _ = i -% i; \\ _ = i - i; \\ _ = i +% i; \\ _ = i + i; \\ _ = i << i; \\ _ = i >> i; \\ _ = i & i; \\ _ = i ^ i; \\ _ = i | i; \\ _ = i >= i; \\ _ = i <= i; \\ _ = i > i; \\ _ = i < i; \\ _ = i and i; \\ _ = i or i; \\} \\ ); } test "zig fmt: precedence" { try testCanonical( \\test "precedence" { \\ a!b(); \\ (a!b)(); \\ !a!b; \\ !(a!b); \\ !a{}; \\ !(a{}); \\ a + b{}; \\ (a + b){}; \\ a << b + c; \\ (a << b) + c; \\ a & b << c; \\ (a & b) << c; \\ a ^ b & c; \\ (a ^ b) & c; \\ a | b ^ c; \\ (a | b) ^ c; \\ a == b | c; \\ (a == b) | c; \\ a and b == c; \\ (a and b) == c; \\ a or b and c; \\ (a or b) and c; \\ (a or b) and c; \\} \\ ); } test "zig fmt: prefix operators" { try testCanonical( \\test "prefix operators" { \\ try return --%~!&0; \\} \\ ); } test "zig fmt: call expression" { try testCanonical( \\test "test calls" { \\ a(); \\ a(1); \\ a(1, 2); \\ a(1, 2) + a(1, 2); \\} \\ ); } test "zig fmt: anytype type" { try testCanonical( \\fn print(args: anytype) anytype {} \\ ); } test "zig fmt: functions" { try testCanonical( \\extern fn puts(s: *const u8) c_int; \\extern "c" fn puts(s: *const u8) c_int; \\export fn puts(s: *const u8) c_int; \\inline fn puts(s: *const u8) c_int; \\noinline fn puts(s: *const u8) c_int; \\pub extern fn puts(s: *const u8) c_int; \\pub extern "c" fn puts(s: *const u8) c_int; \\pub export fn puts(s: *const u8) c_int; \\pub inline fn puts(s: *const u8) c_int; \\pub noinline fn puts(s: *const u8) c_int; \\pub extern fn puts(s: *const u8) align(2 + 2) c_int; \\pub extern "c" fn puts(s: *const u8) align(2 + 2) c_int; \\pub export fn puts(s: *const u8) align(2 + 2) c_int; \\pub inline fn puts(s: *const u8) align(2 + 2) c_int; \\pub noinline fn puts(s: *const u8) align(2 + 2) c_int; \\ ); } test "zig fmt: multiline string" { try testCanonical( \\test "" { \\ const s1 = \\ \\one \\ \\two) \\ \\three \\ ; \\ const s3 = // hi \\ \\one \\ \\two) \\ \\three \\ ; \\} \\ ); } test "zig fmt: values" { try testCanonical( \\test "values" { \\ 1; \\ 1.0; \\ "string"; \\ 'c'; \\ true; \\ false; \\ null; \\ undefined; \\ anyerror; \\ this; \\ unreachable; \\} \\ ); } test "zig fmt: indexing" { try testCanonical( \\test "test index" { \\ a[0]; \\ a[0 + 5]; \\ a[0..]; \\ a[0..5]; \\ a[a[0]]; \\ a[a[0..]]; \\ a[a[0..5]]; \\ a[a[0]..]; \\ a[a[0..5]..]; \\ a[a[0]..a[0]]; \\ a[a[0..5]..a[0]]; \\ a[a[0..5]..a[0..5]]; \\} \\ ); } test "zig fmt: struct declaration" { try testCanonical( \\const S = struct { \\ const Self = @This(); \\ f1: u8, \\ f3: u8, \\ \\ f2: u8, \\ \\ fn method(self: *Self) Self { \\ return self.*; \\ } \\}; \\ \\const Ps = packed struct { \\ a: u8, \\ b: u8, \\ \\ c: u8, \\}; \\ \\const Es = extern struct { \\ a: u8, \\ b: u8, \\ \\ c: u8, \\}; \\ ); } test "zig fmt: enum declaration" { try testCanonical( \\const E = enum { \\ Ok, \\ SomethingElse = 0, \\}; \\ \\const E2 = enum(u8) { \\ Ok, \\ SomethingElse = 255, \\ SomethingThird, \\}; \\ \\const Ee = extern enum { \\ Ok, \\ SomethingElse, \\ SomethingThird, \\}; \\ \\const Ep = packed enum { \\ Ok, \\ SomethingElse, \\ SomethingThird, \\}; \\ ); } test "zig fmt: union declaration" { try testCanonical( \\const U = union { \\ Int: u8, \\ Float: f32, \\ None, \\ Bool: bool, \\}; \\ \\const Ue = union(enum) { \\ Int: u8, \\ Float: f32, \\ None, \\ Bool: bool, \\}; \\ \\const E = enum { \\ Int, \\ Float, \\ None, \\ Bool, \\}; \\ \\const Ue2 = union(E) { \\ Int: u8, \\ Float: f32, \\ None, \\ Bool: bool, \\}; \\ \\const Eu = extern union { \\ Int: u8, \\ Float: f32, \\ None, \\ Bool: bool, \\}; \\ ); } test "zig fmt: arrays" { try testCanonical( \\test "test array" { \\ const a: [2]u8 = [2]u8{ \\ 1, \\ 2, \\ }; \\ const a: [2]u8 = []u8{ \\ 1, \\ 2, \\ }; \\ const a: [0]u8 = []u8{}; \\ const x: [4:0]u8 = undefined; \\} \\ ); } test "zig fmt: container initializers" { try testCanonical( \\const a0 = []u8{}; \\const a1 = []u8{1}; \\const a2 = []u8{ \\ 1, \\ 2, \\ 3, \\ 4, \\}; \\const s0 = S{}; \\const s1 = S{ .a = 1 }; \\const s2 = S{ \\ .a = 1, \\ .b = 2, \\}; \\ ); } test "zig fmt: catch" { try testCanonical( \\test "catch" { \\ const a: anyerror!u8 = 0; \\ _ = a catch return; \\ _ = a catch |err| return; \\} \\ ); } test "zig fmt: blocks" { try testCanonical( \\test "blocks" { \\ { \\ const a = 0; \\ const b = 0; \\ } \\ \\ blk: { \\ const a = 0; \\ const b = 0; \\ } \\ \\ const r = blk: { \\ const a = 0; \\ const b = 0; \\ }; \\} \\ ); } test "zig fmt: switch" { try testCanonical( \\test "switch" { \\ switch (0) { \\ 0 => {}, \\ 1 => unreachable, \\ 2, 3 => {}, \\ 4...7 => {}, \\ 1 + 4 * 3 + 22 => {}, \\ else => { \\ const a = 1; \\ const b = a; \\ }, \\ } \\ \\ const res = switch (0) { \\ 0 => 0, \\ 1 => 2, \\ 1 => a = 4, \\ else => 4, \\ }; \\ \\ const Union = union(enum) { \\ Int: i64, \\ Float: f64, \\ }; \\ \\ switch (u) { \\ Union.Int => |int| {}, \\ Union.Float => |*float| unreachable, \\ } \\} \\ ); } test "zig fmt: while" { try testCanonical( \\test "while" { \\ while (10 < 1) unreachable; \\ \\ while (10 < 1) unreachable else unreachable; \\ \\ while (10 < 1) { \\ unreachable; \\ } \\ \\ while (10 < 1) \\ unreachable; \\ \\ var i: usize = 0; \\ while (i < 10) : (i += 1) { \\ continue; \\ } \\ \\ i = 0; \\ while (i < 10) : (i += 1) \\ continue; \\ \\ i = 0; \\ var j: usize = 0; \\ while (i < 10) : ({ \\ i += 1; \\ j += 1; \\ }) { \\ continue; \\ } \\ \\ var a: ?u8 = 2; \\ while (a) |v| : (a = null) { \\ continue; \\ } \\ \\ while (a) |v| : (a = null) \\ unreachable; \\ \\ label: while (10 < 0) { \\ unreachable; \\ } \\ \\ const res = while (0 < 10) { \\ break 7; \\ } else { \\ unreachable; \\ }; \\ \\ const res = while (0 < 10) \\ break 7 \\ else \\ unreachable; \\ \\ var a: anyerror!u8 = 0; \\ while (a) |v| { \\ a = error.Err; \\ } else |err| { \\ i = 1; \\ } \\ \\ comptime var k: usize = 0; \\ inline while (i < 10) : (i += 1) \\ j += 2; \\} \\ ); } test "zig fmt: for" { try testCanonical( \\test "for" { \\ for (a) |v| { \\ continue; \\ } \\ \\ for (a) |v| continue; \\ \\ for (a) |v| continue else return; \\ \\ for (a) |v| { \\ continue; \\ } else return; \\ \\ for (a) |v| continue else { \\ return; \\ } \\ \\ for (a) |v| \\ continue \\ else \\ return; \\ \\ for (a) |v| \\ continue; \\ \\ for (a) |*v| \\ continue; \\ \\ for (a) |v, i| { \\ continue; \\ } \\ \\ for (a) |v, i| \\ continue; \\ \\ for (a) |b| switch (b) { \\ c => {}, \\ d => {}, \\ }; \\ \\ for (a) |b| \\ switch (b) { \\ c => {}, \\ d => {}, \\ }; \\ \\ const res = for (a) |v, i| { \\ break v; \\ } else { \\ unreachable; \\ }; \\ \\ var num: usize = 0; \\ inline for (a) |v, i| { \\ num += v; \\ num += i; \\ } \\} \\ ); try testTransform( \\test "fix for" { \\ for (a) |x| \\ f(x) else continue; \\} \\ , \\test "fix for" { \\ for (a) |x| \\ f(x) \\ else continue; \\} \\ ); } test "zig fmt: if" { try testCanonical( \\test "if" { \\ if (10 < 0) { \\ unreachable; \\ } \\ \\ if (10 < 0) unreachable; \\ \\ if (10 < 0) { \\ unreachable; \\ } else { \\ const a = 20; \\ } \\ \\ if (10 < 0) { \\ unreachable; \\ } else if (5 < 0) { \\ unreachable; \\ } else { \\ const a = 20; \\ } \\ \\ const is_world_broken = if (10 < 0) true else false; \\ const some_number = 1 + if (10 < 0) 2 else 3; \\ \\ const a: ?u8 = 10; \\ const b: ?u8 = null; \\ if (a) |v| { \\ const some = v; \\ } else if (b) |*v| { \\ unreachable; \\ } else { \\ const some = 10; \\ } \\ \\ const non_null_a = if (a) |v| v else 0; \\ \\ const a_err: anyerror!u8 = 0; \\ if (a_err) |v| { \\ const p = v; \\ } else |err| { \\ unreachable; \\ } \\} \\ ); } test "zig fmt: defer" { try testCanonical( \\test "defer" { \\ var i: usize = 0; \\ defer i = 1; \\ defer { \\ i += 2; \\ i *= i; \\ } \\ \\ errdefer i += 3; \\ errdefer { \\ i += 2; \\ i /= i; \\ } \\} \\ ); } test "zig fmt: comptime" { try testCanonical( \\fn a() u8 { \\ return 5; \\} \\ \\fn b(comptime i: u8) u8 { \\ return i; \\} \\ \\const av = comptime a(); \\const av2 = comptime blk: { \\ var res = a(); \\ res *= b(2); \\ break :blk res; \\}; \\ \\comptime { \\ _ = a(); \\} \\ \\test "comptime" { \\ const av3 = comptime a(); \\ const av4 = comptime blk: { \\ var res = a(); \\ res *= a(); \\ break :blk res; \\ }; \\ \\ comptime var i = 0; \\ comptime { \\ i = a(); \\ i += b(i); \\ } \\} \\ ); } test "zig fmt: fn type" { try testCanonical( \\fn a(i: u8) u8 { \\ return i + 1; \\} \\ \\const a: fn (u8) u8 = undefined; \\const b: fn (u8) callconv(.Naked) u8 = undefined; \\const ap: fn (u8) u8 = a; \\ ); } test "zig fmt: inline asm" { try testCanonical( \\pub fn syscall1(number: usize, arg1: usize) usize { \\ return asm volatile ("syscall" \\ : [ret] "={rax}" (-> usize) \\ : [number] "{rax}" (number), \\ [arg1] "{rdi}" (arg1) \\ : "rcx", "r11" \\ ); \\} \\ ); } test "zig fmt: async functions" { try testCanonical( \\fn simpleAsyncFn() void { \\ const a = async a.b(); \\ x += 1; \\ suspend; \\ x += 1; \\ suspend; \\ const p: anyframe->void = async simpleAsyncFn() catch unreachable; \\ await p; \\} \\ \\test "suspend, resume, await" { \\ const p: anyframe = async testAsyncSeq(); \\ resume p; \\ await p; \\} \\ ); } test "zig fmt: nosuspend" { try testCanonical( \\const a = nosuspend foo(); \\ ); } test "zig fmt: Block after if" { try testCanonical( \\test "Block after if" { \\ if (true) { \\ const a = 0; \\ } \\ \\ { \\ const a = 0; \\ } \\} \\ ); } test "zig fmt: use" { try testCanonical( \\usingnamespace @import("std"); \\pub usingnamespace @import("std"); \\ ); } test "zig fmt: string identifier" { try testCanonical( \\const @"a b" = @"c d".@"e f"; \\fn @"g h"() void {} \\ ); } test "zig fmt: error return" { try testCanonical( \\fn err() anyerror { \\ call(); \\ return error.InvalidArgs; \\} \\ ); } test "zig fmt: comptime block in container" { try testCanonical( \\pub fn container() type { \\ return struct { \\ comptime { \\ if (false) { \\ unreachable; \\ } \\ } \\ }; \\} \\ ); } test "zig fmt: inline asm parameter alignment" { try testCanonical( \\pub fn main() void { \\ asm volatile ( \\ \\ foo \\ \\ bar \\ ); \\ asm volatile ( \\ \\ foo \\ \\ bar \\ : [_] "" (-> usize), \\ [_] "" (-> usize) \\ ); \\ asm volatile ( \\ \\ foo \\ \\ bar \\ : \\ : [_] "" (0), \\ [_] "" (0) \\ ); \\ asm volatile ( \\ \\ foo \\ \\ bar \\ : \\ : \\ : "", "" \\ ); \\ asm volatile ( \\ \\ foo \\ \\ bar \\ : [_] "" (-> usize), \\ [_] "" (-> usize) \\ : [_] "" (0), \\ [_] "" (0) \\ : "", "" \\ ); \\} \\ ); } test "zig fmt: multiline string in array" { try testCanonical( \\const Foo = [][]const u8{ \\ \\aaa \\ , \\ \\bbb \\}; \\ \\fn bar() void { \\ const Foo = [][]const u8{ \\ \\aaa \\ , \\ \\bbb \\ }; \\ const Bar = [][]const u8{ // comment here \\ \\aaa \\ \\ \\ , // and another comment can go here \\ \\bbb \\ }; \\} \\ ); } test "zig fmt: if type expr" { try testCanonical( \\const mycond = true; \\pub fn foo() if (mycond) i32 else void { \\ if (mycond) { \\ return 42; \\ } \\} \\ ); } test "zig fmt: file ends with struct field" { try testCanonical( \\a: bool \\ ); } test "zig fmt: comment after empty comment" { try testTransform( \\const x = true; // \\// \\// \\//a \\ , \\const x = true; \\//a \\ ); } test "zig fmt: line comment in array" { try testTransform( \\test "a" { \\ var arr = [_]u32{ \\ 0 \\ // 1, \\ // 2, \\ }; \\} \\ , \\test "a" { \\ var arr = [_]u32{ \\ 0, // 1, \\ // 2, \\ }; \\} \\ ); try testCanonical( \\test "a" { \\ var arr = [_]u32{ \\ 0, \\ // 1, \\ // 2, \\ }; \\} \\ ); } test "zig fmt: comment after params" { try testTransform( \\fn a( \\ b: u32 \\ // c: u32, \\ // d: u32, \\) void {} \\ , \\fn a( \\ b: u32, // c: u32, \\ // d: u32, \\) void {} \\ ); try testCanonical( \\fn a( \\ b: u32, \\ // c: u32, \\ // d: u32, \\) void {} \\ ); } test "zig fmt: comment in array initializer/access" { try testCanonical( \\test "a" { \\ var a = x{ //aa \\ //bb \\ }; \\ var a = []x{ //aa \\ //bb \\ }; \\ var b = [ //aa \\ _ \\ ]x{ //aa \\ //bb \\ 9, \\ }; \\ var c = b[ //aa \\ 0 \\ ]; \\ var d = [_ \\ //aa \\ ]x{ //aa \\ //bb \\ 9, \\ }; \\ var e = d[0 \\ //aa \\ ]; \\} \\ ); } test "zig fmt: comments at several places in struct init" { try testTransform( \\var bar = Bar{ \\ .x = 10, // test \\ .y = "test" \\ // test \\}; \\ , \\var bar = Bar{ \\ .x = 10, // test \\ .y = "test", // test \\}; \\ ); try testCanonical( \\var bar = Bar{ // test \\ .x = 10, // test \\ .y = "test", \\ // test \\}; \\ ); } test "zig fmt: top level doc comments" { try testCanonical( \\//! tld 1 \\//! tld 2 \\//! tld 3 \\ \\// comment \\ \\/// A doc \\const A = struct { \\ //! A tld 1 \\ //! A tld 2 \\ //! A tld 3 \\}; \\ \\/// B doc \\const B = struct { \\ //! B tld 1 \\ //! B tld 2 \\ //! B tld 3 \\ \\ /// b doc \\ b: u32, \\}; \\ \\/// C doc \\const C = struct { \\ //! C tld 1 \\ //! C tld 2 \\ //! C tld 3 \\ \\ /// c1 doc \\ c1: u32, \\ \\ //! C tld 4 \\ //! C tld 5 \\ //! C tld 6 \\ \\ /// c2 doc \\ c2: u32, \\}; \\ ); try testCanonical( \\//! Top-level documentation. \\ \\/// This is A \\pub const A = usize; \\ ); try testCanonical( \\//! Nothing here \\ ); } test "zig fmt: extern without container keyword returns error" { try testError( \\const container = extern {}; \\ , &[_]Error{ .ExpectedExpr, .ExpectedVarDeclOrFn, }); } test "zig fmt: integer literals with underscore separators" { try testTransform( \\const \\ x = \\ 1_234_567 \\ +(0b0_1-0o7_0+0xff_FF ) + 0_0; , \\const x = 1_234_567 + (0b0_1 - 0o7_0 + 0xff_FF) + 0_0; \\ ); } test "zig fmt: hex literals with underscore separators" { try testTransform( \\pub fn orMask(a: [ 1_000 ]u64, b: [ 1_000] u64) [1_000]u64 { \\ var c: [1_000]u64 = [1]u64{ 0xFFFF_FFFF_FFFF_FFFF}**1_000; \\ for (c [ 0_0 .. ]) |_, i| { \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; \\ } \\ return c; \\} \\ \\ , \\pub fn orMask(a: [1_000]u64, b: [1_000]u64) [1_000]u64 { \\ var c: [1_000]u64 = [1]u64{0xFFFF_FFFF_FFFF_FFFF} ** 1_000; \\ for (c[0_0..]) |_, i| { \\ c[i] = (a[i] | b[i]) & 0xCCAA_CCAA_CCAA_CCAA; \\ } \\ return c; \\} \\ ); } test "zig fmt: decimal float literals with underscore separators" { try testTransform( \\pub fn main() void { \\ const a:f64=(10.0e-0+(10.e+0))+10_00.00_00e-2+00_00.00_10e+4; \\ const b:f64=010.0--0_10.+0_1_0.0_0+1e2; \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); \\} , \\pub fn main() void { \\ const a: f64 = (10.0e-0 + (10.e+0)) + 10_00.00_00e-2 + 00_00.00_10e+4; \\ const b: f64 = 010.0 - -0_10. + 0_1_0.0_0 + 1e2; \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); \\} \\ ); } test "zig fmt: hexadeciaml float literals with underscore separators" { try testTransform( \\pub fn main() void { \\ const a: f64 = (0x10.0p-0+(0x10.p+0))+0x10_00.00_00p-8+0x00_00.00_10p+16; \\ const b: f64 = 0x0010.0--0x00_10.+0x10.00+0x1p4; \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); \\} , \\pub fn main() void { \\ const a: f64 = (0x10.0p-0 + (0x10.p+0)) + 0x10_00.00_00p-8 + 0x00_00.00_10p+16; \\ const b: f64 = 0x0010.0 - -0x00_10. + 0x10.00 + 0x1p4; \\ std.debug.warn("a: {}, b: {} -> a+b: {}\n", .{ a, b, a + b }); \\} \\ ); } test "zig fmt: convert async fn into callconv(.Async)" { try testTransform( \\async fn foo() void {} , \\fn foo() callconv(.Async) void {} \\ ); } test "zig fmt: convert extern fn proto into callconv(.C)" { try testTransform( \\extern fn foo0() void {} \\const foo1 = extern fn () void; , \\extern fn foo0() void {} \\const foo1 = fn () callconv(.C) void; \\ ); } test "zig fmt: C var args" { try testCanonical( \\pub extern "c" fn printf(format: [*:0]const u8, ...) c_int; \\ ); } test "zig fmt: Only indent multiline string literals in function calls" { try testCanonical( \\test "zig fmt:" { \\ try testTransform( \\ \\const X = struct { \\ \\ foo: i32, bar: i8 }; \\ , \\ \\const X = struct { \\ \\ foo: i32, bar: i8 \\ \\}; \\ \\ \\ ); \\} \\ ); } test "zig fmt: Don't add extra newline after if" { try testCanonical( \\pub fn atomicSymLink(allocator: *Allocator, existing_path: []const u8, new_path: []const u8) !void { \\ if (cwd().symLink(existing_path, new_path, .{})) { \\ return; \\ } \\} \\ ); } const std = @import("std"); const mem = std.mem; const warn = std.debug.warn; const io = std.io; const maxInt = std.math.maxInt; var fixed_buffer_mem: [100 * 1024]u8 = undefined; fn testParse(source: []const u8, allocator: *mem.Allocator, anything_changed: *bool) ![]u8 { const stderr = io.getStdErr().outStream(); const tree = try std.zig.parse(allocator, source); defer tree.deinit(); for (tree.errors) |*parse_error| { const token = tree.token_locs[parse_error.loc()]; const loc = tree.tokenLocation(0, parse_error.loc()); try stderr.print("(memory buffer):{}:{}: error: ", .{ loc.line + 1, loc.column + 1 }); try tree.renderError(parse_error, stderr); try stderr.print("\n{}\n", .{source[loc.line_start..loc.line_end]}); { var i: usize = 0; while (i < loc.column) : (i += 1) { try stderr.writeAll(" "); } } { const caret_count = token.end - token.start; var i: usize = 0; while (i < caret_count) : (i += 1) { try stderr.writeAll("~"); } } try stderr.writeAll("\n"); } if (tree.errors.len != 0) { return error.ParseError; } var buffer = std.ArrayList(u8).init(allocator); errdefer buffer.deinit(); const outStream = buffer.outStream(); anything_changed.* = try std.zig.render(allocator, &outStream, tree); return buffer.toOwnedSlice(); } fn testTransform(source: []const u8, expected_source: []const u8) !void { const needed_alloc_count = x: { // Try it once with unlimited memory, make sure it works var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); var failing_allocator = std.testing.FailingAllocator.init(&fixed_allocator.allocator, maxInt(usize)); var anything_changed: bool = undefined; const result_source = try testParse(source, &failing_allocator.allocator, &anything_changed); std.testing.expectEqualStrings(expected_source, result_source); const changes_expected = source.ptr != expected_source.ptr; if (anything_changed != changes_expected) { warn("std.zig.render returned {} instead of {}\n", .{ anything_changed, changes_expected }); return error.TestFailed; } std.testing.expect(anything_changed == changes_expected); failing_allocator.allocator.free(result_source); break :x failing_allocator.index; }; var fail_index: usize = 0; while (fail_index < needed_alloc_count) : (fail_index += 1) { var fixed_allocator = std.heap.FixedBufferAllocator.init(fixed_buffer_mem[0..]); var failing_allocator = std.testing.FailingAllocator.init(&fixed_allocator.allocator, fail_index); var anything_changed: bool = undefined; if (testParse(source, &failing_allocator.allocator, &anything_changed)) |_| { return error.NondeterministicMemoryUsage; } else |err| switch (err) { error.OutOfMemory => { if (failing_allocator.allocated_bytes != failing_allocator.freed_bytes) { warn( "\nfail_index: {}/{}\nallocated bytes: {}\nfreed bytes: {}\nallocations: {}\ndeallocations: {}\n", .{ fail_index, needed_alloc_count, failing_allocator.allocated_bytes, failing_allocator.freed_bytes, failing_allocator.allocations, failing_allocator.deallocations, }, ); return error.MemoryLeakDetected; } }, error.ParseError => @panic("test failed"), else => @panic("test failed"), } } } fn testCanonical(source: []const u8) !void { return testTransform(source, source); } const Error = @TagType(std.zig.ast.Error); fn testError(source: []const u8, expected_errors: []const Error) !void { const tree = try std.zig.parse(std.testing.allocator, source); defer tree.deinit(); std.testing.expect(tree.errors.len == expected_errors.len); for (expected_errors) |expected, i| { std.testing.expect(expected == tree.errors[i]); } }