master
  1const builtin = @import("builtin");
  2const std = @import("std");
  3const expect = std.testing.expect;
  4const expectEqualStrings = std.testing.expectEqualStrings;
  5const expectStringStartsWith = std.testing.expectStringStartsWith;
  6
  7// Most tests here can be comptime but use runtime so that a stacktrace
  8// can show failure location.
  9//
 10// Note certain results of `@typeName()` expect `behavior.zig` to be the
 11// root file. Running a test against this file as root will result in
 12// failures.
 13
 14test "anon fn param" {
 15    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 16    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 17    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 18
 19    // https://github.com/ziglang/zig/issues/9339
 20    try expectEqualStringsIgnoreDigits(
 21        "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__struct_0)",
 22        @typeName(TypeFromFn(struct {})),
 23    );
 24    try expectEqualStringsIgnoreDigits(
 25        "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__union_0)",
 26        @typeName(TypeFromFn(union { unused: u8 })),
 27    );
 28    try expectEqualStringsIgnoreDigits(
 29        "behavior.typename.TypeFromFn(behavior.typename.test.anon fn param__enum_0)",
 30        @typeName(TypeFromFn(enum { unused })),
 31    );
 32
 33    try expectEqualStringsIgnoreDigits(
 34        "behavior.typename.TypeFromFnB(behavior.typename.test.anon fn param__struct_0,behavior.typename.test.anon fn param__union_0,behavior.typename.test.anon fn param__enum_0)",
 35        @typeName(TypeFromFnB(struct {}, union { unused: u8 }, enum { unused })),
 36    );
 37}
 38
 39test "anon field init" {
 40    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 41    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 42    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 43
 44    const Foo = .{
 45        .T1 = struct {},
 46        .T2 = union { unused: u8 },
 47        .T3 = enum { unused },
 48    };
 49
 50    try expectEqualStringsIgnoreDigits(
 51        "behavior.typename.test.anon field init__struct_0",
 52        @typeName(Foo.T1),
 53    );
 54    try expectEqualStringsIgnoreDigits(
 55        "behavior.typename.test.anon field init__union_0",
 56        @typeName(Foo.T2),
 57    );
 58    try expectEqualStringsIgnoreDigits(
 59        "behavior.typename.test.anon field init__enum_0",
 60        @typeName(Foo.T3),
 61    );
 62}
 63
 64test "basic" {
 65    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 66    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 67    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 68
 69    try expectEqualStrings("i64", @typeName(i64));
 70    try expectEqualStrings("*usize", @typeName(*usize));
 71    try expectEqualStrings("[]u8", @typeName([]u8));
 72
 73    try expectEqualStrings("fn () void", @typeName(fn () void));
 74    try expectEqualStrings("fn (u32) void", @typeName(fn (u32) void));
 75    try expectEqualStrings("fn (u32) void", @typeName(fn (a: u32) void));
 76
 77    try expectEqualStrings("fn (comptime u32) void", @typeName(fn (comptime u32) void));
 78    try expectEqualStrings("fn (noalias []u8) void", @typeName(fn (noalias []u8) void));
 79
 80    try expectEqualStrings("fn () callconv(.c) void", @typeName(fn () callconv(.c) void));
 81    try expectEqualStrings("fn (...) callconv(.c) void", @typeName(fn (...) callconv(.c) void));
 82    try expectEqualStrings("fn (u32, ...) callconv(.c) void", @typeName(fn (u32, ...) callconv(.c) void));
 83}
 84
 85test "top level decl" {
 86    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
 87    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 88    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
 89
 90    try expectEqualStrings(
 91        "behavior.typename.A_Struct",
 92        @typeName(A_Struct),
 93    );
 94    try expectEqualStrings(
 95        "behavior.typename.A_Union",
 96        @typeName(A_Union),
 97    );
 98    try expectEqualStrings(
 99        "behavior.typename.A_Enum",
100        @typeName(A_Enum),
101    );
102
103    // regular fn, without error
104    try expectEqualStrings(
105        "fn () void",
106        @typeName(@TypeOf(regular)),
107    );
108    // regular fn inside struct, with error
109    try expectEqualStrings(
110        "fn () @typeInfo(@typeInfo(@TypeOf(behavior.typename.B.doTest)).@\"fn\".return_type.?).error_union.error_set!void",
111        @typeName(@TypeOf(B.doTest)),
112    );
113    // generic fn
114    try expectEqualStrings(
115        "fn (comptime type) type",
116        @typeName(@TypeOf(TypeFromFn)),
117    );
118}
119
120const A_Struct = struct {};
121const A_Union = union {
122    unused: u8,
123};
124const A_Enum = enum {
125    unused,
126};
127
128fn regular() void {}
129
130const B = struct {
131    fn doTest() !void {}
132};
133
134test "fn param" {
135    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
136    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
137    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
138
139    // https://github.com/ziglang/zig/issues/675
140    try expectEqualStrings(
141        "behavior.typename.TypeFromFn(u8)",
142        @typeName(TypeFromFn(u8)),
143    );
144    try expectEqualStrings(
145        "behavior.typename.TypeFromFn(behavior.typename.A_Struct)",
146        @typeName(TypeFromFn(A_Struct)),
147    );
148    try expectEqualStrings(
149        "behavior.typename.TypeFromFn(behavior.typename.A_Union)",
150        @typeName(TypeFromFn(A_Union)),
151    );
152    try expectEqualStrings(
153        "behavior.typename.TypeFromFn(behavior.typename.A_Enum)",
154        @typeName(TypeFromFn(A_Enum)),
155    );
156
157    try expectEqualStrings(
158        "behavior.typename.TypeFromFn2(u8,bool)",
159        @typeName(TypeFromFn2(u8, bool)),
160    );
161}
162
163fn TypeFromFn(comptime T: type) type {
164    return struct {
165        comptime {
166            _ = T;
167        }
168    };
169}
170
171fn TypeFromFn2(comptime T1: type, comptime T2: type) type {
172    return struct {
173        comptime {
174            _ = T1;
175            _ = T2;
176        }
177    };
178}
179
180fn TypeFromFnB(comptime T1: type, comptime T2: type, comptime T3: type) type {
181    return struct {
182        comptime {
183            _ = T1;
184            _ = T2;
185            _ = T3;
186        }
187    };
188}
189
190/// Replaces integers in `actual` with '0' before doing the test.
191pub fn expectEqualStringsIgnoreDigits(expected: []const u8, actual: []const u8) !void {
192    var actual_buf: [1024]u8 = undefined;
193    var actual_i: usize = 0;
194    var last_digit = false;
195    for (actual) |byte| {
196        switch (byte) {
197            '0'...'9' => {
198                if (last_digit) continue;
199                last_digit = true;
200                actual_buf[actual_i] = '0';
201                actual_i += 1;
202            },
203            else => {
204                last_digit = false;
205                actual_buf[actual_i] = byte;
206                actual_i += 1;
207            },
208        }
209    }
210    return expectEqualStrings(expected, actual_buf[0..actual_i]);
211}
212
213test "local variable" {
214    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
215    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
216    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
217
218    const Foo = struct { a: u32 };
219    const Bar = union { a: u32 };
220    const Baz = enum { a, b };
221    const Qux = enum { a, b };
222    const Quux = enum { a, b };
223
224    try expectEqualStrings("behavior.typename.test.local variable.Foo", @typeName(Foo));
225    try expectEqualStrings("behavior.typename.test.local variable.Bar", @typeName(Bar));
226    try expectEqualStrings("behavior.typename.test.local variable.Baz", @typeName(Baz));
227    try expectEqualStrings("behavior.typename.test.local variable.Qux", @typeName(Qux));
228    try expectEqualStrings("behavior.typename.test.local variable.Quux", @typeName(Quux));
229}
230
231test "comptime parameters not converted to anytype in function type" {
232    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
233    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
234    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
235
236    const T = fn (comptime fn (comptime type) void, void) void;
237    try expectEqualStrings("fn (comptime fn (comptime type) void, void) void", @typeName(T));
238}
239
240test "anon name strategy used in sub expression" {
241    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
242    if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
243    if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
244
245    const S = struct {
246        fn getTheName() []const u8 {
247            return struct {
248                const name = @typeName(@This());
249            }.name;
250        }
251    };
252    try expectEqualStringsIgnoreDigits(
253        "behavior.typename.test.anon name strategy used in sub expression.S.getTheName__struct_0",
254        S.getTheName(),
255    );
256}