master
  1const std = @import("std");
  2
  3const expect = std.testing.expect;
  4const expectEqual = std.testing.expectEqual;
  5const expectEqualDeep = std.testing.expectEqualDeep;
  6const expectEqualSlices = std.testing.expectEqualSlices;
  7const expectEqualStrings = std.testing.expectEqualStrings;
  8
  9test "bool" {
 10    try expectEqual(true, @as(bool, @import("zon/true.zon")));
 11    try expectEqual(false, @as(bool, @import("zon/false.zon")));
 12}
 13
 14test "optional" {
 15    const some: ?u32 = @import("zon/some.zon");
 16    const none: ?u32 = @import("zon/none.zon");
 17    const @"null": @TypeOf(null) = @import("zon/none.zon");
 18    try expectEqual(@as(u32, 10), some);
 19    try expectEqual(@as(?u32, null), none);
 20    try expectEqual(null, @"null");
 21}
 22
 23test "union" {
 24    // No tag
 25    {
 26        const Union = union {
 27            x: f32,
 28            y: bool,
 29            z: void,
 30        };
 31
 32        const union1: Union = @import("zon/union1.zon");
 33        const union2: Union = @import("zon/union2.zon");
 34        const union3: Union = @import("zon/union3.zon");
 35
 36        try expectEqual(1.5, union1.x);
 37        try expectEqual(true, union2.y);
 38        try expectEqual({}, union3.z);
 39    }
 40
 41    // Inferred tag
 42    {
 43        const Union = union(enum) {
 44            x: f32,
 45            y: bool,
 46            z: void,
 47        };
 48
 49        const union1: Union = comptime @import("zon/union1.zon");
 50        const union2: Union = @import("zon/union2.zon");
 51        const union3: Union = @import("zon/union3.zon");
 52
 53        try expectEqual(1.5, union1.x);
 54        try expectEqual(true, union2.y);
 55        try expectEqual({}, union3.z);
 56    }
 57
 58    // Explicit tag
 59    {
 60        const Tag = enum(i128) {
 61            x = -1,
 62            y = 2,
 63            z = 1,
 64        };
 65        const Union = union(Tag) {
 66            x: f32,
 67            y: bool,
 68            z: void,
 69        };
 70
 71        const union1: Union = @import("zon/union1.zon");
 72        const union2: Union = @import("zon/union2.zon");
 73        const union3: Union = @import("zon/union3.zon");
 74
 75        try expectEqual(1.5, union1.x);
 76        try expectEqual(true, union2.y);
 77        try expectEqual({}, union3.z);
 78    }
 79}
 80
 81test "struct" {
 82    const Vec0 = struct {};
 83    const Vec1 = struct { x: f32 };
 84    const Vec2 = struct { x: f32, y: f32 };
 85    const Escaped = struct { @"0": f32, foo: f32 };
 86    try expectEqual(Vec0{}, @as(Vec0, @import("zon/vec0.zon")));
 87    try expectEqual(Vec1{ .x = 1.5 }, @as(Vec1, @import("zon/vec1.zon")));
 88    try expectEqual(Vec2{ .x = 1.5, .y = 2 }, @as(Vec2, @import("zon/vec2.zon")));
 89    try expectEqual(Escaped{ .@"0" = 1.5, .foo = 2 }, @as(Escaped, @import("zon/escaped_struct.zon")));
 90}
 91
 92test "struct default fields" {
 93    const Vec3 = struct {
 94        x: f32,
 95        y: f32,
 96        z: f32 = 123.4,
 97    };
 98    try expectEqual(Vec3{ .x = 1.5, .y = 2.0, .z = 123.4 }, @as(Vec3, @import("zon/vec2.zon")));
 99    const ascribed: Vec3 = @import("zon/vec2.zon");
100    try expectEqual(Vec3{ .x = 1.5, .y = 2.0, .z = 123.4 }, ascribed);
101
102    const Vec2 = struct {
103        x: f32 = 20.0,
104        y: f32 = 10.0,
105    };
106    try expectEqual(Vec2{ .x = 1.5, .y = 2.0 }, @as(Vec2, @import("zon/vec2.zon")));
107}
108
109test "struct enum field" {
110    const Struct = struct {
111        x: enum { x, y, z },
112    };
113    try expectEqual(Struct{ .x = .z }, @as(Struct, @import("zon/enum_field.zon")));
114}
115
116test "tuple" {
117    const Tuple = struct { f32, bool, []const u8, u16 };
118    try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
119}
120
121test "comptime fields" {
122    // Test setting comptime tuple fields to the correct value
123    {
124        const Tuple = struct {
125            comptime f32 = 1.2,
126            comptime bool = true,
127            comptime []const u8 = "hello",
128            comptime u16 = 3,
129        };
130        try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
131    }
132
133    // Test setting comptime struct fields to the correct value
134    {
135        const Vec2 = struct {
136            comptime x: f32 = 1.5,
137            comptime y: f32 = 2.0,
138        };
139        try expectEqualDeep(Vec2{}, @as(Vec2, @import("zon/vec2.zon")));
140    }
141
142    // Test allowing comptime tuple fields to be set to their defaults
143    {
144        const Tuple = struct {
145            f32,
146            bool,
147            []const u8,
148            u16,
149            comptime u8 = 255,
150        };
151        try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
152    }
153
154    // Test allowing comptime struct fields to be set to their defaults
155    {
156        const Vec2 = struct {
157            comptime x: f32 = 1.5,
158            comptime y: f32 = 2.0,
159        };
160        try expectEqualDeep(Vec2{}, @as(Vec2, @import("zon/slice-empty.zon")));
161    }
162}
163
164test "char" {
165    try expectEqual(@as(u8, 'a'), @as(u8, @import("zon/a.zon")));
166    try expectEqual(@as(u8, 'z'), @as(u8, @import("zon/z.zon")));
167}
168
169test "arrays" {
170    try expectEqual([0]u8{}, @as([0]u8, @import("zon/vec0.zon")));
171    try expectEqual([0:1]u8{}, @as([0:1]u8, @import("zon/vec0.zon")));
172    try expectEqual(1, @as([0:1]u8, @import("zon/vec0.zon"))[0]);
173    try expectEqual([4]u8{ 'a', 'b', 'c', 'd' }, @as([4]u8, @import("zon/array.zon")));
174    try expectEqual([4:2]u8{ 'a', 'b', 'c', 'd' }, @as([4:2]u8, @import("zon/array.zon")));
175    try expectEqual(2, @as([4:2]u8, @import("zon/array.zon"))[4]);
176}
177
178test "slices, arrays, tuples" {
179    {
180        const expected_slice: []const u8 = &.{};
181        const found_slice: []const u8 = @import("zon/slice-empty.zon");
182        try expectEqualSlices(u8, expected_slice, found_slice);
183
184        const expected_array: [0]u8 = .{};
185        const found_array: [0]u8 = @import("zon/slice-empty.zon");
186        try expectEqual(expected_array, found_array);
187
188        const T = struct {};
189        const expected_tuple: T = .{};
190        const found_tuple: T = @import("zon/slice-empty.zon");
191        try expectEqual(expected_tuple, found_tuple);
192    }
193
194    {
195        const expected_slice: []const u8 = &.{1};
196        const found_slice: []const u8 = @import("zon/slice1_no_newline.zon");
197        try expectEqualSlices(u8, expected_slice, found_slice);
198
199        const expected_array: [1]u8 = .{1};
200        const found_array: [1]u8 = @import("zon/slice1_no_newline.zon");
201        try expectEqual(expected_array, found_array);
202
203        const T = struct { u8 };
204        const expected_tuple: T = .{1};
205        const found_tuple: T = @import("zon/slice1_no_newline.zon");
206        try expectEqual(expected_tuple, found_tuple);
207    }
208
209    {
210        const expected_slice: []const u8 = &.{ 'a', 'b', 'c' };
211        const found_slice: []const u8 = @import("zon/slice-abc.zon");
212        try expectEqualSlices(u8, expected_slice, found_slice);
213
214        const expected_array: [3]u8 = .{ 'a', 'b', 'c' };
215        const found_array: [3]u8 = @import("zon/slice-abc.zon");
216        try expectEqual(expected_array, found_array);
217
218        const T = struct { u8, u8, u8 };
219        const expected_tuple: T = .{ 'a', 'b', 'c' };
220        const found_tuple: T = @import("zon/slice-abc.zon");
221        try expectEqual(expected_tuple, found_tuple);
222    }
223}
224
225test "string literals" {
226    try expectEqualSlices(u8, "abc", @import("zon/abc.zon"));
227    try expectEqualSlices(u8, "ab\\c", @import("zon/abc-escaped.zon"));
228    const zero_terminated: [:0]const u8 = @import("zon/abc.zon");
229    try expectEqualDeep(zero_terminated, "abc");
230    try expectEqual(0, zero_terminated[zero_terminated.len]);
231    try expectEqualStrings(
232        \\Hello, world!
233        \\This is a multiline string!
234        \\ There are no escapes, we can, for example, include \n in the string
235    , @import("zon/multiline_string.zon"));
236    try expectEqualStrings("a\nb\x00c", @import("zon/string_embedded_null.zon"));
237}
238
239test "enum literals" {
240    const Enum = enum {
241        foo,
242        bar,
243        baz,
244        @"0\na",
245    };
246    try expectEqual(Enum.foo, @as(Enum, @import("zon/foo.zon")));
247    try expectEqual(.foo, @as(@TypeOf(.foo), @import("zon/foo.zon")));
248    try expectEqual(Enum.@"0\na", @as(Enum, @import("zon/escaped_enum.zon")));
249}
250
251test "int" {
252    const T = struct {
253        u8,
254        i16,
255        i14,
256        i32,
257        i8,
258        i8,
259        u8,
260        u8,
261        u65,
262        u65,
263        i128,
264        i128,
265        i66,
266        i66,
267        i8,
268        i8,
269        i16,
270        i16,
271        i16,
272        i16,
273        i16,
274        i16,
275        u65,
276        i66,
277        i66,
278        u65,
279        i66,
280        i66,
281        u65,
282        i66,
283        i66,
284    };
285    const expected: T = .{
286        // Test various numbers and types
287        10,
288        24,
289        -4,
290        -123,
291
292        // Test limits
293        127,
294        -128,
295
296        // Test characters
297        'a',
298        'z',
299
300        // Test big integers
301        36893488147419103231,
302        36893488147419103231,
303        -18446744073709551615, // Only a big int due to negation
304        -9223372036854775809, // Only a big int due to negation
305
306        // Test big integer limits
307        36893488147419103231,
308        -36893488147419103232,
309
310        // Test parsing whole number floats as integers
311        -1,
312        123,
313
314        // Test non-decimal integers
315        0xff,
316        -0xff,
317        0o77,
318        -0o77,
319        0b11,
320        -0b11,
321
322        // Test non-decimal big integers
323        0x1ffffffffffffffff,
324        0x1ffffffffffffffff,
325        -0x1ffffffffffffffff,
326        0x1ffffffffffffffff,
327        0x1ffffffffffffffff,
328        -0x1ffffffffffffffff,
329        0x1ffffffffffffffff,
330        0x1ffffffffffffffff,
331        -0x1ffffffffffffffff,
332    };
333    const actual: T = @import("zon/ints.zon");
334    try expectEqual(expected, actual);
335}
336
337test "floats" {
338    const T = struct {
339        f16,
340        f32,
341        f64,
342        f128,
343        f16,
344        f16,
345        f32,
346        f32,
347        f32,
348        f32,
349        f32,
350        f32,
351        f128,
352        f32,
353        f32,
354        f32,
355        f32,
356        f32,
357    };
358    const expected: T = .{
359        // Test decimals
360        0.5,
361        123.456,
362        -123.456,
363        42.5,
364
365        // Test whole numbers with and without decimals
366        5.0,
367        5.0,
368        -102,
369        -102,
370
371        // Test characters and negated characters
372        'a',
373        'z',
374
375        // Test big integers
376        36893488147419103231,
377        -36893488147419103231,
378        0x1ffffffffffffffff,
379        0x1ffffffffffffffff,
380
381        // Exponents, underscores
382        123.0E+77,
383
384        // Hexadecimal
385        0x103.70p-5,
386        -0x103.70,
387        0x1234_5678.9ABC_CDEFp-10,
388    };
389    const actual: T = @import("zon/floats.zon");
390    try expectEqual(expected, actual);
391}
392
393test "inf and nan" {
394    // f32
395    {
396        const actual: struct { f32, f32, f32 } = @import("zon/inf_and_nan.zon");
397        try expect(std.math.isNan(actual[0]));
398        try expect(std.math.isPositiveInf(actual[1]));
399        try expect(std.math.isNegativeInf(actual[2]));
400    }
401
402    // f128
403    {
404        const actual: struct { f128, f128, f128 } = @import("zon/inf_and_nan.zon");
405        try expect(std.math.isNan(actual[0]));
406        try expect(std.math.isPositiveInf(actual[1]));
407        try expect(std.math.isNegativeInf(actual[2]));
408    }
409}
410
411test "vector" {
412    {
413        const actual: @Vector(0, bool) = @import("zon/vec0.zon");
414        const expected: @Vector(0, bool) = .{};
415        try expectEqual(expected, actual);
416    }
417    {
418        const actual: @Vector(3, bool) = @import("zon/vec3_bool.zon");
419        const expected: @Vector(3, bool) = .{ false, false, true };
420        try expectEqual(expected, actual);
421    }
422
423    {
424        const actual: @Vector(0, f32) = @import("zon/vec0.zon");
425        const expected: @Vector(0, f32) = .{};
426        try expectEqual(expected, actual);
427    }
428    {
429        const actual: @Vector(3, f32) = @import("zon/vec3_float.zon");
430        const expected: @Vector(3, f32) = .{ 1.5, 2.5, 3.5 };
431        try expectEqual(expected, actual);
432    }
433
434    {
435        const actual: @Vector(0, u8) = @import("zon/vec0.zon");
436        const expected: @Vector(0, u8) = .{};
437        try expectEqual(expected, actual);
438    }
439    {
440        const actual: @Vector(3, u8) = @import("zon/vec3_int.zon");
441        const expected: @Vector(3, u8) = .{ 2, 4, 6 };
442        try expectEqual(expected, actual);
443    }
444
445    {
446        const actual: @Vector(0, *const u8) = @import("zon/vec0.zon");
447        const expected: @Vector(0, *const u8) = .{};
448        try expectEqual(expected, actual);
449    }
450    {
451        const actual: @Vector(3, *const u8) = @import("zon/vec3_int.zon");
452        const expected: @Vector(3, *const u8) = .{ &2, &4, &6 };
453        try expectEqual(expected, actual);
454    }
455
456    {
457        const actual: @Vector(0, ?*const u8) = @import("zon/vec0.zon");
458        const expected: @Vector(0, ?*const u8) = .{};
459        try expectEqual(expected, actual);
460    }
461    {
462        const actual: @Vector(3, ?*const u8) = @import("zon/vec3_int_opt.zon");
463        const expected: @Vector(3, ?*const u8) = .{ &2, null, &6 };
464        try expectEqual(expected, actual);
465    }
466}
467
468test "pointers" {
469    // Primitive with varying levels of pointers
470    try expectEqual(@as(u8, 'a'), @as(*const u8, @import("zon/a.zon")).*);
471    try expectEqual(@as(u8, 'a'), @as(*const *const u8, @import("zon/a.zon")).*.*);
472    try expectEqual(@as(u8, 'a'), @as(*const *const *const u8, @import("zon/a.zon")).*.*.*);
473
474    // Primitive optional with varying levels of pointers
475    try expectEqual(@as(u8, 'a'), @as(?*const u8, @import("zon/a.zon")).?.*);
476    try expectEqual(null, @as(?*const u8, @import("zon/none.zon")));
477
478    try expectEqual(@as(u8, 'a'), @as(*const ?u8, @import("zon/a.zon")).*.?);
479    try expectEqual(null, @as(*const ?u8, @import("zon/none.zon")).*);
480
481    try expectEqual(@as(u8, 'a'), @as(?*const *const u8, @import("zon/a.zon")).?.*.*);
482    try expectEqual(null, @as(?*const *const u8, @import("zon/none.zon")));
483
484    try expectEqual(@as(u8, 'a'), @as(*const ?*const u8, @import("zon/a.zon")).*.?.*);
485    try expectEqual(null, @as(*const ?*const u8, @import("zon/none.zon")).*);
486
487    try expectEqual(@as(u8, 'a'), @as(*const *const ?u8, @import("zon/a.zon")).*.*.?);
488    try expectEqual(null, @as(*const *const ?u8, @import("zon/none.zon")).*.*);
489
490    try expectEqual([3]u8{ 2, 4, 6 }, @as(*const [3]u8, @import("zon/vec3_int.zon")).*);
491
492    // A complicated type with nested internal pointers and string allocations
493    {
494        const Inner = struct {
495            f1: *const ?*const []const u8,
496            f2: *const ?*const []const u8,
497        };
498        const Outer = struct {
499            f1: *const ?*const Inner,
500            f2: *const ?*const Inner,
501        };
502        const expected: Outer = .{
503            .f1 = &&.{
504                .f1 = &null,
505                .f2 = &&"foo",
506            },
507            .f2 = &null,
508        };
509
510        const found: ?*const Outer = @import("zon/complex.zon");
511        try std.testing.expectEqualDeep(expected, found.?.*);
512    }
513}
514
515test "recursive" {
516    const Recursive = struct { foo: ?*const @This() };
517    const expected: Recursive = .{ .foo = &.{ .foo = null } };
518    try expectEqualDeep(expected, @as(Recursive, @import("zon/recursive.zon")));
519}
520
521test "anon" {
522    const expected = .{
523        .{
524            .bool_true = true,
525            .bool_false = false,
526            .string = "foo",
527        },
528        .{
529            null,
530            10,
531            36893488147419103232,
532            1.234,
533            'z',
534            .bar,
535            .{},
536        },
537    };
538
539    const actual = @import("zon/anon.zon");
540    try expectEqual(expected.len, actual.len);
541    try expectEqual(expected[1], actual[1]);
542    const expected_struct = expected[0];
543    const actual_struct = actual[0];
544    const expected_fields = @typeInfo(@TypeOf(expected_struct)).@"struct".fields;
545    const actual_fields = @typeInfo(@TypeOf(actual_struct)).@"struct".fields;
546    try expectEqual(expected_fields.len, actual_fields.len);
547    inline for (expected_fields) |field| {
548        try expectEqual(@field(expected_struct, field.name), @field(actual_struct, field.name));
549    }
550}
551
552test "build.zig.zon" {
553    const build = @import("zon/build.zig.zon");
554
555    try expectEqual(4, @typeInfo(@TypeOf(build)).@"struct".fields.len);
556    try expectEqualStrings("temp", build.name);
557    try expectEqualStrings("0.0.0", build.version);
558
559    const dependencies = build.dependencies;
560    try expectEqual(2, @typeInfo(@TypeOf(dependencies)).@"struct".fields.len);
561
562    const example_0 = dependencies.example_0;
563    try expectEqual(2, @typeInfo(@TypeOf(dependencies)).@"struct".fields.len);
564    try expectEqualStrings("https://example.com/foo.tar.gz", example_0.url);
565    try expectEqualStrings("...", example_0.hash);
566
567    const example_1 = dependencies.example_1;
568    try expectEqual(2, @typeInfo(@TypeOf(dependencies)).@"struct".fields.len);
569    try expectEqualStrings("../foo", example_1.path);
570    try expectEqual(false, example_1.lazy);
571
572    try expectEqual(.{ "build.zig", "build.zig.zon", "src" }, build.paths);
573}