Git Product home page Git Product logo

Comments (18)

sjamesr avatar sjamesr commented on July 27, 2024 2

Oh, that's good to know, thanks! (I'm using Truth 0.23).

As far as dealing with the original issue is concerned, I think a sensible
scheme for disambiguation could be:

assertThat(ImmutableList.of("1")).containsExactly(1L);
java.lang.AssertionError: Not true that <[1]> contains exactly <[1]>.

It is missing <[1 (java.lang.Long)]>

This could be done by introducing a Disambiguator class that keeps track of
the string representations of all the elements. When time comes to emit the
differences, the disambiguator is asked to disambiguate each element before
it is emitted.

from truth.

sjamesr avatar sjamesr commented on July 27, 2024 1

What if the hashcodes are equal too? !a.equals(b) does not imply a.hashCode() != b.hashCode(). :)

I would be happy if the basic case of int literals vs longs (and probably float literals vs doubles) worked for collections.

from truth.

kluever avatar kluever commented on July 27, 2024

We do disambiguate for direct comparisons, but we don't do it for collections.

It's a little difficult to come up with a perfect error message here though. If we do what you're proposing, these two would have identical error messages:
assertThat(ImmutableList.of("1L")).containsExactly(1);
assertThat(ImmutableList.of(1L)).containsExactly(1);

from truth.

hagbard avatar hagbard commented on July 27, 2024

I generally agree with pulling out strings to look like the literals they
started as. This means re-escaping double-quotes, but it should be
unambiguous (assuming you also single quote chars). This embeds string- or
char-ness nicely in the output.

Obviously this is hard when things like \uxxxx chars are used (there's no
way to know what went into the string).

My approach to this would be simply construct the common case error message
parts and if both the expected and actual strings were equal, annotate then
with type information.

Not true that <1> (java.lang.Integer) is equal to <1> (java.math.BigInteger)

Obviously it's harder for collections, but maybe just where types differ:

Not true that <[1, 2 (java.lang.Integer), 3]> is equal to <[1, 2 (
java.math.BigInteger), 3]>

Even then there's an issue with things like Unicode combining characters:
http://en.wikipedia.org/wiki/Combining_character

Which could lead to messages like:
Not true that <"ångström"> equals <"ångström">

In this case you'd need to use a machine form of some kind (*):

Not true that <"ångström"> (\u00E5ngstr\u00F6m) equals <"ångström">
(\u0061\u030Angstr\u00F6m)

I feel that Truth is great opportunity to "do the right thing" for every
use case; even if it's super hard to get it right inside Truth.

David

(*) This reminds me to look at adding Unicode aware assertions into a truth
extension for use with I18n code.

On 11 November 2014 15:45, James Ring [email protected] wrote:

In your example, wouldn't the error messages look like

Not true that <["1L"]> contains exactly <[1L]>

?

I suppose it's possible to construct examples that would foil any
disambiguation scheme. I just thought the int vs. long thing is fairly
common.


Reply to this email directly or view it on GitHub
#151 (comment).

from truth.

sjamesr avatar sjamesr commented on July 27, 2024

The general problem is that a.equals(b) does not imply a.toString().equals(b.toString()). It will always be possible for unequal objects to have equal toString(), if they are of the same type then adding type information will obviously not help. I don't think there is a general solution to that problem.

However, emitting the type when toString() is equal and the types differ would definitely help for the case of integer literals, which I think is a very common use case.

from truth.

hagbard avatar hagbard commented on July 27, 2024

Oh, and if the objects are not equals, but the toString() is the same, and
the type is the same, then you print the hashcode (and if that's the same
you print the Object hashcode).
By this time I'd expect a good few lines of "Warning: Stop being daft..."
type messages with it too.

I know it sounds like a lot of work, but every time I get a useless assert
failure message, it makes me sad. Truth would really differentiate itself
in my eyes by going the extra mile here.

David

On 12 November 2014 08:00, James Ring [email protected] wrote:

The general problem is that a.equals(b) does not imply
a.toString().equals(b.toString()). It will always be possible for unequal
objects to have equal toString(), if they are of the same type then adding
type information will obviously not help. I don't think there is a general
solution to that problem.

However, emitting the type when toString() is equal and the types differ
would definitely help for the case of integer literals, which I think is a
very common use case.


Reply to this email directly or view it on GitHub
#151 (comment).

from truth.

lowasser avatar lowasser commented on July 27, 2024

Worth mentioning: a long in int range will have the same hashCode as that
int, so you're not buying yourself anything for that case...

On Wed Nov 12 2014 at 11:03:11 AM James Ring [email protected]
wrote:

What if the hashcodes are equal too? !a.equals(b) does not imply a.hashCode()
!= b.hashCode(). :)

I would be happy if the basic case of int literals vs longs (and probably
float literals vs doubles) worked for collections.


Reply to this email directly or view it on GitHub
#151 (comment).

from truth.

hagbard avatar hagbard commented on July 27, 2024

Yes, but the types are distinct, so we'd already have found uniqueness.

x.toString() > x.getClass() > x.hashcode() > Objects.hashcode(x)

Stop whenever we see a difference. There is always going to be something
we can put in front of a user to distinguish the cases.

