Search code examples
unit-testingtemplatesmetaprogrammingd

Testing function signatures with ParameterTypeTuple


I'm writing a module with mixin templates to supply a main function for unit-testing purposes. Usage is as follows:

/* For modules without their own main, e.g. libraries.
 * main is conditionally supplied using version(unittest).
 */
mixin Main;

/* For executable modules defining function "realMain".
 * Generated main has the same signature and return type
 * as realMain, and transfers control to it.  Additionally,
 * main exits without calling realMain for version (unittest).
 */
mixin Main!realMain;

The idea is that every module of mine mixes in main appropriately, so that:

  • Libraries don't need --main passed to rdmd, because
  • There seems no good way to decide not to pass --main for modules that define their own, when automatically running unit tests for every file in a directory hierarchy -- the exit code from rdmd is the same as for a failed compile.

I'm using std.traits to determine realMain's validity as a main function, and ensure that my generated main has the same signature. Everything seems to be working, but I think it could be cleaner. Currently, my template for checking valid main arguments looks like this:

template isMainArgTypes(alias main)
{
    static if (is(ParameterTypeTuple!main == TypeTuple!()))
        enum isMainArgTypes = true;
    else static if (ParameterTypeTuple!main.length == 1
        && is(ParameterTypeTuple!main[0] T : const T[]))
    {
        enum isMainArgTypes = is(T : const char[]);
    }
    else
        enum isMainArgTypes = false;
}

I feel sure there must be some way to condense the middle condition into a single is expression, without explicitly testing the tuple length and separately checking for a string type, but so far my nascent metaprogramming-fu has fallen short.

Any ideas, D wizards?


Solution

  • You could try comparing it to a function type:

    enum isMainArgTypes = is(typeof(&main) == int function()) || 
                          is(typeof(&main) == void function()) || 
                          is(typeof(&main) == int function(string[])) || 
                          is(typeof(&main) == void function(string[]));
    

    No shorter but it looks cleaner as it needs no static if