Thread overview | |||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 15, 2007 better assertions and __FILE__ | ||||
---|---|---|---|---|
| ||||
Hi, Another FAQ item I couldn't find. I'm looking to implement some wrappers around assert as assert is too primative and doesn't give me enough information. I want to go down the xUnit path E.g. in the code: assertEqual(foo,bar); leading to output: Equality assertion failed in file.cpp at line 10 Expected Value: 10 Actual Value: 5 I got as far as: void assertEqual(Type)(Type actual_, Type expected_, char[] file_, uint line_) { if (actual_ != expected_) { writefln("Equality assertion failed"); writefln("actual: '", actual_, "'"); writefln("expected: '", expected_, "'"); _d_assert(file_,line_); } } This lets me use: assertEqual!(string)("foo","bar",cast(char[])(__FILE__),__LINE__); Where I'm having trouble is getting __FILE__ and __LINE__ added (presumably using a mixin) so I can avoid the cruft. As a side issue how do I get string constants implicitly converted to char[] or better yet string. In my example above assertEqual("foo","bar",cast(char[])(__FILE__),__LINE__); also works but only because "foo".length == "bar".length // broken! assertEqual("foo","bar2",cast(char[])(__FILE__),__LINE__); Final question to prove I'm a noob. In std.asserterror shouldn't _d_assert(char[] file_,uint line_); actually be: _d_assert(string file_,uint line_); Regards, Bruce. |
August 16, 2007 Re: better assertions and __FILE__ | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams | Bruce Adams Wrote:
>
> Hi,
> Another FAQ item I couldn't find. I'm looking to implement some wrappers around assert as assert is too primative and doesn't give me enough information. I want to go down the xUnit path E.g.
>
> in the code:
> assertEqual(foo,bar);
>
> leading to output:
> Equality assertion failed in file.cpp at line 10
> Expected Value: 10
> Actual Value: 5
>
> I got as far as:
>
> void assertEqual(Type)(Type actual_,
> Type expected_,
> char[] file_,
> uint line_) {
> if (actual_ != expected_) {
> writefln("Equality assertion failed");
> writefln("actual: '", actual_, "'");
> writefln("expected: '", expected_, "'");
> _d_assert(file_,line_);
> }
> }
>
> This lets me use:
>
> assertEqual!(string)("foo","bar",cast(char[])(__FILE__),__LINE__);
>
> Where I'm having trouble is getting __FILE__ and __LINE__ added (presumably using a mixin) so I can avoid the cruft.
>
Here are a few more things I've learned on my travels around the various D web-pages.
__FILE__ & __LINE__ are expanded by the tokeniser not the parser. This implies that they would not be available for use in mixins as they will already have been expanded. This is confirmed with a quick test. So what I'm trying to do is not currently possible.
I have seen two proposals for improvements to D bandied around.
1) "context" functions
// does not exist
void context(__line, __file) assertEqual(int a, int b) {
if (a != b) {
writefln("equality assertion failed");
writefln("expected: ",a);
writefln("actual: ",b);
_d_assert(__line,__file);
}
}
2) Access to the call stack through "trace" something like:
import std.trace; // does not exist yet
void assertEqual(int a, int b) {
if (a != b) {
writefln("equality assertion failed");
writefln("expected: ",a);
writefln("actual: ",b);
StackFrame callerFrame = getStack().up();
uint callingLine = callerFrame.getLine();
char[] callingFile = callerFrame.getFile();
_d_assert(callingLine, callingFile);
}
}
I think the latter has more appeal and more support. You can use it for generating stack traces and core dumps for example. However, I have no idea of what status these ideas are at. There's nothing in the issue tracking system. I'm not sure if that's the right place for frivolous feature requests. Has anyone heard anything on the grapevine?
Are there language development roadmap and feature request pages knocking around the web somewhere that I've yet to find?
Regards,
Bruce.
|
August 16, 2007 Re: better assertions and __FILE__ (char[] vs. string) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams |
Okay. So having realised my first idea is not possible with current D (prove me wrong please!). What about the char array versus string
malarcky. Can anyone help with that?
How do I get "foo" to be implicitly interpreted as char[] rather than char[3]. I though the WYSIWYG thing might do it i.e. r"foo" but it doesn't. In fact I'm not sure what it does do.
Bruce Adams Wrote:
>
> Hi,
> Another FAQ item I couldn't find. I'm looking to implement some wrappers around assert as assert is too primative and doesn't give me enough information. I want to go down the xUnit path E.g.
>
> in the code:
> assertEqual(foo,bar);
>
> leading to output:
> Equality assertion failed in file.cpp at line 10
> Expected Value: 10
> Actual Value: 5
>
> I got as far as:
>
> void assertEqual(Type)(Type actual_,
> Type expected_,
> char[] file_,
> uint line_) {
> if (actual_ != expected_) {
> writefln("Equality assertion failed");
> writefln("actual: '", actual_, "'");
> writefln("expected: '", expected_, "'");
> _d_assert(file_,line_);
> }
> }
>
> This lets me use:
>
> assertEqual!(string)("foo","bar",cast(char[])(__FILE__),__LINE__);
>
> Where I'm having trouble is getting __FILE__ and __LINE__ added (presumably using a mixin) so I can avoid the cruft.
>
> As a side issue how do I get string constants implicitly converted to
> char[] or better yet string.
> In my example above
>
> assertEqual("foo","bar",cast(char[])(__FILE__),__LINE__);
>
> also works but only because "foo".length == "bar".length
>
> // broken!
> assertEqual("foo","bar2",cast(char[])(__FILE__),__LINE__);
>
> Final question to prove I'm a noob. In std.asserterror shouldn't
>
> _d_assert(char[] file_,uint line_);
>
> actually be:
>
> _d_assert(string file_,uint line_);
>
> Regards,
>
> Bruce.
>
|
August 16, 2007 Re: better assertions and __FILE__ (char[] vs. string) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams | Bruce Adams schrieb:
> How do I get "foo" to be implicitly interpreted as char[] rather than char[3].
"foo"[]
|
August 17, 2007 Re: better assertions and __FILE__ (char[] vs. string) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Frank Benoit | Frank Benoit Wrote: > Bruce Adams schrieb: > > How do I get "foo" to be implicitly interpreted as char[] rather than char[3]. > > "foo"[] Thanks. Where is that piece of syntactic sugar documented? There's still a problem though. The following line: assertEqual("foo"[],"bar2"[],cast(char[])(__FILE__),__LINE__); fails to compile with: UnitTest.d(49): template UnitTest.assertEqual(Type) cannot deduce template fun ion from argument types (invariant(char)[],invariant(char)[],char[],long) but the explicit instantiation below works. assertEqual!(invariant(char[]))("foo"[],"bar2"[],cast(char[])(__FILE__),__LINE__); What's going on? Regards, Bruce. |
August 17, 2007 Re: better assertions and __FILE__ (call stack reflection) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams | I have given in and raised this as an issue: http://d.puremagic.com/issues/show_bug.cgi?id=1425 duplicated below for discussion purposes: For improved support for assertions, logging code and stack traces it would be useful to have means of identifying the calling frame of reference. This would also have the advantage of rendering __LINE__ and its ilk redundant. For example it is not currently possible to implement a cppunit like assertEqual function. The best I can achieve is: void assertEqual(Type)(Type actual_, Type expected_, char[] file_, uint line_) { if (actual_ != expected_) { writefln("Equality assertion failed"); writefln("actual: '", actual_, "'"); writefln("expected: '", expected_, "'"); } _d_assert(file_,line_); } Which has to be used as: assertEqual!(string)("foo","bar",cast(char[])(__FILE__),__LINE__); It should be possible to achieve a more natural syntax like: assertEqual("foo","bar"); Several proposals seem have been made on the newsgroups but none has been raised as a request here. I personally think the best approach is to have a library function stackFrame[] callStack = std.trace(); By default the calling frame would be something like: class stackFrame { stackFrame* parent; object[] arguments; } When functions request source identification the compiler would have to include mapping information so its not a pure library issue. E.g class SourceStackFrame: public StackFrame { // inherited // stackFrame* parent; // object[] arguments; uint parentLine; string* parentFile; string* parentFunction; } I imagine two ways of creating such a structure. Use of an analogue to __FILE__ e.g. the so called "context" keyword would tell the compiler to use the special stack frame for a specific call only. A command line switch could tell the compiler to always use the source stack frame format - with resulting code bloat. |
August 17, 2007 Re: better assertions and __FILE__ (char[] vs. string) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams | Bruce Adams wrote: > Frank Benoit Wrote: >> Bruce Adams schrieb: >>> How do I get "foo" to be implicitly interpreted as char[] rather than char[3]. >> "foo"[] > > Thanks. Where is that piece of syntactic sugar documented? > http://www.digitalmars.com/d/arrays.html "The [] is shorthand for a slice of the entire array." -- Remove ".doesnotlike.spam" from the mail address. |
August 17, 2007 Re: better assertions and __FILE__ | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruce Adams | Bruce Adams wrote: > > Here are a few more things I've learned on my travels around the various D web-pages. > > __FILE__ & __LINE__ are expanded by the tokeniser not the parser. This implies that they would not be available for use in mixins as they will already have been expanded. This is confirmed with a quick test. So what I'm trying to do is not currently possible. > It's possible to use CTFE with string mixins to achieve this. I have whipped up something quick, ugly as hell but could be improved using std.metastrings.Format: char[] assertEqual(char[] actual, char[] expected) { return `if (` ~ actual ~ `!=` ~ expected ~ `) { ` `writefln("Equality assertion failed in " ~ __FILE__ ~ " at line " ~ std.metastrings.ToString!(__LINE__));` `writefln("expected value: '", ` ~ expected ~ `, "'");` `writefln("actual value: '", ` ~ actual ~ `, "'");` `assert(false);}`; } used as: mixin(assertEqual("foo","bar")); If you can live with a) having to use 'mixin', b) ugliness of compile time string manipulation and perhaps c) sometimes hard to follow error messages, you can do most of anything you want with CTFE and string mixins. I think if one would make work of this most of the tediousness could be solved with some boilerplate code. |
August 17, 2007 Re: better assertions and __FILE__ | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lutger | Also note that it is necessary to 'public import std.metastrings' if this code is used across modules, due to the mixin thing. |
August 20, 2007 Re: better assertions and __FILE__ (compile time functions) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Lutger | Lutger Wrote: > Bruce Adams wrote: > > > > Here are a few more things I've learned on my travels around the various D web-pages. > > > > __FILE__ & __LINE__ are expanded by the tokeniser not the parser. This implies that they would not be available for use in mixins as they will already have been expanded. This is confirmed with a quick test. So what I'm trying to do is not currently possible. > > > > It's possible to use CTFE with string mixins to achieve this. I have whipped up something quick, ugly as hell but could be improved using std.metastrings.Format: > > > char[] assertEqual(char[] actual, char[] expected) > { > return `if (` ~ actual ~ `!=` ~ expected ~ `) { ` > `writefln("Equality assertion failed in " ~ __FILE__ ~ > " at line " ~ std.metastrings.ToString!(__LINE__));` > `writefln("expected value: '", ` ~ expected ~ `, "'");` > > `writefln("actual value: '", ` ~ actual ~ `, "'");` > `assert(false);}`; > } > > used as: > > mixin(assertEqual("foo","bar")); > > > If you can live with a) having to use 'mixin', b) ugliness of compile > time string manipulation and perhaps c) sometimes hard to follow error > messages, you can do most of anything you want with CTFE and string mixins. > I think if one would make work of this most of the tediousness could be > solved with some boilerplate code. > I'd rather live with A) - than without the option to do this at all. B) is better than it was in C++. I'm already struggling with C) using DMD, if you'll pardon the pun. I can see from using a variant of your example that is possible now. I forgot we had CTFE. I was surprised it allows arbitrary strings to be compiled as I though mxins were supposed to use code segments that have been parsed already. Anyway, I'm still struggling a bit with it. My main problem can be boiled down to the following example. char[] int2str(int foo_) { return std.metastrings.ToString!(foo_); } Fails to compile with c:\dmd\bin\..\src\phobos\std\metastrings.d(102): Error: expression cast(long)foo _ is not a valid template value argument c:\dmd\bin\..\src\phobos\std\metastrings.d(85): Error: expression cast(long)foo_ < 0L is not constant or does not evaluate to a bool Without the shriek it also fails: char[] int2str(int foo_) { return std.metastrings.ToString(foo_); } dmd.exe -c UnitTest.d -ofUnitTest.do -cov c:\dmd\bin\..\src\phobos\std\metastrings.d(74): template std.metastrings.ToStrin g(ulong U) is not a function template UnitTest.d(124): template std.metastrings.ToString(ulong U) cannot deduce templa te function from argument types (int) UnitTest.d(124): Error: cannot implicitly convert expression ((ToString(ulong U) )(foo_)) of type int to char[] Its not obvious to me what I'm doing wrong. Incidentally is there a way of specifying you only want a function to be evaluated at compile time? Perhaps the static keyword? My plan when this kind of thing comes up is to have one function for the run-time portion and a seperate code generator for the compile time stuff. Regards, Bruce. |
Copyright © 1999-2021 by the D Language Foundation