www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Suggestion (ping Walter): Improve unit testing.

reply Gregor Richards <Richards codu.org> writes:
There are a number of improvements I'd like to see in D's unit testing 
framework. All of them are standard library changes, and I've made them 
work in Tango (as an external patch). If they were added to both Phobos 
and Tango, DSSS could easily run unit tests, which would improve its 
test suite.

Here are two major problems I see with unit tests right now:
1) You can't run only unit tests, you are forced to run main() as well.
2) Unit testing doesn't actually output anything useful, it just works 
under the no-news-is-good-news principle.

Each problem has a fairly easy solution in the core library:



1) Adding a special option, handled by the core library's main function, 
which will cause only unit tests to run. The changes I made in Tango:
Index: lib/compiler/gdc/dgccmain2.d
===================================================================
--- lib/compiler/gdc/dgccmain2.d	(revision 2100)
+++ lib/compiler/gdc/dgccmain2.d	(working copy)
   -35,7 +35,7   
  extern (C) void _minit();
  extern (C) void _moduleCtor();
  extern (C) void _moduleDtor();
-extern (C) void _moduleUnitTests();
+extern (C) void _moduleUnitTests(int);

  /***********************************
   * These functions must be defined for any D program linked
   -108,6 +108,7   
  {
      char[][] args;
      int result;
+    int testOnly = 0;

      version (GC_Use_Stack_Guess)
      {
   -137,11 +138,17   
          }
          args = am[0 .. argc];
      }
+
+    // check for --d-unittests-only
+    foreach (arg; args) {
+        if (arg == "--d-unittests-only")
+            testOnly = 1;
+    }

      void run()
      {
          _moduleCtor();
-        _moduleUnitTests();
+        _moduleUnitTests(testOnly);
          result = main_func(args);
          isHalting = true;
          _moduleDtor();


As you can see, if --d-unittests-only is supplied, it passes a 1 into 
the (now modified) _moduleUnitTests function, which will cause it to 
exit when finished testing.



2) The _moduleUnitTests function can be improved to provide useful 
output. The output I've implemented for Tango is:
Failure in test for module 'test':
   tango.core.Exception.AssertException on test.d(7): Assertion failure
TESTS: 1  PASSED: 0  FAILED: 1

The patch to make this work was fairly simple as well:
Index: lib/compiler/gdc/genobj.d
===================================================================
--- lib/compiler/gdc/genobj.d	(revision 2100)
+++ lib/compiler/gdc/genobj.d	(working copy)
   -42,7 +42,8   
      import tango.stdc.string; // : memcmp, memcpy;
      import tango.stdc.stdlib; // : calloc, realloc, free;
      import util.string;
-    debug(PRINTF) import tango.stdc.stdio; // : printf;
+    //debug(PRINTF) import tango.stdc.stdio; // : printf;
+    extern (C) int printf(char*, ...);

      extern (C) void onOutOfMemoryError();
      extern (C) Object _d_newclass(ClassInfo ci);
   -1054,11 +1055,13   
  }

  /**
- * Run unit tests.
+ * Run unit tests. If testOnly is true, output results and quit.
   */

-extern (C) void _moduleUnitTests()
+extern (C) void _moduleUnitTests(int testOnly)
  {
+    int testCount, testFail;
+    testCount = testFail = 0;
      debug(PRINTF) printf("_moduleUnitTests()\n");
      for (uint i = 0; i < _moduleinfo_array.length; i++)
      {
   -1070,9 +1073,26   
          debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name);
          if (m.unitTest)
          {
-            (*m.unitTest)();
+            testCount++;
+            try {
+                (*m.unitTest)();
+            } catch (Exception e) {
+                printf("Failure in test for module '%.*s':\n", m.name);
+                printf("  %.*s on %.*s(%d): %.*s\n",
+                       e.classinfo.name, e.file, e.line, e.msg);
+                testFail++;
+            }
          }
      }
+    if (testOnly != 0 || testFail > 0)
+    {
+        printf("TESTS: %d  PASSED: %d  FAILED: %d\n",
+               testCount, testCount - testFail, testFail);
+        if (testFail == 0)
+            exit(0);
+        else
+            exit(1);
+    }
  }



These additions are fairly minor, and would make unit testing 
immeasurably better than it is right now. The sections I modified in 
Tango are mostly the same as the Phobos versions, so the patch should be 
almost exactly the same as mine above.

