How can one reliably run unittests

jfondren julian.fondren at gmail.com
Thu Aug 26 11:32:06 UTC 2021


On Thursday, 26 August 2021 at 09:38:54 UTC, deadalnix wrote:
> The root of the problem, really, is that I don't cares about 
> main when running unit tests. I don't want to know if it is 
> there or not, I don't want it to run, nothing. If the compiler 
> needs one to link under the hood, then good for it, but this is 
> an implementation detail.

OK. Create a bugzilla issue. There are some related bugs that 
someone might want to fix at the same time (#20340 it doesn't use 
a betterC main when -betterC is passed, #16440 it breaks with -c 
and -of).

This is about the extent of the current support, in 
src/dmd/mars.d's tryMain:

```d
     if (params.addMain)
         files.push("__main.d");
     // Create Modules
     Modules modules = createModules(files, libmodules);
     // Read files
     // Start by "reading" the special files (__main.d, __stdin.d)
     foreach (m; modules)
     {
         if (params.addMain && m.srcfile.toString() == "__main.d")
         {
             auto data = arraydup("int main(){return 
0;}\0\0\0\0"); // need 2 trailing nulls for sentinel and 2 for 
lexer
             m.srcBuffer = new FileBuffer(cast(ubyte[]) data[0 .. 
$-4]);
         }
```

and src/dmd/glue.d:

```d
private bool onlyOneMain(Loc loc)
{
     __gshared Loc lastLoc;
     __gshared bool hasMain = false;
     if (hasMain)
     {
         const(char)* msg = "";
         if (global.params.addMain)
             msg = ", -main switch added another `main()`";
```

It's not surprising that such a lightweight implementation 
doesn't result in world-class ergonomics. It's something I use 
all the time to test individual modules at the CLI, and I'd much 
rather have this than nothing. But for bells and whistles I'd 
look to dub.

In a pinch you could write a dmd wrapper that calls dmd, sees if 
it gets a linker complaint about main, and if so calls dmd again 
with -main. An obvious performance hit, probably not that bad in 
most cases where you would consider this, but now you don't have 
care about main.

```d
#! /usr/bin/env rdmd
import std.process : execute, spawnProcess, wait;
import std.algorithm : canFind;
import std.stdio : write;

int main(string[] args) {
     auto result = execute(["dmd"] ~ args[1..$]);
     if (result.status != 0 && result.output.canFind("undefined 
reference to `main'")) {
         return spawnProcess(["dmd", "-main"] ~ args[1..$]).wait;
     }
     write(result.output);
     return result.status;
}
```

usage:

```
$ cat nomain.d
unittest {
     import std.stdio : writeln;

     writeln("no main");
}
$ cat hasmain.d
unittest {
     import std.stdio : writeln;

     writeln("has main");
}

void main() {}
$ ./automain.d -unittest -run nomain.d
no main
1 modules passed unittests
$ ./automain.d -unittest -run hasmain.d
1 modules passed unittests
has main
```


More information about the Digitalmars-d mailing list