Re: std.unittests for (final?) review [Update]

2011-01-11 Thread Jonathan M Davis
On Tuesday, January 11, 2011 12:25:53 Tomek Sowiński wrote:
> Jonathan M Davis napisał:
> > On Monday, January 10, 2011 13:48:50 Tomek Sowiński wrote:
> > > Jonathan M Davis napisał:
> > > > I followed Andrei's suggestion and merged most of the functions into
> > > > a highly flexible assertPred. I also renamed the functions as
> > > > suggested and attempted to fully document everything with fully
> > > > functional examples instead of examples using types or functions
> > > > which don't actually exist.
> > > 
> > > Did you zip the right file? I still see things like nameFunc and
> > > assertPlease.
> > 
> > ??? Those are supposed to be there. All examples are tested in the unit
> > tests exactly as they are.
> 
> I just thought "instead of examples using types or functions which don't
> actually exist" meant well-known Phobos functions would be used.

Well, that would be better, but at least when it comes to types, that doesn't 
work. Not only is Phobos generally lacking in types, but some of the examples 
which show what a typical error message from the functions would look like 
require incorrectly implemented types. I might be able to use existing 
functions 
for the examples using functions though.

> > > assertThrown: I'd rather see generified collectException (call it
> > > collectThrown?). assertThrown may stay as a convenience wrapper,
> > > though.
> > 
> > ??? I don't get what you're trying for here. assertThrown isn't trying to
> > collect exceptions at all. It's testing whether the given exception was
> > thrown like it's supposed to be for the given function call. If it was,
> > then the assertion succeeded. If it wasn't, then an AssertError is
> > thrown. Just like assert.
> 
> I mean now collectException doesn't have a parametrized catch block like
> assertThrown does. If it did, the latter could come down to:
> 
> void assertThrown(T : Throwable = Exception, F)
>(lazy F funcToCall, string msg = null, string file =
> __FILE__, size_t line = __LINE__) {
>   T e = collectThrown!T(funcToCall);
>   if (e is null)
>   throw new AssertError(...);
> }
> 
> Shortening assertThrown's implementation is a bonus, main gain is better
> collectThrown().
> 
> [there's more down]
> 
> > > Looking at the code I'm seeing the same cancerous coding style
> > > std.datetime suffered from (to a lesser extent, I admit).
> > > 
> > > For instance, this routine:
> > > if(result != expected)
> > > {
> > > 
> > > if(msg.empty)
> > > {
> > > 
> > > throw new AssertError(format(`assertPred!"%s" failed: [%s]
> > > %s
> > > 
> > > [%s]: actual [%s], expected [%s].`, op,
> > > 
> > >  lhs,
> > >  op,
> > >  rhs,
> > >  result,
> > >  expected),
> > >
> > >file,
> > >line);
> > > 
> > > }
> > > else
> > > {
> > > 
> > > throw new AssertError(format(`assertPred!"%s" failed: [%s]
> > > %s
> > > 
> > > [%s]: actual [%s], expected [%s]: %s`, op,
> > > 
> > >  lhs,
> > >  op,
> > >  rhs,
> > >  result,
> > >  expected,
> > >  msg),
> > >   
> > >   file,
> > >   line);
> > > 
> > > }
> > > 
> > > }
> > > 
> > > can be easily compressed to:
> > > 
> > > enforce(result==expected, new AssertError(
> > > 
> > > format("[%s] %s [%s] failed: actual [%s], expected [%s]" ~
> > > (msg.empty ?
> > > 
> > > "." : ": %s"), op, lhs, op, rhs, result, expected, msg), file, line));
> > 
> > I really have no problem with them being separate as they are. I think
> > that I end up writing them that way because I see them as two separate
> > code paths. It wouldn't necessarily be a bad idea to combine them, but I
> > really don't think that it's a big deal.
> > 
> > > Another example:
> > > 
> > > {
> > > 
> > > bool thrown = false;
> > > try
> > > 
> > > assertNotThrown!AssertError(throwEx(new AssertError("It's
> > > an
> > > 
> > > AssertError", __FILE__, __LINE__)), "It's a message");
> > > catch(AssertError)
> > > 
> > > thrown = true;
> > > 
> > > assert(thrown);
> > > 
> > > }
> > > 
> > > can be:
> > > try {
> > > 
> > > assertNotThrown!AssertError(throwEx(new AssertError("It's an
> > > 
> > > AssertError", __FILE__,

Re: std.unittests for (final?) review [Update]

2011-01-11 Thread Tomek Sowiński
Jonathan M Davis napisał:

> On Monday, January 10, 2011 13:48:50 Tomek Sowiński wrote:
> > Jonathan M Davis napisał:
> > > I followed Andrei's suggestion and merged most of the functions into a
> > > highly flexible assertPred. I also renamed the functions as suggested
> > > and attempted to fully document everything with fully functional
> > > examples instead of examples using types or functions which don't
> > > actually exist.
> > 
> > Did you zip the right file? I still see things like nameFunc and
> > assertPlease.
> 
> ??? Those are supposed to be there. All examples are tested in the unit tests 
> exactly as they are.

I just thought "instead of examples using types or functions which don't 
actually exist" meant well-known Phobos functions would be used.

> > On the whole the examples are too long. It's just daunting I can't see docs
> > for *one* function without scrolling. Please give them a solid hair-cut --
> > max 10 lines with a median of 5. The descriptions are also watered down by
> > over-explanatory writing.
> 
> Perhaps. If I cut down on the examples though, the usage wouldn't be as 
> clear. 
> The idea was to be thorough. Andrei wanted better examples, so I gave better 
> examples.

Not sure if longer means better.

> However, it is a bit of a balancing act, and I may have put too many 
> in. It's debatable. Nick's suggestion of a main description before each 
> individual overload would help with that.

I agree. Perhaps a synopsis for the whole module like in std.variant would help 
too.

> > > So, now there's just assertThrown, assertNotThrown, collectExceptionMsg,
> > > and assertPred (though there are eight different overloads of
> > > assertPred). So, review away.
> > 
> > Some suggestions:
> > 
> > assertPred:
> > Try putting expected in front; uniform call syntax can then set it apart
> > from the operands: assertPred!"%"(7, 5, 2); // old
> > 2.assertPred!"%"(7, 5); // new
> 
> I really don't see any value to this.
> 
> 1. You can't do that with assert, and assertPred is essentially supposed to 
> be a 
> fancy assert.
> 
> 2. A number of assertPred overloads don't even have an expected, so it would 
> be 
> inconsistent.
> 
> 3. People already are annoyed enough that the operator doesn't end up between 
> the arguments. Putting the result on the left-hand side of the operator like 
> that would make it that much more confusing.

OK, I understand.

> > assertNotThrown: chain the original exception with AssertError as its
> > cause? Oh, this one badly needs a real-life example.
> 
> I suppose that chaining it would be a good idea. I didn't think of that. But 
> if 
> you want examples, it's used in the unit tests in this very module, and I 
> used 
> it heavily in std.datetime.

I meant a real-life example in documentation. People may often ask themselves 
"how is it different than !assertThrown()?".

> > assertThrown: I'd rather see generified collectException (call it
> > collectThrown?). assertThrown may stay as a convenience wrapper, though.
> 
> ??? I don't get what you're trying for here. assertThrown isn't trying to 
> collect exceptions at all. It's testing whether the given exception was 
> thrown 
> like it's supposed to be for the given function call. If it was, then the 
> assertion succeeded. If it wasn't, then an AssertError is thrown. Just like 
> assert.

I mean now collectException doesn't have a parametrized catch block like 
assertThrown does. If it did, the latter could come down to:

void assertThrown(T : Throwable = Exception, F)
   (lazy F funcToCall, string msg = null, string file = 
__FILE__, size_t line = __LINE__)
{
T e = collectThrown!T(funcToCall);
if (e is null)
throw new AssertError(...);
}

Shortening assertThrown's implementation is a bonus, main gain is better 
collectThrown().

[there's more down]

> > Looking at the code I'm seeing the same cancerous coding style std.datetime
> > suffered from (to a lesser extent, I admit).
> > 
> > For instance, this routine:
> > 
> > if(result != expected)
> > {
> > if(msg.empty)
> > {
> > throw new AssertError(format(`assertPred!"%s" failed: [%s] %s
> > [%s]: actual [%s], expected [%s].`, op,
> >  lhs,
> >  op,
> >  rhs,
> >  result,
> >  expected),
> >file,
> >line);
> > }
> > else
> > {
> > throw new AssertError(format(`assertPred!"%s" failed: [%s] %s
> > [%s]: actual [%s], expected [%s]: %s`, op,
> >  lhs,
> >  op,
> >  rhs,
> >  result,
> > 

Re: std.unittests for (final?) review [Update]

2011-01-11 Thread Justin Johansson

On 11/01/11 03:09, Jonathan M Davis wrote:

On Monday 10 January 2011 05:40:39 Justin Johansson wrote:

On 10/01/11 23:29, Jonathan M Davis wrote:

   From the sounds of it, if this code gets voted in, it'll be going into

std.exception.

- Jonathan M Davis


May it be asked by what authority you can say that (ie. as said above)?


Andrei's posts in this thread. Assuming that the code passes the vote (the
deadline for which he set as February 7th), he thinks that std.exception is the
best place for it rather than it being in its own module.


Oh okay.  Thanks for that; I missed Andrei's post in earlier this thread 
but found it now.  Good luck with the voting.  -- Justin


Re: std.unittests for (final?) review [Update]

2011-01-10 Thread Jonathan M Davis
On Monday, January 10, 2011 14:41:51 Jonathan M Davis wrote:
> On Monday, January 10, 2011 13:48:50 Tomek Sowiński wrote:
> > Another example:
> > 
> > {
> > 
> > bool thrown = false;
> > try
> > 
> > assertNotThrown!AssertError(throwEx(new AssertError("It's an
> > 
> > AssertError", __FILE__, __LINE__)), "It's a message"); catch(AssertError)
> > 
> > thrown = true;
> > 
> > assert(thrown);
> > 
> > }
> > 
> > can be:
> > try {
> > 
> > assertNotThrown!AssertError(throwEx(new AssertError("It's an
> > 
> > AssertError", __FILE__, __LINE__)), "It's a message"); assert(false);
> > 
> > } catch(AssertError) { /*OK*/ }
> > 
> > and you don't have to introduce a new scope every time.
> 
> Doesn't work actually - at least not in the general case (for this
> particular test, it's arguably okay). It doesn't take into account the
> case where an exception other than AssertError is thrown. The exception
> escapes instead of hitting the assertion. I believe that they are the way
> they are because I was essentialy re-writing assertThrown to test
> assertThrown. Regardless, we're talking about the unit tests here, not the
> actual code, so I don't think that it's as big a deal.

Actually, I now remember the big reason that your version doesn't work at all. 
The AssertError thrown by assert(false); inside of the try block would just be 
caught by the catch block. So, it doesn't work at all. You have to do it pretty 
much the way that I did it. It was one of those nuances in writing 
assertNotThrown that initially missed when coming up with it in the first 
place. 
So, the ugly way is necessary.

- Jonathan M Davis


Re: std.unittests for (final?) review [Update]

2011-01-10 Thread Jonathan M Davis
On Monday, January 10, 2011 13:48:50 Tomek Sowiński wrote:
> Jonathan M Davis napisał:
> > I followed Andrei's suggestion and merged most of the functions into a
> > highly flexible assertPred. I also renamed the functions as suggested
> > and attempted to fully document everything with fully functional
> > examples instead of examples using types or functions which don't
> > actually exist.
> 
> Did you zip the right file? I still see things like nameFunc and
> assertPlease.

??? Those are supposed to be there. All examples are tested in the unit tests 
exactly as they are.

> On the whole the examples are too long. It's just daunting I can't see docs
> for *one* function without scrolling. Please give them a solid hair-cut --
> max 10 lines with a median of 5. The descriptions are also watered down by
> over-explanatory writing.

Perhaps. If I cut down on the examples though, the usage wouldn't be as clear. 
The idea was to be thorough. Andrei wanted better examples, so I gave better 
examples. However, it is a bit of a balancing act, and I may have put too many 
in. It's debatable. Nick's suggestion of a main description before each 
individual overload would help with that.

> > So, now there's just assertThrown, assertNotThrown, collectExceptionMsg,
> > and assertPred (though there are eight different overloads of
> > assertPred). So, review away.
> 
> Some suggestions:
> 
> assertPred:
> Try putting expected in front; uniform call syntax can then set it apart
> from the operands: assertPred!"%"(7, 5, 2); // old
> 2.assertPred!"%"(7, 5); // new

I really don't see any value to this.

1. You can't do that with assert, and assertPred is essentially supposed to be 
a 
fancy assert.

2. A number of assertPred overloads don't even have an expected, so it would be 
inconsistent.

3. People already are annoyed enough that the operator doesn't end up between 
the arguments. Putting the result on the left-hand side of the operator like 
that would make it that much more confusing.

> assertNotThrown: chain the original exception with AssertError as its
> cause? Oh, this one badly needs a real-life example.

I suppose that chaining it would be a good idea. I didn't think of that. But if 
you want examples, it's used in the unit tests in this very module, and I used 
it heavily in std.datetime.

> assertThrown: I'd rather see generified collectException (call it
> collectThrown?). assertThrown may stay as a convenience wrapper, though.

??? I don't get what you're trying for here. assertThrown isn't trying to 
collect exceptions at all. It's testing whether the given exception was thrown 
like it's supposed to be for the given function call. If it was, then the 
assertion succeeded. If it wasn't, then an AssertError is thrown. Just like 
assert.

> Looking at the code I'm seeing the same cancerous coding style std.datetime
> suffered from (to a lesser extent, I admit).
> 
> For instance, this routine:
> 
> if(result != expected)
> {
> if(msg.empty)
> {
> throw new AssertError(format(`assertPred!"%s" failed: [%s] %s
> [%s]: actual [%s], expected [%s].`, op,
>  lhs,
>  op,
>  rhs,
>  result,
>  expected),
>file,
>line);
> }
> else
> {
> throw new AssertError(format(`assertPred!"%s" failed: [%s] %s
> [%s]: actual [%s], expected [%s]: %s`, op,
>  lhs,
>  op,
>  rhs,
>  result,
>  expected,
>  msg),
>   file,
>   line);
> }
> }
> 
> can be easily compressed to:
> 
> enforce(result==expected, new AssertError(
> format("[%s] %s [%s] failed: actual [%s], expected [%s]" ~ (msg.empty ?
> "." : ": %s"), op, lhs, op, rhs, result, expected, msg), file, line));

I really have no problem with them being separate as they are. I think that I 
end up writing them that way because I see them as two separate code paths. It 
wouldn't necessarily be a bad idea to combine them, but I really don't think 
that it's a big deal.

> BTW, actual and expected should be in new lines directly under each other
> for eye-diffing (does wonders for long input): format("[%s] %s [%s]
> failed:\n[%s] - actual\n[%s] - expected" ~ ...

Good idea.

> Another example:
> 
> {
> bool thrown = false;
> try
> assertNotThrown!AssertError(throwEx(new AssertError("It's an
> AssertError", __FILE__, __LINE__)), "It's a message"); catch(AssertError)
> thrown = true;
> 
>   

Re: std.unittests for (final?) review [Update]

2011-01-10 Thread Tomek Sowiński
Jonathan M Davis napisał:

> I followed Andrei's suggestion and merged most of the functions into a highly 
> flexible assertPred. I also renamed the functions as suggested and attempted 
> to 
> fully document everything with fully functional examples instead of examples 
> using types or functions which don't actually exist.

Did you zip the right file? I still see things like nameFunc and assertPlease.

On the whole the examples are too long. It's just daunting I can't see docs for 
*one* function without scrolling. Please give them a solid hair-cut -- max 10 
lines with a median of 5. The descriptions are also watered down by 
over-explanatory writing.

> So, now there's just assertThrown, assertNotThrown, collectExceptionMsg, and 
> assertPred (though there are eight different overloads of assertPred). So, 
> review 
> away.

Some suggestions:

assertPred:
Try putting expected in front; uniform call syntax can then set it apart from 
the operands:
assertPred!"%"(7, 5, 2); // old
2.assertPred!"%"(7, 5); // new

assertNotThrown: chain the original exception with AssertError as its cause?
Oh, this one badly needs a real-life example.

assertThrown: I'd rather see generified collectException (call it 
collectThrown?). assertThrown may stay as a convenience wrapper, though.


Looking at the code I'm seeing the same cancerous coding style std.datetime 
suffered from (to a lesser extent, I admit).

For instance, this routine:

if(result != expected)
{
if(msg.empty)
{
throw new AssertError(format(`assertPred!"%s" failed: [%s] %s [%s]: 
actual [%s], expected [%s].`,
 op,
 lhs,
 op,
 rhs,
 result,
 expected),
   file,
   line);
}
else
{
throw new AssertError(format(`assertPred!"%s" failed: [%s] %s [%s]: 
actual [%s], expected [%s]: %s`,
 op,
 lhs,
 op,
 rhs,
 result,
 expected,
 msg),
  file,
  line);
}
}

can be easily compressed to:

enforce(result==expected, new AssertError(
format("[%s] %s [%s] failed: actual [%s], expected [%s]" ~ (msg.empty ? "." 
: ": %s"),
op, lhs, op, rhs, result, expected, msg), file, line));

BTW, actual and expected should be in new lines directly under each other for 
eye-diffing (does wonders for long input):
format("[%s] %s [%s] failed:\n[%s] - actual\n[%s] - expected" ~ ...

Another example:

{
bool thrown = false;
try
assertNotThrown!AssertError(throwEx(new AssertError("It's an 
AssertError", __FILE__, __LINE__)), "It's a message");
catch(AssertError)
thrown = true;

assert(thrown);
}

can be:

try {
assertNotThrown!AssertError(throwEx(new AssertError("It's an 
AssertError", __FILE__, __LINE__)), "It's a message");
assert(false);
} catch(AssertError) { /*OK*/ }

and you don't have to introduce a new scope every time.

Not to mention that such routines recur in your code with little discrepancies, 
so abstracting out private helpers may pay off. Fixing such "readability bugs" 
is essential for a standard library module.

On the bright side, I do appreciate the thoroughness and extent of unittests in 
this module. Is coverage 100%?

> From the sounds of it, if this code gets voted in, it'll be going into 
> std.exception.

Please don't rush the adoption. This module, albeit useful, still needs work.

-- 
Tomek



Re: std.unittests for (final?) review [Update]

2011-01-10 Thread Nick Sabalausky
"Jonathan M Davis"  wrote in message 
news:mailman.535.1294662576.4748.digitalmar...@puremagic.com...
>Okay, here's the new code and its documentation: http://is.gd/ktURa
>
>I followed Andrei's suggestion and merged most of the functions into a 
>highly
>flexible assertPred. I also renamed the functions as suggested and 
>attempted to
>fully document everything with fully functional examples instead of 
>examples
>using types or functions which don't actually exist.
>
>So, now there's just assertThrown, assertNotThrown, collectExceptionMsg, 
>and
>assertPred (though there are eight different overloads of assertPred). So, 
>review
>away.
>
>From the sounds of it, if this code gets voted in, it'll be going into
>std.exception.

I like it. (I still think a way to make them collect an array of exceptions 
instead of throwing should make it's way in there at some point though.)

Couple small things though:

- The error message from the conditional version of assertPred should 
probably omit the two words "is not". That much is already clear from the 
fact that assertPred threw and says "failed:", and getting rid of it makes 
it much more readable as an expression: "failed: [hello] == [goodbye]" or 
"failed: [5] < [2]"

- The docs should have a section that gives an overview of assertPred by 
using a few simple examples of each of the assertPred uses. The way it is 
now, it's hard to see the overall logic behind the design of the 
assertPred's params since it's spread out all over. For instance:

-
//Equivalent to assert(4 <= 5);
assertPred!"<="(4, 5);

//Equivalent to assert(1 * 2 == 2);
assertPred!"=="(1 * 2, 2);

//Equivalent to assert(7 + 5 == 12);
assertPred!"+"(7, 5, 12);

/*
   Equivalent to
   void func(T, U)(T lhs, U rhs)
   {
   auto result = lhs = rhs;

   assert(lhs == rhs);
   assert(result == rhs);
   }

   func(5, 7);
 */
assertPred!"opAssign"(5, 7);

/*
   Equivalent to
   void func(T, U, E)(T lhs, U rhs, E expected)
   {
   auto result = lhs += rhs;

   assert(lhs == expected);
   assert(result == expected);
   }

   func(5, 7, 12);
*/
assertPred!"-="(7, 5, 2);

assertPred!"*="(7, 5, 35);

//Equivalent to assert("hello " ~ "world" == "hello world");
assertPred!"~"("hello ", "world", "hello world");

//Equivalent to assert(1 == 1);
assertPred!"a == 1"(1);

//Equivalent to assert(2 * 3.0 == 6);
assertPred!"a * 3.0 == 6.0"(2);

//Equivalent to assert(42 == 42);
assertPred!"a == b"(42, 42);

//Equivalent to assert("hello " ~ "world" == "hello world");
assertPred!`a ~ b == "hello world"`("hello ", "world");

//Equivalent to assert((int[] range, int i){return canFind(range, i);}([1, 
5, 7, 2], 7));
assertPred!((int[] range, int i){return canFind(range, i);})([1, 5, 7, 2], 
7);

//Equivalent to assert((int a, int b, int c){return a == b && b == c;}(5, 5, 
5));
assertPred!((int a, int b, int c){return a == b && b == c;})(5, 5, 5);

struct IntWrapper
{
int value;

int opCmp(const ref IntWrapper rhs) const
{
if(value < rhs.value)
return -1;
else if(value > rhs.value)
return 1;

return 0;
}

string toString()
{
return to!string(value);
}
}

// Equivalent to assert(IntWrapper(0).opCmp(IntWrapper(6)) < 0);
assertPred!("opCmp", "<")(IntWrapper(0), IntWrapper(6));

// Equivalent to assert(IntWrapper(42).opCmp(IntWrapper(42)) == 0);
assertPred!("opCmp", "==")(IntWrapper(42), IntWrapper(42));
-

Also notice that I cleaned up a few things, like eliminating the unnecessary 
struct constructor and making a few of the assert equivalents more clear.




Re: std.unittests for (final?) review [Update]

2011-01-10 Thread Jonathan M Davis
On Monday 10 January 2011 05:40:39 Justin Johansson wrote:
> On 10/01/11 23:29, Jonathan M Davis wrote:
> >  From the sounds of it, if this code gets voted in, it'll be going into
> > 
> > std.exception.
> > 
> > - Jonathan M Davis
> 
> May it be asked by what authority you can say that (ie. as said above)?

Andrei's posts in this thread. Assuming that the code passes the vote (the 
deadline for which he set as February 7th), he thinks that std.exception is the 
best place for it rather than it being in its own module.

- Jonathan M Davis


Re: std.unittests for (final?) review [Update]

2011-01-10 Thread Justin Johansson

On 10/01/11 23:29, Jonathan M Davis wrote:

 From the sounds of it, if this code gets voted in, it'll be going into
std.exception.

- Jonathan M Davis


May it be asked by what authority you can say that (ie. as said above)?


Re: std.unittests for (final?) review [Update]

2011-01-10 Thread Jonathan M Davis
Okay, here's the new code and its documentation: http://is.gd/ktURa

I followed Andrei's suggestion and merged most of the functions into a highly 
flexible assertPred. I also renamed the functions as suggested and attempted to 
fully document everything with fully functional examples instead of examples 
using types or functions which don't actually exist.

So, now there's just assertThrown, assertNotThrown, collectExceptionMsg, and 
assertPred (though there are eight different overloads of assertPred). So, 
review 
away.

From the sounds of it, if this code gets voted in, it'll be going into 
std.exception.

- Jonathan M Davis