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}