[phobos] Silent failure of std.container unittests
Walter Bright
walter at digitalmars.com
Tue Jul 13 23:06:50 PDT 2010
Sean Kelly wrote:
> Walter's change fixed the issue where non-throwing asserts weren't triggering a unittest failure, but it also reverted my change to trap unhandled exceptions, set a "fail" flag, and continue with the next test. I'd fix this, but what I'm confused about is why the support-non-throwing-asserts change was re-added in the first place. So instead I'd like to ask what the eventual/intended/desired/whatever behavior is for unit tests so I can work towards that. I'd like throwing asserts and for each unittest in a module to be run separately so recovery from an AssertError (which I'd like for unit tests) is at the granularity of the unittest block, not the module. The best I can do without a compiler change is module-level granularity like we have now, but asserts could all throw again, etc. Should this be an intermediate step? Should we keep non-throwing asserts? Halp plzz.
>
>
Perhaps what will help is examining the output of the compiler. For the
program:
import std.c.stdio;
unittest
{
int x = printf("inside unittest\n");
assert(x == 100000);
}
void main(string args[])
{
printf("inside main\n");
}
The output is:
_TEXT segment dword use32 public 'CODE' ;size is 0
_TEXT ends
_DATA segment para use32 public 'DATA' ;size is 64
_DATA ends
CONST segment para use32 public 'CONST' ;size is 0
CONST ends
_BSS segment para use32 public 'BSS' ;size is 0
_BSS ends
FLAT group
extrn _D3foo11__unittest1FZv
includelib phobos.lib
extrn _main
extrn __acrtused_con
extrn __Dmain
extrn __D3foo9__modtestFZv
FMB segment dword use32 public 'DATA' ;size is 0
FMB ends
FM segment dword use32 public 'DATA' ;size is 4
FM ends
FME segment dword use32 public 'DATA' ;size is 0
FME ends
extrn _D3foo15__unittest_failFiZv
extrn __d_unittestm
extrn _printf
public _D3foo12__ModuleInfoZ
_D3foo11__unittest1FZv COMDAT flags=x0 attr=x0 align=x0
__Dmain COMDAT flags=x0 attr=x0 align=x0
__D3foo9__modtestFZv COMDAT flags=x0 attr=x0 align=x0
_D3foo15__unittest_failFiZv COMDAT flags=x0 attr=x0 align=x0
_TEXT segment
assume CS:_TEXT
_TEXT ends
_DATA segment
db 069h,06eh,073h,069h,064h,065h,020h,075h ;inside u
db 06eh,069h,074h,074h,065h,073h,074h,00ah ;nittest.
db 000h,000h,000h,000h,069h,06eh,073h,069h ;....insi
db 064h,065h,020h,06dh,061h,069h,06eh,00ah ;de main.
db 000h,000h,000h,000h,000h,000h,000h,000h ;........
db 000h,000h,000h,000h,000h,000h,000h,000h ;........
_D3foo12__ModuleInfoZ:
db 004h,002h,000h,0ffffff80h,000h,000h,000h,000h ;........
dd offset FLAT:__D3foo9__modtestFZv
db 066h,06fh,06fh,000h ;foo.
_DATA ends
CONST segment
CONST ends
_BSS segment
_BSS ends
FMB segment
FMB ends
FM segment
dd offset FLAT:_D3foo12__ModuleInfoZ
FM ends
FME segment
FME ends
_D3foo11__unittest1FZv comdat
assume CS:_D3foo11__unittest1FZv
L0: mov EAX,offset FLAT:_DATA
push EAX
call near ptr _printf
cmp EAX,0186A0h
je L1C
mov EAX,7
call near ptr _D3foo15__unittest_failFiZv
L1C: add ESP,4
ret
_D3foo11__unittest1FZv ends
__Dmain comdat
assume CS:__Dmain
L0: mov EAX,offset FLAT:_DATA[014h]
push EAX
call near ptr _printf
xor EAX,EAX
add ESP,4
ret
__Dmain ends
__D3foo9__modtestFZv comdat
assume CS:__D3foo9__modtestFZv
L0: call near ptr _D3foo11__unittest1FZv
ret
__D3foo9__modtestFZv ends
_D3foo15__unittest_failFiZv comdat
assume CS:_D3foo15__unittest_failFiZv
L0: enter 4,0
push EAX
mov ECX,offset FLAT:_D3foo12__ModuleInfoZ
push ECX
call near ptr __d_unittestm
add ESP,8
leave
ret
_D3foo15__unittest_failFiZv ends
end
What is happening is that the compiler inserts the address of
__D3foo9__modtestFZv into the ModuleInfo record. The druntime calls this
function. This function, in turn, runs the unittest code for that
module. When a unittest fails, the function
__d_unittestm(&__ModuleInfoZ, __LINE__) is called. This function is in
the druntime.
Note that the compiler generated code does not throw any exceptions.
What happens when __d_unittestm() is called is ENTIRELY up to druntime,
which can be:
1. nothing
2. print a message
3. abort
4. throw an exception chosen by druntime
5. whatever druntime wants to
The important thing to note is that this is up to druntime, not the
compiler. The part that is up to the compiler is the granularity of the
unittests, which is set at the module, not the individual unittest blocks.
More information about the phobos
mailing list