David

On 12 November 2014 12:19, Louis Wasserman [email protected] wrote:

Worth mentioning: a long in int range will have the same hashCode as that
int, so you're not buying yourself anything for that case...

On Wed Nov 12 2014 at 11:03:11 AM James Ring [email protected]
wrote:

What if the hashcodes are equal too? !a.equals(b) does not imply
a.hashCode()
!= b.hashCode(). :)

I would be happy if the basic case of int literals vs longs (and
probably
float literals vs doubles) worked for collections.


Reply to this email directly or view it on GitHub
#151 (comment).


Reply to this email directly or view it on GitHub
#151 (comment).

from truth.

sjamesr avatar sjamesr commented on July 27, 2024

Not always:

class Test {
    @Override public int hashCode() { return 0; }
    @Override public boolean equals(Object o) { return false; }
    @Override public String toString() { return "Silly class"; }
}

It's a pathological case but it demonstrates that there are situations where the objects simply cannot be distinguished. This is because the equals predicate can be defined in terms of things outside of string representation and type.

from truth.

hagbard avatar hagbard commented on July 27, 2024

Sorry, that last one should have read:

https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#identityHashCode(java.lang.Object)

David

On 12 November 2014 18:28, James Ring [email protected] wrote:

Not always:

class Test {
@OverRide public int hashCode() { return 0; }
@OverRide public boolean equals(Object o) { return false; }
@OverRide public String toString() { return "Silly class"; }
}

It's a pathological case but it demonstrates that there are situations
where the objects simply cannot be distinguished. This is because the
equals predicate can be defined in terms of things outside of string
representation and type.


Reply to this email directly or view it on GitHub
#151 (comment).

from truth.

sjamesr avatar sjamesr commented on July 27, 2024

Flogging the dead horse: this would give something like

Test t = new Test();
assertThat(t).isEqualTo(t);

Expected "Silly class" (identity hashcode=1234) but was "Silly class" (identity hashcode=1234).

There's no way to solve this for all cases.

from truth.

hagbard avatar hagbard commented on July 27, 2024

You are totally missing the point here I'm afraid. We only care about
putting out the message when they are different in some way. Even if
everything about their toString/hashcode is the same, to be different in
the assert they must be different instances. Different instances always
have different IDENTITY hash codes. If I literally do what you wrote, the
asset won't fail and therefore we don't care about making failure messages.

David
On 12 Nov 2014 18:38, "James Ring" [email protected] wrote:

Flogging the dead horse: this would give something like

Test t = new Test();
assertThat(t).isEqualTo(t);

Expected "Silly class" (hashcode=0) but was "Silly class" (hashcode=0).

There's no way to solve this for all cases.


Reply to this email directly or view it on GitHub
#151 (comment).

from truth.

sjamesr avatar sjamesr commented on July 27, 2024

If you look at the implementation of isEqualTo, you'll find that identity equality is never considered. In my example, the identity hashcodes are equal and yet the assertion fails, so you'll still end up with a useless error message.

from truth.

hagbard avatar hagbard commented on July 27, 2024

Ok, so I would have assumed that identity equality should be considered a
"gospel" anywhere.

Your case is possible but relies on violating identity equality, which is
not a case I particularly care about; it's not realistic and could be
caught with an equality behaviour test (which can be often be automated).

Truth could still catch this by saying:

if (expected == actual) {
assertTrue(Objects.equal(expected, actual), "message about how you
instances are badly implemented");
}
// ... run sane test from here on.

Basically if a human can look at the situation and figure out that, despite
looking the same, the objects didn't match the equality test, Truth can
also do sufficient reasoning and print out messages that are distinct.
There is no case where we have to fall back to "expected but was
" ... none (even if it involves a completely different message in
extreme cases).

David

On 12 November 2014 20:55, James Ring [email protected] wrote:

If you look at the implementation of isEqualTo, you'll find that identity
equality is never considered. In my example, the identity hashcodes are
equal and yet the assertion fails, so you'll still end up with a useless
error message.

Try it! :)


Reply to this email directly or view it on GitHub
#151 (comment).

from truth.

kluever avatar kluever commented on July 27, 2024

@sjamesr wrote:

If you look at the implementation of isEqualTo, you'll find that identity equality is never considered. In my example, the identity hashcodes are equal and yet the assertion fails, so you'll still end up with a useless error message.

Hmm, Subject.isEqualTo() calls Objects.equal() which checks a == b.

from truth.

sjamesr avatar sjamesr commented on July 27, 2024

This is easily falsifiable:

@Test
public void sillyTest() {
  Object o = new Object() {
    @Override
    public boolean equals(Object ignored) {
      return false;
    }
  };
  assertThat(o).isEqualTo(o);
}

from truth.

kluever avatar kluever commented on July 27, 2024

@sjamesr That test passes for me. I suspect you're using an older version of Truth. I made the change to use Objects.equal() in Subject.isEqualTo() back in early August:
339e62d

from truth.

cpovirk avatar cpovirk commented on July 27, 2024

I believe that we now do this. (Certainly we do a bunch of things like this; if we're missing something specific, please let us know.)

from truth.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.