Comments?

  - Gregor Richards
Apr 21 2007
next sibling parent reply "David B. Held" <dheld codelogicconsulting.com> writes:
Gregor Richards wrote:
 There are a number of improvements I'd like to see in D's unit testing 
 framework. All of them are standard library changes, and I've made them 
 work in Tango (as an external patch). If they were added to both Phobos 
 and Tango, DSSS could easily run unit tests, which would improve its 
 test suite.
 
 Here are two major problems I see with unit tests right now:
 1) You can't run only unit tests, you are forced to run main() as well.
 2) Unit testing doesn't actually output anything useful, it just works 
 under the no-news-is-good-news principle.
 [...]
Yeah, these are good points. There are a few things that you want from unit tests: * Consistent design This is already handled by the unittest mechanism, which is great. However, a unit testing library that offers all the typical primitives found in xUnit would be even greater. This would help a lot in common reporting. * Consistent invocation This means that there is a standard, well-known way to run the tests. Typically 'make test' is a good way. However, 'dmd -unittest foo.d' is also a perfectly good way, as is 'foo.exe --unittest'. At any rate, it doesn't really make sense that unittests are just functions that get executed before main(). I'm pretty sure nobody expects that. * Consistent output This means that someone who has never seen your tests before can tell whether they passed or failed. The problem with the 'no-gnus-is-good-gnus' principle is that it makes it difficult to tell the difference between "the tests all passed" and "the tests didn't run". Having a standard result summary makes it possible for automated tools to parse the results and display them in alternative formats. Dave
Apr 21 2007
parent reply Derek Parnell <derek psych.ward> writes:
On Sat, 21 Apr 2007 01:43:25 -0700, David B. Held wrote:

 * Consistent output
 
 This means that someone who has never seen your tests before can tell 
 whether they passed or failed.  The problem with the 
 'no-gnus-is-good-gnus' principle is that it makes it difficult to tell 
 the difference between "the tests all passed" and "the tests didn't 
 run". 
I find myself often writing a unittest that will deliberately and definitely fail, just to make sure I'm invoking any of the unittests. -- Derek Parnell Melbourne, Australia "Justice for David Hicks!" skype: derek.j.parnell
Apr 21 2007
parent Deewiant <deewiant.doesnotlike.spam gmail.com> writes:
Derek Parnell wrote:
 On Sat, 21 Apr 2007 01:43:25 -0700, David B. Held wrote:
 
 * Consistent output

 This means that someone who has never seen your tests before can tell 
 whether they passed or failed.  The problem with the 
 'no-gnus-is-good-gnus' principle is that it makes it difficult to tell 
 the difference between "the tests all passed" and "the tests didn't 
 run". 
I find myself often writing a unittest that will deliberately and definitely fail, just to make sure I'm invoking any of the unittests.
Ditto. Whenever I add a new test, I test the test by adding "assert (false);" after it to make sure it gets run. -- Remove ".doesnotlike.spam" from the mail address.
Apr 21 2007
prev sibling next sibling parent Tom <tom nospam.com> writes:
I agree. Unit testing needs a lot of improvement to be really useful.

--
Tom;
(Tomás Rossi)

