www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to iterate through all modules for use with the new getUnitTests

reply "Gary Willoughby" <dev nomad.so> writes:
As part of developing the DUnit framework i'm looking into 
executing the unit test at a more fine grain level. The new 
'getUnitTests' trait looks interesting but it's value is a symbol 
of an aggregate (e.g. struct/class/module).

	foreach (module_; ModuleInfo)
	{
		if (module_)
		{
			foreach (unitTest; __traits(getUnitTests, module_.name))
			{
				...
			}
		}
			
	}

Obviously the 'module_.name' property doesn't work in this 
scenario so i wondered how can i iterate through the all of the 
compiling modules to make this code work?
Nov 06 2013
parent reply "Dicebot" <public dicebot.lv> writes:
module aaa;

import std.string;

template Alias(alias S)
{
	alias Alias = S;
}

void main()
{
	import std.string;
	
	foreach (symbol_name; __traits(allMembers, aaa))
	{
		alias symbol = Alias!(__traits(getMember, aaa, symbol_name));
		static if (symbol.stringof.startsWith("module "))
		{
		}
		else static if (symbol.stringof.startsWith("package "))
		{
			// recursion
		}
	}
}
Nov 06 2013
parent reply "Gary Willoughby" <dev nomad.so> writes:
On Wednesday, 6 November 2013 at 19:56:19 UTC, Dicebot wrote:
 module aaa;

 import std.string;

 template Alias(alias S)
 {
 	alias Alias = S;
 }

 void main()
 {
 	import std.string;
 	
 	foreach (symbol_name; __traits(allMembers, aaa))
 	{
 		alias symbol = Alias!(__traits(getMember, aaa, symbol_name));
 		static if (symbol.stringof.startsWith("module "))
 		{
 		}
 		else static if (symbol.stringof.startsWith("package "))
 		{
 			// recursion
 		}
 	}
 }
Unfortunately this still suffers the same problem in that you need a module symbol name to do anything. I need to get all module symbols at compile time.
Nov 06 2013
parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 6 November 2013 at 21:07:47 UTC, Gary Willoughby 
wrote:
 Unfortunately this still suffers the same problem in that you 
 need a module symbol name to do anything. I need to get all 
 module symbols at compile time.
You need only symbol name of your root compiled module which imports all others. All imported ones will be available in its member list, exactly what this snippet shows.
Nov 06 2013
next sibling parent reply "Daniel Davidson" <nospam spam.com> writes:
On Wednesday, 6 November 2013 at 21:26:09 UTC, Dicebot wrote:
 On Wednesday, 6 November 2013 at 21:07:47 UTC, Gary Willoughby 
 wrote:
 Unfortunately this still suffers the same problem in that you 
 need a module symbol name to do anything. I need to get all 
 module symbols at compile time.
You need only symbol name of your root compiled module which imports all others. All imported ones will be available in its member list, exactly what this snippet shows.
I think what OP wants to do is not as straightforward. I believe the goal is to have a module somewhere "out there" that looks at all other modules in the executable. I don't think it works that way, as how could a compile time test module know about modules that have pulled it in? Have a look at (https://github.com/patefacio/d-help/blob/master/d-help/opmix/ut.d) where I used dicebot's previous example code to find all unittests of the *current module*. The trick is to mixin code that examines the current __MODULE__ for your tests. This may not be the best way but it is working well for me. The thread was `selectively running unittest functions` http://forum.dlang.org/post/xjcgtbyrqzbosajxbgod forum.dlang.org
Nov 06 2013
parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 6 November 2013 at 21:36:52 UTC, Daniel Davidson 
wrote:
 I don't think it works that way, as how could a compile time 
 test module know about modules that have pulled it in?
Exactly. __traits work during compile-time. If module is not imported, it is not known during compile-time -> no trait unittest access possible. In lot of programs it will be accessible recursively via some indirect import though.
Nov 06 2013
parent reply "Gary Willoughby" <dev nomad.so> writes:
foreach (module_; ModuleInfo)
{
     auto func = module_.unitTest;
     func(); // run tests;
}

The above code retrieves all of the current project's modules and 
then grabs each module's unit test blocks. The only trouble is 
that the module's unit tests are kinda rolled into one function 
as show by the 'func' variable above. It would be nice to do this 
but get each individual unit test instead of dealing with these 
rolled up versions.
Nov 06 2013
next sibling parent "Dicebot" <public dicebot.lv> writes:
On Wednesday, 6 November 2013 at 22:33:48 UTC, Gary Willoughby 
wrote:
 The above code retrieves all of the current project's modules 
 and then grabs each module's unit test blocks. The only trouble 
 is that the module's unit tests are kinda rolled into one 
 function as show by the 'func' variable above. It would be nice 
 to do this but get each individual unit test instead of dealing 
 with these rolled up versions.
It is done via runtime reflection and completely different from __traits approach. You will also 100% loose all User Defined Attributes attached to test blocks because of their compile-time nature. This is IMHO why it was somewhat abandoned as less promising approach.
Nov 06 2013
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-11-06 23:33, Gary Willoughby wrote:
 foreach (module_; ModuleInfo)
 {
      auto func = module_.unitTest;
      func(); // run tests;
 }

 The above code retrieves all of the current project's modules and then
 grabs each module's unit test blocks. The only trouble is that the
 module's unit tests are kinda rolled into one function as show by the
 'func' variable above. It would be nice to do this but get each
 individual unit test instead of dealing with these rolled up versions.
