On Friday, 30 July 2021 at 01:01:02 UTC, Brian Tiffin wrote:
Is this good, bad or indifferent (a right left choice, first one doesn't matter)?
I think you're opening yourself up to errors where some program state persists from one run of main to another. You could think that some set of flags works fine because it tests OK, but then it doesn't work at the CLI with fresh state. This seems more appropriate for an external tester, which could also run multiple mains in parallel to save on time, etc.
But you could also have a smarter test runner instead of a magic unittest, https://dlang.org/spec/traits.html#getUnitTests has an example of replacing the built-in test runner. That could exit before main for you, or fork and run CLI tests in a separate process (even if just to avoid persistent state, with the parent just waiting for the child to finish).
Quick example of that: ```d module udatest; struct testCLI { } unittest { // unrelated test assert(true); } @testCLI unittest { main(["exe", "world"]); } @testCLI unittest { main(["exe", "note: static int wasn't altered"]); } unittest { import std.exception : enforce; main(["exe"]); enforce(false, new Exception("dummy")); } @testCLI unittest { main(["exe", "up to main#2 now"]); } version (unittest) { bool tester() { import std.meta : AliasSeq, Filter; import std.traits : getUDAs; import core.sys.posix.unistd : fork; import core.sys.posix.sys.wait : waitpid; import core.sys.posix.stdlib : _Exit; import std.stdio; alias cli = AliasSeq!(__traits(getUnitTests, udatest)); static foreach (i; 0 .. cli.length) { writefln!"Test %d/%d"(i + 1, cli.length); try { if (getUDAs!(cli[i], testCLI).length) { if (auto child = fork) { int res; assert(-1 != waitpid(child, &res, 0)); assert(res == 0); } else { cli[i](); stdout.flush; stderr.flush; _Exit(0); } } else cli[i](); } catch (Exception e) { writeln(e); } } return false; } shared static this() { import core.runtime : Runtime; Runtime.moduleUnitTester = &tester; } } void main(string[] args) { import std.stdio : writefln; static int n = 0; writefln!"main#%d called with %s"(++n, args[1 .. $]); } ```