Is.EqualTo calling ToString on implicit conversion

137 views
Skip to first unread message

Berryl Hesh

unread,
Dec 25, 2008, 1:56:07 PM12/25/08
to NUnit-Discuss
I have a class called a DatePoint that wraps a DateTime. The purpose
is to conveniently control precision in cases where time zone,
seconds, etc. are not relevant or could be detrimental to a given
requirement.

Is.EqualTo fails when comparing a DateTime to a DatePoint, and only
then (tests && code below), because it calls DatePoint.ToString()
instead of DatePoint.Equals(object).

Any suggestions?

Thanks for sharing`! BH

// testing code

[Test]
public void Implicit_Equality_DatePoint_DateTime_OpEq() {
Assert.That(DatePoint.Today == DateTime.Today);
Assert.That(DateTime.Today == DatePoint.Today);
Assert.That(DatePoint.Tomorrow != DateTime.Today);
Assert.That(DateTime.Today != DatePoint.Tomorrow);
}

[Test]
public void Implicit_Equality_DatePoint_DateTime_Equals() {
Assert.That(DatePoint.Today.Equals(DateTime.Today));
Assert.That(DateTime.Today.Equals(DatePoint.Today));
Assert.That(DatePoint.Today, Is.EqualTo(DatePoint.Today));
Assert.That(DateTime.Today, Is.EqualTo(DatePoint.Today));
Assert.That(DatePoint.Today, Is.EqualTo(DateTime.Today));
=======> Only failure
}

// class code that does the implicit conversion

public static implicit operator DateTime(DatePoint datepoint)
{
return datepoint._wrappedDate;
}

public static implicit operator DatePoint(DateTime datetime) {
return new DatePoint(datetime, TimeSlice.Second);
}

Charlie Poole

unread,
Dec 25, 2008, 2:22:32 PM12/25/08
to nunit-...@googlegroups.com
Hi Berryl,

Interesting problem. What version of NUnit are you using?

Charlie

Berryl Hesh

unread,
Dec 25, 2008, 3:10:51 PM12/25/08
to NUnit-Discuss
Hi Charlie

version is 2.4.8.0

Berryl

Charlie Poole

unread,
Dec 25, 2008, 4:35:34 PM12/25/08
to nunit-...@googlegroups.com
Hi Berryl,

Where are you seeing the use of ToString()? Of course, it is used in
displaying the error message, but NUnit stopped comparing string
representations internally a while back.

As the 2.4.8 code is written, you should be getting the result
of expected.Equals(actual). My guess, however, is that DateTime
will not find the implicit conversion in this context, because
actual declared as an object, and DateTime knows nothing about
DatePoints.

In general, implicit conversion operators can only be relied
upon for one level of conversion, at one specific point in
the code. In this case, your DatePoint is simply an object
by the time it is handed over to te low-level routines. The
only way we could make this work is if we returned
expected.Equals(actual) || actual.Equals(expected)
but I'm afraid that would mess up more folks than it would help.

Berryl Hesh

unread,
Dec 25, 2008, 6:56:55 PM12/25/08
to NUnit-Discuss
The order of execution is below, as is the error message. Do you know
of a good summary of what is guaranteed on an implicit conversion? Or
if I can somehow make the DateTime aware of it through an extension
method?

1 Smack.Core.Tests.DLL!
Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals
() Line 94 + 0x2d bytes
2 Smack.Core.DLL!Smack.Core.Domain.Temporal.DatePoint.implicit
operator Smack.Core.Domain.Temporal.DatePoint(System.DateTime datetime
= {12/25/2008 12:00:00 AM}) Line 202
3 Smack.Core.Tests.DLL!
Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals
() Line 94 + 0x63 bytes [External Code]
4 Smack.Core.DLL!Smack.Core.Domain.Temporal.DatePoint.ToString(string
format = null, System.IFormatProvider formatProvider = {}) Line 222
[External Code]

TestCase
'Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals'
failed:
Expected: 2008-12-25 00:00:00.000
But was: <12/25/2008>


Smack.Core.DLL!Smack.Core.Domain.Temporal.DatePoint.ToString(string
format = null, System.IFormatProvider formatProvider = {}) Line 222 C#
[External Code]
Smack.Core.Tests.DLL!
Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals
() Line 94 + 0x63 bytes C#
[External Code]

Charlie Poole

unread,
Dec 25, 2008, 7:52:11 PM12/25/08
to nunit-...@googlegroups.com
Hi Berryl,

How did you get the stack trace? It doesn't look like the format
that NUnit uses. I'm suspicious that we are not looking at a
trace of the original failure, but of some later failure that
occurred, possibly in formatting the error message.

Regarding use of implicit conversion... It was once a favorite
trick of mine. In fact some versions of NUnit use it in evaluating
syntactic elements. It causes lots of problems. For one thing,
even though it seems like it should work across all languagees,
it's specific to C#. It also depends on the static type of the
variable that holds your DatePoint. Try
object dpObj = new DatePoint(...)
and see what happens. :-) I've stopped using it for most purposes.

What exactly are you trying to test with the failing assert?
Would this...
    Assert.That((DateTime)DatePoint.Today,
Is.EqualTo(DateTime.Today));
do the job for you equally well?

I imagine you could make this work with a conversion method,
provided you ran your tests using .NET 3.5. But what's the
point of making the test work? It isn't testing what you
thought it was testing - rather it's testing an obscure
bit of code in the depths of NUnit, which is equivalent to

    Assert.That((object)DatePoint.Today,
Is.EqualTo((object)DateTime.Today));

... or something like that - I haven't actually tried it. :-)

Charlie

> -----Original Message-----
> From: nunit-...@googlegroups.com
> [mailto:nunit-...@googlegroups.com] On Behalf Of Berryl Hesh
> Sent: Thursday, December 25, 2008 3:57 PM
> To: NUnit-Discuss
> Subject: [nunit-discuss] Re: Is.EqualTo calling ToString on
> implicit conversion
>
>

Berryl Hesh

unread,
Dec 25, 2008, 10:11:40 PM12/25/08
to NUnit-Discuss
Hi Charlie. Responses below, and thanks for all the good stuff you do
- I've learned a lot from it. Berryl

On Dec 25, 4:52 pm, "Charlie Poole" <char...@nunit.com> wrote:
> Hi Berryl,
>
> How did you get the stack trace? It doesn't look like the format
> that NUnit uses.

NUnit didn't throw a stack trace - just the failed expectation of a
TestCase gone wrong, I think. To show you what I was seeing in the
debugger I copied the VS call stack (twice) and formatted it into a
numbered table.

I'm suspicious that we are not looking at a
> trace of the original failure, but of some later failure that
> occurred, possibly in formatting the error message.

Quite possibly, but what exception? And why wouldn't NUnit have left a
stack trace if an exception was thrown?

> Regarding use of implicit conversion... It was once a favorite
> trick of mine.

I'm not all that tricky! Honestly my insecurity about implicit
conversions is partly why I posted this. It does seem like the perfect
solution here because I think of the DatePoint as an internal
mechanism to make DateTime easier and more reliable to work with in
some context. An end client shouldn't really know or care, or have to
even think about it (which is the other reason I posted this - I want
it to work!)

In fact some versions of NUnit use it in evaluating
> syntactic elements. It causes lots of problems. For one thing,
> even though it seems like it should work across all languagees,
> it's specific to C#. It also depends on the static type of the
> variable that holds your DatePoint. Try
>    object dpObj = new DatePoint(...)
> and see what happens. :-) I've stopped using it for most purposes.

I don't get it. dpObj seems to look like my DatePoint

> What exactly are you trying to test with the failing assert?

A method I wanted to use takes a DateTime and wasn't working. I
suspected the implicit conversion and realized I hadn't tested it
thoroughly enough, so I wrote the test cases I posted to you. Now it
looks like the real culprit was I hadn't used the DatePoint properly
(I hadn't set the Precision internally, which is the whole Point!)

Anyway, I still want to know whether I can rely on the implicit
conversion or I need to *think* (ouch) and cast it. I rely on testing
to tell me what works or not, and if I have to treat it special in
NUnit than I don't trust it.

> Would this...
>     Assert.That((DateTime)DatePoint.Today,
>         Is.EqualTo(DateTime.Today));
> do the job for you equally well?

Casting works fine. I can do Assert.That(DatePoint.Today, Is.EqualTo
((DatePoint)DateTime.Today) too.

> I imagine you could make this work with a conversion method,

How would that method look? Wouldn't it be just as tiresome or more so
to remember to use the method as i would be to cast?

Charlie Poole

unread,
Dec 26, 2008, 1:01:24 AM12/26/08
to nunit-...@googlegroups.com
Hi Berryl,
> Hi Charlie. Responses below, and thanks for all the good stuff you do
> - I've learned a lot from it. Berryl
>
> On Dec 25, 4:52 pm, "Charlie Poole" <char...@nunit.com> wrote:
> > Hi Berryl,
> >
> > How did you get the stack trace? It doesn't look like the
> format that
> > NUnit uses.
>
> NUnit didn't throw a stack trace - just the failed
> expectation of a TestCase gone wrong, I think. To show you
> what I was seeing in the debugger I copied the VS call stack
> (twice) and formatted it into a numbered table.

Well, NUnit always shows a stack trace on an assertion failure,
but it may be truncated to just the method that failed. So, is
what you're seeing in the debugger the just-in-time trace for
the NUnit AssertionExcetpion? According to the trace, it's not.
Rather, it shows your test calling ToString() directly.

> I'm suspicious that we are not looking at a
> > trace of the original failure, but of some later failure that
> > occurred, possibly in formatting the error message.
>
> Quite possibly, but what exception? And why wouldn't NUnit
> have left a stack trace if an exception was thrown?

It should have.

>
> > Regarding use of implicit conversion... It was once a
> favorite trick
> > of mine.
>
> I'm not all that tricky! Honestly my insecurity about
> implicit conversions is partly why I posted this. It does
> seem like the perfect solution here because I think of the
> DatePoint as an internal mechanism to make DateTime easier
> and more reliable to work with in some context. An end client
> shouldn't really know or care, or have to even think about it
> (which is the other reason I posted this - I want it to work!)

I call it tricky because it doesn't do what it seems to do.

> In fact some versions of NUnit use it in evaluating
> > syntactic elements. It causes lots of problems. For one thing, even
> > though it seems like it should work across all languagees, it's
> > specific to C#. It also depends on the static type of the variable
> > that holds your DatePoint. Try
> >    object dpObj = new DatePoint(...)
> > and see what happens. :-) I've stopped using it for most purposes.
>
> I don't get it. dpObj seems to look like my DatePoint

Except it's declared as an object. Since implicit conversion
is a compiler trick, the conversion instructions can only be
emitted if the compiler knows it is dealing with an object
that implements the implicit conversion. My dpObj will never
exhibit the behavior you expect unless you convert it back to
a DatePoint first.

> > What exactly are you trying to test with the failing assert?
>
> A method I wanted to use takes a DateTime and wasn't working.
> I suspected the implicit conversion and realized I hadn't
> tested it thoroughly enough, so I wrote the test cases I
> posted to you. Now it looks like the real culprit was I
> hadn't used the DatePoint properly (I hadn't set the
> Precision internally, which is the whole Point!)

But do you understand that the failing assert is not testing
the implicit conversion? In order to test it, you would have
to perform the conversion in your test. You do perform it in
several of your tests, but not in that one. Instead you pass
an *object* to Assert.That, which passes it to EqualConstraint,
which passes it through several layers of internal methods -
all the time as an object. Finally, an internal method checks
to see if this object is of a special type that it understands
and - failing that - just calls the Equals method on the
expected value.

NUnit's code doesn't know about DatePoint at all, so when
that code was compiled, no special conversion instructions
were inserted by the compiler.

All of which goes to show: it's tricky. :-)

> Anyway, I still want to know whether I can rely on the
> implicit conversion or I need to *think* (ouch) and cast it.
> I rely on testing to tell me what works or not, and if I have
> to treat it special in NUnit than I don't trust it.

You can rely on it at any point where the compiler knows it
is dealing with a DatePoint and needs a DateTime.

"A user-defined implicit conversion consists of an optional
standard implicit conversion, followed by execution of a
user-defined implicit conversion operator, followed by
another optional standard implicit conversion."

Since Assert.That takes an object as its first argument,
there is no reason for the compiler to go looking for
any conversions in this case.

> > Would this...
> >     Assert.That((DateTime)DatePoint.Today,
> >         Is.EqualTo(DateTime.Today));
> > do the job for you equally well?
>
> Casting works fine. I can do Assert.That(DatePoint.Today, Is.EqualTo
> ((DatePoint)DateTime.Today) too.
>
> > I imagine you could make this work with a conversion method,
>
> How would that method look? Wouldn't it be just as tiresome
> or more so to remember to use the method as i would be to cast?

Sure...

So I guess the real point is whether that particular test adds
anything to what you're already testing.

Charlie

Berryl Hesh

unread,
Dec 26, 2008, 1:45:27 AM12/26/08
to NUnit-Discuss
No, I don't think I did appreciate fully what NUnit was testing or
that I wasn't even testing the implicit conversion there, and the
ToString() call just buggers my brain on top of that. 20% of it is
still sinking in, but thank you very much for the patient and thorough
explanation

And yes...NUnit does leave the advertised stack trace below.
DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals :
FailedNUnit.Framework.AssertionException: Expected: 2008-12-25
00:00:00.000
But was: <12/25/2008>

Berryl

at NUnit.Framework.Assert.That(Object actual, Constraint constraint,
String message, Object[] args)
at NUnit.Framework.Assert.That(Object actual, Constraint constraint)
at
Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals
() in DatePointTest.EqualityComparison.cs: line 95
> ...
>
> read more »

Charlie Poole

unread,
Dec 26, 2008, 2:00:36 AM12/26/08
to nunit-...@googlegroups.com
Hi Berryl,

> No, I don't think I did appreciate fully what NUnit was
> testing or that I wasn't even testing the implicit conversion
> there, and the
> ToString() call just buggers my brain on top of that. 20% of
> it is still sinking in, but thank you very much for the
> patient and thorough explanation

No problem - hope it keeps sinking in. :-)

> And yes...NUnit does leave the advertised stack trace below.

With no ToString(), btw. That must have been some other error
that VS trapped at some point.

Charlie

Simone Busoli

unread,
Dec 26, 2008, 5:26:06 AM12/26/08
to nunit-...@googlegroups.com
Ok I'll take on this, it's intriguing and I would like to know what's going on.

Simone Busoli

unread,
Dec 26, 2008, 6:36:58 AM12/26/08
to nunit-...@googlegroups.com
Ok first observation. You cannot use an extension method on DateTime because Equals(object) will be used anyway.
Then as Charlie said the expected DateTime won't be cast to DatePoint in this line:

            Assert.That(DatePoint.Today, Is.EqualTo(DateTime.Today));

That's because cast operators are emitted by the compiler. Another story would be if you could override equals on DateTime or provide an overload which let you compare it with a DatePoint, since NUnit calls expected.Equals(actual), where expected is a DateTime and actual a DatePoint, and if expected had an Equals method aware of DatePoints it would be polimorphically called, but that's not the case since you can't do that with extension methods.

Charlie, time to put generics on constraints? :)

Berryl Hesh

unread,
Dec 26, 2008, 11:07:21 AM12/26/08
to NUnit-Discuss
Thanks for walking through this too Simone. Until you do have generic
constraints, I wonder if NUnit can identify that the test can't
succeed and leave a more informative message.

> >> With no ToString(), btw. That must have been some other error
> >> that VS trapped at some point.

Any ideas on how to flush that other error out? Could the error be
that DateTime doesn't know about the DatePoint?

- Berryl


On Dec 26, 3:36 am, "Simone Busoli" <simone.bus...@gmail.com> wrote:
> Ok first observation. You cannot use an extension method on DateTime because
> Equals(object) will be used anyway.Then as Charlie said the expected
> DateTime won't be cast to DatePoint in this line:
>
>             Assert.That(DatePoint.Today, Is.EqualTo(DateTime.Today));
>
> That's because cast operators are emitted by the compiler. Another story
> would be if you could override equals on DateTime or provide an overload
> which let you compare it with a DatePoint, since NUnit calls
> expected.Equals(actual), where expected is a DateTime and actual a
> DatePoint, and if expected had an Equals method aware of DatePoints it would
> be polimorphically called, but that's not the case since you can't do that
> with extension methods.
>
> Charlie, time to put generics on constraints? :)
>
> On Fri, Dec 26, 2008 at 11:26 AM, Simone Busoli <simone.bus...@gmail.com>wrote:
>
> > Ok I'll take on this, it's intriguing and I would like to know what's going
> > on.
>
> ...
>
> read more »

Simone Busoli

unread,
Dec 26, 2008, 12:22:26 PM12/26/08
to nunit-...@googlegroups.com
On Fri, Dec 26, 2008 at 5:07 PM, Berryl Hesh <ef74...@gmail.com> wrote:
Thanks for walking through this too Simone. Until you do have generic
constraints, I wonder if  NUnit can identify that the test can't
succeed and leave a more informative message.

Theoretically, it could, but it would get tricky because NUnit should make assumptions about the two objects that might now be always true. When comparing objects about equality or disequality, NUnit could assume that in order to perform a successful comparison the two objects should be of the same type or on the same hierarchy. That should be solved by generic constraints, but what if one of the objects, for example, implements IEquatable<TOfOtherObject>? NUnit should be aware of this and give them a chance to compare too.
I dunno, Charlie might have a clearer opinion on this. Maybe NUnit could provide a warning message?
 
> >> With no ToString(), btw. That must have been some other error
> >> that VS trapped at some point.

Any ideas on how to flush that other error out? Could the error be
that DateTime doesn't know about the DatePoint?

I have no idea about the ToString stuff, I couldn't replicate it. Can you show the exact stack trace you get? What does the implementation of DatePoint's ToString look like?
What do you mean with "DateTime doesn't know about DatePoint"?

Berryl Hesh

unread,
Dec 26, 2008, 1:32:19 PM12/26/08
to NUnit-Discuss


On Dec 26, 9:22 am, "Simone Busoli" <simone.bus...@gmail.com> wrote:
> On Fri, Dec 26, 2008 at 5:07 PM, Berryl Hesh <ef747...@gmail.com> wrote:
> > Thanks for walking through this too Simone. Until you do have generic
> > constraints, I wonder if  NUnit can identify that the test can't
> > succeed and leave a more informative message.
>
> Theoretically, it could, but it would get tricky because NUnit should make
> assumptions about the two objects that might now be always true. When
> comparing objects about equality or disequality, NUnit could assume that in
> order to perform a successful comparison the two objects should be of the
> same type or on the same hierarchy. That should be solved by generic
> constraints, but what if one of the objects, for example, implements
> IEquatable<TOfOtherObject>? NUnit should be aware of this and give them a
> chance to compare too.
> I dunno, Charlie might have a clearer opinion on this. Maybe NUnit could
> provide a warning message?
>
> > > >> With no ToString(), btw. That must have been some other error
> > > >> that VS trapped at some point.
>
> > Any ideas on how to flush that other error out? Could the error be
> > that DateTime doesn't know about the DatePoint?
>
> I have no idea about the ToString stuff, I couldn't replicate it. Can you
> show the exact stack trace you get?

There no exception being thrown that I know of, so I don't think I can
do better than the trace left by NUnit I posted earlier (and below so
you don't have to hunt for it), or my copied view of the call stack.
Do you have a better idea how to get an exact trace.

DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals :
FailedNUnit.Framework.AssertionException: Expected: 2008-12-25
00:00:00.000 But was: <12/25/2008>
at NUnit.Framework.Assert.That(Object actual, Constraint constraint,
String message, Object[] args)
at NUnit.Framework.Assert.That(Object actual, Constraint constraint)
at
Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals
() in DatePointTest.EqualityComparison.cs: line 95

What does the implementation of
> DatePoint's ToString look like?

Below. Two special cases DatePoint needs to account for as a Range
object are what you see as Past & Future below, which are both static
(and which do call op implicit when they are created. The class isn't
a total beast, but it's not trivial and there sure could be something
off in it. I'm showing just the ToString() override that's doing most
of the work, the Past and the static op == to keep it digestible.

/// <summary>pass thru of <see cref="DateTime"/> formats only
for now</summary>
public string ToString(string format, IFormatProvider
formatProvider)
{
if (_isPast(this)) return "The Past";
if (_isFuture(this)) return "The Future";

var workingFormat = _validateFormat(format, Precision);
return _wrappedDate.ToString(workingFormat,
formatProvider);
}

/// <summary>overload of operator == both <see
cref="DatePoint"/>s</summary>
public static bool operator ==(DatePoint lhs, DatePoint rhs) {
// If both are null, or both are same instance, return
true.
if (ReferenceEquals(lhs, rhs)) {
return true;
}
// If one is null, but not both, return false.
if (((object)lhs == null) || ((object)rhs == null)) {
return false;
}

var areEqual = lhs._wrappedDate.Equals(rhs._wrappedDate);

/// account for undefined end cases (Past && Future); each
can only be equal to itself
if (_isFuture(lhs) || _isFuture(rhs) || _isPast(lhs) ||
_isPast(rhs)) {
areEqual = false;
}

return areEqual;
}

/// <summary>overload of operator == one is <see
cref="DateTime"/>s</summary>
public static bool operator ==(DateTime lhs, DatePoint rhs)
{ return lhs == rhs._wrappedDate; }

/// <summary>overload of operator == one is <see
cref="DateTime"/>s</summary>
public static bool operator ==(DatePoint lhs, DateTime rhs)
{ return lhs._wrappedDate == rhs; }

/// <summary>Undefined <see cref="DatePoint"/> known only to
be in the past, and smaller than any other date except itself.</
summary>
public readonly static DatePoint Past = DateTime.MinValue;


> What do you mean with "DateTime doesn't know about DatePoint"?

As Charlie put it, "My guess, however, is that DateTime will not find

Charlie Poole

unread,
Dec 26, 2008, 1:40:28 PM12/26/08
to nunit-...@googlegroups.com
HI Simone,

Charlie, time to put generics on constraints? :)
 
I guess the simplest approach would be to deal only with constraints taking an actual and an expected value - which is most of them anyway. In order to avoid ambiguity among the Assert.That overloads, it would probably have to be a completely new class, rather than deriving from Constraint. It could have a generic member Matches, which would take a Type parameter for the supplied actual value. Is that along the lines you are suggesting?
 
Charlie

Charlie Poole

unread,
Dec 26, 2008, 1:41:36 PM12/26/08
to nunit-...@googlegroups.com
Hi Berryl,

> Any ideas on how to flush that other error out? Could the
> error be that DateTime doesn't know about the DatePoint?

Can you replicate it in a small example?

Charlie

Simone Busoli

unread,
Dec 26, 2008, 1:50:06 PM12/26/08
to nunit-...@googlegroups.com
Actually it was just a joke, I have no idea how I would go to implement it right now, and not sure it would be bullet proof. I'm not sure it would let us get rid of the non generic variant.

Charlie Poole

unread,
Dec 26, 2008, 1:49:38 PM12/26/08
to nunit-...@googlegroups.com
Hi Simone,
 
Theoretically, it could, but it would get tricky because NUnit should make assumptions about the two objects that might now be always true. When comparing objects about equality or disequality, NUnit could assume that in order to perform a successful comparison the two objects should be of the same type or on the same hierarchy. That should be solved by generic constraints, but what if one of the objects, for example, implements IEquatable<TOfOtherObject>? NUnit should be aware of this and give them a chance to compare too.
I dunno, Charlie might have a clearer opinion on this. Maybe NUnit could provide a warning message? 
 
It does - the test fails! :-)
 
Seriously, that's what test frameworks do, they run tests and give error messages when a test fails. Sometimes, it's hard to figure out why the test failed - as in this case. But that's usually related to .NET corner cases rather than NUnit.
 
It's true that Generics would make this test pass, but the test would still depend on some non-obvious details of the internal implementation of NUnit. IMO, that makes it not such a good test. Still, I agree that the current result violates the principle
of least surprise, so it would be good to fix it.
 
Charlie

Simone Busoli

unread,
Dec 26, 2008, 1:53:57 PM12/26/08
to nunit-...@googlegroups.com
Berryl, I don't see the ToString method being called in the trace, so I'm not sure I understand what problem you're talking about. Is it that you get a strange formatting of the actual result in the output? I mean, <12/25/2008> instead of something else?

Simone Busoli

unread,
Dec 26, 2008, 1:57:18 PM12/26/08
to nunit-...@googlegroups.com
What I mean is that it would be too much for NUnit to make the test pass, but it would still make the test fail trying to figure out why the test failed and reporting an hypothetic reason on the output.
About fixing it, do you have any idea how to accomplish that?

Charlie Poole

unread,
Dec 26, 2008, 2:04:10 PM12/26/08
to nunit-...@googlegroups.com
Hi Berryl,

> There no exception being thrown that I know of, so I don't
> think I can do better than the trace left by NUnit I posted
> earlier (and below so you don't have to hunt for it), or my
> copied view of the call stack.

I may have misunderstood something earlier. I was assuming that
your call stack was the result of an exception that VS caught.
Could you explain again how you got it?

Charlie

Charlie Poole

unread,
Dec 26, 2008, 2:08:06 PM12/26/08
to nunit-...@googlegroups.com
Hi SImone,
 
Re fixing it: I figured you'd write that generic constraint. :-)
 
Seriously, a generic approach would be usefuil, but I think it's too big a change
to add to the 2.5 release - I'd rathe get it out first.
 
Charlie


From: nunit-...@googlegroups.com [mailto:nunit-...@googlegroups.com] On Behalf Of Simone Busoli
Sent: Friday, December 26, 2008 10:57 AM
To: nunit-...@googlegroups.com

Subject: [nunit-discuss] Re: Is.EqualTo calling ToString on implicit conversion

Simone Busoli

unread,
Dec 26, 2008, 2:12:32 PM12/26/08
to nunit-...@googlegroups.com
Sure Charlie. Actually, I have already implemented something with a totally different syntax a while ago. It was something like

Assert.That(1, i => i.Is.EqualTo(1)).

That used the same constraints as NUnit but provided syntactic sugar so that you couldn't pass a string to the above EqualTo method. If you're interested I'll give you the url of the repo.

Charlie Poole

unread,
Dec 26, 2008, 2:22:33 PM12/26/08
to nunit-...@googlegroups.com
Hi Simone,

Sure Charlie. Actually, I have already implemented something with a totally different syntax a while ago. It was something like

Assert.That(1, i => i.Is.EqualTo(1)).

That used the same constraints as NUnit but provided syntactic sugar so that you couldn't pass a string to the above EqualTo method. If you're interested I'll give you the url of the repo.
 
I'd like to take a look.
 
Charlie 

Simone Busoli

unread,
Dec 26, 2008, 2:28:36 PM12/26/08
to nunit-...@googlegroups.com

Berryl Hesh

unread,
Dec 26, 2008, 3:12:48 PM12/26/08
to NUnit-Discuss
The call stack I first showed was the result of copy paste of the VS
call stack window as I stepped through the debugger. I wanted to
communicate that I was jumping straight from Assert.That(actObject,
Is.EqualTo(expObject) to ToString() instead of Equals(object). No
error other than the test failure was thrown.

Berryl

Charlie Poole

unread,
Dec 26, 2008, 4:33:27 PM12/26/08
to nunit-...@googlegroups.com
Hi Berryl,

> The call stack I first showed was the result of copy paste of
> the VS call stack window as I stepped through the debugger. I
> wanted to communicate that I was jumping straight from
> Assert.That(actObject,
> Is.EqualTo(expObject) to ToString() instead of
> Equals(object). No error other than the test failure was thrown.

Here's that original call stack:

1 Smack.Core.Tests.DLL!
Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_D
ateTime_Equals
() Line 94 + 0x2d bytes
2 Smack.Core.DLL!Smack.Core.Domain.Temporal.DatePoint.implicit
operator Smack.Core.Domain.Temporal.DatePoint(System.DateTime datetime =
{12/25/2008 12:00:00 AM}) Line 202

3 Smack.Core.Tests.DLL!
Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_D
ateTime_Equals


() Line 94 + 0x63 bytes [External Code]
4 Smack.Core.DLL!Smack.Core.Domain.Temporal.DatePoint.ToString(string
format = null, System.IFormatProvider formatProvider = {}) Line 222
[External Code]

I don't see an entry for NUnit.Framework.Assert.That().

Charlie

Simone Busoli

unread,
Dec 26, 2008, 6:15:26 PM12/26/08
to nunit-...@googlegroups.com
Here's the other one that you posted, I'm not sure I understand what's going on exactly:

DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals :
FailedNUnit.Framework.AssertionException:   Expected: 2008-12-25
00:00:00.000  But was:  <12/25/2008>
at NUnit.Framework.Assert.That(Object actual, Constraint constraint,
String message, Object[] args)
at NUnit.Framework.Assert.That(Object actual, Constraint constraint)
at
Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals
() in DatePointTest.EqualityComparison.cs: line 95

Berryl Hesh

unread,
Dec 26, 2008, 7:50:31 PM12/26/08
to NUnit-Discuss
I thought my home-made call stack copy would shed some insight into
why DatePoint.ToString() is the last call but it's just more noise at
this point.

Do an assert on object and DateTime and you see the same message with
the same trace (or look below). Nunit is just plain calling ToString()
as part of the failure message, and the last call, to help make it as
clear as it can that the expectation of equality did not happen.

My take away here is that this Assert form, while elegant, needs to be
better understood by the less experienced user (ie, me). If and when
you get a generic or other solution to this I for one will understand
the release notes much better :-)

Thx!

Berryl

[Test]public void TestCase() {Assert.That(new object(),
Is.EqualTo(DateTime.Today));}

NUnit.Framework.AssertionException: Expected: 2008-12-26
00:00:00.000
But was: <System.Object>

at NUnit.Framework.Assert.That(Object actual, Constraint constraint,
String message, Object[] args)
at NUnit.Framework.Assert.That(Object actual, Constraint constraint)
at
Smack.Core.Tests.Domain.Planning.ResourceAllocations.ActivityTest.TestCase
() in ActivityTest.cs: line 291 `




