summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dub.json16
-rw-r--r--middle/tanya/memory/mmappool.d17
-rw-r--r--source/tanya/bitmanip.d43
-rw-r--r--source/tanya/conv.d204
-rw-r--r--source/tanya/format.d251
-rw-r--r--source/tanya/typecons.d227
-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
11 files changed, 801 insertions, 751 deletions
diff --git a/dub.json b/dub.json
index 9883955..8a30c7b 100644
--- a/dub.json
+++ b/dub.json
@@ -52,6 +52,22 @@
},
{
"name": "unittest",
+ "versions": ["TanyaPhobos"],
+ "importPaths": [
+ "./source",
+ "./tests"
+ ],
+ "sourcePaths": [
+ "./source",
+ "./tests"
+ ]
+ },
+ {
+ "name": "unittest-native",
+ "platforms": ["linux-x86_64-gdc"],
+ "preBuildCommands": ["ninja -C arch"],
+ "lflags": ["arch/tanya.a"],
+ "versions": ["TanyaNative"],
"importPaths": [
"./source",
"./tests"
diff --git a/middle/tanya/memory/mmappool.d b/middle/tanya/memory/mmappool.d
index 05f71c6..b6cd7d0 100644
--- a/middle/tanya/memory/mmappool.d
+++ b/middle/tanya/memory/mmappool.d
@@ -501,3 +501,20 @@ final class MmapPool : Allocator
}
private alias Block = shared BlockEntry*;
}
+
+@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);
+}
diff --git a/source/tanya/bitmanip.d b/source/tanya/bitmanip.d
index 98e7042..c4526d8 100644
--- a/source/tanya/bitmanip.d
+++ b/source/tanya/bitmanip.d
@@ -5,7 +5,7 @@
/**
* Bit manipulation.
*
- * Copyright: Eugene Wissner 2018.
+ * Copyright: Eugene Wissner 2018-2019.
* License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
* Mozilla Public License, v. 2.0).
* Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
@@ -276,47 +276,6 @@ if (isBitFlagEnum!E)
}
}
-@nogc nothrow pure @safe unittest
-{
- enum E : int
- {
- one = 1,
- }
-
- // Casts to a boolean
- assert(BitFlags!E(E.one));
- assert(!BitFlags!E());
-
- // Assigns to and compares with a single value
- {
- BitFlags!E bitFlags;
- bitFlags = E.one;
- assert(bitFlags == E.one);
- }
- // Assigns to and compares with the same type
- {
- auto bitFlags1 = BitFlags!E(E.one);
- BitFlags!E bitFlags2;
- bitFlags2 = bitFlags1;
- assert(bitFlags1 == bitFlags2);
- }
- assert((BitFlags!E() | E.one) == BitFlags!E(E.one));
- assert((BitFlags!E() | BitFlags!E(E.one)) == BitFlags!E(E.one));
-
- assert(!(BitFlags!E() & BitFlags!E(E.one)));
-
- assert(!(BitFlags!E(E.one) ^ E.one));
- assert(BitFlags!E() ^ BitFlags!E(E.one));
-
- assert(~BitFlags!E());
-
- assert(BitFlags!E().toHash() == 0);
- assert(BitFlags!E(E.one).toHash() != 0);
-
- // opBinaryRight is allowed
- static assert(is(typeof({ E.one | BitFlags!E(); })));
-}
-
/**
* Creates a $(D_PSYMBOL BitFlags) object initialized with $(D_PARAM field).
*
diff --git a/source/tanya/conv.d b/source/tanya/conv.d
index 4010cb5..13e9235 100644
--- a/source/tanya/conv.d
+++ b/source/tanya/conv.d
@@ -22,12 +22,6 @@ import tanya.meta.trait;
import tanya.meta.transform;
import tanya.range;
-version (unittest)
-{
- import tanya.test.assertion;
- import tanya.test.stub;
-}
-
/**
* Thrown if a type conversion fails.
*/
@@ -143,86 +137,6 @@ do
return n;
}
-// ':' 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');
-}
-
/**
* If the source type $(D_PARAM From) and the target type $(D_PARAM To) are
* equal, does nothing. If $(D_PARAM From) can be implicitly converted to
@@ -262,12 +176,6 @@ template to(To)
static assert(is(typeof(val) == int));
}
-@nogc nothrow pure @safe unittest
-{
- int val = 5;
- assert(val.to!int() == 5);
-}
-
/**
* Performs checked conversion from an integral type $(D_PARAM From) to an
* integral type $(D_PARAM To).
@@ -330,83 +238,6 @@ if (isIntegral!From
}
}
-@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);
-}
-
/**
* Converts a floating point number to an integral type.
*
@@ -449,13 +280,6 @@ if (isFloatingPoint!From
assert(2147483646.5.to!uint == 2147483646);
}
-@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);
-}
-
/**
* Performs checked conversion from an integral type $(D_PARAM From) to an
* $(D_KEYWORD enum).
@@ -497,16 +321,6 @@ if (isIntegral!From && is(To == enum))
assert(1.to!Test == Test.two);
}
-@nogc pure @safe unittest
-{
- enum Test : uint
- {
- one,
- two,
- }
- assertThrown!ConvException(&to!(Test, int), 5);
-}
-
/**
* Converts $(D_PARAM from) to a boolean.
*
@@ -558,12 +372,6 @@ if (isNumeric!From && is(Unqual!To == bool) && !is(Unqual!To == Unqual!From))
assert(1.to!bool);
}
-@nogc pure @safe unittest
-{
- assertThrown!ConvException(&to!(bool, int), -1);
- assertThrown!ConvException(&to!(bool, int), 2);
-}
-
/// ditto
To to(To, From)(auto ref const From from)
if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool))
@@ -590,11 +398,6 @@ if ((is(From == String) || isSomeString!From) && is(Unqual!To == bool))
}
-@nogc pure @safe unittest
-{
- assertThrown!ConvException(() => "1".to!bool);
-}
-
/**
* Converts a boolean to $(D_PARAM To).
*
@@ -761,12 +564,5 @@ if (isInputRange!From && isSomeChar!(ElementType!From) && isIntegral!To)
assert("010".to!int() == 8);
assert("-010".to!int() == -8);
-
assert("-128".to!byte == cast(byte) -128);
-
- 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/source/tanya/format.d b/source/tanya/format.d
index db372c4..5c63a5e 100644
--- a/source/tanya/format.d
+++ b/source/tanya/format.d
@@ -124,18 +124,6 @@ if (isIntegral!T)
return buffer[$ - l - 1 .. $ - 1];
}
-// 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");
-}
-
private int frexp(const double x) @nogc nothrow pure @safe
{
const FloatBits!double bits = { x };
@@ -2419,245 +2407,6 @@ if (isOutputRange!(R, const(char)[]))
return output;
}
-// 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");
-}
-
-// One argument tests.
-@nogc pure @safe unittest
-{
- // Modifiers.
- 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.
- assert(format!"{}"("Some weired string") == "Some weired string");
- assert(format!"{}"(cast(string) null) == "");
- assert(format!"{}"('c') == "c");
-
- // Integer.
- 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.
- 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).
- assert(format!"{}"(null) == "null");
-
- // Boolean.
- 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());
-}
-
private struct FormatSpec
{
const size_t position;
diff --git a/source/tanya/typecons.d b/source/tanya/typecons.d
index 700e2dd..507cd3c 100644
--- a/source/tanya/typecons.d
+++ b/source/tanya/typecons.d
@@ -21,7 +21,6 @@ import tanya.format;
import tanya.memory.lifetime;
import tanya.meta.metafunction;
import tanya.meta.trait;
-version (unittest) import tanya.test.stub;
/**
* $(D_PSYMBOL Tuple) can store two or more heterogeneous objects.
@@ -117,25 +116,6 @@ template Tuple(Specs...)
assert(pair[1] == "second");
}
-@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")));
-}
-
/**
* Creates a new $(D_PSYMBOL Tuple).
*
@@ -428,112 +408,6 @@ struct Option(T)
assert(option.isNothing);
}
-// Assigns a new value
-@nogc nothrow pure @safe unittest
-{
- {
- Option!int option = 5;
- option = 8;
- assert(!option.isNothing);
- assert(option == 8);
- }
- {
- Option!int option;
- const int newValue = 8;
- assert(option.isNothing);
- option = newValue;
- assert(!option.isNothing);
- assert(option == newValue);
- }
- {
- 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()))));
- {
- NonCopyable notCopyable;
- static assert(is(typeof(Option!NonCopyable().or(notCopyable))));
- }
- {
- Option!NonCopyable option;
- assert(option.isNothing);
- option = NonCopyable();
- assert(!option.isNothing);
- }
- {
- 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);
-}
-
/**
* Creates a new $(D_PSYMBOL Option).
*
@@ -829,104 +703,3 @@ if (isTypeTuple!Specs && NoDuplicates!Specs.length == Specs.length)
assert(!variant.peek!int);
assert(variant.get!double == 5.4);
}
-
-@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)));
-}
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)));
+}