Separate non-documentation tests from the code
This commit is contained in:
16
test/dub.json
Normal file
16
test/dub.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "test",
|
||||
"description": "Test suite for unittest-blocks",
|
||||
"targetType": "library",
|
||||
|
||||
"dependencies": {
|
||||
"tanya:middle": "*"
|
||||
},
|
||||
|
||||
"sourcePaths": [
|
||||
"."
|
||||
],
|
||||
"importPaths": [
|
||||
"."
|
||||
]
|
||||
}
|
105
test/tanya/test/assertion.d
Normal file
105
test/tanya/test/assertion.d
Normal file
@ -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());
|
||||
}
|
18
test/tanya/test/package.d
Normal file
18
test/tanya/test/package.d
Normal file
@ -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;
|
373
test/tanya/test/stub.d
Normal file
373
test/tanya/test/stub.d
Normal file
@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user