www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why the very same code works in main and not in unittest?

reply Pablo De =?UTF-8?B?TsOhcG9saQ==?= <nospam devnull.com> writes:
Still working on my project of a D wrapped for libmpdec 
(https://www.bytereef.org/mpdecimal/).

Consider the following code:

     void main()
     {
       mpd_context_t ctx;
       mpd_t* a;
       mpd_ieee_context(&ctx, 128);
       a= mpd_new(&ctx);
     }

It seems to work fine. mpd_new is a C function for allocating a 
new mpdecimal object via
malloc, prototype:

mpd_t *mpd_new(mpd_context_t *ctx);

see the documentation at:

https://www.bytereef.org/mpdecimal/doc/libmpdec/decimals.html?highlight=mpd_new#std:topic-mpd_new

However, if I put the very same code in the unittest section of a 
module, it fails with
a segmentation fault and I don't understand why!

     Personally, I found the unittest mechanism rather obscure. 
For instance I have tried to debug the problem using gdb and I 
found that the following code was run
     	
     module dub_test_root;
     2	import std.typetuple;
     3	static import mpdec.decimal;
     4	static import mpdec.mpdec;
     5	alias allModules = TypeTuple!(mpdec.decimal, mpdec.mpdec);
     6	
     7							import std.stdio;
     8							import core.runtime;
     9	
     10							void main() { writeln("All unit tests have been run 
successfully."); }
     11							shared static this() {
     12								version (Have_tested) {
     13									import tested;
     14									import core.runtime;
     15									import std.exception;
     16									Runtime.moduleUnitTester = () => true;
     17									enforce(runUnitTests!allModules(new 
ConsoleTestResultWriter), "Unit tests failed.");
     18								}
     19							}
     20	

I didn't even new that this code was there! (and I didn't manage 
to set a breakpoint
in my unit test, is there a way to do that?). I rather prefer a 
separate test program!
Aug 20 2021
parent jfondren <julian.fondren gmail.com> writes:
On Friday, 20 August 2021 at 16:02:22 UTC, Pablo De NĂ¡poli wrote:
 Consider the following code:

     void main()
     {
       mpd_context_t ctx;
       mpd_t* a;
       mpd_ieee_context(&ctx, 128);
       a= mpd_new(&ctx);
     }

 It seems to work fine.
...
 However, if I put the very same code in the unittest section of 
 a module, it fails with
 a segmentation fault and I don't understand why!
unittest blocks are just functions, so this is pretty strange. At a guess, you have some library setup code and are putting that in a module with main() instead of in `shared static this()` in the module you're getting mpd_new from, so unit testing is skipping this setup code.
     Personally, I found the unittest mechanism rather obscure. 
 For instance I have tried to debug the problem using gdb and I 
 found that the following code was run
     	
     module dub_test_root;
 ...
dub, probably mainly for historical dmd reasons, has some extra steps to make unittests more convenient. You can call dmd directly with -unittest to avoid that, or accept that it's there.
 I rather prefer a separate test program!
unittest builds are generally separate programs. dub manually removes your main(), but recent dmd also skip it automatically. If you mean that you'd prefer to have your tests in separate source files, there's nothing stopping you from doing that, you're just going slightly off the beaten path. Probably the easiest way to do it is to have a configuration that excludes your main(), and other configurations that exclude your tests. dcd's dub.json shows this off well with its client/server/library builds: https://github.com/dlang-community/DCD/blob/master/dub.json Another way to do this is to create a separate 'tests' dub application in a subdirectory which includes all of the library. Whatever works for you.
Aug 20 2021