zig/test/cases/enum.zig
2018-10-15 18:23:47 -04:00

895 lines
12 KiB
Zig

const assert = @import("std").debug.assert;
const mem = @import("std").mem;
test "enum type" {
const foo1 = Foo.{ .One = 13 };
const foo2 = Foo.{
.Two = Point.{
.x = 1234,
.y = 5678,
},
};
const bar = Bar.B;
assert(bar == Bar.B);
assert(@memberCount(Foo) == 3);
assert(@memberCount(Bar) == 4);
assert(@sizeOf(Foo) == @sizeOf(FooNoVoid));
assert(@sizeOf(Bar) == 1);
}
test "enum as return value" {
switch (returnAnInt(13)) {
Foo.One => |value| assert(value == 13),
else => unreachable,
}
}
const Point = struct.{
x: u64,
y: u64,
};
const Foo = union(enum).{
One: i32,
Two: Point,
Three: void,
};
const FooNoVoid = union(enum).{
One: i32,
Two: Point,
};
const Bar = enum.{
A,
B,
C,
D,
};
fn returnAnInt(x: i32) Foo {
return Foo.{ .One = x };
}
test "constant enum with payload" {
var empty = AnEnumWithPayload.{ .Empty = {} };
var full = AnEnumWithPayload.{ .Full = 13 };
shouldBeEmpty(empty);
shouldBeNotEmpty(full);
}
fn shouldBeEmpty(x: AnEnumWithPayload) void {
switch (x) {
AnEnumWithPayload.Empty => {},
else => unreachable,
}
}
fn shouldBeNotEmpty(x: AnEnumWithPayload) void {
switch (x) {
AnEnumWithPayload.Empty => unreachable,
else => {},
}
}
const AnEnumWithPayload = union(enum).{
Empty: void,
Full: i32,
};
const Number = enum.{
Zero,
One,
Two,
Three,
Four,
};
test "enum to int" {
shouldEqual(Number.Zero, 0);
shouldEqual(Number.One, 1);
shouldEqual(Number.Two, 2);
shouldEqual(Number.Three, 3);
shouldEqual(Number.Four, 4);
}
fn shouldEqual(n: Number, expected: u3) void {
assert(@enumToInt(n) == expected);
}
test "int to enum" {
testIntToEnumEval(3);
}
fn testIntToEnumEval(x: i32) void {
assert(@intToEnum(IntToEnumNumber, @intCast(u3, x)) == IntToEnumNumber.Three);
}
const IntToEnumNumber = enum.{
Zero,
One,
Two,
Three,
Four,
};
test "@tagName" {
assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
comptime assert(mem.eql(u8, testEnumTagNameBare(BareNumber.Three), "Three"));
}
fn testEnumTagNameBare(n: BareNumber) []const u8 {
return @tagName(n);
}
const BareNumber = enum.{
One,
Two,
Three,
};
test "enum alignment" {
comptime {
assert(@alignOf(AlignTestEnum) >= @alignOf([9]u8));
assert(@alignOf(AlignTestEnum) >= @alignOf(u64));
}
}
const AlignTestEnum = union(enum).{
A: [9]u8,
B: u64,
};
const ValueCount1 = enum.{
I0,
};
const ValueCount2 = enum.{
I0,
I1,
};
const ValueCount256 = enum.{
I0,
I1,
I2,
I3,
I4,
I5,
I6,
I7,
I8,
I9,
I10,
I11,
I12,
I13,
I14,
I15,
I16,
I17,
I18,
I19,
I20,
I21,
I22,
I23,
I24,
I25,
I26,
I27,
I28,
I29,
I30,
I31,
I32,
I33,
I34,
I35,
I36,
I37,
I38,
I39,
I40,
I41,
I42,
I43,
I44,
I45,
I46,
I47,
I48,
I49,
I50,
I51,
I52,
I53,
I54,
I55,
I56,
I57,
I58,
I59,
I60,
I61,
I62,
I63,
I64,
I65,
I66,
I67,
I68,
I69,
I70,
I71,
I72,
I73,
I74,
I75,
I76,
I77,
I78,
I79,
I80,
I81,
I82,
I83,
I84,
I85,
I86,
I87,
I88,
I89,
I90,
I91,
I92,
I93,
I94,
I95,
I96,
I97,
I98,
I99,
I100,
I101,
I102,
I103,
I104,
I105,
I106,
I107,
I108,
I109,
I110,
I111,
I112,
I113,
I114,
I115,
I116,
I117,
I118,
I119,
I120,
I121,
I122,
I123,
I124,
I125,
I126,
I127,
I128,
I129,
I130,
I131,
I132,
I133,
I134,
I135,
I136,
I137,
I138,
I139,
I140,
I141,
I142,
I143,
I144,
I145,
I146,
I147,
I148,
I149,
I150,
I151,
I152,
I153,
I154,
I155,
I156,
I157,
I158,
I159,
I160,
I161,
I162,
I163,
I164,
I165,
I166,
I167,
I168,
I169,
I170,
I171,
I172,
I173,
I174,
I175,
I176,
I177,
I178,
I179,
I180,
I181,
I182,
I183,
I184,
I185,
I186,
I187,
I188,
I189,
I190,
I191,
I192,
I193,
I194,
I195,
I196,
I197,
I198,
I199,
I200,
I201,
I202,
I203,
I204,
I205,
I206,
I207,
I208,
I209,
I210,
I211,
I212,
I213,
I214,
I215,
I216,
I217,
I218,
I219,
I220,
I221,
I222,
I223,
I224,
I225,
I226,
I227,
I228,
I229,
I230,
I231,
I232,
I233,
I234,
I235,
I236,
I237,
I238,
I239,
I240,
I241,
I242,
I243,
I244,
I245,
I246,
I247,
I248,
I249,
I250,
I251,
I252,
I253,
I254,
I255,
};
const ValueCount257 = enum.{
I0,
I1,
I2,
I3,
I4,
I5,
I6,
I7,
I8,
I9,
I10,
I11,
I12,
I13,
I14,
I15,
I16,
I17,
I18,
I19,
I20,
I21,
I22,
I23,
I24,
I25,
I26,
I27,
I28,
I29,
I30,
I31,
I32,
I33,
I34,
I35,
I36,
I37,
I38,
I39,
I40,
I41,
I42,
I43,
I44,
I45,
I46,
I47,
I48,
I49,
I50,
I51,
I52,
I53,
I54,
I55,
I56,
I57,
I58,
I59,
I60,
I61,
I62,
I63,
I64,
I65,
I66,
I67,
I68,
I69,
I70,
I71,
I72,
I73,
I74,
I75,
I76,
I77,
I78,
I79,
I80,
I81,
I82,
I83,
I84,
I85,
I86,
I87,
I88,
I89,
I90,
I91,
I92,
I93,
I94,
I95,
I96,
I97,
I98,
I99,
I100,
I101,
I102,
I103,
I104,
I105,
I106,
I107,
I108,
I109,
I110,
I111,
I112,
I113,
I114,
I115,
I116,
I117,
I118,
I119,
I120,
I121,
I122,
I123,
I124,
I125,
I126,
I127,
I128,
I129,
I130,
I131,
I132,
I133,
I134,
I135,
I136,
I137,
I138,
I139,
I140,
I141,
I142,
I143,
I144,
I145,
I146,
I147,
I148,
I149,
I150,
I151,
I152,
I153,
I154,
I155,
I156,
I157,
I158,
I159,
I160,
I161,
I162,
I163,
I164,
I165,
I166,
I167,
I168,
I169,
I170,
I171,
I172,
I173,
I174,
I175,
I176,
I177,
I178,
I179,
I180,
I181,
I182,
I183,
I184,
I185,
I186,
I187,
I188,
I189,
I190,
I191,
I192,
I193,
I194,
I195,
I196,
I197,
I198,
I199,
I200,
I201,
I202,
I203,
I204,
I205,
I206,
I207,
I208,
I209,
I210,
I211,
I212,
I213,
I214,
I215,
I216,
I217,
I218,
I219,
I220,
I221,
I222,
I223,
I224,
I225,
I226,
I227,
I228,
I229,
I230,
I231,
I232,
I233,
I234,
I235,
I236,
I237,
I238,
I239,
I240,
I241,
I242,
I243,
I244,
I245,
I246,
I247,
I248,
I249,
I250,
I251,
I252,
I253,
I254,
I255,
I256,
};
test "enum sizes" {
comptime {
assert(@sizeOf(ValueCount1) == 0);
assert(@sizeOf(ValueCount2) == 1);
assert(@sizeOf(ValueCount256) == 1);
assert(@sizeOf(ValueCount257) == 2);
}
}
const Small2 = enum(u2).{
One,
Two,
};
const Small = enum(u2).{
One,
Two,
Three,
Four,
};
test "set enum tag type" {
{
var x = Small.One;
x = Small.Two;
comptime assert(@TagType(Small) == u2);
}
{
var x = Small2.One;
x = Small2.Two;
comptime assert(@TagType(Small2) == u2);
}
}
const A = enum(u3).{
One,
Two,
Three,
Four,
One2,
Two2,
Three2,
Four2,
};
const B = enum(u3).{
One3,
Two3,
Three3,
Four3,
One23,
Two23,
Three23,
Four23,
};
const C = enum(u2).{
One4,
Two4,
Three4,
Four4,
};
const BitFieldOfEnums = packed struct.{
a: A,
b: B,
c: C,
};
const bit_field_1 = BitFieldOfEnums.{
.a = A.Two,
.b = B.Three3,
.c = C.Four4,
};
test "bit field access with enum fields" {
var data = bit_field_1;
assert(getA(&data) == A.Two);
assert(getB(&data) == B.Three3);
assert(getC(&data) == C.Four4);
comptime assert(@sizeOf(BitFieldOfEnums) == 1);
data.b = B.Four3;
assert(data.b == B.Four3);
data.a = A.Three;
assert(data.a == A.Three);
assert(data.b == B.Four3);
}
fn getA(data: *const BitFieldOfEnums) A {
return data.a;
}
fn getB(data: *const BitFieldOfEnums) B {
return data.b;
}
fn getC(data: *const BitFieldOfEnums) C {
return data.c;
}
test "casting enum to its tag type" {
testCastEnumToTagType(Small2.Two);
comptime testCastEnumToTagType(Small2.Two);
}
fn testCastEnumToTagType(value: Small2) void {
assert(@enumToInt(value) == 1);
}
const MultipleChoice = enum(u32).{
A = 20,
B = 40,
C = 60,
D = 1000,
};
test "enum with specified tag values" {
testEnumWithSpecifiedTagValues(MultipleChoice.C);
comptime testEnumWithSpecifiedTagValues(MultipleChoice.C);
}
fn testEnumWithSpecifiedTagValues(x: MultipleChoice) void {
assert(@enumToInt(x) == 60);
assert(1234 == switch (x) {
MultipleChoice.A => 1,
MultipleChoice.B => 2,
MultipleChoice.C => u32(1234),
MultipleChoice.D => 4,
});
}
const MultipleChoice2 = enum(u32).{
Unspecified1,
A = 20,
Unspecified2,
B = 40,
Unspecified3,
C = 60,
Unspecified4,
D = 1000,
Unspecified5,
};
test "enum with specified and unspecified tag values" {
testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2.D);
}
fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
assert(@enumToInt(x) == 1000);
assert(1234 == switch (x) {
MultipleChoice2.A => 1,
MultipleChoice2.B => 2,
MultipleChoice2.C => 3,
MultipleChoice2.D => u32(1234),
MultipleChoice2.Unspecified1 => 5,
MultipleChoice2.Unspecified2 => 6,
MultipleChoice2.Unspecified3 => 7,
MultipleChoice2.Unspecified4 => 8,
MultipleChoice2.Unspecified5 => 9,
});
}
test "cast integer literal to enum" {
assert(@intToEnum(MultipleChoice2, 0) == MultipleChoice2.Unspecified1);
assert(@intToEnum(MultipleChoice2, 40) == MultipleChoice2.B);
}
const EnumWithOneMember = enum.{
Eof,
};
fn doALoopThing(id: EnumWithOneMember) void {
while (true) {
if (id == EnumWithOneMember.Eof) {
break;
}
@compileError("above if condition should be comptime");
}
}
test "comparison operator on enum with one member is comptime known" {
doALoopThing(EnumWithOneMember.Eof);
}
const State = enum.{
Start,
};
test "switch on enum with one member is comptime known" {
var state = State.Start;
switch (state) {
State.Start => return,
}
@compileError("analysis should not reach here");
}
const EnumWithTagValues = enum(u4).{
A = 1 << 0,
B = 1 << 1,
C = 1 << 2,
D = 1 << 3,
};
test "enum with tag values don't require parens" {
assert(@enumToInt(EnumWithTagValues.C) == 0b0100);
}
test "enum with 1 field but explicit tag type should still have the tag type" {
const Enum = enum(u8).{
B = 2,
};
comptime @import("std").debug.assert(@sizeOf(Enum) == @sizeOf(u8));
}
test "empty extern enum with members" {
const E = extern enum.{
A,
B,
C,
};
assert(@sizeOf(E) == @sizeOf(c_int));
}
test "aoeu" {
const LocalFoo = enum.{
A = 1,
B = 0,
};
var b = LocalFoo.B;
assert(mem.eql(u8, @tagName(b), "B"));
}