Gregor Richards escribió:
 There are a number of improvements I'd like to see in D's unit testing 
 framework. All of them are standard library changes, and I've made them 
 work in Tango (as an external patch). If they were added to both Phobos 
 and Tango, DSSS could easily run unit tests, which would improve its 
 test suite.
 
 Here are two major problems I see with unit tests right now:
 1) You can't run only unit tests, you are forced to run main() as well.
 2) Unit testing doesn't actually output anything useful, it just works 
 under the no-news-is-good-news principle.
 
 Each problem has a fairly easy solution in the core library:
 
 
 
 1) Adding a special option, handled by the core library's main function, 
 which will cause only unit tests to run. The changes I made in Tango:
 Index: lib/compiler/gdc/dgccmain2.d
 ===================================================================
 --- lib/compiler/gdc/dgccmain2.d    (revision 2100)
 +++ lib/compiler/gdc/dgccmain2.d    (working copy)
    -35,7 +35,7   
  extern (C) void _minit();
  extern (C) void _moduleCtor();
  extern (C) void _moduleDtor();
 -extern (C) void _moduleUnitTests();
 +extern (C) void _moduleUnitTests(int);
 
  /***********************************
   * These functions must be defined for any D program linked
    -108,6 +108,7   
  {
      char[][] args;
      int result;
 +    int testOnly = 0;
 
      version (GC_Use_Stack_Guess)
      {
    -137,11 +138,17   
          }
          args = am[0 .. argc];
      }
 +
 +    // check for --d-unittests-only
 +    foreach (arg; args) {
 +        if (arg == "--d-unittests-only")
 +            testOnly = 1;
 +    }
 
      void run()
      {
          _moduleCtor();
 -        _moduleUnitTests();
 +        _moduleUnitTests(testOnly);
          result = main_func(args);
          isHalting = true;
          _moduleDtor();
 
 
 As you can see, if --d-unittests-only is supplied, it passes a 1 into 
 the (now modified) _moduleUnitTests function, which will cause it to 
 exit when finished testing.
 
 
 
 2) The _moduleUnitTests function can be improved to provide useful 
 output. The output I've implemented for Tango is:
 Failure in test for module 'test':
   tango.core.Exception.AssertException on test.d(7): Assertion failure
 TESTS: 1  PASSED: 0  FAILED: 1
 
 The patch to make this work was fairly simple as well:
 Index: lib/compiler/gdc/genobj.d
 ===================================================================
 --- lib/compiler/gdc/genobj.d    (revision 2100)
 +++ lib/compiler/gdc/genobj.d    (working copy)
    -42,7 +42,8   
      import tango.stdc.string; // : memcmp, memcpy;
      import tango.stdc.stdlib; // : calloc, realloc, free;
      import util.string;
 -    debug(PRINTF) import tango.stdc.stdio; // : printf;
 +    //debug(PRINTF) import tango.stdc.stdio; // : printf;
 +    extern (C) int printf(char*, ...);
 
      extern (C) void onOutOfMemoryError();
      extern (C) Object _d_newclass(ClassInfo ci);
    -1054,11 +1055,13   
  }
 
  /**
 - * Run unit tests.
 + * Run unit tests. If testOnly is true, output results and quit.
   */
 
 -extern (C) void _moduleUnitTests()
 +extern (C) void _moduleUnitTests(int testOnly)
  {
 +    int testCount, testFail;
 +    testCount = testFail = 0;
      debug(PRINTF) printf("_moduleUnitTests()\n");
      for (uint i = 0; i < _moduleinfo_array.length; i++)
      {
    -1070,9 +1073,26   
          debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name);
          if (m.unitTest)
          {
 -            (*m.unitTest)();
 +            testCount++;
 +            try {
 +                (*m.unitTest)();
 +            } catch (Exception e) {
 +                printf("Failure in test for module '%.*s':\n", m.name);
 +                printf("  %.*s on %.*s(%d): %.*s\n",
 +                       e.classinfo.name, e.file, e.line, e.msg);
 +                testFail++;
 +            }
          }
      }
 +    if (testOnly != 0 || testFail > 0)
 +    {
 +        printf("TESTS: %d  PASSED: %d  FAILED: %d\n",
 +               testCount, testCount - testFail, testFail);
 +        if (testFail == 0)
 +            exit(0);
 +        else
 +            exit(1);
 +    }
  }
 
 
 
 These additions are fairly minor, and would make unit testing 
 immeasurably better than it is right now. The sections I modified in 
 Tango are mostly the same as the Phobos versions, so the patch should be 
 almost exactly the same as mine above.
 
 Comments?
 
  - Gregor Richards
Apr 21 2007
prev sibling next sibling parent reply Ary Manzana <ary esperanto.org.ar> writes:
I also very much agree.

If a summary is going to be printed for the unittests (i.e. TESTS: 1 
PASSED: 0  FAILED: 1), it could be great also to label unittests with a 
name. This is more informative that just the file and line where the 
assertion failed. Compare "foo.bar.Exception.AssertException on 
test.d(7)" to "heap sort makes list sorted".

To to this, you can optionaly pass a string to the unittest:

unittest("heap sort makes list sorted") {
    // ...
}

It's backward compatible, and allows future nicer integration with IDEs: 
they could show a list of the tests passed and failed, and names are 
mandatory in this case.

