-
-
Notifications
You must be signed in to change notification settings - Fork 608
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add enhanced unittest support #3518
Conversation
Easiest way is probably to pad the module name to the target word size. |
|
Thanks @yebblies , I've updated the code to pad the module name as you suggested. |
| @@ -182,8 +185,17 @@ void Module::genmoduleinfo() | |||
| const char *name = toPrettyChars(); | |||
| namelen = strlen(name); | |||
| dtnbytes(&dt, namelen + 1, name); | |||
| if((namelen + 1) % Target::ptrsize != 0) | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment on what's going on here? Too much magic to my eyes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. It's padding the length to a multiple of Target::ptrsize.
|
Ah, I see this is rebooted as dlang/druntime#782 |
|
Added named unittests. @WalterBright do Identifiers have some maximum length? IIRC @andralex wanted the name to be part of the mangled symbol name. That code generates names using |
|
I get the intended use of |
|
Is V1/V2 about D1/D2? Then I guess we shouldn't complicate things with D1 support. |
| return Lexer::uniqueId(buf.peekString()); | ||
| } | ||
|
|
||
| UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, char *codedoc) | ||
| : FuncDeclaration(loc, endloc, unitTestId(loc), STCundefined, NULL) | ||
| UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc, char *codedoc, const char *name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a name is supplied, that name should be used. unitTestId should only be used if a name is not supplied.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm sorry, but I can't read your mind. If you have such detailed beliefs how this should be implemented you could tell me and at least give detailed specifications instead of one line answers before I implement this stuff. This would save me and you lots of time. Or you could have written these 10 lines of code and pasted them here, or file a pull request against my dmd fork....
For example unitTestId should only be used if a name is not supplied. does not make sense to me. This immediately opens lots of questions:
- Should unittest identfiers conflict with other identifiers in the same module (functions, variables, ...)
- How should named test be mangled then? Using
unitTestIdbut not usinguniqueIdwould make sense, but not usingunitTestId? Than named /unnamed test have completely different mangles? - What does
that name should be usedmean? You don't want thelinein the mangled name?
So please, give exact mangle strings for the following examples:
unittest NamedTest {}
unittest {}
unittest {}|
Seems like some comments were lost when rebasing:
That was not my decision, you have to ask @WalterBright about that. |
| { | ||
| if (!StructDeclaration::UnitTest) | ||
| { | ||
| warning(loc, "mismatch between compiler and object.d or object.di found. " |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have a special Funktion for that, named something like ObjectWarnIfMissing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure? I grepped for object.d but only found ObjectNotFound which errors and is for typeinfo afaik. So should we make this an error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used exactly for this purpose (see here)
The new information is available from the 'unitTests' member of every ModuleInfo. 'unitTests' is an array of __UnitTest structs. The __UnitTest struct provides the unittest function, location etc.
|
Rebased.
//unnamed tests (unchanged)
__unittestL{line}_{unique id}
//named tests (N for NAME)
__unittestL{LINE}_N{identifier}
example:
unittest{} => _D4test14__unittestL1_1FZv
unittest testA {} => _D4test20__unittestL6_N5testAFZvThe druntime pull was pulled with the |
How would the test runner know such things from a function pointer? |
|
I think adding some more meta information to unittests makes a lot of sense. Using @disabled to disable runningof a test is superior to disable compiling them with version (none), so we should support it. Location information is very useful for tooling. |
|
There should be a test case for the parser addition, we'll need an update of the grammar, the specification should mention @disable and named tests and this needs to go into the changelog. |
|
Are we (@WalterBright) sure about using an identifier? It makes it look like a symbol although it's just runtime information and not possible to reference the test. unittest("my_test_for_foobar")
{
}vs. unittest my_test_for_foobar
{
} |
|
@MartinNowak what is the rationale for @disable ? Why not make it a symbol accessible via the symbolic debug info? How would you set a breakpoint on a random string? I disagree with all this meta information, as I've pointed out before. There is no gain from essentially duplicating symbolic debug info. |
A disabled test (which is currently failing) can still be listed in the output. Also @disabled tests are still compiled, so they are semantically checked.
That makes sense, the syntax still looks a little weird to me.
It's very little information and symbolic debug info is not accessible to a test runner. Being able to know the location of a test is useful for tooling (like IDEs). |
Since failing a unittest no longer stops the rest of the unittests from running, this doesn't seem to add much value.
Also seems of little value. (Note that
Having individual names for the unittests makes them trivially greppable. The module name is also available via the ModuleInfo, no need to duplicate it. |
Agreed, it's only a marginal improvement.
But most tests aren't named and likely never will be named.
Yes, but the module name is not the file name. It's difficult to map module names back to files when you have multiple import pathes. |
Does this actually work? I tried applying this pull to dmd/Linux_32 and running the druntime and phobos tests: the tests stop whenever a single test fails. @jpf91, I notice that in your simple example above, the failing test is the last one, so maybe that aspect needs more work, likely in druntime? |
|
@joakim-noah This wasn't added to the druntime test runner as it is a user visible change and when I initially proposed this people were completely against changing any user facing output. (Even printing 'pass' for passing modules was considered unacceptable. Ironically we now print passing modules.) All: |
I think we're pretty close, @disable is out, identifiers/symbols are used for debugging, instead of the filename we can use ModuleInfo.name and the line number can be put into the unittest name field for anonymous tests. |
Add OpenBSD backtrace support
As discussed in the newsgroup this reboots dlang/druntime#308
and #1131
Ping @andralex
This provides enough to run unittests separately and in different threads, no support for naming tests yet. @andralex what's the preferred syntax for that?
Detailed description
The new information is available from the
unitTestsmember of every ModuleInfo.unitTestsis an array of__UnitTeststructs. The__UnitTeststruct provides the unittest function, location, etc.Example
Example test runners
Simple example: http://dpaste.dzfl.pl/56697348500c
Output: http://dpaste.dzfl.pl/c0c706b0cea4
Parallel runner: http://dpaste.dzfl.pl/cef0a42936d6
Output: http://dpaste.dzfl.pl/d2445d87a9d7
Available information
The following information is emitted for every unittest:
void function() func. Call it, pass it to another thread, disassemble, ...string file: file name. nice for IDE cause not all unittests always belong to the module (for example, importingstd.stdioimports two unittests fromstd.format)uint line: line of test declaration. For IDEbool disabledtrue if test is marked@disable. (This can be removed if it's controversial)