summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/tanya/memory/tests/mmappool.d27
-rw-r--r--tests/tanya/tests/bitmanip.d54
-rw-r--r--tests/tanya/tests/conv.d206
-rw-r--r--tests/tanya/tests/format.d269
-rw-r--r--tests/tanya/tests/typecons.d238
5 files changed, 767 insertions, 27 deletions
diff --git a/tests/tanya/memory/tests/mmappool.d b/tests/tanya/memory/tests/mmappool.d
index cdfee8a..adef1ab 100644
--- a/tests/tanya/memory/tests/mmappool.d
+++ b/tests/tanya/memory/tests/mmappool.d
@@ -19,23 +19,6 @@ import tanya.memory.mmappool;
@nogc nothrow pure @system unittest
{
- // allocate() check.
- size_t tooMuchMemory = size_t.max
- - MmapPool.alignment_
- - BlockEntry.sizeof * 2
- - RegionEntry.sizeof
- - pageSize;
- assert(MmapPool.instance.allocate(tooMuchMemory) is null);
-
- assert(MmapPool.instance.allocate(size_t.max) is null);
-
- // initializeRegion() check.
- tooMuchMemory = size_t.max - MmapPool.alignment_;
- assert(MmapPool.instance.allocate(tooMuchMemory) is null);
-}
-
-@nogc nothrow pure @system unittest
-{
auto p = MmapPool.instance.allocate(20);
assert(MmapPool.instance.deallocate(p));
@@ -93,16 +76,6 @@ import tanya.memory.mmappool;
MmapPool.instance.deallocate(p);
}
-@nogc nothrow pure @system unittest
-{
- assert(instance is instance);
-}
-
-@nogc nothrow pure @system unittest
-{
- assert(MmapPool.instance.alignment == MmapPool.alignment_);
-}
-
// A lot of allocations/deallocations, but it is the minimum caused a
// segmentation fault because MmapPool reallocateInPlace moves a block wrong.
@nogc nothrow pure @system unittest
diff --git a/tests/tanya/tests/bitmanip.d b/tests/tanya/tests/bitmanip.d
new file mode 100644
index 0000000..06d71f8
--- /dev/null
+++ b/tests/tanya/tests/bitmanip.d
@@ -0,0 +1,54 @@
+module tanya.tests.bitmanip;
+
+import tanya.bitmanip;
+
+// Casts to a boolean
+@nogc nothrow pure @safe unittest
+{
+ assert(BitFlags!One(One.one));
+ assert(!BitFlags!One());
+}
+
+// Assigns to and compares with a single value
+@nogc nothrow pure @safe unittest
+{
+ BitFlags!One bitFlags;
+ bitFlags = One.one;
+ assert(bitFlags == One.one);
+}
+
+// Assigns to and compares with the same type
+@nogc nothrow pure @safe unittest
+{
+ auto bitFlags1 = BitFlags!One(One.one);
+ BitFlags!One bitFlags2;
+ bitFlags2 = bitFlags1;
+ assert(bitFlags1 == bitFlags2);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ assert((BitFlags!One() | One.one) == BitFlags!One(One.one));
+ assert((BitFlags!One() | BitFlags!One(One.one)) == BitFlags!One(One.one));
+
+ assert(!(BitFlags!One() & BitFlags!One(One.one)));
+
+ assert(!(BitFlags!One(One.one) ^ One.one));
+ assert(BitFlags!One() ^ BitFlags!One(One.one));
+
+ assert(~BitFlags!One());
+
+ assert(BitFlags!One().toHash() == 0);
+ assert(BitFlags!One(One.one).toHash() != 0);
+}
+
+// opBinaryRight is allowed
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(typeof({ One.one | BitFlags!One(); })));
+}
+
+private enum One : int
+{
+ one = 1,
+}
diff --git a/tests/tanya/tests/conv.d b/tests/tanya/tests/conv.d
new file mode 100644
index 0000000..2b8e76d
--- /dev/null
+++ b/tests/tanya/tests/conv.d
@@ -0,0 +1,206 @@
+module tanya.tests.conv;
+
+import tanya.conv;
+import tanya.range;
+import tanya.test.assertion;
+import tanya.test.stub;
+
+// ':' is not a hex value
+@nogc nothrow pure @safe unittest
+{
+ string colon = ":";
+ auto actual = readIntegral!ubyte(colon, 16);
+ assert(actual == 0);
+ assert(colon.length == 1);
+}
+
+// reads ubyte.max
+@nogc nothrow pure @safe unittest
+{
+ string number = "255";
+ assert(readIntegral!ubyte(number) == 255);
+ assert(number.empty);
+}
+
+// detects integer overflow
+@nogc nothrow pure @safe unittest
+{
+ string number = "500";
+ readIntegral!ubyte(number);
+ assert(number.front == '0');
+ assert(number.length == 1);
+}
+
+// stops on a non-digit
+@nogc nothrow pure @safe unittest
+{
+ string number = "10-";
+ readIntegral!ubyte(number);
+ assert(number.front == '-');
+}
+
+// returns false if the number string is empty
+@nogc nothrow pure @safe unittest
+{
+ string number = "";
+ readIntegral!ubyte(number);
+ assert(number.empty);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ string number = "29";
+ assert(readIntegral!ubyte(number) == 29);
+ assert(number.empty);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ string number = "25467";
+ readIntegral!ubyte(number);
+ assert(number.front == '6');
+}
+
+// Converts lower case hexadecimals
+@nogc nothrow pure @safe unittest
+{
+ string number = "a";
+ assert(readIntegral!ubyte(number, 16) == 10);
+ assert(number.empty);
+}
+
+// Converts upper case hexadecimals
+@nogc nothrow pure @safe unittest
+{
+ string number = "FF";
+ assert(readIntegral!ubyte(number, 16) == 255);
+ assert(number.empty);
+}
+
+// Handles small overflows
+@nogc nothrow pure @safe unittest
+{
+ string number = "256";
+ assert(readIntegral!ubyte(number, 10) == 25);
+ assert(number.front == '6');
+}
+
+@nogc nothrow pure @safe unittest
+{
+ int val = 5;
+ assert(val.to!int() == 5);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ // ubyte -> ushort
+ assert((cast(ubyte) 0).to!ushort == 0);
+ assert((cast(ubyte) 1).to!ushort == 1);
+ assert((cast(ubyte) (ubyte.max - 1)).to!ushort == ubyte.max - 1);
+ assert((cast(ubyte) ubyte.max).to!ushort == ubyte.max);
+
+ // ubyte -> short
+ assert((cast(ubyte) 0).to!short == 0);
+ assert((cast(ubyte) 1).to!short == 1);
+ assert((cast(ubyte) (ubyte.max - 1)).to!short == ubyte.max - 1);
+ assert((cast(ubyte) ubyte.max).to!short == ubyte.max);
+}
+
+@nogc pure @safe unittest
+{
+ // ubyte <- ushort
+ assert((cast(ushort) 0).to!ubyte == 0);
+ assert((cast(ushort) 1).to!ubyte == 1);
+ assert((cast(ushort) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
+ assert((cast(ushort) ubyte.max).to!ubyte == ubyte.max);
+
+ // ubyte <- short
+ assert((cast(short) 0).to!ubyte == 0);
+ assert((cast(short) 1).to!ubyte == 1);
+ assert((cast(short) (ubyte.max - 1)).to!ubyte == ubyte.max - 1);
+ assert((cast(short) ubyte.max).to!ubyte == ubyte.max);
+
+ // short <-> int
+ assert(short.min.to!int == short.min);
+ assert((short.min + 1).to!int == short.min + 1);
+ assert((cast(short) -1).to!int == -1);
+ assert((cast(short) 0).to!int == 0);
+ assert((cast(short) 1).to!int == 1);
+ assert((short.max - 1).to!int == short.max - 1);
+ assert(short.max.to!int == short.max);
+
+ assert((cast(int) short.min).to!short == short.min);
+ assert((cast(int) short.min + 1).to!short == short.min + 1);
+ assert((cast(int) -1).to!short == -1);
+ assert((cast(int) 0).to!short == 0);
+ assert((cast(int) 1).to!short == 1);
+ assert((cast(int) short.max - 1).to!short == short.max - 1);
+ assert((cast(int) short.max).to!short == short.max);
+
+ // uint <-> int
+ assert((cast(uint) 0).to!int == 0);
+ assert((cast(uint) 1).to!int == 1);
+ assert((cast(uint) (int.max - 1)).to!int == int.max - 1);
+ assert((cast(uint) int.max).to!int == int.max);
+
+ assert((cast(int) 0).to!uint == 0);
+ assert((cast(int) 1).to!uint == 1);
+ assert((cast(int) (int.max - 1)).to!uint == int.max - 1);
+ assert((cast(int) int.max).to!uint == int.max);
+}
+
+@nogc pure @safe unittest
+{
+ assertThrown!ConvException(&to!(short, int), int.min);
+ assertThrown!ConvException(&to!(short, int), int.max);
+ assertThrown!ConvException(&to!(ushort, uint), uint.max);
+ assertThrown!ConvException(&to!(uint, int), -1);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ enum Test : int
+ {
+ one,
+ two,
+ }
+ assert(Test.one.to!int == 0);
+ assert(Test.two.to!int == 1);
+}
+
+@nogc pure @safe unittest
+{
+ assertThrown!ConvException(&to!(int, double), 2147483647.5);
+ assertThrown!ConvException(&to!(int, double), -2147483648.5);
+ assertThrown!ConvException(&to!(uint, double), -21474.5);
+}
+
+@nogc pure @safe unittest
+{
+ enum Test : uint
+ {
+ one,
+ two,
+ }
+ assertThrown!ConvException(&to!(Test, int), 5);
+}
+
+@nogc pure @safe unittest
+{
+ assertThrown!ConvException(&to!(bool, int), -1);
+ assertThrown!ConvException(&to!(bool, int), 2);
+}
+
+@nogc pure @safe unittest
+{
+ assertThrown!ConvException(() => "1".to!bool);
+}
+
+@nogc pure @safe unittest
+{
+ assertThrown!ConvException(() => "".to!int);
+ assertThrown!ConvException(() => "-".to!int);
+ assertThrown!ConvException(() => "-5".to!uint);
+ assertThrown!ConvException(() => "-129".to!byte);
+ assertThrown!ConvException(() => "256".to!ubyte);
+}
diff --git a/tests/tanya/tests/format.d b/tests/tanya/tests/format.d
new file mode 100644
index 0000000..b4a019d
--- /dev/null
+++ b/tests/tanya/tests/format.d
@@ -0,0 +1,269 @@
+module tanya.tests.format;
+
+import tanya.format;
+import tanya.range;
+
+// Converting an integer to string.
+@nogc nothrow pure @system unittest
+{
+ char[21] buf;
+
+ assert(integral2String(80, buf) == "80");
+ assert(integral2String(-80, buf) == "-80");
+ assert(integral2String(0, buf) == "0");
+ assert(integral2String(uint.max, buf) == "4294967295");
+ assert(integral2String(int.min, buf) == "-2147483648");
+}
+
+// Doesn't print the first argument repeatedly
+@nogc nothrow pure @safe unittest
+{
+ assert(format!"{}{}"(1, 2) == "12");
+}
+
+@nogc nothrow pure @safe unittest
+{
+ assert(format!"Without arguments"() == "Without arguments");
+ assert(format!""().length == 0);
+
+ static assert(!is(typeof(format!"{}"())));
+ static assert(!is(typeof(format!"{j}"(5))));
+}
+
+// Enum
+@nogc nothrow pure @safe unittest
+{
+ enum E1 : int
+ {
+ one,
+ two,
+ }
+ assert(format!"{}"(E1.one) == "one");
+
+ const E1 e1;
+ assert(format!"{}"(e1) == "one");
+}
+
+// Modifiers
+@nogc pure @safe unittest
+{
+ assert(format!"{}"(8.5) == "8.5");
+ assert(format!"{}"(8.6) == "8.6");
+ assert(format!"{}"(1000) == "1000");
+ assert(format!"{}"(1) == "1");
+ assert(format!"{}"(10.25) == "10.25");
+ assert(format!"{}"(1) == "1");
+ assert(format!"{}"(0.01) == "0.01");
+}
+
+// String printing
+@nogc pure @safe unittest
+{
+ assert(format!"{}"("Some weired string") == "Some weired string");
+ assert(format!"{}"(cast(string) null) == "");
+ assert(format!"{}"('c') == "c");
+}
+
+// Integer
+@nogc pure @safe unittest
+{
+ assert(format!"{}"(8) == "8");
+ assert(format!"{}"(8) == "8");
+ assert(format!"{}"(-8) == "-8");
+ assert(format!"{}"(-8L) == "-8");
+ assert(format!"{}"(8) == "8");
+ assert(format!"{}"(100000001) == "100000001");
+ assert(format!"{}"(99999999L) == "99999999");
+ assert(format!"{}"(10) == "10");
+ assert(format!"{}"(10L) == "10");
+}
+
+// Floating point
+@nogc pure @safe unittest
+{
+ assert(format!"{}"(0.1234) == "0.1234");
+ assert(format!"{}"(0.3) == "0.3");
+ assert(format!"{}"(0.333333333333) == "0.333333");
+ assert(format!"{}"(38234.1234) == "38234.1");
+ assert(format!"{}"(-0.3) == "-0.3");
+ assert(format!"{}"(0.000000000000000006) == "6e-18");
+ assert(format!"{}"(0.0) == "0");
+ assert(format!"{}"(double.init) == "NaN");
+ assert(format!"{}"(-double.init) == "-NaN");
+ assert(format!"{}"(double.infinity) == "Inf");
+ assert(format!"{}"(-double.infinity) == "-Inf");
+ assert(format!"{}"(0.000000000000000000000000003) == "3e-27");
+ assert(format!"{}"(0.23432e304) == "2.3432e+303");
+ assert(format!"{}"(-0.23432e8) == "-2.3432e+07");
+ assert(format!"{}"(1e-307) == "1e-307");
+ assert(format!"{}"(1e+8) == "1e+08");
+ assert(format!"{}"(111234.1) == "111234");
+ assert(format!"{}"(0.999) == "0.999");
+ assert(format!"{}"(0x1p-16382L) == "0");
+ assert(format!"{}"(1e+3) == "1000");
+ assert(format!"{}"(38234.1234) == "38234.1");
+ assert(format!"{}"(double.max) == "1.79769e+308");
+}
+
+// typeof(null)
+@nogc pure @safe unittest
+{
+ assert(format!"{}"(null) == "null");
+}
+
+// Boolean
+@nogc pure @safe unittest
+{
+ assert(format!"{}"(true) == "true");
+ assert(format!"{}"(false) == "false");
+}
+
+// Unsafe tests with pointers
+@nogc pure @system unittest
+{
+ // Pointer convesions
+ assert(format!"{}"(cast(void*) 1) == "0x1");
+ assert(format!"{}"(cast(void*) 20) == "0x14");
+ assert(format!"{}"(cast(void*) null) == "0x0");
+}
+
+// Structs
+@nogc pure @safe unittest
+{
+ static struct WithoutStringify1
+ {
+ int a;
+ void func()
+ {
+ }
+ }
+ assert(format!"{}"(WithoutStringify1(6)) == "WithoutStringify1(6)");
+
+ static struct WithoutStringify2
+ {
+ }
+ assert(format!"{}"(WithoutStringify2()) == "WithoutStringify2()");
+
+ static struct WithoutStringify3
+ {
+ int a = -2;
+ int b = 8;
+ }
+ assert(format!"{}"(WithoutStringify3()) == "WithoutStringify3(-2, 8)");
+
+ struct Nested
+ {
+ int i;
+
+ void func()
+ {
+ }
+ }
+ assert(format!"{}"(Nested()) == "Nested(0)");
+
+ static struct WithToString
+ {
+ OR toString(OR)(OR range) const
+ {
+ put(range, "toString method");
+ return range;
+ }
+ }
+ assert(format!"{}"(WithToString()) == "toString method");
+}
+
+// Aggregate types
+@system unittest // Object.toString has no attributes.
+{
+ import tanya.memory;
+ import tanya.memory.smartref;
+
+ interface I
+ {
+ }
+ class A : I
+ {
+ }
+ auto instance = defaultAllocator.unique!A();
+ assert(format!"{}"(instance.get()) == instance.get().toString());
+ assert(format!"{}"(cast(I) instance.get()) == I.classinfo.name);
+ assert(format!"{}"(cast(A) null) == "null");
+
+ class B
+ {
+ OR toString(OR)(OR range) const
+ {
+ put(range, "Class B");
+ return range;
+ }
+ }
+ assert(format!"{}"(cast(B) null) == "null");
+}
+
+// Unions
+unittest
+{
+ union U
+ {
+ int i;
+ char c;
+ }
+ assert(format!"{}"(U(2)) == "U");
+}
+
+// Ranges
+@nogc pure @safe unittest
+{
+ static struct Stringish
+ {
+ private string content = "Some content";
+
+ immutable(char) front() const @nogc nothrow pure @safe
+ {
+ return this.content[0];
+ }
+
+ void popFront() @nogc nothrow pure @safe
+ {
+ this.content = this.content[1 .. $];
+ }
+
+ bool empty() const @nogc nothrow pure @safe
+ {
+ return this.content.length == 0;
+ }
+ }
+ assert(format!"{}"(Stringish()) == "Some content");
+
+ static struct Intish
+ {
+ private int front_ = 3;
+
+ int front() const @nogc nothrow pure @safe
+ {
+ return this.front_;
+ }
+
+ void popFront() @nogc nothrow pure @safe
+ {
+ --this.front_;
+ }
+
+ bool empty() const @nogc nothrow pure @safe
+ {
+ return this.front == 0;
+ }
+ }
+ assert(format!"{}"(Intish()) == "[3, 2, 1]");
+}
+
+// Typeid
+nothrow pure @safe unittest
+{
+ assert(format!"{}"(typeid(int[])) == "int[]");
+
+ class C
+ {
+ }
+ assert(format!"{}"(typeid(C)) == typeid(C).toString());
+}
diff --git a/tests/tanya/tests/typecons.d b/tests/tanya/tests/typecons.d
new file mode 100644
index 0000000..c49c266
--- /dev/null
+++ b/tests/tanya/tests/typecons.d
@@ -0,0 +1,238 @@
+module tanya.tests.typecons;
+
+import tanya.test.stub;
+import tanya.typecons;
+
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(Tuple!(int, int)));
+ static assert(!is(Tuple!(int, 5)));
+
+ static assert(is(Tuple!(int, "first", int)));
+ static assert(is(Tuple!(int, "first", int, "second")));
+ static assert(is(Tuple!(int, "first", int)));
+
+ static assert(is(Tuple!(int, int, "second")));
+ static assert(!is(Tuple!("first", int, "second", int)));
+ static assert(!is(Tuple!(int, int, int)));
+
+ static assert(!is(Tuple!(int, "first")));
+
+ static assert(!is(Tuple!(int, double, char)));
+ static assert(!is(Tuple!(int, "first", double, "second", char, "third")));
+}
+
+// Assigns a new value
+@nogc nothrow pure @safe unittest
+{
+ Option!int option = 5;
+ option = 8;
+ assert(!option.isNothing);
+ assert(option == 8);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Option!int option;
+ const int newValue = 8;
+ assert(option.isNothing);
+ option = newValue;
+ assert(!option.isNothing);
+ assert(option == newValue);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Option!int option1;
+ Option!int option2 = 5;
+ assert(option1.isNothing);
+ option1 = option2;
+ assert(!option1.isNothing);
+ assert(option1.get == 5);
+}
+
+// Constructs with a value passed by reference
+@nogc nothrow pure @safe unittest
+{
+ int i = 5;
+ assert(Option!int(i).get == 5);
+}
+
+// Moving
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(typeof(Option!NonCopyable(NonCopyable()))));
+ // The value cannot be returned by reference because the default value
+ // isn't passed by reference
+ static assert(!is(typeof(Option!DisabledPostblit().or(NonCopyable()))));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ NonCopyable notCopyable;
+ static assert(is(typeof(Option!NonCopyable().or(notCopyable))));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Option!NonCopyable option;
+ assert(option.isNothing);
+ option = NonCopyable();
+ assert(!option.isNothing);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Option!NonCopyable option;
+ assert(option.isNothing);
+ option = Option!NonCopyable(NonCopyable());
+ assert(!option.isNothing);
+}
+
+// Cast to bool is done before touching the encapsulated value
+@nogc nothrow pure @safe unittest
+{
+ assert(Option!bool(false));
+}
+
+// Option can be const
+@nogc nothrow pure @safe unittest
+{
+ assert((const Option!int(5)).get == 5);
+ assert((const Option!int()).or(5) == 5);
+}
+
+// Equality
+@nogc nothrow pure @safe unittest
+{
+ assert(Option!int() == Option!int());
+ assert(Option!int(0) != Option!int());
+ assert(Option!int(5) == Option!int(5));
+ assert(Option!int(5) == 5);
+ assert(Option!int(5) == cast(ubyte) 5);
+}
+
+// Returns default value
+@nogc nothrow pure @safe unittest
+{
+ int i = 5;
+ assert(((ref e) => e)(Option!int().or(i)) == 5);
+}
+
+// Implements toHash() for nothing
+@nogc nothrow pure @safe unittest
+{
+ alias OptionT = Option!Hashable;
+ assert(OptionT().toHash() == 0U);
+ assert(OptionT(Hashable(1U)).toHash() == 1U);
+}
+
+// Can assign Option that is nothing
+@nogc nothrow pure @safe unittest
+{
+ auto option1 = Option!int(5);
+ Option!int option2;
+ option1 = option2;
+ assert(option1.isNothing);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Variant!(int, double) variant;
+ variant = 5;
+ assert(variant.peek!int);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Variant!(int, double) variant;
+ variant = 5.0;
+ assert(!variant.peek!int);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Variant!(int, double) variant = 5;
+ assert(variant.get!int == 5);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(Variant!(int, float)));
+ static assert(is(Variant!int));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ static struct WithDestructorAndCopy
+ {
+ this(this) @nogc nothrow pure @safe
+ {
+ }
+
+ ~this() @nogc nothrow pure @safe
+ {
+ }
+ }
+ static assert(is(Variant!WithDestructorAndCopy));
+}
+
+// Equality compares the underlying objects
+@nogc nothrow pure @safe unittest
+{
+ Variant!(int, double) variant1 = 5;
+ Variant!(int, double) variant2 = 5;
+ assert(variant1 == variant2);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Variant!(int, double) variant1 = 5;
+ Variant!(int, double) variant2 = 6;
+ assert(variant1 != variant2);
+}
+
+// Differently typed variants aren't equal
+@nogc nothrow pure @safe unittest
+{
+ Variant!(int, double) variant1 = 5;
+ Variant!(int, double) variant2 = 5.0;
+ assert(variant1 != variant2);
+}
+
+// Uninitialized variants are equal
+@nogc nothrow pure @safe unittest
+{
+ Variant!(int, double) variant1, variant2;
+ assert(variant1 == variant2);
+}
+
+// Calls postblit constructor of the active type
+@nogc nothrow pure @safe unittest
+{
+ static struct S
+ {
+ bool called;
+
+ this(this)
+ {
+ this.called = true;
+ }
+ }
+ Variant!(int, S) variant1 = S();
+ auto variant2 = variant1;
+ assert(variant2.get!S.called);
+}
+
+// Variant.type is null if the Variant doesn't have a value
+@nogc nothrow pure @safe unittest
+{
+ Variant!(int, uint) variant;
+ assert(variant.type is null);
+}
+
+// Variant can contain only distinct types
+@nogc nothrow pure @safe unittest
+{
+ static assert(!is(Variant!(int, int)));
+}