www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Static unittests?

reply "Bosak" <bosak gmail.com> writes:
Are compile-time unittests possible in D? Maybe something like:

static unittest {
     assert(2 == 1 + 1);
}

So that every assert in the unittest is translated to static 
assert. And no normal asserts to be allowed in static unittest?
So the above code would be executed at compile time and 
translated to:

unittest {
     static assert(2 == 1 + 1);
}
Aug 05 2013
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Monday, 5 August 2013 at 12:25:36 UTC, Bosak wrote:
 Are compile-time unittests possible in D? Maybe something like:

 static unittest {
     assert(2 == 1 + 1);
 }

 So that every assert in the unittest is translated to static 
 assert. And no normal asserts to be allowed in static unittest?
 So the above code would be executed at compile time and 
 translated to:

 unittest {
     static assert(2 == 1 + 1);
 }
Not right now at the very least. Use case?
Aug 05 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 5 August 2013 at 14:02:06 UTC, Dicebot wrote:
 Use case?
The use case is simply checking that your functions can be CTFE'd, and that they produce the correct result.
 Not right now at the very least.
std.exception defines the package "assertCTFEable". It allows code such as: unittest { assertCTFEable!( { assert(to!string(1uL << 62) == "4611686018427387904"); assert(to!string(0x100000000) == "4294967296"); assert(to!string(-138L) == "-138"); }); } If this code does not run at CTFE, then a static assert triggers. This is currently "package", but it proves that what you asked for is not only possible, it is implemented *and* used in phobos. So either duplicate locally, or file an ER to make it public I guess.
Aug 05 2013
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Monday, 5 August 2013 at 16:50:12 UTC, monarch_dodra wrote:
 On Monday, 5 August 2013 at 14:02:06 UTC, Dicebot wrote:
 Use case?
The use case is simply checking that your functions can be CTFE'd, and that they produce the correct result.
Considering your, example, you can always do `static assert(to!string(1uL << 62) == "4611686018427387904");` What is the crucial difference?
Aug 05 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 5 August 2013 at 17:13:52 UTC, Dicebot wrote:
 On Monday, 5 August 2013 at 16:50:12 UTC, monarch_dodra wrote:
 On Monday, 5 August 2013 at 14:02:06 UTC, Dicebot wrote:
 Use case?