On Dec 26, 3:15 pm, "Simone Busoli" <simone.bus...@gmail.com> wrote:
> Here's the other one that you posted, I'm not sure I understand what's going
> on exactly:
> DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals :
> FailedNUnit.Framework.AssertionException:   Expected: 2008-12-25
> 00:00:00.000  But was:  <12/25/2008>
> at NUnit.Framework.Assert.That(Object actual, Constraint constraint,
> String message, Object[] args)
> at NUnit.Framework.Assert.That(Object actual, Constraint constraint)
> at
> Smack.Core.Tests.Domain.Temporal.DatePointTest.Implicit_Equality_DatePoint_DateTime_Equals
> () in DatePointTest.EqualityComparison.cs: line 95
>

Charlie Poole

unread,
Dec 26, 2008, 8:07:05 PM12/26/08
to nunit-...@googlegroups.com
Hi Berryl,

To be clear, there was never any doubt about ToString() being called
as a part of displaying the error message - that's how it gets the
strings to display for the expected and actual values. I thought
you were saying that Is.Equal was comparing the string representations
of the two objects in order to make the comparison, which would
definitely be a bug.

Unless I hear further on this, I think we can conclude that the
trace you copied from VSS is at a point *after* the failure,
when Assert.That is calling the EqualConstraint methods that
display the descriptions of the values.