Gregor Richards escribió:
 There are a number of improvements I'd like to see in D's unit testing 
 framework. All of them are standard library changes, and I've made them 
 work in Tango (as an external patch). If they were added to both Phobos 
 and Tango, DSSS could easily run unit tests, which would improve its 
 test suite.
 
 Here are two major problems I see with unit tests right now:
 1) You can't run only unit tests, you are forced to run main() as well.
 2) Unit testing doesn't actually output anything useful, it just works 
 under the no-news-is-good-news principle.
 
 Each problem has a fairly easy solution in the core library:
 
 
 
 1) Adding a special option, handled by the core library's main function, 
 which will cause only unit tests to run. The changes I made in Tango:
 Index: lib/compiler/gdc/dgccmain2.d
 ===================================================================
 --- lib/compiler/gdc/dgccmain2.d    (revision 2100)
 +++ lib/compiler/gdc/dgccmain2.d    (working copy)
    -35,7 +35,7   
  extern (C) void _minit();
  extern (C) void _moduleCtor();
  extern (C) void _moduleDtor();
 -extern (C) void _moduleUnitTests();
 +extern (C) void _moduleUnitTests(int);
 
  /***********************************
   * These functions must be defined for any D program linked
    -108,6 +108,7   
  {
      char[][] args;
      int result;
 +    int testOnly = 0;
 
      version (GC_Use_Stack_Guess)
      {
    -137,11 +138,17   
          }
          args = am[0 .. argc];
      }
 +
 +    // check for --d-unittests-only
 +    foreach (arg; args) {
 +        if (arg == "--d-unittests-only")
 +            testOnly = 1;
 +    }
 
      void run()
      {
          _moduleCtor();
 -        _moduleUnitTests();
 +        _moduleUnitTests(testOnly);
          result = main_func(args);
          isHalting = true;
          _moduleDtor();
 
 
 As you can see, if --d-unittests-only is supplied, it passes a 1 into 
 the (now modified) _moduleUnitTests function, which will cause it to 
 exit when finished testing.
 
 
 
 2) The _moduleUnitTests function can be improved to provide useful 
 output. The output I've implemented for Tango is:
 Failure in test for module 'test':
   tango.core.Exception.AssertException on test.d(7): Assertion failure
 TESTS: 1  PASSED: 0  FAILED: 1
 
 The patch to make this work was fairly simple as well:
 Index: lib/compiler/gdc/genobj.d
 ===================================================================
 --- lib/compiler/gdc/genobj.d    (revision 2100)
 +++ lib/compiler/gdc/genobj.d    (working copy)
    -42,7 +42,8   
      import tango.stdc.string; // : memcmp, memcpy;
      import tango.stdc.stdlib; // : calloc, realloc, free;
      import util.string;
 -    debug(PRINTF) import tango.stdc.stdio; // : printf;
 +    //debug(PRINTF) import tango.stdc.stdio; // : printf;
 +    extern (C) int printf(char*, ...);
 
      extern (C) void onOutOfMemoryError();
      extern (C) Object _d_newclass(ClassInfo ci);
    -1054,11 +1055,13   
  }
 
  /**
 - * Run unit tests.
 + * Run unit tests. If testOnly is true, output results and quit.
   */
 
 -extern (C) void _moduleUnitTests()
 +extern (C) void _moduleUnitTests(int testOnly)
  {
 +    int testCount, testFail;
 +    testCount = testFail = 0;
      debug(PRINTF) printf("_moduleUnitTests()\n");
      for (uint i = 0; i < _moduleinfo_array.length; i++)
      {
    -1070,9 +1073,26   
          debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name);
          if (m.unitTest)
          {
 -            (*m.unitTest)();
 +            testCount++;
 +            try {
 +                (*m.unitTest)();
 +            } catch (Exception e) {
 +                printf("Failure in test for module '%.*s':\n", m.name);
 +                printf("  %.*s on %.*s(%d): %.*s\n",
 +                       e.classinfo.name, e.file, e.line, e.msg);
 +                testFail++;
 +            }
          }
      }
 +    if (testOnly != 0 || testFail > 0)
 +    {
 +        printf("TESTS: %d  PASSED: %d  FAILED: %d\n",
 +               testCount, testCount - testFail, testFail);
 +        if (testFail == 0)
 +            exit(0);
 +        else
 +            exit(1);
 +    }
  }
 
 
 
 These additions are fairly minor, and would make unit testing 
 immeasurably better than it is right now. The sections I modified in 
 Tango are mostly the same as the Phobos versions, so the patch should be 
 almost exactly the same as mine above.
 
 Comments?
 
  - Gregor Richards