The use case is simply checking that your functions can be CTFE'd, and that they produce the correct result.
Considering your, example, you can always do `static assert(to!string(1uL << 62) == "4611686018427387904");` What is the crucial difference?
Well, the "crucial" difference is that this tests a single expression, and not an entire block. For example, the simple test that int.init is 0: static assert({int i; assert(i == 0;}); This doesn't work. You'd have to write: static assert({int i; assert(i == 0; return 1;}()); or static assert({int i; assert(i == 0);}(), 1); Both of which are a bit combersome. "assertCTFEable" allows testing that the *block* will actually will compile and ctfe run conveniently.
Aug 05 2013
parent reply "Dicebot" <public dicebot.lv> writes:
On Monday, 5 August 2013 at 17:30:38 UTC, monarch_dodra wrote:
 static assert({int i; assert(i == 0;});
enum i; static assert(i == 0); I am really struggling to understand the use case. D has a tool to force CTFE execution - `enum`. It has a tool for compile-time checks - `static assert`. Any possible compile-time test can be expressed via those. All assertCTFEable or similar tool adds is ability to save on some `static` markers.
Aug 05 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 5 August 2013 at 18:15:22 UTC, Dicebot wrote:
 On Monday, 5 August 2013 at 17:30:38 UTC, monarch_dodra wrote:
 static assert({int i; assert(i == 0;});
enum i; static assert(i == 0); I am really struggling to understand the use case. D has a tool to force CTFE execution - `enum`. It has a tool for compile-time checks - `static assert`. Any possible compile-time test can be expressed via those. All assertCTFEable or similar tool adds is ability to save on some `static` markers.
You are working around the argument. The point is that some calls simply can't be reduced to a single call. How would you deal with testing "parse" then? assertCTFEable!({ string s = "1234abc"; assert(parse! int(s) == 1234 && s == "abc"); }); The point is that you can write "native" runtime code, and then only CTFE test it once. It brings more than just "saving" on markers. What about, for example: assertCTFEable!({ int i = 5; string s; while (i--) s ~= 'a'; assert(s == "aaaaa"); }); And still, all of these are just simple cases.
Aug 05 2013
next sibling parent "Dicebot" <public dicebot.lv> writes:
On Monday, 5 August 2013 at 18:27:02 UTC, monarch_dodra wrote:
 ...
Saying "test CTFE function that mutates its arguments" would have been perfectly enough for me :) Okay, that makes sense, thanks for the explanation.
Aug 05 2013
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 08/05/13 20:27, monarch_dodra wrote:
 On Monday, 5 August 2013 at 18:15:22 UTC, Dicebot wrote:
 On Monday, 5 August 2013 at 17:30:38 UTC, monarch_dodra wrote:
 static assert({int i; assert(i == 0;});
enum i; static assert(i == 0); I am really struggling to understand the use case. D has a tool to force CTFE execution - `enum`. It has a tool for compile-time checks - `static assert`. Any possible compile-time test can be expressed via those. All assertCTFEable or similar tool adds is ability to save on some `static` markers.
You are working around the argument. The point is that some calls simply can't be reduced to a single call. How would you deal with testing "parse" then? assertCTFEable!({ string s = "1234abc"; assert(parse! int(s) == 1234 && s == "abc"); }); The point is that you can write "native" runtime code, and then only CTFE test it once. It brings more than just "saving" on markers. What about, for example: assertCTFEable!({ int i = 5; string s; while (i--) s ~= 'a'; assert(s == "aaaaa"); }); And still, all of these are just simple cases.
static assert({ int i = 5; string s; while (i--) s ~= 'a'; return s == "aaaaa"; }()); etc artur
Aug 05 2013
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 8/5/2013 11:27 AM, monarch_dodra wrote:
 What about, for example:

 assertCTFEable!({
      int i = 5;
      string s;
      while (i--)
          s ~= 'a';
      assert(s == "aaaaa");
 });
I don't believe that is a valid use case because the code being tested is not accessible from anything other than the test.
Aug 18 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 18 August 2013 at 20:35:06 UTC, Walter Bright wrote:
 On 8/5/2013 11:27 AM, monarch_dodra wrote:
 What about, for example:

 assertCTFEable!({
     int i = 5;
     string s;
     while (i--)
         s ~= 'a';
     assert(s == "aaaaa");
 });
I don't believe that is a valid use case because the code being tested is not accessible from anything other than the test.
I'm not sure what that means. Isn't that the case of all unittest? In any case, I was just saying the above template was enough for our needs, and that I don't think a language solution is in order. Also, I think the: //---- unittest { void dg() { BODY OF UNITTEST } dg(); //test runtime assertCTFEable!dg; //test compiletime } //---- usecase makes it useful. Although arguably, you could just: //---- unittest { bool dg() { BODY OF UNITTEST return true; } dg(); //test runtime enum a = dg(); or static assert(dg); } //---- But really, I'm just saying why type that when the template does it pretty well for us, while being self-docuenting?
Aug 19 2013
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Monday, 5 August 2013 at 16:50:12 UTC, monarch_dodra wrote:
 This is currently "package", but it proves that what you asked 
 for is not only possible, it is implemented *and* used in 
 phobos.
topic-starter has been asking about _language_ feature and my answer was related to this possible _language_ feature. Existence of some template in Phobos does not prove anything here.
Aug 05 2013
parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 5 August 2013 at 17:15:34 UTC, Dicebot wrote:
 On Monday, 5 August 2013 at 16:50:12 UTC, monarch_dodra wrote:
 This is currently "package", but it proves that what you asked 
 for is not only possible, it is implemented *and* used in 
 phobos.
topic-starter has been asking about _language_ feature and my answer was related to this possible _language_ feature. Existence of some template in Phobos does not prove anything here.
Well, it's not about *proving* anything :/ Technically, the question asked was: "Are compile-time unittests possible in D?", so I'm not even sure the question *was* strictly about language. But even if someone asks if a "language" can *do* something you *have* to take into account what the library can do. For example, D doesn't have "native" octals because they are library implemented. Does this mean that "D doesn't have octals" ? So sure, I guess that strictly speaking, no, D language doesn't have static unittests. However, when someone asks the question, if you just answer "No" without pointing out that the language allows this semantic: version(unittest) assertCTFEAble!({ //YOUR CODE HERE }); Then I believe you are giving an incomplete answer.
Aug 05 2013
parent reply "Dicebot" <public dicebot.lv> writes:
On Monday, 5 August 2013 at 17:38:22 UTC, monarch_dodra wrote:
 So sure, I guess that strictly speaking, no, D language doesn't 
 have static unittests. However, when someone asks the question, 
 if you just answer "No" without pointing out that the language 
 allows this semantic:

 version(unittest) assertCTFEAble!({
     //YOUR CODE HERE
 });

 Then I believe you are giving an incomplete answer.
Well, the problem is, D does have static unit-tests in a form of `static assert`. But topic starter has immediately provided an example that shows that his understanding of "static unit-tests" is different one, making it pretty hard to reason about proper alternative. Even assertCTFEAble does not _exactly_ match what was asked here. Thus I feel the need to first ask about specific use case and only then propose any real solutions. So, yes, of course, it is incomplete - because question is incomplete and requires further clarification. Which is the main point.
Aug 05 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Monday, 5 August 2013 at 18:21:37 UTC, Dicebot wrote:
 On Monday, 5 August 2013 at 17:38:22 UTC, monarch_dodra wrote:
 So sure, I guess that strictly speaking, no, D language 
 doesn't have static unittests. However, when someone asks the 
 question, if you just answer "No" without pointing out that 
 the language allows this semantic:

 version(unittest) assertCTFEAble!({
    //YOUR CODE HERE
 });

 Then I believe you are giving an incomplete answer.
Well, the problem is, D does have static unit-tests in a form of `static assert`. But topic starter has immediately provided an example that shows that his understanding of "static unit-tests" is different one, making it pretty hard to reason about proper alternative. Even assertCTFEAble does not _exactly_ match what was asked here. Thus I feel the need to first ask about specific use case and only then propose any real solutions. So, yes, of course, it is incomplete - because question is incomplete and requires further clarification. Which is the main point.
Alright. I tend to try to give as much information as possible in answers, even when the question isn't completely clear, or it was not exactly what was asked. With some luck, I can provide enough information to get the question answered, or give enough background to provide better understanding. This may or may not be the best thing to do, and sometimes it may indeed be better to stop and ask for clarification. I'll agree my answer is not 100% exact, but I feel it does bring something to the conversation. In any case, while it was a reply/quote to what you said, it was not meant as a rebutal to what you were saying.
Aug 05 2013
prev sibling next sibling parent "Jacob Carlborg" <doob me.com> writes:
On Monday, 5 August 2013 at 12:25:36 UTC, Bosak wrote:
 Are compile-time unittests possible in D? Maybe something like:

 static unittest {
     assert(2 == 1 + 1);
 }

 So that every assert in the unittest is translated to static 
 assert. And no normal asserts to be allowed in static unittest?
 So the above code would be executed at compile time and 
 translated to:

 unittest {
     static assert(2 == 1 + 1);
 }
Not exactly as you describe but you can do unit tests for CTFE functions. Have a look at this thread: http://forum.dlang.org/thread/ks1brj$1l6c$1 digitalmars.com -- /Jacob Carlborg
Aug 05 2013
prev sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 8/5/13, Bosak <bosak gmail.com> wrote:
 Are compile-time unittests possible in D? Maybe something like:

 static unittest {
      assert(2 == 1 + 1);
 }
Nope. Interestingly, in git-head we now have the getUnitTests trait, however this won't allow us to call the tests at compile time, I get back: Error: __unittestL5_1 cannot be interpreted at compile time, because it has no available source code This trait is fairly new, so maybe we could expand on this to allow invoking the tests at compile time. Note of course that fundamentally not all tests can be executed at compile-time (e.g. any kind of use of files makes them non-CTFE-able)
Aug 05 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-08-05 16:24, Andrej Mitrovic wrote:

 Nope.

 Interestingly, in git-head we now have the getUnitTests trait, however
 this won't allow us to call the tests at compile time, I get back:

 Error: __unittestL5_1 cannot be interpreted at compile time, because
 it has no available source code

 This trait is fairly new, so maybe we could expand on this to allow
 invoking the tests at compile time.
It does work, at least when I added it: http://forum.dlang.org/thread/ks1brj$1l6c$1 digitalmars.com -- /Jacob Carlborg
Aug 12 2013
parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 8/12/13, Jacob Carlborg <doob me.com> wrote:
 It does work, at least when I added it:

 http://forum.dlang.org/thread/ks1brj$1l6c$1 digitalmars.com
Hmm that does work! Looks like I must have hit some kind of bug somewhere, but I lost the sample code that failed. I'll report it if I run into it again.
Aug 12 2013
parent reply "Borislav Kosharov" <boby_dsm abv.bg> writes:
monarch_dodra got my point. So a static unittest is just like a 
normal one, but it will be executed in compile time. And every 
assert in it is a static assert. They will be only used to test 
CTFE's results and to insure that all constants are initialized 
correctly.

I really think that this should be added to the language, because 
it doesn't break stuff and it is useful. And the 'static' keyword 
is already used in many places like module imports and ifs.
Aug 17 2013
parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 8/17/13, Borislav Kosharov <boby_dsm abv.bg> wrote:
 I really think that this should be added to the language, because
 it doesn't break stuff and it is useful. And the 'static' keyword
 is already used in many places like module imports and ifs.
Have you tried using the new getUnitTests trait in the git-head version? If not it will be in the 2.064 release. Btw such a 'static unittest' feature is certainly going to break code because static can be applied as a label, for example: class C { static: void foo() { } unittest { /* Test the foo method. */ } // suddenly evaluated at compile-time }
Aug 17 2013
parent reply "Borislav Kosharov" <boby_dsm abv.bg> writes:
On Saturday, 17 August 2013 at 17:48:04 UTC, Andrej Mitrovic 
wrote:
 On 8/17/13, Borislav Kosharov <boby_dsm abv.bg> wrote:
 I really think that this should be added to the language, 
 because
 it doesn't break stuff and it is useful. And the 'static' 
 keyword
 is already used in many places like module imports and ifs.
Have you tried using the new getUnitTests trait in the git-head version? If not it will be in the 2.064 release. Btw such a 'static unittest' feature is certainly going to break code because static can be applied as a label, for example: class C { static: void foo() { } unittest { /* Test the foo method. */ } // suddenly evaluated at compile-time }
Oh I really haven't tough about that. Maybe, I will try this new trait. Or another solution is to add a compiler switch that will try to execute all the tests during compilation or something.
Aug 18 2013
parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Sunday, 18 August 2013 at 16:15:30 UTC, Borislav Kosharov 
wrote:
 On Saturday, 17 August 2013 at 17:48:04 UTC, Andrej Mitrovic 
 wrote:
 On 8/17/13, Borislav Kosharov <boby_dsm abv.bg> wrote:
 I really think that this should be added to the language, 
 because
 it doesn't break stuff and it is useful. And the 'static' 
 keyword
 is already used in many places like module imports and ifs.
Have you tried using the new getUnitTests trait in the git-head version? If not it will be in the 2.064 release. Btw such a 'static unittest' feature is certainly going to break code because static can be applied as a label, for example: class C { static: void foo() { } unittest { /* Test the foo method. */ } // suddenly evaluated at compile-time }
Oh I really haven't tough about that. Maybe, I will try this new trait. Or another solution is to add a compiler switch that will try to execute all the tests during compilation or something.
Well, that assumes all your code is ctfe-able... I've taken to doing something along the line of: unittest { void dg() { BODY OF UNITTEST } dg(); //test runtime assertCTFEable!dg; //test compiletime } It's a quick and easy way of testing both code paths, with minimal duplication and hassle.
Aug 18 2013