summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/tanya/algorithm/tests/comparison.d97
-rw-r--r--tests/tanya/algorithm/tests/iteration.d127
-rw-r--r--tests/tanya/algorithm/tests/mutation.d128
-rw-r--r--tests/tanya/algorithm/tests/searching.d17
-rw-r--r--tests/tanya/async/tests/loop.d97
-rw-r--r--tests/tanya/container/tests/array.d196
-rw-r--r--tests/tanya/container/tests/buffer.d17
-rw-r--r--tests/tanya/container/tests/entry.d17
-rw-r--r--tests/tanya/container/tests/hashtable.d133
-rw-r--r--tests/tanya/container/tests/list.d120
-rw-r--r--tests/tanya/container/tests/set.d155
-rw-r--r--tests/tanya/container/tests/string.d121
12 files changed, 1225 insertions, 0 deletions
diff --git a/tests/tanya/algorithm/tests/comparison.d b/tests/tanya/algorithm/tests/comparison.d
new file mode 100644
index 0000000..5bd561a
--- /dev/null
+++ b/tests/tanya/algorithm/tests/comparison.d
@@ -0,0 +1,97 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.algorithm.tests.comparison;
+
+import tanya.algorithm.comparison;
+import tanya.math;
+import tanya.range;
+
+@nogc nothrow pure @safe unittest
+{
+ static assert(!is(typeof(min(1, 1UL))));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ assert(min(5, 3) == 3);
+ assert(min(4, 4) == 4);
+ assert(min(5.2, 3.0) == 3.0);
+
+ assert(min(5.2, double.nan) == 5.2);
+ assert(min(double.nan, 3.0) == 3.0);
+ assert(isNaN(min(double.nan, double.nan)));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ assert(min(cast(ubyte[]) []).empty);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ static assert(!is(typeof(max(1, 1UL))));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ assert(max(5, 3) == 5);
+ assert(max(4, 4) == 4);
+ assert(max(5.2, 3.0) == 5.2);
+
+ assert(max(5.2, double.nan) == 5.2);
+ assert(max(double.nan, 3.0) == 3.0);
+ assert(isNaN(max(double.nan, double.nan)));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ assert(max(cast(ubyte[]) []).empty);
+}
+
+// min/max compare const and mutable structs.
+@nogc nothrow pure @safe unittest
+{
+ static struct S
+ {
+ int s;
+
+ int opCmp(typeof(this) that) const @nogc nothrow pure @safe
+ {
+ return this.s - that.s;
+ }
+ }
+ {
+ const s1 = S(1);
+ assert(min(s1, S(2)).s == 1);
+ assert(max(s1, S(2)).s == 2);
+ }
+ {
+ auto s2 = S(2), s3 = S(3);
+ assert(min(s2, s3).s == 2);
+ assert(max(s2, s3).s == 3);
+ }
+}
+
+@nogc nothrow pure @safe unittest
+{
+ static struct OpCmp(int value)
+ {
+ int opCmp(OpCmp) @nogc nothrow pure @safe
+ {
+ return value;
+ }
+ }
+ {
+ OpCmp!(-1)[1] range;
+ assert(compare(range[], range[]) < 0);
+ }
+ {
+ OpCmp!1[1] range;
+ assert(compare(range[], range[]) > 0);
+ }
+ {
+ OpCmp!0[1] range;
+ assert(compare(range[], range[]) == 0);
+ }
+}
diff --git a/tests/tanya/algorithm/tests/iteration.d b/tests/tanya/algorithm/tests/iteration.d
new file mode 100644
index 0000000..52e99b3
--- /dev/null
+++ b/tests/tanya/algorithm/tests/iteration.d
@@ -0,0 +1,127 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.algorithm.tests.iteration;
+
+import tanya.algorithm.iteration;
+import tanya.range;
+import tanya.test.stub;
+
+// length is unknown when taking from a range without length
+@nogc nothrow pure @safe unittest
+{
+ static struct R
+ {
+ mixin InputRangeStub;
+ }
+ auto actual = take(R(), 100);
+
+ static assert(!hasLength!(typeof(actual)));
+}
+
+// Takes minimum length if the range length > n
+@nogc nothrow pure @safe unittest
+{
+ auto range = take(cast(int[]) null, 8);
+ assert(range.length == 0);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ const int[9] range = [1, 2, 3, 4, 5, 6, 7, 8, 9];
+ {
+ auto slice = take(range[], 8)[1 .. 3];
+
+ assert(slice.length == 2);
+ assert(slice.front == 2);
+ assert(slice.back == 3);
+ }
+ {
+ auto slice = takeExactly(range[], 8)[1 .. 3];
+
+ assert(slice.length == 2);
+ assert(slice.front == 2);
+ assert(slice.back == 3);
+ }
+}
+
+// Elements are accessible in reverse order
+@nogc nothrow pure @safe unittest
+{
+ const int[3] given = [1, 2, 3];
+ auto actual = retro(given[]);
+
+ assert(actual.back == given[].front);
+ assert(actual[0] == 3);
+ assert(actual[2] == 1);
+
+ actual.popBack();
+ assert(actual.back == 2);
+ assert(actual[1] == 2);
+
+ // Check slicing.
+ auto slice = retro(given[])[1 .. $];
+ assert(slice.length == 2 && slice.front == 2 && slice.back == 1);
+}
+
+// Elements can be assigned
+@nogc nothrow pure @safe unittest
+{
+ int[4] given = [1, 2, 3, 4];
+ auto actual = retro(given[]);
+
+ actual.front = 5;
+ assert(given[].back == 5);
+
+ actual.back = 8;
+ assert(given[].front == 8);
+
+ actual[2] = 10;
+ assert(given[1] == 10);
+}
+
+// Singleton range is bidirectional and random-access
+@nogc nothrow pure @safe unittest
+{
+ static assert(isBidirectionalRange!(typeof(singleton('a'))));
+ static assert(isRandomAccessRange!(typeof(singleton('a'))));
+
+ assert({ char a; return isBidirectionalRange!(typeof(singleton(a))); });
+ assert({ char a; return isRandomAccessRange!(typeof(singleton(a))); });
+}
+
+@nogc nothrow pure @safe unittest
+{
+ char a = 'a';
+ auto single = singleton(a);
+
+ assert(single.front == 'a');
+ assert(single.back == 'a');
+ assert(single[0] == 'a');
+ assert(single.length == 1);
+ assert(!single.empty);
+}
+
+// popFront makes SingletonByRef empty
+@nogc nothrow pure @safe unittest
+{
+ char a = 'a';
+ auto single = singleton(a);
+
+ single.popFront();
+ assert(single.empty);
+ assert(single.length == 0);
+ assert(single.empty);
+}
+
+// popBack makes SingletonByRef empty
+@nogc nothrow pure @safe unittest
+{
+ char a = 'b';
+ auto single = singleton(a);
+
+ single.popBack();
+ assert(single.empty);
+ assert(single.length == 0);
+ assert(single.empty);
+}
diff --git a/tests/tanya/algorithm/tests/mutation.d b/tests/tanya/algorithm/tests/mutation.d
new file mode 100644
index 0000000..5d98233
--- /dev/null
+++ b/tests/tanya/algorithm/tests/mutation.d
@@ -0,0 +1,128 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.algorithm.tests.mutation;
+
+import tanya.algorithm.mutation;
+import tanya.range;
+import tanya.test.stub;
+
+// Returns advanced target
+@nogc nothrow pure @safe unittest
+{
+ int[5] input = [1, 2, 3, 4, 5];
+ assert(copy(input[3 .. 5], input[]).front == 3);
+}
+
+// Copies overlapping arrays
+@nogc nothrow pure @safe unittest
+{
+ import tanya.algorithm.comparison : equal;
+
+ int[6] actual = [1, 2, 3, 4, 5, 6];
+ const int[6] expected = [1, 2, 1, 2, 3, 4];
+
+ copy(actual[0 .. 4], actual[2 .. 6]);
+ assert(equal(actual[], expected[]));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(typeof(copy((ubyte[]).init, (ushort[]).init))));
+ static assert(!is(typeof(copy((ushort[]).init, (ubyte[]).init))));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ static struct OutPutRange
+ {
+ int value;
+
+ void opCall(int value) @nogc nothrow pure @safe
+ in (this.value == 0)
+ {
+ this.value = value;
+ }
+ }
+ int[1] source = [5];
+ OutPutRange target;
+
+ assert(copy(source[], target).value == 5);
+}
+
+// [] is called where possible
+@nogc nothrow pure @system unittest
+{
+ static struct Slice
+ {
+ bool* slicingCalled;
+
+ int front() @nogc nothrow pure @safe
+ {
+ return 0;
+ }
+
+ void front(int) @nogc nothrow pure @safe
+ {
+ }
+
+ void popFront() @nogc nothrow pure @safe
+ {
+ }
+
+ bool empty() @nogc nothrow pure @safe
+ {
+ return true;
+ }
+
+ void opIndexAssign(int) @nogc nothrow pure @safe
+ {
+ *this.slicingCalled = true;
+ }
+ }
+ bool slicingCalled;
+ auto range = Slice(&slicingCalled);
+ fill(range, 0);
+ assert(slicingCalled);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ NonCopyable[] nonCopyable;
+ initializeAll(nonCopyable);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ import tanya.algorithm.comparison : equal;
+
+ const int[5] expected = [1, 2, 3, 4, 5];
+ int[5] actual = [4, 5, 1, 2, 3];
+
+ rotate(actual[0 .. 2], actual[2 .. $]);
+ assert(equal(actual[], expected[]));
+}
+
+// Doesn't cause an infinite loop if back is shorter than the front
+@nogc nothrow pure @safe unittest
+{
+ import tanya.algorithm.comparison : equal;
+
+ const int[5] expected = [1, 2, 3, 4, 5];
+ int[5] actual = [3, 4, 5, 1, 2];
+
+ rotate(actual[0 .. 3], actual[3 .. $]);
+ assert(equal(actual[], expected[]));
+}
+
+// Doesn't call .front on an empty front
+@nogc nothrow pure @safe unittest
+{
+ import tanya.algorithm.comparison : equal;
+
+ const int[2] expected = [2, 8];
+ int[2] actual = expected;
+
+ rotate(actual[0 .. 0], actual[]);
+ assert(equal(actual[], expected[]));
+}
diff --git a/tests/tanya/algorithm/tests/searching.d b/tests/tanya/algorithm/tests/searching.d
new file mode 100644
index 0000000..ca8fdb0
--- /dev/null
+++ b/tests/tanya/algorithm/tests/searching.d
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.algorithm.tests.searching;
+
+import tanya.algorithm.searching;
+import tanya.test.stub;
+
+@nogc nothrow pure @safe unittest
+{
+ @Count(3)
+ static struct Range
+ {
+ mixin InputRangeStub!int;
+ }
+ assert(count(Range()) == 3);
+}
diff --git a/tests/tanya/async/tests/loop.d b/tests/tanya/async/tests/loop.d
new file mode 100644
index 0000000..60841b1
--- /dev/null
+++ b/tests/tanya/async/tests/loop.d
@@ -0,0 +1,97 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.async.tests.loop;
+
+import core.time;
+import tanya.async.loop;
+import tanya.async.watcher;
+import tanya.memory;
+
+private final class DummyWatcher : Watcher
+{
+ bool invoked;
+
+ override void invoke() @nogc
+ {
+ this.invoked = true;
+ }
+}
+
+private final class TestLoop : Loop
+{
+ override protected bool reify(SocketWatcher watcher,
+ EventMask oldEvents,
+ EventMask events) @nogc
+ {
+ return true;
+ }
+
+ override protected void poll() @nogc
+ {
+ assert(!this.done);
+ unloop();
+ }
+
+ override protected @property uint maxEvents()
+ const pure nothrow @safe @nogc
+ {
+ return 64U;
+ }
+
+ @nogc @system unittest
+ {
+ auto loop = defaultAllocator.make!TestLoop;
+ assert(loop.blockTime == 1.dur!"minutes");
+
+ loop.blockTime = 2.dur!"minutes";
+ assert(loop.blockTime == 2.dur!"minutes");
+
+ defaultAllocator.dispose(loop);
+ }
+
+ @nogc @system unittest
+ {
+ auto loop = defaultAllocator.make!TestLoop;
+ assert(loop.done);
+
+ loop.run();
+ assert(loop.done);
+
+ defaultAllocator.dispose(loop);
+ }
+
+ @nogc @system unittest
+ {
+ auto loop = defaultAllocator.make!TestLoop;
+ auto watcher = defaultAllocator.make!DummyWatcher;
+ loop.pendings.insertBack(watcher);
+
+ assert(!watcher.invoked);
+ loop.run();
+ assert(watcher.invoked);
+
+ defaultAllocator.dispose(loop);
+ defaultAllocator.dispose(watcher);
+ }
+}
+
+@nogc @system unittest
+{
+ auto loop = defaultAllocator.make!TestLoop;
+ assert(loop.maxEvents == 64);
+
+ defaultAllocator.dispose(loop);
+}
+
+@nogc @system unittest
+{
+ auto oldLoop = defaultLoop;
+ auto loop = defaultAllocator.make!TestLoop;
+
+ defaultLoop = loop;
+ assert(defaultLoop is loop);
+
+ defaultLoop = oldLoop;
+ defaultAllocator.dispose(loop);
+}
diff --git a/tests/tanya/container/tests/array.d b/tests/tanya/container/tests/array.d
new file mode 100644
index 0000000..f551fb9
--- /dev/null
+++ b/tests/tanya/container/tests/array.d
@@ -0,0 +1,196 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.container.tests.array;
+
+import tanya.algorithm.comparison;
+import tanya.container.array;
+import tanya.memory;
+import tanya.test.stub;
+
+// const arrays return usable ranges
+@nogc nothrow pure @safe unittest
+{
+ auto v = const Array!int([1, 2, 4]);
+ auto r1 = v[];
+
+ assert(r1.back == 4);
+ r1.popBack();
+ assert(r1.back == 2);
+ r1.popBack();
+ assert(r1.back == 1);
+ r1.popBack();
+ assert(r1.length == 0);
+
+ static assert(!is(typeof(r1[0] = 5)));
+ static assert(!is(typeof(v[0] = 5)));
+
+ const r2 = r1[];
+ static assert(is(typeof(r2[])));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Array!int v1;
+ const Array!int v2;
+
+ auto r1 = v1[];
+ auto r2 = v1[];
+
+ assert(r1.length == 0);
+ assert(r2.empty);
+ assert(r1 == r2);
+
+ v1.insertBack([1, 2, 4]);
+ assert(v1[] == v1);
+ assert(v2[] == v2);
+ assert(v2[] != v1);
+ assert(v1[] != v2);
+ assert(v1[].equal(v1[]));
+ assert(v2[].equal(v2[]));
+ assert(!v1[].equal(v2[]));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ struct MutableEqualsStruct
+ {
+ bool opEquals(typeof(this) that) @nogc nothrow pure @safe
+ {
+ return true;
+ }
+ }
+ struct ConstEqualsStruct
+ {
+ bool opEquals(const typeof(this) that) const @nogc nothrow pure @safe
+ {
+ return true;
+ }
+ }
+ auto v1 = Array!ConstEqualsStruct();
+ auto v2 = Array!ConstEqualsStruct();
+ assert(v1 == v2);
+ assert(v1[] == v2);
+ assert(v1 == v2[]);
+ assert(v1[].equal(v2[]));
+
+ auto v3 = const Array!ConstEqualsStruct();
+ auto v4 = const Array!ConstEqualsStruct();
+ assert(v3 == v4);
+ assert(v3[] == v4);
+ assert(v3 == v4[]);
+ assert(v3[].equal(v4[]));
+
+ auto v7 = Array!MutableEqualsStruct(1, MutableEqualsStruct());
+ auto v8 = Array!MutableEqualsStruct(1, MutableEqualsStruct());
+ assert(v7 == v8);
+ assert(v7[] == v8);
+ assert(v7 == v8[]);
+ assert(v7[].equal(v8[]));
+}
+
+// Destructor can destroy empty arrays
+@nogc nothrow pure @safe unittest
+{
+ auto v = Array!WithDtor();
+}
+
+@nogc nothrow pure @safe unittest
+{
+ class A
+ {
+ }
+ A a1, a2;
+ auto v1 = Array!A([a1, a2]);
+
+ static assert(is(Array!(A*)));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto v = Array!int([5, 15, 8]);
+ {
+ size_t i;
+
+ foreach (e; v)
+ {
+ assert(i != 0 || e == 5);
+ assert(i != 1 || e == 15);
+ assert(i != 2 || e == 8);
+ ++i;
+ }
+ assert(i == 3);
+ }
+ {
+ size_t i = 3;
+
+ foreach_reverse (e; v)
+ {
+ --i;
+ assert(i != 2 || e == 8);
+ assert(i != 1 || e == 15);
+ assert(i != 0 || e == 5);
+ }
+ assert(i == 0);
+ }
+}
+
+// const constructor tests
+@nogc nothrow pure @safe unittest
+{
+ auto v1 = const Array!int([1, 2, 3]);
+ auto v2 = Array!int(v1);
+ assert(v1.get !is v2.get);
+ assert(v1 == v2);
+
+ auto v3 = const Array!int(Array!int([1, 2, 3]));
+ assert(v1 == v3);
+ assert(v3.length == 3);
+ assert(v3.capacity == 3);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto v1 = Array!int(defaultAllocator);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Array!int v;
+ auto r = v[];
+ assert(r.length == 0);
+ assert(r.empty);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto v1 = const Array!int([5, 15, 8]);
+ Array!int v2;
+ v2 = v1[0 .. 2];
+ assert(equal(v1[0 .. 2], v2[]));
+}
+
+// Move assignment
+@nogc nothrow pure @safe unittest
+{
+ Array!int v1;
+ v1 = Array!int([5, 15, 8]);
+}
+
+// Postblit is safe
+@nogc nothrow pure @safe unittest
+{
+ auto array = Array!int(3);
+ void func(Array!int arg)
+ {
+ assert(arg.capacity == 3);
+ }
+ func(array);
+}
+
+// Can have non-copyable elements
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(Array!NonCopyable));
+ static assert(is(typeof({ Array!NonCopyable.init[0] = NonCopyable(); })));
+}
diff --git a/tests/tanya/container/tests/buffer.d b/tests/tanya/container/tests/buffer.d
new file mode 100644
index 0000000..7071976
--- /dev/null
+++ b/tests/tanya/container/tests/buffer.d
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.container.tests.buffer;
+
+import tanya.container.buffer;
+
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(ReadBuffer!int));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(typeof(WriteBuffer!int(5))));
+}
+
diff --git a/tests/tanya/container/tests/entry.d b/tests/tanya/container/tests/entry.d
new file mode 100644
index 0000000..e4a13c1
--- /dev/null
+++ b/tests/tanya/container/tests/entry.d
@@ -0,0 +1,17 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.container.tests.entry;
+
+import tanya.container.entry;
+import tanya.test.stub;
+
+// Can be constructed with non-copyable key/values
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(Bucket!NonCopyable));
+ static assert(is(Bucket!(NonCopyable, NonCopyable)));
+
+ static assert(is(HashArray!((ref NonCopyable) => 0U, NonCopyable)));
+ static assert(is(HashArray!((ref NonCopyable) => 0U, NonCopyable, NonCopyable)));
+}
diff --git a/tests/tanya/container/tests/hashtable.d b/tests/tanya/container/tests/hashtable.d
new file mode 100644
index 0000000..98c9c53
--- /dev/null
+++ b/tests/tanya/container/tests/hashtable.d
@@ -0,0 +1,133 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.container.tests.hashtable;
+
+import tanya.container.hashtable;
+import tanya.test.stub;
+
+@nogc nothrow pure @safe unittest
+{
+ import tanya.range.primitive : isForwardRange;
+ static assert(is(HashTable!(string, int) a));
+ static assert(is(const HashTable!(string, int)));
+ static assert(isForwardRange!(HashTable!(string, int).Range));
+
+ static assert(is(HashTable!(int, int, (ref const int) => size_t.init)));
+ static assert(is(HashTable!(int, int, (int) => size_t.init)));
+}
+
+// Constructs by reference
+@nogc nothrow pure @safe unittest
+{
+ auto hashTable1 = HashTable!(string, int)(7);
+ auto hashTable2 = HashTable!(string, int)(hashTable1);
+ assert(hashTable1.length == hashTable2.length);
+ assert(hashTable1.capacity == hashTable2.capacity);
+}
+
+// Constructs by value
+@nogc nothrow pure @safe unittest
+{
+ auto hashTable = HashTable!(string, int)(HashTable!(string, int)(7));
+ assert(hashTable.capacity == 7);
+}
+
+// Assigns by reference
+@nogc nothrow pure @safe unittest
+{
+ auto hashTable1 = HashTable!(string, int)(7);
+ HashTable!(string, int) hashTable2;
+ hashTable1 = hashTable2;
+ assert(hashTable1.length == hashTable2.length);
+ assert(hashTable1.capacity == hashTable2.capacity);
+}
+
+// Assigns by value
+@nogc nothrow pure @safe unittest
+{
+ HashTable!(string, int) hashTable;
+ hashTable = HashTable!(string, int)(7);
+ assert(hashTable.capacity == 7);
+}
+
+// Postblit copies
+@nogc nothrow pure @safe unittest
+{
+ auto hashTable = HashTable!(string, int)(7);
+ void testFunc(HashTable!(string, int) hashTable)
+ {
+ assert(hashTable.capacity == 7);
+ }
+ testFunc(hashTable);
+}
+
+// Issue 53: https://github.com/caraus-ecms/tanya/issues/53
+@nogc nothrow pure @safe unittest
+{
+ {
+ HashTable!(uint, uint) hashTable;
+ foreach (uint i; 0 .. 14)
+ {
+ hashTable[i + 1] = i;
+ }
+ assert(hashTable.length == 14);
+ }
+ {
+ HashTable!(int, int) hashtable;
+
+ hashtable[1194250162] = 3;
+ hashtable[-1131293824] = 6;
+ hashtable[838100082] = 9;
+
+ hashtable.rehash(11);
+
+ assert(hashtable[-1131293824] == 6);
+ }
+}
+
+@nogc nothrow pure @safe unittest
+{
+ static struct String
+ {
+ bool opEquals(string) const @nogc nothrow pure @safe
+ {
+ return true;
+ }
+
+ bool opEquals(ref const string) const @nogc nothrow pure @safe
+ {
+ return true;
+ }
+
+ bool opEquals(String) const @nogc nothrow pure @safe
+ {
+ return true;
+ }
+
+ bool opEquals(ref const String) const @nogc nothrow pure @safe
+ {
+ return true;
+ }
+
+ size_t toHash() const @nogc nothrow pure @safe
+ {
+ return 0;
+ }
+ }
+ static assert(is(typeof("asdf" in HashTable!(String, int)())));
+ static assert(is(typeof(HashTable!(String, int)()["asdf"])));
+}
+
+// Can have non-copyable keys and elements
+@nogc nothrow pure @safe unittest
+{
+ @NonCopyable @Hashable
+ static struct S
+ {
+ mixin StructStub;
+ }
+ static assert(is(HashTable!(S, int)));
+ static assert(is(HashTable!(int, S)));
+ static assert(is(HashTable!(S, S)));
+}
diff --git a/tests/tanya/container/tests/list.d b/tests/tanya/container/tests/list.d
new file mode 100644
index 0000000..58fb34e
--- /dev/null
+++ b/tests/tanya/container/tests/list.d
@@ -0,0 +1,120 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.container.tests.list;
+
+import tanya.container.list;
+import tanya.test.stub;
+
+@nogc nothrow pure @safe unittest
+{
+ interface Stuff
+ {
+ }
+ static assert(is(SList!Stuff));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto l = SList!int(0, 0);
+ assert(l.empty);
+}
+
+// foreach called using opIndex().
+@nogc nothrow pure @safe unittest
+{
+ SList!int l;
+ size_t i;
+
+ l.insertFront(5);
+ l.insertFront(4);
+ l.insertFront(9);
+ foreach (e; l)
+ {
+ assert(i != 0 || e == 9);
+ assert(i != 1 || e == 4);
+ assert(i != 2 || e == 5);
+ ++i;
+ }
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto l1 = SList!int();
+ auto l2 = SList!int([9, 4]);
+ l1 = l2[];
+ assert(l1 == l2);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ class A
+ {
+ }
+ static assert(is(SList!(A*)));
+ static assert(is(DList!(A*)));
+}
+
+// Removes all elements
+@nogc nothrow pure @safe unittest
+{
+ auto l = DList!int([5]);
+ assert(l.remove(l[]).empty);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto l1 = DList!int([5, 234, 30, 1]);
+ auto l2 = DList!int([5, 1]);
+ auto r = l1[];
+
+ r.popFront();
+ r.popBack();
+ assert(r.front == 234);
+ assert(r.back == 30);
+
+ assert(!l1.remove(r).empty);
+ assert(l1 == l2);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto l = DList!int(0, 0);
+ assert(l.empty);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ DList!int l;
+ l.insertAfter(l[], 234);
+ assert(l.front == 234);
+ assert(l.back == 234);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto l1 = DList!int();
+ auto l2 = DList!int([9, 4]);
+ l1 = l2[];
+ assert(l1 == l2);
+}
+
+// Sets the new head
+@nogc nothrow pure @safe unittest
+{
+ auto l1 = DList!int([5, 234, 30, 1]);
+ auto l2 = DList!int([1]);
+ auto r = l1[];
+
+ r.popBack();
+
+ assert(!l1.remove(r).empty);
+ assert(l1 == l2);
+}
+
+// Can have non-copyable elements
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(SList!NonCopyable));
+ static assert(is(DList!NonCopyable));
+}
diff --git a/tests/tanya/container/tests/set.d b/tests/tanya/container/tests/set.d
new file mode 100644
index 0000000..187869f
--- /dev/null
+++ b/tests/tanya/container/tests/set.d
@@ -0,0 +1,155 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.container.tests.set;
+
+import tanya.container.set;
+import tanya.memory;
+import tanya.test.stub;
+
+// Basic insertion logic.
+@nogc nothrow pure @safe unittest
+{
+ Set!int set;
+
+ assert(set.insert(5) == 1);
+ assert(5 in set);
+ assert(set.capacity == 3);
+
+ assert(set.insert(5) == 0);
+ assert(5 in set);
+ assert(set.capacity == 3);
+
+ assert(set.insert(9) == 1);
+ assert(9 in set);
+ assert(5 in set);
+ assert(set.capacity == 3);
+
+ assert(set.insert(7) == 1);
+ assert(set.insert(8) == 1);
+ assert(8 in set);
+ assert(5 in set);
+ assert(9 in set);
+ assert(7 in set);
+ assert(set.capacity == 7);
+
+ assert(set.insert(16) == 1);
+ assert(16 in set);
+ assert(set.capacity == 7);
+}
+
+// Static checks.
+@nogc nothrow pure @safe unittest
+{
+ import tanya.range.primitive;
+
+ static assert(isBidirectionalRange!(Set!int.ConstRange));
+ static assert(isBidirectionalRange!(Set!int.Range));
+
+ static assert(!isInfinite!(Set!int.Range));
+ static assert(!hasLength!(Set!int.Range));
+
+ static assert(is(Set!uint));
+ static assert(is(Set!long));
+ static assert(is(Set!ulong));
+ static assert(is(Set!short));
+ static assert(is(Set!ushort));
+ static assert(is(Set!bool));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ const Set!int set;
+ assert(set[].empty);
+}
+
+@nogc nothrow pure @safe unittest
+{
+ Set!int set;
+ set.insert(8);
+
+ auto r1 = set[];
+ auto r2 = r1.save();
+
+ r1.popFront();
+ assert(r1.empty);
+
+ r2.popBack();
+ assert(r2.empty);
+}
+
+// Initial capacity is 0.
+@nogc nothrow pure @safe unittest
+{
+ auto set = Set!int(defaultAllocator);
+ assert(set.capacity == 0);
+}
+
+// Capacity is set to a prime.
+@nogc nothrow pure @safe unittest
+{
+ auto set = Set!int(8);
+ assert(set.capacity == 13);
+}
+
+// Constructs by reference
+@nogc nothrow pure @safe unittest
+{
+ auto set1 = Set!int(7);
+ auto set2 = Set!int(set1);
+ assert(set1.length == set2.length);
+ assert(set1.capacity == set2.capacity);
+}
+
+// Constructs by value
+@nogc nothrow pure @safe unittest
+{
+ auto set = Set!int(Set!int(7));
+ assert(set.capacity == 7);
+}
+
+// Assigns by reference
+@nogc nothrow pure @safe unittest
+{
+ auto set1 = Set!int(7);
+ Set!int set2;
+ set1 = set2;
+ assert(set1.length == set2.length);
+ assert(set1.capacity == set2.capacity);
+}
+
+// Assigns by value
+@nogc nothrow pure @safe unittest
+{
+ Set!int set;
+ set = Set!int(7);
+ assert(set.capacity == 7);
+}
+
+// Postblit copies
+@nogc nothrow pure @safe unittest
+{
+ auto set = Set!int(7);
+ void testFunc(Set!int set)
+ {
+ assert(set.capacity == 7);
+ }
+ testFunc(set);
+}
+
+// Hasher can take argument by ref
+@nogc nothrow pure @safe unittest
+{
+ static assert(is(Set!(int, (const ref x) => cast(size_t) x)));
+}
+
+// Can have non-copyable elements
+@nogc nothrow pure @safe unittest
+{
+ @NonCopyable @Hashable
+ static struct S
+ {
+ mixin StructStub;
+ }
+ static assert(is(Set!S));
+}
diff --git a/tests/tanya/container/tests/string.d b/tests/tanya/container/tests/string.d
new file mode 100644
index 0000000..755cf22
--- /dev/null
+++ b/tests/tanya/container/tests/string.d
@@ -0,0 +1,121 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+module tanya.container.tests.string;
+
+import tanya.container.string;
+import tanya.test.assertion;
+
+@nogc nothrow pure @safe unittest
+{
+ auto s = String(0, 'K');
+ assert(s.length == 0);
+}
+
+// Allocates enough space for 3-byte character.
+@nogc pure @safe unittest
+{
+ String s;
+ s.insertBack('\u8100');
+}
+
+@nogc pure @safe unittest
+{
+ assertThrown!UTFException(() => String(1, cast(dchar) 0xd900));
+ assertThrown!UTFException(() => String(1, cast(wchar) 0xd900));
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto s1 = String("Buttercup");
+ auto s2 = String("Cap");
+ s2[] = s1[6 .. $];
+ assert(s2 == "cup");
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto s1 = String("Wow");
+ s1[] = 'a';
+ assert(s1 == "aaa");
+}
+
+@nogc nothrow pure @safe unittest
+{
+ auto s1 = String("ö");
+ s1[] = "oe";
+ assert(s1 == "oe");
+}
+
+// Postblit works
+@nogc nothrow pure @safe unittest
+{
+ void internFunc(String arg)
+ {
+ }
+ void middleFunc(S...)(S args)
+ {
+ foreach (arg; args)
+ {
+ internFunc(arg);
+ }
+ }
+ void topFunc(String args)
+ {
+ middleFunc(args);
+ }
+ topFunc(String("asdf"));
+}
+
+// Const range produces mutable ranges
+@nogc pure @safe unittest
+{
+ auto s = const String("И снизу лед, и сверху - маюсь между.");
+ {
+ const constRange = s[];
+
+ auto fromConstRange = constRange[];
+ fromConstRange.popFront();
+ assert(fromConstRange.front == s[1]);
+
+ fromConstRange = constRange[0 .. $];
+ fromConstRange.popFront();
+ assert(fromConstRange.front == s[1]);
+
+ assert(constRange.get() is s.get());
+ }
+ {
+ const constRange = s.byCodePoint();
+
+ auto fromConstRange = constRange[];
+ fromConstRange.popFront();
+ assert(fromConstRange.front == ' ');
+ }
+}
+
+// Can pop multibyte characters
+@nogc pure @safe unittest
+{
+ auto s = String("\U00024B62\U00002260");
+ auto range = s.byCodePoint();
+
+ range.popFront();
+ assert(!range.empty);
+
+ range.popFront();
+ assert(range.empty);
+
+ range = s.byCodePoint();
+ range.popFront();
+ s[$ - 3] = 0xf0;
+ assertThrown!UTFException(&(range.popFront));
+}
+
+// Inserts own char range correctly
+@nogc nothrow pure @safe unittest
+{
+ auto s1 = String(`ü`);
+ String s2;
+ s2.insertBack(s1[]);
+ assert(s1 == s2);
+}