mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
574 lines
17 KiB
Zig
574 lines
17 KiB
Zig
const std = @import("std");
|
|
|
|
const expect = std.testing.expect;
|
|
const expectEqual = std.testing.expectEqual;
|
|
const expectEqualDeep = std.testing.expectEqualDeep;
|
|
const expectEqualSlices = std.testing.expectEqualSlices;
|
|
const expectEqualStrings = std.testing.expectEqualStrings;
|
|
|
|
test "bool" {
|
|
try expectEqual(true, @as(bool, @import("zon/true.zon")));
|
|
try expectEqual(false, @as(bool, @import("zon/false.zon")));
|
|
}
|
|
|
|
test "optional" {
|
|
const some: ?u32 = @import("zon/some.zon");
|
|
const none: ?u32 = @import("zon/none.zon");
|
|
const @"null": @TypeOf(null) = @import("zon/none.zon");
|
|
try expectEqual(@as(u32, 10), some);
|
|
try expectEqual(@as(?u32, null), none);
|
|
try expectEqual(null, @"null");
|
|
}
|
|
|
|
test "union" {
|
|
// No tag
|
|
{
|
|
const Union = union {
|
|
x: f32,
|
|
y: bool,
|
|
z: void,
|
|
};
|
|
|
|
const union1: Union = @import("zon/union1.zon");
|
|
const union2: Union = @import("zon/union2.zon");
|
|
const union3: Union = @import("zon/union3.zon");
|
|
|
|
try expectEqual(1.5, union1.x);
|
|
try expectEqual(true, union2.y);
|
|
try expectEqual({}, union3.z);
|
|
}
|
|
|
|
// Inferred tag
|
|
{
|
|
const Union = union(enum) {
|
|
x: f32,
|
|
y: bool,
|
|
z: void,
|
|
};
|
|
|
|
const union1: Union = comptime @import("zon/union1.zon");
|
|
const union2: Union = @import("zon/union2.zon");
|
|
const union3: Union = @import("zon/union3.zon");
|
|
|
|
try expectEqual(1.5, union1.x);
|
|
try expectEqual(true, union2.y);
|
|
try expectEqual({}, union3.z);
|
|
}
|
|
|
|
// Explicit tag
|
|
{
|
|
const Tag = enum(i128) {
|
|
x = -1,
|
|
y = 2,
|
|
z = 1,
|
|
};
|
|
const Union = union(Tag) {
|
|
x: f32,
|
|
y: bool,
|
|
z: void,
|
|
};
|
|
|
|
const union1: Union = @import("zon/union1.zon");
|
|
const union2: Union = @import("zon/union2.zon");
|
|
const union3: Union = @import("zon/union3.zon");
|
|
|
|
try expectEqual(1.5, union1.x);
|
|
try expectEqual(true, union2.y);
|
|
try expectEqual({}, union3.z);
|
|
}
|
|
}
|
|
|
|
test "struct" {
|
|
const Vec0 = struct {};
|
|
const Vec1 = struct { x: f32 };
|
|
const Vec2 = struct { x: f32, y: f32 };
|
|
const Escaped = struct { @"0": f32, foo: f32 };
|
|
try expectEqual(Vec0{}, @as(Vec0, @import("zon/vec0.zon")));
|
|
try expectEqual(Vec1{ .x = 1.5 }, @as(Vec1, @import("zon/vec1.zon")));
|
|
try expectEqual(Vec2{ .x = 1.5, .y = 2 }, @as(Vec2, @import("zon/vec2.zon")));
|
|
try expectEqual(Escaped{ .@"0" = 1.5, .foo = 2 }, @as(Escaped, @import("zon/escaped_struct.zon")));
|
|
}
|
|
|
|
test "struct default fields" {
|
|
const Vec3 = struct {
|
|
x: f32,
|
|
y: f32,
|
|
z: f32 = 123.4,
|
|
};
|
|
try expectEqual(Vec3{ .x = 1.5, .y = 2.0, .z = 123.4 }, @as(Vec3, @import("zon/vec2.zon")));
|
|
const ascribed: Vec3 = @import("zon/vec2.zon");
|
|
try expectEqual(Vec3{ .x = 1.5, .y = 2.0, .z = 123.4 }, ascribed);
|
|
|
|
const Vec2 = struct {
|
|
x: f32 = 20.0,
|
|
y: f32 = 10.0,
|
|
};
|
|
try expectEqual(Vec2{ .x = 1.5, .y = 2.0 }, @as(Vec2, @import("zon/vec2.zon")));
|
|
}
|
|
|
|
test "struct enum field" {
|
|
const Struct = struct {
|
|
x: enum { x, y, z },
|
|
};
|
|
try expectEqual(Struct{ .x = .z }, @as(Struct, @import("zon/enum_field.zon")));
|
|
}
|
|
|
|
test "tuple" {
|
|
const Tuple = struct { f32, bool, []const u8, u16 };
|
|
try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
|
|
}
|
|
|
|
test "comptime fields" {
|
|
// Test setting comptime tuple fields to the correct value
|
|
{
|
|
const Tuple = struct {
|
|
comptime f32 = 1.2,
|
|
comptime bool = true,
|
|
comptime []const u8 = "hello",
|
|
comptime u16 = 3,
|
|
};
|
|
try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
|
|
}
|
|
|
|
// Test setting comptime struct fields to the correct value
|
|
{
|
|
const Vec2 = struct {
|
|
comptime x: f32 = 1.5,
|
|
comptime y: f32 = 2.0,
|
|
};
|
|
try expectEqualDeep(Vec2{}, @as(Vec2, @import("zon/vec2.zon")));
|
|
}
|
|
|
|
// Test allowing comptime tuple fields to be set to their defaults
|
|
{
|
|
const Tuple = struct {
|
|
f32,
|
|
bool,
|
|
[]const u8,
|
|
u16,
|
|
comptime u8 = 255,
|
|
};
|
|
try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
|
|
}
|
|
|
|
// Test allowing comptime struct fields to be set to their defaults
|
|
{
|
|
const Vec2 = struct {
|
|
comptime x: f32 = 1.5,
|
|
comptime y: f32 = 2.0,
|
|
};
|
|
try expectEqualDeep(Vec2{}, @as(Vec2, @import("zon/slice-empty.zon")));
|
|
}
|
|
}
|
|
|
|
test "char" {
|
|
try expectEqual(@as(u8, 'a'), @as(u8, @import("zon/a.zon")));
|
|
try expectEqual(@as(u8, 'z'), @as(u8, @import("zon/z.zon")));
|
|
}
|
|
|
|
test "arrays" {
|
|
try expectEqual([0]u8{}, @as([0]u8, @import("zon/vec0.zon")));
|
|
try expectEqual([0:1]u8{}, @as([0:1]u8, @import("zon/vec0.zon")));
|
|
try expectEqual(1, @as([0:1]u8, @import("zon/vec0.zon"))[0]);
|
|
try expectEqual([4]u8{ 'a', 'b', 'c', 'd' }, @as([4]u8, @import("zon/array.zon")));
|
|
try expectEqual([4:2]u8{ 'a', 'b', 'c', 'd' }, @as([4:2]u8, @import("zon/array.zon")));
|
|
try expectEqual(2, @as([4:2]u8, @import("zon/array.zon"))[4]);
|
|
}
|
|
|
|
test "slices, arrays, tuples" {
|
|
{
|
|
const expected_slice: []const u8 = &.{};
|
|
const found_slice: []const u8 = @import("zon/slice-empty.zon");
|
|
try expectEqualSlices(u8, expected_slice, found_slice);
|
|
|
|
const expected_array: [0]u8 = .{};
|
|
const found_array: [0]u8 = @import("zon/slice-empty.zon");
|
|
try expectEqual(expected_array, found_array);
|
|
|
|
const T = struct {};
|
|
const expected_tuple: T = .{};
|
|
const found_tuple: T = @import("zon/slice-empty.zon");
|
|
try expectEqual(expected_tuple, found_tuple);
|
|
}
|
|
|
|
{
|
|
const expected_slice: []const u8 = &.{1};
|
|
const found_slice: []const u8 = @import("zon/slice1_no_newline.zon");
|
|
try expectEqualSlices(u8, expected_slice, found_slice);
|
|
|
|
const expected_array: [1]u8 = .{1};
|
|
const found_array: [1]u8 = @import("zon/slice1_no_newline.zon");
|
|
try expectEqual(expected_array, found_array);
|
|
|
|
const T = struct { u8 };
|
|
const expected_tuple: T = .{1};
|
|
const found_tuple: T = @import("zon/slice1_no_newline.zon");
|
|
try expectEqual(expected_tuple, found_tuple);
|
|
}
|
|
|
|
{
|
|
const expected_slice: []const u8 = &.{ 'a', 'b', 'c' };
|
|
const found_slice: []const u8 = @import("zon/slice-abc.zon");
|
|
try expectEqualSlices(u8, expected_slice, found_slice);
|
|
|
|
const expected_array: [3]u8 = .{ 'a', 'b', 'c' };
|
|
const found_array: [3]u8 = @import("zon/slice-abc.zon");
|
|
try expectEqual(expected_array, found_array);
|
|
|
|
const T = struct { u8, u8, u8 };
|
|
const expected_tuple: T = .{ 'a', 'b', 'c' };
|
|
const found_tuple: T = @import("zon/slice-abc.zon");
|
|
try expectEqual(expected_tuple, found_tuple);
|
|
}
|
|
}
|
|
|
|
test "string literals" {
|
|
try expectEqualSlices(u8, "abc", @import("zon/abc.zon"));
|
|
try expectEqualSlices(u8, "ab\\c", @import("zon/abc-escaped.zon"));
|
|
const zero_terminated: [:0]const u8 = @import("zon/abc.zon");
|
|
try expectEqualDeep(zero_terminated, "abc");
|
|
try expectEqual(0, zero_terminated[zero_terminated.len]);
|
|
try expectEqualStrings(
|
|
\\Hello, world!
|
|
\\This is a multiline string!
|
|
\\ There are no escapes, we can, for example, include \n in the string
|
|
, @import("zon/multiline_string.zon"));
|
|
try expectEqualStrings("a\nb\x00c", @import("zon/string_embedded_null.zon"));
|
|
}
|
|
|
|
test "enum literals" {
|
|
const Enum = enum {
|
|
foo,
|
|
bar,
|
|
baz,
|
|
@"0\na",
|
|
};
|
|
try expectEqual(Enum.foo, @as(Enum, @import("zon/foo.zon")));
|
|
try expectEqual(.foo, @as(@TypeOf(.foo), @import("zon/foo.zon")));
|
|
try expectEqual(Enum.@"0\na", @as(Enum, @import("zon/escaped_enum.zon")));
|
|
}
|
|
|
|
test "int" {
|
|
const T = struct {
|
|
u8,
|
|
i16,
|
|
i14,
|
|
i32,
|
|
i8,
|
|
i8,
|
|
u8,
|
|
u8,
|
|
u65,
|
|
u65,
|
|
i128,
|
|
i128,
|
|
i66,
|
|
i66,
|
|
i8,
|
|
i8,
|
|
i16,
|
|
i16,
|
|
i16,
|
|
i16,
|
|
i16,
|
|
i16,
|
|
u65,
|
|
i66,
|
|
i66,
|
|
u65,
|
|
i66,
|
|
i66,
|
|
u65,
|
|
i66,
|
|
i66,
|
|
};
|
|
const expected: T = .{
|
|
// Test various numbers and types
|
|
10,
|
|
24,
|
|
-4,
|
|
-123,
|
|
|
|
// Test limits
|
|
127,
|
|
-128,
|
|
|
|
// Test characters
|
|
'a',
|
|
'z',
|
|
|
|
// Test big integers
|
|
36893488147419103231,
|
|
36893488147419103231,
|
|
-18446744073709551615, // Only a big int due to negation
|
|
-9223372036854775809, // Only a big int due to negation
|
|
|
|
// Test big integer limits
|
|
36893488147419103231,
|
|
-36893488147419103232,
|
|
|
|
// Test parsing whole number floats as integers
|
|
-1,
|
|
123,
|
|
|
|
// Test non-decimal integers
|
|
0xff,
|
|
-0xff,
|
|
0o77,
|
|
-0o77,
|
|
0b11,
|
|
-0b11,
|
|
|
|
// Test non-decimal big integers
|
|
0x1ffffffffffffffff,
|
|
0x1ffffffffffffffff,
|
|
-0x1ffffffffffffffff,
|
|
0x1ffffffffffffffff,
|
|
0x1ffffffffffffffff,
|
|
-0x1ffffffffffffffff,
|
|
0x1ffffffffffffffff,
|
|
0x1ffffffffffffffff,
|
|
-0x1ffffffffffffffff,
|
|
};
|
|
const actual: T = @import("zon/ints.zon");
|
|
try expectEqual(expected, actual);
|
|
}
|
|
|
|
test "floats" {
|
|
const T = struct {
|
|
f16,
|
|
f32,
|
|
f64,
|
|
f128,
|
|
f16,
|
|
f16,
|
|
f32,
|
|
f32,
|
|
f32,
|
|
f32,
|
|
f32,
|
|
f32,
|
|
f128,
|
|
f32,
|
|
f32,
|
|
f32,
|
|
f32,
|
|
f32,
|
|
};
|
|
const expected: T = .{
|
|
// Test decimals
|
|
0.5,
|
|
123.456,
|
|
-123.456,
|
|
42.5,
|
|
|
|
// Test whole numbers with and without decimals
|
|
5.0,
|
|
5.0,
|
|
-102,
|
|
-102,
|
|
|
|
// Test characters and negated characters
|
|
'a',
|
|
'z',
|
|
|
|
// Test big integers
|
|
36893488147419103231,
|
|
-36893488147419103231,
|
|
0x1ffffffffffffffff,
|
|
0x1ffffffffffffffff,
|
|
|
|
// Exponents, underscores
|
|
123.0E+77,
|
|
|
|
// Hexadecimal
|
|
0x103.70p-5,
|
|
-0x103.70,
|
|
0x1234_5678.9ABC_CDEFp-10,
|
|
};
|
|
const actual: T = @import("zon/floats.zon");
|
|
try expectEqual(expected, actual);
|
|
}
|
|
|
|
test "inf and nan" {
|
|
// f32
|
|
{
|
|
const actual: struct { f32, f32, f32 } = @import("zon/inf_and_nan.zon");
|
|
try expect(std.math.isNan(actual[0]));
|
|
try expect(std.math.isPositiveInf(actual[1]));
|
|
try expect(std.math.isNegativeInf(actual[2]));
|
|
}
|
|
|
|
// f128
|
|
{
|
|
const actual: struct { f128, f128, f128 } = @import("zon/inf_and_nan.zon");
|
|
try expect(std.math.isNan(actual[0]));
|
|
try expect(std.math.isPositiveInf(actual[1]));
|
|
try expect(std.math.isNegativeInf(actual[2]));
|
|
}
|
|
}
|
|
|
|
test "vector" {
|
|
{
|
|
const actual: @Vector(0, bool) = @import("zon/vec0.zon");
|
|
const expected: @Vector(0, bool) = .{};
|
|
try expectEqual(expected, actual);
|
|
}
|
|
{
|
|
const actual: @Vector(3, bool) = @import("zon/vec3_bool.zon");
|
|
const expected: @Vector(3, bool) = .{ false, false, true };
|
|
try expectEqual(expected, actual);
|
|
}
|
|
|
|
{
|
|
const actual: @Vector(0, f32) = @import("zon/vec0.zon");
|
|
const expected: @Vector(0, f32) = .{};
|
|
try expectEqual(expected, actual);
|
|
}
|
|
{
|
|
const actual: @Vector(3, f32) = @import("zon/vec3_float.zon");
|
|
const expected: @Vector(3, f32) = .{ 1.5, 2.5, 3.5 };
|
|
try expectEqual(expected, actual);
|
|
}
|
|
|
|
{
|
|
const actual: @Vector(0, u8) = @import("zon/vec0.zon");
|
|
const expected: @Vector(0, u8) = .{};
|
|
try expectEqual(expected, actual);
|
|
}
|
|
{
|
|
const actual: @Vector(3, u8) = @import("zon/vec3_int.zon");
|
|
const expected: @Vector(3, u8) = .{ 2, 4, 6 };
|
|
try expectEqual(expected, actual);
|
|
}
|
|
|
|
{
|
|
const actual: @Vector(0, *const u8) = @import("zon/vec0.zon");
|
|
const expected: @Vector(0, *const u8) = .{};
|
|
try expectEqual(expected, actual);
|
|
}
|
|
{
|
|
const actual: @Vector(3, *const u8) = @import("zon/vec3_int.zon");
|
|
const expected: @Vector(3, *const u8) = .{ &2, &4, &6 };
|
|
try expectEqual(expected, actual);
|
|
}
|
|
|
|
{
|
|
const actual: @Vector(0, ?*const u8) = @import("zon/vec0.zon");
|
|
const expected: @Vector(0, ?*const u8) = .{};
|
|
try expectEqual(expected, actual);
|
|
}
|
|
{
|
|
const actual: @Vector(3, ?*const u8) = @import("zon/vec3_int_opt.zon");
|
|
const expected: @Vector(3, ?*const u8) = .{ &2, null, &6 };
|
|
try expectEqual(expected, actual);
|
|
}
|
|
}
|
|
|
|
test "pointers" {
|
|
// Primitive with varying levels of pointers
|
|
try expectEqual(@as(u8, 'a'), @as(*const u8, @import("zon/a.zon")).*);
|
|
try expectEqual(@as(u8, 'a'), @as(*const *const u8, @import("zon/a.zon")).*.*);
|
|
try expectEqual(@as(u8, 'a'), @as(*const *const *const u8, @import("zon/a.zon")).*.*.*);
|
|
|
|
// Primitive optional with varying levels of pointers
|
|
try expectEqual(@as(u8, 'a'), @as(?*const u8, @import("zon/a.zon")).?.*);
|
|
try expectEqual(null, @as(?*const u8, @import("zon/none.zon")));
|
|
|
|
try expectEqual(@as(u8, 'a'), @as(*const ?u8, @import("zon/a.zon")).*.?);
|
|
try expectEqual(null, @as(*const ?u8, @import("zon/none.zon")).*);
|
|
|
|
try expectEqual(@as(u8, 'a'), @as(?*const *const u8, @import("zon/a.zon")).?.*.*);
|
|
try expectEqual(null, @as(?*const *const u8, @import("zon/none.zon")));
|
|
|
|
try expectEqual(@as(u8, 'a'), @as(*const ?*const u8, @import("zon/a.zon")).*.?.*);
|
|
try expectEqual(null, @as(*const ?*const u8, @import("zon/none.zon")).*);
|
|
|
|
try expectEqual(@as(u8, 'a'), @as(*const *const ?u8, @import("zon/a.zon")).*.*.?);
|
|
try expectEqual(null, @as(*const *const ?u8, @import("zon/none.zon")).*.*);
|
|
|
|
try expectEqual([3]u8{ 2, 4, 6 }, @as(*const [3]u8, @import("zon/vec3_int.zon")).*);
|
|
|
|
// A complicated type with nested internal pointers and string allocations
|
|
{
|
|
const Inner = struct {
|
|
f1: *const ?*const []const u8,
|
|
f2: *const ?*const []const u8,
|
|
};
|
|
const Outer = struct {
|
|
f1: *const ?*const Inner,
|
|
f2: *const ?*const Inner,
|
|
};
|
|
const expected: Outer = .{
|
|
.f1 = &&.{
|
|
.f1 = &null,
|
|
.f2 = &&"foo",
|
|
},
|
|
.f2 = &null,
|
|
};
|
|
|
|
const found: ?*const Outer = @import("zon/complex.zon");
|
|
try std.testing.expectEqualDeep(expected, found.?.*);
|
|
}
|
|
}
|
|
|
|
test "recursive" {
|
|
const Recursive = struct { foo: ?*const @This() };
|
|
const expected: Recursive = .{ .foo = &.{ .foo = null } };
|
|
try expectEqualDeep(expected, @as(Recursive, @import("zon/recursive.zon")));
|
|
}
|
|
|
|
test "anon" {
|
|
const expected = .{
|
|
.{
|
|
.bool_true = true,
|
|
.bool_false = false,
|
|
.string = "foo",
|
|
},
|
|
.{
|
|
null,
|
|
10,
|
|
36893488147419103232,
|
|
1.234,
|
|
'z',
|
|
.bar,
|
|
.{},
|
|
},
|
|
};
|
|
|
|
const actual = @import("zon/anon.zon");
|
|
try expectEqual(expected.len, actual.len);
|
|
try expectEqual(expected[1], actual[1]);
|
|
const expected_struct = expected[0];
|
|
const actual_struct = actual[0];
|
|
const expected_fields = @typeInfo(@TypeOf(expected_struct)).@"struct".fields;
|
|
const actual_fields = @typeInfo(@TypeOf(actual_struct)).@"struct".fields;
|
|
try expectEqual(expected_fields.len, actual_fields.len);
|
|
inline for (expected_fields) |field| {
|
|
try expectEqual(@field(expected_struct, field.name), @field(actual_struct, field.name));
|
|
}
|
|
}
|
|
|
|
test "build.zig.zon" {
|
|
const build = @import("zon/build.zig.zon");
|
|
|
|
try expectEqual(4, @typeInfo(@TypeOf(build)).@"struct".fields.len);
|
|
try expectEqualStrings("temp", build.name);
|
|
try expectEqualStrings("0.0.0", build.version);
|
|
|
|
const dependencies = build.dependencies;
|
|
try expectEqual(2, @typeInfo(@TypeOf(dependencies)).@"struct".fields.len);
|
|
|
|
const example_0 = dependencies.example_0;
|
|
try expectEqual(2, @typeInfo(@TypeOf(dependencies)).@"struct".fields.len);
|
|
try expectEqualStrings("https://example.com/foo.tar.gz", example_0.url);
|
|
try expectEqualStrings("...", example_0.hash);
|
|
|
|
const example_1 = dependencies.example_1;
|
|
try expectEqual(2, @typeInfo(@TypeOf(dependencies)).@"struct".fields.len);
|
|
try expectEqualStrings("../foo", example_1.path);
|
|
try expectEqual(false, example_1.lazy);
|
|
|
|
try expectEqual(.{ "build.zig", "build.zig.zon", "src" }, build.paths);
|
|
}
|