Apr 21 2007
next sibling parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Ary Manzana wrote:
 I also very much agree.
 
 If a summary is going to be printed for the unittests (i.e. TESTS: 1 
 PASSED: 0  FAILED: 1), it could be great also to label unittests with a 
 name. This is more informative that just the file and line where the 
 assertion failed. Compare "foo.bar.Exception.AssertException on 
 test.d(7)" to "heap sort makes list sorted".
 
 To to this, you can optionaly pass a string to the unittest:
 
 unittest("heap sort makes list sorted") {
    // ...
 }
 
 It's backward compatible, and allows future nicer integration with IDEs: 
 they could show a list of the tests passed and failed, and names are 
 mandatory in this case.
 
Ary, I was just about to suggest that. And i would also like very much to see these kind of improvements made. (And Gregor, that's darn slick work.) Reiner Pope and I tried to make unittests at least a little more verbal in Cashew's UTest module, but it ends up taking over the way you write unittests. Consider this snip from Cashew's array utils: -------------------------------------------------- version (Unittest) { static import UTest = cashew .utils .UTest ; } unittest { UTest.Stdout(""c); UTest.beginModule("cashew.utils.array"); } unittest { UTest.beginSection("stand-alone"); } T[] repeat (T) (T needle, size_t len) body { T[] haystack = new T[len]; haystack[] = needle; return haystack; } unittest { UTest.begin(r" repeat(T [, N])"c); assert(repeat(3, 3U) == [3, 3, 3]); UTest.end; } unittest { UTest.endSection; UTest.beginSection("pseudo-member"); } bool contains (T) (T[] haystack, T needle) body { return haystack.indexOf(needle) != NOT_FOUND; } unittest { UTest.begin(r".contains(T)"c); int[] foo = [1, 2, 3]; assert( foo.contains(2)); assert(! foo.contains(4)); UTest.end; } unittest { UTest.endSection; UTest.endModule; } -------------------------------------------------- Ack. But the output is nice. -------------------------------------------------- Unittest: cashew.utils.array: begin [stand-alone] , array(...)------------------> Pass , repeat(T [, N])-------------> Pass , repeatSub(T[], N)-----------> Pass , assoc([],[])----------------> Pass [pseudo-member] , .defaultLength(N)------------> Pass , .contains(T)-----------------> Pass , .diff(T[])-------------------> Pass , .intersect(A,A)--------------> Pass , .indexOf(T)------------------> Pass , .indexOfSub(T[])-------------> Pass , .rindexOf(T)-----------------> Pass , .rindexOfSub(T[])------------> Pass , .remove(T)-------------------> Pass , .removeAll(T)----------------> Pass , .drop(N)---------------------> Pass , .dropIf(Dlg)-----------------> Pass , .dropRange(N,M)--------------> Pass , .extract(N)------------------> Pass , .extractRange(N,M)-----------> Pass , .shift()---------------------> Pass , .rshift()--------------------> Pass , .eat(N)----------------------> Pass , .reat(N)---------------------> Pass , .fill (T [, N])--------------> Pass , .fillSub (T[] [, N])---------> Pass , .unique()--------------------> Pass , .rotl(N)---------------------> Pass , .rotr(N)---------------------> Pass , .push(...)-------------------> Pass , .shove(...)------------------> Pass , .filter(Dlg)-----------------> Pass , .find(Dlg)-------------------> Pass , .apply(Dlg)------------------> Pass , .replace(T,T)----------------> Pass , .replacePairs(T[T])----------> Pass , .join(T[][], T[])------------> Pass , .append(T[], T[]...)---------> Pass , .split(T[]...)---------------> Pass , .splitLen(N)-----------------> Pass , .greedySplitLen(N)-----------> Pass Unittest: cashew.utils.array: end -------------------------------------------------- I'd very much like to be able to just toss that thing out some day. :) For the morbidly curious, here is UTest: http://dsource.org/projects/cashew/browser/trunk/cashew/utils/UTest.d -- Chris Nicholson-Sauls
Apr 21 2007
prev sibling next sibling parent Dan <murpsoft hotmail.com> writes:
Interesting... I just wrote the first iteration of unittest for my Walnut 2.x
engine, and I found the concept rather intuitive.

