Liskov principle and unittest

Philippe Sigaud philippe.sigaud at gmail.com
Mon Sep 26 12:23:00 PDT 2011


On Mon, Sep 26, 2011 at 14:05, deadalnix <deadalnix at gmail.com> wrote:
>> The limitation is I'm not sure that would work for class templates
>> hierarchies.
>
> Sounds nice ! I'm pretty sure this has some limitations, but that
> definitively a step forward.
>
> I'll do some tests about that.
>
> If the getDerived isn't devellopped, then the whole stuff will fail at
> compile time, so this ok. We can be sure that tests are performed for every
> derived classes, and so, even if the devellopper of the derived class forgot
> to do unittest or don't want to.

Here is the missing code:

/** finds all local (module-level) classes */
template LocalClasses()
{
    mixin("alias TypeTuple!" ~ localClasses() ~ " LocalClasses;");
}

string localClasses()
{
    string result;
    foreach(i, symbol;mixin("__traits(allMembers, " ~ .stringof[7..$] ~ ")"))
        mixin("static if (is(" ~ symbol ~ " == class))
            result ~= symbol ~ \",\";");

    return "(" ~ result[0..$-1] ~ ")";
}

/** Given a class type, returns the local (module-level)
 children classes. */
template GetDerived(Type) if (is(Type == class))
{
    mixin("alias TypeTuple!(" ~ getDerivedFrom!Type ~ ") GetDerived;");
}

string getDerivedFrom(Type)() if (is(Type == class))
{
    string result;
    foreach(i, Class; LocalClasses!())
        static if (is(Class : Type))
            result ~=  Class.stringof ~ ",";
    return result;
}


string testDerived(Origin, alias generator)() if (is(Origin == class))
{
    alias GetDerived!Origin Children;
    string result;
    foreach(i, Child; Children)
        result ~= "unittest\n{\n" ~ generator!Child ~ "\n}\n";
    return result;
}

/** Stub unit-test, just generating a pragma(msg, ...) call */
string genUT(Type)()
{
    return "pragma(msg, \"testing for \", " ~ Type.stringof ~ ");";
}


// Usage:
class C1 {}

class C2 {}
class C3: C2 {}
class C4 : C2 {}
class C5 : C4 {}

mixin(testDerived!(C2, genUT));


This will find that C2 derived classes are C3, C4 and C5 and will
generate stub unit-tests for each of them. Not for C1, because it's
not derived from C2.

Hey, I even found a way to statically reconstitute the entire class
tree. It feels good to code in D again!

Limitations :
- not tested with multi-modules hierarchies. I know how to get the
module (not package) imports from a module name, so I could recurse on
them. But packages are problematic.
- class templates may cause problems.


More information about the Digitalmars-d mailing list