On Monday, 9 February 2015 at 01:41:33 UTC, Walter Bright wrote:
More and more, D code is written as a component that takes a
type parameters that are ranges. Unit testing becomes
inconvenient, as types must be mocked up to call them. Using an
array of data often is inadequate, because the component may
have specializations for an array, or specifies a range that is
a subset of what an array provides.
For example, here's a test range I wrote once for a unittest:
struct Adapter
{
this(ubyte[] r) { this.r = r; }
@property bool empty() { return r.length == 0; }
@property ubyte front() { return r[0]; }
void popFront() { r = r[1 .. $]; }
@property size_t length() { return r.length; }
private:
ubyte[] r;
}
I propose a std.test.ranges package, which contains templates
defining each of the range types (InputRange,
BiDirectionalRange, etc.). Each accepts an argument which is a
static array of T, and then implements exactly the range
interface indicated by its name, nothing more. The range will
also have asserts to guarantee they are used correctly, i.e.
front() cannot be called before empty() returns false.
Great idea. It might even be better to split the two concerns:
Mock ranges taking the static array as data and testing wrappers
that enforce correct usage of wrapped ranges.
So that I can
TokenRange lex() { ... } // returns a range of token
// check that the TokenRange is a valid forward range
testIsForwardRange!TokenRange
// parser
auto parse(TR)(TR r) { ... }
// normal use
auto result = parse(lex());
// testing that parse uses the TR correctly
auto result = parse(assertingForwardRange(lex()));
This way it's easier to craft input for testing the correctness
of parse.