The stack trace that NUnit shows is the stack at the point where
the constraint has failed, and that's the one we want.

Charlie

> -----Original Message-----
> From: nunit-...@googlegroups.com
> [mailto:nunit-...@googlegroups.com] On Behalf Of Berryl Hesh
> Sent: Friday, December 26, 2008 4:51 PM
> To: NUnit-Discuss
> Subject: [nunit-discuss] Re: Is.EqualTo calling ToString on
> implicit conversion
>
>

Berryl Hesh

unread,
Dec 26, 2008, 9:17:30 PM12/26/08
to NUnit-Discuss
Crystal clear as to where the ToString call is coming from now. I
never said this was a bug, only that I didn't get it, and what I
didn't get.

But it's the why I didn't get it that I was and am implying could be a
potential release note or clarification. Equals in this narrow case is
not symmetric (If x == y, then y == x) as it is when presented to the
compiler statically. Do you agree that the semantics of Equals should
ideally be symmetric? If you could easily make the assertion guarantee
symmetry in all cases would you do so?

I just want to use your very fine product to do a better job, not
knock it or claim it's broken when I don't get something. Thanks again
for your patience and insights.

- Berryl

Charlie Poole

unread,
Dec 26, 2008, 10:10:28 PM12/26/08
to nunit-...@googlegroups.com
Hi Berryl,
> Crystal clear as to where the ToString call is coming from
> now. I never said this was a bug, only that I didn't get it,
> and what I didn't get.

