Fix MmapPool private tests; move remaining tests

This commit is contained in:
Eugen Wissner 2019-03-21 14:54:16 +01:00
parent 0fe7308a22
commit a36b51f0c3
11 changed files with 801 additions and 751 deletions

View File

@ -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"

View File

@ -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);
}

View File

@ -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).
*

View File

@ -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);
}

View File

@ -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;

View File

@ -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)));
}

View File

@ -17,23 +17,6 @@ import tanya.memory.mmappool;
assert(p.length == 0);
}
@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);
@ -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

View File

@ -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,
}

206
tests/tanya/tests/conv.d Normal file
View File

@ -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);
}

269
tests/tanya/tests/format.d Normal file
View File

@ -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());
}

View File

@ -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)));
}