| 1 | const builtin = @import("builtin"); |
| 2 | const std = @import("std"); |
| 3 | const expect = std.testing.expect; |
| 4 | const expectEqualStrings = std.testing.expectEqualStrings; |
| 5 | const 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 | |
| 14 | test "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 | |
| 39 | test "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 | |
| 64 | test "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 | |
| 85 | test "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 | |
| 120 | const A_Struct = struct {}; |
| 121 | const A_Union = union { |
| 122 | unused: u8, |
| 123 | }; |
| 124 | const A_Enum = enum { |
| 125 | unused, |
| 126 | }; |
| 127 | |
| 128 | fn regular() void {} |
| 129 | |
| 130 | const B = struct { |
| 131 | fn doTest() !void {} |
| 132 | }; |
| 133 | |
| 134 | test "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 | |
| 163 | fn TypeFromFn(comptime T: type) type { |
| 164 | return struct { |
| 165 | comptime { |
| 166 | _ = T; |
| 167 | } |
| 168 | }; |
| 169 | } |
| 170 | |
| 171 | fn TypeFromFn2(comptime T1: type, comptime T2: type) type { |
| 172 | return struct { |
| 173 | comptime { |
| 174 | _ = T1; |
| 175 | _ = T2; |
| 176 | } |
| 177 | }; |
| 178 | } |
| 179 | |
| 180 | fn 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. |
| 191 | pub 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 | |
| 213 | test "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 | |
| 231 | test "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 | |
| 240 | test "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 | } |