Feasible Idea?: Range Tester

Nick Sabalausky SeeWebsiteToContactMe at semitwist.com
Thu Mar 21 11:43:25 PDT 2013


On Thu, 21 Mar 2013 11:04:31 -0700
"H. S. Teoh" <hsteoh at quickfur.ath.cx> wrote:
>
> > - Calling popFront and then front returns the next element.
> 
> How do you know if something is the "next element"? What if the range
> is repeat(1)?
> 
> 
> > - If range has length, then 'empty' returns true IFF popFront has
> > been called at least 'myRange.length' times.
> 
> This should also be easy to test. But it requires the ability to
> instantiate the range with some given number of elements. So you still
> need a range-specific function to create the range in the first place.
> 

What I had in mind was something like:

void testForwardRange(R, E)(R range, E[] content)
{
    // Deliberately not contraints, because this *is* a test, after all.
    // *Or* maybe it just auto-detects range type and leaves it
    // up to the user to check for "isForwardRange!R" or whatever.
    static assert(isForwardRange!R);
    static assert(is(ElementTypeOf!R == E));

    static if(hasLength!R)
        assert(range.length == content.length);
    
    foreach(i; 0...content.length)
    {
        assert(range.front == content[i]);
        range.popFront();
    }

    // More tests
}

unittest{
    testForwardRange(createMyRangeSomehow(), [...expected elements...]);
}


> 
> > - Calling popFront on an empty range throws a RangeError.
> 
> Is this part of the official requirement on ranges? I've been guilty
> of writing ranges whose popFront are no-ops when the range is empty
> (simply because for some ranges, it's a pain to explicitly check for
> this and throw, when the popFront computation doesn't actually assume
> anything about emptiness).
> 

Actually, I'm not sure on that one. I would think that calling
front on an empty range should throw. Or at least in a typical
well-behaved range it should, even if it's not specifically stated as
being technically mandatory. But in any case, it was only an example.

> 
> > - Iterating via back/popBack yields the same elements as
> >   front/popFront, but in reverse order.
> 
> Doesn't work on infinite ranges. :) (You *can* have infinite ranges
> with two ends. There's no good reason to do that, of course, because
> they are effectively just two infinite forward ranges stuck together
> at their infinite ends, which is kinda pointless, but in theory, this
> *can* happen.)
> 

Naturally, the testing would be different on different types of ranges.
The tester could auto-detect things like "isInfiniteRage" and
"hasLength", and act accordingly.

And of course, if you want to guarantee your range is indeed, for
example, a "hasLength", then you can also just add "static
assert(hasLength!MyRange);" alongside your call to the tester.



More information about the Digitalmars-d mailing list