It's merely a block of code that gets executed.  You may use asserts,
try/catch, scope(failure), printf, and all the rest to produce a unittest that
satisfies your needs.  I suppose it leaves need for a standard, but it's not
lacking for power.

I agree with the "unittests without main()".  I never want to run both at the
same time, unittest is for development, not for production.

Sincerely,
Dan
Apr 21 2007
prev sibling parent Jason House <jason.james.house gmail.com> writes:
Ary Manzana wrote:
 I also very much agree.
 
 If a summary is going to be printed for the unittests (i.e. TESTS: 1 
 PASSED: 0  FAILED: 1), it could be great also to label unittests with a 
 name. This is more informative that just the file and line where the 
 assertion failed. Compare "foo.bar.Exception.AssertException on 
 test.d(7)" to "heap sort makes list sorted".
 
 To to this, you can optionaly pass a string to the unittest:
 
 unittest("heap sort makes list sorted") {
    // ...
 }
 
This method of output would also implicitly require unit tests are run as if they were in try{} blocks. Currently, a unit test failure makes the entire program exit (and other unit tests are not run). It'd probably be good to expand the output a bit more to distinguish which tests were run even though a unit test in an imported module failed.
Apr 22 2007
prev sibling parent reply Gregor Richards <Richards codu.org> writes:
I hate to do this, but ... BUMP!

It's been three weeks since I posted this, and nobody in any kind of 
position of authority (*cough* Walter) has responded ... a lot of people 
have said this would be nifty, and yet it continues to be ignored.

Can I at least get a "no, I don't agree"? I hate the halting problem :-(

  - Gregor Richards
May 12 2007
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Gregor,

 I hate to do this, but ... BUMP!
 
 It's been three weeks since I posted this, and nobody in any kind of
 position of authority (*cough* Walter) has responded ... a lot of
 people have said this would be nifty, and yet it continues to be
 ignored.
 
 Can I at least get a "no, I don't agree"? I hate the halting problem
 :-(
 
 - Gregor Richards
 
do-nothing main (with a lib tool you might not even have to rebuild it
May 13 2007
parent Gregor Richards <Richards codu.org> writes:
BCS wrote:

 do-nothing main (with a lib tool you might not even have to rebuild it
 
 
Please note that a patch to solve both problems is included in my original post. - Gregor Richards
May 13 2007
prev sibling next sibling parent reply Greg Weber <webs.dev gmail.com> writes:
Gregor Richards Wrote:

 I hate to do this, but ... BUMP!
 
 It's been three weeks since I posted this, and nobody in any kind of 
 position of authority (*cough* Walter) has responded ... a lot of people 
 have said this would be nifty, and yet it continues to be ignored.
 
 Can I at least get a "no, I don't agree"? I hate the halting problem :-(
 
   - Gregor Richards
I am new to D and have been using it a lot over the last month. One of the things that is nice about D is how things seem to 'make sense'. Unit testing requiring the program to be run was completely unexpected. I think that the unit testing in the source code feature is one of the best things about D, but also probably the feature that is lacking most for a better implementation. Greg Weber
May 14 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Greg Weber wrote:
 Gregor Richards Wrote:
 
 I hate to do this, but ... BUMP!

 It's been three weeks since I posted this, and nobody in any kind of 
 position of authority (*cough* Walter) has responded ... a lot of people 
 have said this would be nifty, and yet it continues to be ignored.

 Can I at least get a "no, I don't agree"? I hate the halting problem :-(

   - Gregor Richards
I am new to D and have been using it a lot over the last month. One of the things that is nice about D is how things seem to 'make sense'. Unit testing requiring the program to be run was completely unexpected. I think that the unit testing in the source code feature is one of the best things about D, but also probably the feature that is lacking most for a better implementation. Greg Weber
I agree too. I was baffled when I first started getting linker errors trying to run unittests on some source code that lacked a main(). --bb
May 14 2007
prev sibling parent Walter Bright <newshound1 digitalmars.com> writes:
Gregor Richards wrote:
 Can I at least get a "no, I don't agree"? I hate the halting problem :-(
There's too much else going on that needs to get done asap. The const/invariant/final is currently sucking all my time.
May 14 2007