No problem - your ToString() will always be called if your
object is used with a formatted write.

> But it's the why I didn't get it that I was and am implying
> could be a potential release note or clarification. Equals in
> this narrow case is not symmetric (If x == y, then y == x) as
> it is when presented to the compiler statically. Do you agree
> that the semantics of Equals should ideally be symmetric? If
> you could easily make the assertion guarantee symmetry in all
> cases would you do so?

Unfortunately - and maybe I'm just dense - I can't figure out
what sort of a note we would put on the EqualConstraint. It
would have to be quite detailed to get down to the situation
you ran into, because I can think of about five other things
that someone could do in their code that would break the
equality test and all of them are a lot more common than
a user-defined implicit conversion operator.

It seems to me that such a note would be more appropriate in a
C# tutorial than in the NUnit docs. Oh yes... and we'd have to
do it for VB, C++, etc. as well. :-)

I'm not dissin' you here. I'm just trying to make it clear
what a major piece of writing you're asking for.

I guess the only note I can think of that *might* help would
be one that explained the steps NUnit takes in testing an
equality constraint. The last step would say something like
"If none of the other conditions apply, then the Equals(object)
method on your expected object is used." Do you think that
would help?

> I just want to use your very fine product to do a better job,
> not knock it or claim it's broken when I don't get something.
> Thanks again for your patience and insights.

In either case, Berryl, there would be nothing wrong. We like
it when you point out that things are broken. You'll get a
lively lively discussion some of the time, but that's how
we find out what's really happening.

Charlie

Berryl Hesh

unread,
Dec 27, 2008, 1:20:02 PM12/27/08
to NUnit-Discuss
Hi Charlie

> I guess the only note I can think of that *might* help would
> be one that explained the steps NUnit takes in testing an
> equality constraint. The last step would say something like
> "If none of the other conditions apply, then the Equals(object)
> method on your expected object is used." Do you think that
> would help?

Other than for the time it would take to write it and the space it
takes to display it, sure. It's always good to know what the rules
are. Now if you asked me whether this was a high priority item, I
would agree with you and anyone else reading this thread and say of
course not.

> Unfortunately - and maybe I'm just dense

Fortunately - you are anything but.

- Berryl

Charlie Poole

unread,
Dec 27, 2008, 2:20:38 PM12/27/08
to nunit-...@googlegroups.com
Hi Berryl,

I'll see what I can do in the final release. It has proven
confusing to new users that the semantics of Is.EqualTo()
are not spelled out completely.
Reply all
Reply to author
Forward
0 new messages