See my reply to Dicebot: http://forum.dlang.org/thread/ewtbainwyxxyaqwhfwmw forum.dlang.org#post-l5fjfe:242nvb:241:40digitalmars.com -- /Jacob Carlborg
Nov 07 2013
prev sibling parent reply Jacob Carlborg <doob me.com> writes:
On 2013-11-06 22:26, Dicebot wrote:

 You need only symbol name of your root compiled module which imports all
 others. All imported ones will be available in its member list, exactly
 what this snippet shows.
That is the problem. One needs to import all other modules. That's not a good solution when creating a unit test framework. One would basically have to scan a directory for all D files. Then generate a new file that imports all these files, with a main function that runs all tests. Alternatively have something like RTInfo but for modules: Bugzilla: https://d.puremagic.com/issues/show_bug.cgi?id=10023 Pull request DMD: https://github.com/D-Programming-Language/dmd/pull/2271 Pull request druntime: https://github.com/D-Programming-Language/druntime/pull/534 Unfortunately my solution has the same problem as RTInfo, one needs to modify object.d. I had an idea that would solve this both for RTInfo and the new RMInfo, but that would most likely require building an associative array at runtime. That was not liked. See the comments in the pull requests and this: https://d.puremagic.com/issues/show_bug.cgi?id=10023#c3 -- /Jacob Carlborg
Nov 07 2013
next sibling parent reply =?UTF-8?B?U8O2bmtlIEx1ZHdpZw==?= <sludwig outerproduct.org> writes:
Am 07.11.2013 09:37, schrieb Jacob Carlborg:
 On 2013-11-06 22:26, Dicebot wrote:

 You need only symbol name of your root compiled module which imports all
 others. All imported ones will be available in its member list, exactly
 what this snippet shows.
That is the problem. One needs to import all other modules. That's not a good solution when creating a unit test framework. One would basically have to scan a directory for all D files. Then generate a new file that imports all these files, with a main function that runs all tests. Alternatively have something like RTInfo but for modules: Bugzilla: https://d.puremagic.com/issues/show_bug.cgi?id=10023 Pull request DMD: https://github.com/D-Programming-Language/dmd/pull/2271 Pull request druntime: https://github.com/D-Programming-Language/druntime/pull/534 Unfortunately my solution has the same problem as RTInfo, one needs to modify object.d. I had an idea that would solve this both for RTInfo and the new RMInfo, but that would most likely require building an associative array at runtime. That was not liked. See the comments in the pull requests and this: https://d.puremagic.com/issues/show_bug.cgi?id=10023#c3
Can't you do something like this? Or is the unit test framework supposed to provide its own "root"/main module? --- module unittestframework; void runTests(string root_module = __MODULE__)() { // start recursion from root_module } --- --- module appmain; import unittestframework; void main() { runTests(); } ---
Nov 07 2013
parent reply "Dicebot" <public dicebot.lv> writes:
On Thursday, 7 November 2013 at 10:04:57 UTC, Sönke Ludwig wrote:
 Can't you do something like this? Or is the unit test framework 
 supposed to provide its own "root"/main module?
 ...

 void runTests(string root_module = __MODULE__)()
 {
    // start recursion from root_module
 }
 ---
Only issue is .di file usage - you can't access implementation declarations when importing those via compile-time reflection. Other than that I don't see any possible failure sources.
Nov 07 2013
parent "Dicebot" <public dicebot.lv> writes:
On Thursday, 7 November 2013 at 12:07:40 UTC, Dicebot wrote:
 Only issue is .di file usage - you can't access implementation 
 declarations when importing those via compile-time reflection. 
 Other than that I don't see any possible failure sources.
As there is also an issue of having modules "a" and "b" both importing "c" (and being binary coupled via it) and not aware of each other. Probably not a typical architecture but possible.
Nov 07 2013
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Thursday, 7 November 2013 at 08:37:02 UTC, Jacob Carlborg 
wrote:
 That is the problem. One needs to import all other modules. 
 That's not a good solution when creating a unit test framework. 
 One would basically have to scan a directory for all D files. 
 Then generate a new file that imports all these files, with a 
 main function that runs all tests.
I don't see this much an issue as expect good testing framework to be coupled with a build system anyway. Also in really _lot_ of programs simply adding mixin to your `app.d` / `main.d` is enough as everything else is transitively imported from there. But in general yes, this an inherent flaw of compile-time reflection.
 Alternatively have something like RTInfo but for modules:

 Bugzilla: https://d.puremagic.com/issues/show_bug.cgi?id=10023
 Pull request DMD: 
 https://github.com/D-Programming-Language/dmd/pull/2271
 Pull request druntime: 
 https://github.com/D-Programming-Language/druntime/pull/534
I kind of both like it and hate it. Improving runtime reflection power is useful but it implies using special RT-tied UDA's and won't be able to use same declarations as compile-time version. Whatever solution is chosen for RT approach, I'd love to see it implicit and compatible with CT one.
Nov 07 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-11-07 13:22, Dicebot wrote:

 I don't see this much an issue as expect good testing framework to be
 coupled with a build system anyway. Also in really _lot_ of programs
 simply adding mixin to your `app.d` / `main.d` is enough as everything
 else is transitively imported from there.
That doesn't work with libraries. You can have a library consisting of two separate files that doesn't import each other. I also prefer to put my tests in its own files, in a separate directory. They are not imported by any other file. -- /Jacob Carlborg
Nov 07 2013
parent "Dicebot" <public dicebot.lv> writes:
On Thursday, 7 November 2013 at 15:03:40 UTC, Jacob Carlborg 
wrote:
 That doesn't work with libraries. You can have a library 
 consisting of two separate files that doesn't import each other.

 I also prefer to put my tests in its own files, in a separate 
 directory. They are not imported by any other file.
->
 I don't see this much an issue as expect good testing 
 framework to be
 coupled with a build system anyway.
Nov 07 2013