summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/dub.json16
-rw-r--r--test/tanya/test/assertion.d105
-rw-r--r--test/tanya/test/package.d18
-rw-r--r--test/tanya/test/stub.d373
4 files changed, 512 insertions, 0 deletions
diff --git a/test/dub.json b/test/dub.json
new file mode 100644
index 0000000..292bd9d
--- /dev/null
+++ b/test/dub.json
@@ -0,0 +1,16 @@
+{
+ "name": "test",
+ "description": "Test suite for unittest-blocks",
+ "targetType": "library",
+
+ "dependencies": {
+ "tanya:middle": "*"
+ },
+
+ "sourcePaths": [
+ "."
+ ],
+ "importPaths": [
+ "."
+ ]
+}
diff --git a/test/tanya/test/assertion.d b/test/tanya/test/assertion.d
new file mode 100644
index 0000000..10105d7
--- /dev/null
+++ b/test/tanya/test/assertion.d
@@ -0,0 +1,105 @@
+/* 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/. */
+
+/**
+ * Additional assertions.
+ *
+ * This module provides functions that assert whether a given expression
+ * satisfies some complex condition, that can't be tested with
+ * $(D_KEYWORD assert) in a single line. Internally all the functions
+ * just evaluate the expression and call $(D_KEYWORD assert).
+ *
+ * The functions can cause segmentation fault if the module is compiled
+ * in production mode and the condition fails.
+ *
+ * Copyright: Eugene Wissner 2017-2018.
+ * 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)
+ * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/assertion.d,
+ * tanya/test/assertion.d)
+ */
+module tanya.test.assertion;
+
+import tanya.memory;
+import tanya.meta.trait;
+
+/**
+ * Asserts whether the function $(D_PARAM expr) throws an exception of type
+ * $(D_PARAM E). If it does, the exception is catched and properly destroyed.
+ * If it doesn't, an assertion error is thrown. If the exception doesn't match
+ * $(D_PARAM E) type, it isn't catched and escapes.
+ *
+ * Params:
+ * E = Expected exception type.
+ * T = Throwing function type.
+ * Args = Argument types of the throwing function.
+ * expr = Throwing function.
+ * args = Arguments for $(D_PARAM expr).
+ */
+void assertThrown(E : Exception, T, Args...)(T expr, auto ref Args args)
+if (isSomeFunction!T)
+{
+ try
+ {
+ cast(void) expr(args);
+ assert(false, "Expected exception not thrown");
+ }
+ catch (E exception)
+ {
+ defaultAllocator.dispose(exception);
+ }
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ // If you want to test that an expression throws, you can wrap it into an
+ // arrow function.
+ static struct CtorThrows
+ {
+ this(int i) @nogc pure @safe
+ {
+ throw defaultAllocator.make!Exception();
+ }
+ }
+ assertThrown!Exception(() => CtorThrows(8));
+}
+
+/**
+ * Asserts that the function $(D_PARAM expr) doesn't throw.
+ *
+ * If it does, the thrown exception is catched, properly destroyed and an
+ * assertion error is thrown instead.
+ *
+ * Params:
+ * T = Tested function type.
+ * Args = Argument types of $(D_PARAM expr).
+ * expr = Tested function.
+ * args = Arguments for $(D_PARAM expr).
+ */
+void assertNotThrown(T, Args...)(T expr, auto ref Args args)
+if (isSomeFunction!T)
+{
+ try
+ {
+ cast(void) expr(args);
+ }
+ catch (Exception exception)
+ {
+ defaultAllocator.dispose(exception);
+ assert(false, "Unexpected exception thrown");
+ }
+}
+
+///
+@nogc nothrow pure @safe unittest
+{
+ // If you want to test that an expression doesn't throw, you can wrap it
+ // into an arrow function.
+ static struct S
+ {
+ }
+ assertNotThrown(() => S());
+}
diff --git a/test/tanya/test/package.d b/test/tanya/test/package.d
new file mode 100644
index 0000000..ab6f861
--- /dev/null
+++ b/test/tanya/test/package.d
@@ -0,0 +1,18 @@
+/* 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/. */
+
+/**
+ * Test suite for $(D_KEYWORD unittest)-blocks.
+ *
+ * Copyright: Eugene Wissner 2017-2018.
+ * 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)
+ * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/package.d,
+ * tanya/test/package.d)
+ */
+module tanya.test;
+
+public import tanya.test.assertion;
+public import tanya.test.stub;
diff --git a/test/tanya/test/stub.d b/test/tanya/test/stub.d
new file mode 100644
index 0000000..e1f8dcb
--- /dev/null
+++ b/test/tanya/test/stub.d
@@ -0,0 +1,373 @@
+/* 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/. */
+
+/**
+ * Range and generic type generators.
+ *
+ * Copyright: Eugene Wissner 2018.
+ * 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)
+ * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/test/stub.d,
+ * tanya/test/stub.d)
+ */
+module tanya.test.stub;
+
+/**
+ * Attribute signalizing that the generated range should contain the given
+ * number of elements.
+ *
+ * $(D_PSYMBOL Count) should be always specified with some value and not as a
+ * type, so $(D_INLINECODE Count(1)) instead just $(D_INLINECODE Count),
+ * otherwise you can just omit $(D_PSYMBOL Count) and it will default to 0.
+ *
+ * $(D_PSYMBOL Count) doesn't generate `.length` property - use
+ * $(D_PSYMBOL Length) for that.
+ *
+ * If neither $(D_PSYMBOL Length) nor $(D_PSYMBOL Infinite) is given,
+ * $(D_ILNINECODE Count(0)) is assumed.
+ *
+ * This attribute conflicts with $(D_PSYMBOL Infinite) and $(D_PSYMBOL Length).
+ */
+struct Count
+{
+ /// Original range length.
+ size_t count = 0;
+
+ @disable this();
+
+ /**
+ * Constructs the attribute with the given length.
+ *
+ * Params:
+ * count = Original range length.
+ */
+ this(size_t count) @nogc nothrow pure @safe
+ {
+ this.count = count;
+ }
+}
+
+/**
+ * Attribute signalizing that the generated range should be infinite.
+ *
+ * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Length).
+ */
+struct Infinite
+{
+}
+
+/**
+ * Generates `.length` property for the range.
+ *
+ * The length of the range can be specified as a constructor argument,
+ * otherwise it is 0.
+ *
+ * This attribute conflicts with $(D_PSYMBOL Count) and $(D_PSYMBOL Infinite).
+ */
+struct Length
+{
+ /// Original range length.
+ size_t length = 0;
+}
+
+/**
+ * Attribute signalizing that the generated range should return values by
+ * reference.
+ *
+ * This atribute affects the return values of `.front`, `.back` and `[]`.
+ */
+struct WithLvalueElements
+{
+}
+
+/**
+ * Generates an input range.
+ *
+ * Params:
+ * E = Element type.
+ */
+mixin template InputRangeStub(E = int)
+{
+ import tanya.meta.metafunction : Alias;
+ import tanya.meta.trait : evalUDA, getUDAs, hasUDA;
+
+ /*
+ * Aliases for the attribute lookups to access them faster
+ */
+ private enum bool infinite = hasUDA!(typeof(this), Infinite);
+ private enum bool withLvalueElements = hasUDA!(typeof(this),
+ WithLvalueElements);
+ private alias Count = getUDAs!(typeof(this), .Count);
+ private alias Length = getUDAs!(typeof(this), .Length);
+
+ static if (Count.length != 0)
+ {
+ private enum size_t count = Count[0].count;
+
+ static assert (!infinite,
+ "Range cannot have count and be infinite at the same time");
+ static assert (Length.length == 0,
+ "Range cannot have count and length at the same time");
+ }
+ else static if (Length.length != 0)
+ {
+ private enum size_t count = evalUDA!(Length[0]).length;
+
+ static assert (!infinite,
+ "Range cannot have length and be infinite at the same time");
+ }
+ else static if (!infinite)
+ {
+ private enum size_t count = 0;
+ }
+
+ /*
+ * Member generation
+ */
+ static if (infinite)
+ {
+ enum bool empty = false;
+ }
+ else
+ {
+ private size_t length_ = count;
+
+ @property bool empty() const @nogc nothrow pure @safe
+ {
+ return this.length_ == 0;
+ }
+ }
+
+ static if (withLvalueElements)
+ {
+ private E* element; // Pointer to enable range copying in save()
+ }
+
+ void popFront() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ static if (!infinite)
+ {
+ --this.length_;
+ }
+ }
+
+ static if (withLvalueElements)
+ {
+ ref E front() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ return *this.element;
+ }
+ }
+ else
+ {
+ E front() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ return E.init;
+ }
+ }
+
+ static if (Length.length != 0)
+ {
+ size_t length() const @nogc nothrow pure @safe
+ {
+ return this.length_;
+ }
+ }
+}
+
+/**
+ * Generates a forward range.
+ *
+ * This mixin includes input range primitives as well, but can be combined with
+ * $(D_PSYMBOL RandomAccessRangeStub).
+ *
+ * Params:
+ * E = Element type.
+ */
+mixin template ForwardRangeStub(E = int)
+{
+ static if (!is(typeof(this.InputRangeMixin) == void))
+ {
+ mixin InputRangeStub!E InputRangeMixin;
+ }
+
+ auto save() @nogc nothrow pure @safe
+ {
+ return this;
+ }
+}
+
+/**
+ * Generates a bidirectional range.
+ *
+ * This mixin includes forward range primitives as well, but can be combined with
+ * $(D_PSYMBOL RandomAccessRangeStub).
+ *
+ * Params:
+ * E = Element type.
+ */
+mixin template BidirectionalRangeStub(E = int)
+{
+ mixin ForwardRangeStub!E;
+
+ void popBack() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ static if (!infinite)
+ {
+ --this.length_;
+ }
+ }
+
+ static if (withLvalueElements)
+ {
+ ref E back() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ return *this.element;
+ }
+ }
+ else
+ {
+ E back() @nogc nothrow pure @safe
+ in (!empty)
+ {
+ return E.init;
+ }
+ }
+}
+
+/**
+ * Generates a random-access range.
+ *
+ * This mixin includes input range primitives as well, but can be combined with
+ * $(D_PSYMBOL ForwardRangeStub) or $(D_PSYMBOL BidirectionalRangeStub).
+ *
+ * Note that a random-access range also requires $(D_PSYMBOL Length) or
+ * $(D_PARAM Infinite) by definition.
+ *
+ * Params:
+ * E = Element type.
+ */
+mixin template RandomAccessRangeStub(E = int)
+{
+ static if (!is(typeof(this.InputRangeMixin) == void))
+ {
+ mixin InputRangeStub!E InputRangeMixin;
+ }
+
+ static if (withLvalueElements)
+ {
+ ref E opIndex(size_t) @nogc nothrow pure @safe
+ {
+ return *this.element;
+ }
+ }
+ else
+ {
+ E opIndex(size_t) @nogc nothrow pure @safe
+ {
+ return E.init;
+ }
+ }
+}
+
+/**
+ * Struct with a disabled postblit constructor.
+ *
+ * $(D_PSYMBOL NonCopyable) can be used as an attribute for
+ * $(D_PSYMBOL StructStub) or as a standalone type.
+ */
+struct NonCopyable
+{
+ @disable this(this);
+}
+
+/**
+ * Struct with an elaborate destructor.
+ *
+ * $(D_PSYMBOL WithDtor) can be used as an attribute for
+ * $(D_PSYMBOL StructStub) or as a standalone type.
+ *
+ * When used as a standalone object the constructor of $(D_PSYMBOL WithDtor)
+ * accepts an additional `counter` argument, which is incremented by the
+ * destructor. $(D_PSYMBOL WithDtor) stores a pointer to the passed variable,
+ * so the variable can be investigated after the struct isn't available
+ * anymore.
+ */
+struct WithDtor
+{
+ size_t* counter;
+
+ this(ref size_t counter) @nogc nothrow pure @trusted
+ {
+ this.counter = &counter;
+ }
+
+ ~this() @nogc nothrow pure @safe
+ {
+ if (this.counter !is null)
+ {
+ ++*this.counter;
+ }
+ }
+}
+
+/**
+ * Struct supporting hashing.
+ *
+ * $(D_PSYMBOL Hashable) can be used as an attribute for
+ * $(D_PSYMBOL StructStub) or as a standalone type.
+ *
+ * The constructor accepts an additional parameter, which is returned by the
+ * `toHash()`-function. `0U` is returned if no hash value is given.
+ */
+struct Hashable
+{
+ size_t hash;
+
+ size_t toHash() const @nogc nothrow pure @safe
+ {
+ return this.hash;
+ }
+}
+
+/**
+ * Generates a $(D_KEYWORD struct) with common functionality.
+ *
+ * To specify the needed functionality use user-defined attributes on the
+ * $(D_KEYWORD struct) $(D_PSYMBOL StructStub) is mixed in.
+ *
+ * Supported attributes are: $(D_PSYMBOL NonCopyable), $(D_PSYMBOL Hashable),
+ * $(D_PSYMBOL WithDtor).
+ */
+mixin template StructStub()
+{
+ import tanya.meta.trait : evalUDA, getUDAs, hasUDA;
+
+ static if (hasUDA!(typeof(this), NonCopyable))
+ {
+ @disable this(this);
+ }
+
+ private alias Hashable = getUDAs!(typeof(this), .Hashable);
+ static if (Hashable.length > 0)
+ {
+ size_t toHash() const @nogc nothrow pure @safe
+ {
+ return evalUDA!(Hashable[0]).hash;
+ }
+ }
+
+ static if (hasUDA!(typeof(this), WithDtor))
+ {
+ ~this() @nogc nothrow pure @safe
+ {
+ }
+ }
+}