|
@@ -60,6 +60,7 @@ import junit.framework.TestCase;
|
|
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Arrays;
|
|
|
|
+import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -2684,6 +2685,224 @@ public class NanoTest extends TestCase {
|
|
assertHasWireData(message, false);
|
|
assertHasWireData(message, false);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ public void testHashCodeEquals() throws Exception {
|
|
|
|
+ // Complete equality:
|
|
|
|
+ TestAllTypesNano a = createMessageForHashCodeEqualsTest();
|
|
|
|
+ TestAllTypesNano aEquivalent = createMessageForHashCodeEqualsTest();
|
|
|
|
+
|
|
|
|
+ // Null and empty array for repeated fields equality:
|
|
|
|
+ TestAllTypesNano b = createMessageForHashCodeEqualsTest();
|
|
|
|
+ b.repeatedBool = null;
|
|
|
|
+ b.repeatedFloat = new float[0];
|
|
|
|
+ TestAllTypesNano bEquivalent = createMessageForHashCodeEqualsTest();
|
|
|
|
+ bEquivalent.repeatedBool = new boolean[0];
|
|
|
|
+ bEquivalent.repeatedFloat = null;
|
|
|
|
+
|
|
|
|
+ // Ref-element-type repeated fields use non-null subsequence equality:
|
|
|
|
+ TestAllTypesNano c = createMessageForHashCodeEqualsTest();
|
|
|
|
+ c.repeatedString = null;
|
|
|
|
+ c.repeatedStringPiece = new String[] {null, "one", null, "two"};
|
|
|
|
+ c.repeatedBytes = new byte[][] {{3, 4}, null};
|
|
|
|
+ TestAllTypesNano cEquivalent = createMessageForHashCodeEqualsTest();
|
|
|
|
+ cEquivalent.repeatedString = new String[3];
|
|
|
|
+ cEquivalent.repeatedStringPiece = new String[] {"one", "two", null};
|
|
|
|
+ cEquivalent.repeatedBytes = new byte[][] {{3, 4}};
|
|
|
|
+
|
|
|
|
+ // Complete equality for messages with has fields:
|
|
|
|
+ TestAllTypesNanoHas d = createMessageWithHasForHashCodeEqualsTest();
|
|
|
|
+ TestAllTypesNanoHas dEquivalent = createMessageWithHasForHashCodeEqualsTest();
|
|
|
|
+
|
|
|
|
+ // If has-fields exist, fields with the same default values but
|
|
|
|
+ // different has-field values are different.
|
|
|
|
+ TestAllTypesNanoHas e = createMessageWithHasForHashCodeEqualsTest();
|
|
|
|
+ e.optionalInt32++; // make different from d
|
|
|
|
+ e.hasDefaultString = false;
|
|
|
|
+ TestAllTypesNanoHas eDifferent = createMessageWithHasForHashCodeEqualsTest();
|
|
|
|
+ eDifferent.optionalInt32 = e.optionalInt32;
|
|
|
|
+ eDifferent.hasDefaultString = true;
|
|
|
|
+
|
|
|
|
+ // Complete equality for messages with accessors:
|
|
|
|
+ TestNanoAccessors f = createMessageWithAccessorsForHashCodeEqualsTest();
|
|
|
|
+ TestNanoAccessors fEquivalent = createMessageWithAccessorsForHashCodeEqualsTest();
|
|
|
|
+ System.out.println("equals: " + f.equals(fEquivalent));
|
|
|
|
+ System.out.println("hashCode: " + f.hashCode() + " vs " + fEquivalent.hashCode());
|
|
|
|
+
|
|
|
|
+ // If using accessors, explicitly setting a field to its default value
|
|
|
|
+ // should make the message different.
|
|
|
|
+ TestNanoAccessors g = createMessageWithAccessorsForHashCodeEqualsTest();
|
|
|
|
+ g.setOptionalInt32(g.getOptionalInt32() + 1); // make different from f
|
|
|
|
+ g.clearDefaultString();
|
|
|
|
+ TestNanoAccessors gDifferent = createMessageWithAccessorsForHashCodeEqualsTest();
|
|
|
|
+ gDifferent.setOptionalInt32(g.getOptionalInt32());
|
|
|
|
+ gDifferent.setDefaultString(g.getDefaultString());
|
|
|
|
+
|
|
|
|
+ // Complete equality for reference typed messages:
|
|
|
|
+ NanoReferenceTypes.TestAllTypesNano h = createRefTypedMessageForHashCodeEqualsTest();
|
|
|
|
+ NanoReferenceTypes.TestAllTypesNano hEquivalent = createRefTypedMessageForHashCodeEqualsTest();
|
|
|
|
+
|
|
|
|
+ // Inequality of null and default value for reference typed messages:
|
|
|
|
+ NanoReferenceTypes.TestAllTypesNano i = createRefTypedMessageForHashCodeEqualsTest();
|
|
|
|
+ i.optionalInt32 = 1; // make different from h
|
|
|
|
+ i.optionalFloat = null;
|
|
|
|
+ NanoReferenceTypes.TestAllTypesNano iDifferent = createRefTypedMessageForHashCodeEqualsTest();
|
|
|
|
+ iDifferent.optionalInt32 = i.optionalInt32;
|
|
|
|
+ iDifferent.optionalFloat = 0.0f;
|
|
|
|
+
|
|
|
|
+ HashMap<MessageNano, String> hashMap = new HashMap<MessageNano, String>();
|
|
|
|
+ hashMap.put(a, "a");
|
|
|
|
+ hashMap.put(b, "b");
|
|
|
|
+ hashMap.put(c, "c");
|
|
|
|
+ hashMap.put(d, "d");
|
|
|
|
+ hashMap.put(e, "e");
|
|
|
|
+ hashMap.put(f, "f");
|
|
|
|
+ hashMap.put(g, "g");
|
|
|
|
+ hashMap.put(h, "h");
|
|
|
|
+ hashMap.put(i, "i");
|
|
|
|
+
|
|
|
|
+ assertEquals(9, hashMap.size()); // a-i should be different from each other.
|
|
|
|
+
|
|
|
|
+ assertEquals("a", hashMap.get(a));
|
|
|
|
+ assertEquals("a", hashMap.get(aEquivalent));
|
|
|
|
+
|
|
|
|
+ assertEquals("b", hashMap.get(b));
|
|
|
|
+ assertEquals("b", hashMap.get(bEquivalent));
|
|
|
|
+
|
|
|
|
+ assertEquals("c", hashMap.get(c));
|
|
|
|
+ assertEquals("c", hashMap.get(cEquivalent));
|
|
|
|
+
|
|
|
|
+ assertEquals("d", hashMap.get(d));
|
|
|
|
+ assertEquals("d", hashMap.get(dEquivalent));
|
|
|
|
+
|
|
|
|
+ assertEquals("e", hashMap.get(e));
|
|
|
|
+ assertNull(hashMap.get(eDifferent));
|
|
|
|
+
|
|
|
|
+ assertEquals("f", hashMap.get(f));
|
|
|
|
+ assertEquals("f", hashMap.get(fEquivalent));
|
|
|
|
+
|
|
|
|
+ assertEquals("g", hashMap.get(g));
|
|
|
|
+ assertNull(hashMap.get(gDifferent));
|
|
|
|
+
|
|
|
|
+ assertEquals("h", hashMap.get(h));
|
|
|
|
+ assertEquals("h", hashMap.get(hEquivalent));
|
|
|
|
+
|
|
|
|
+ assertEquals("i", hashMap.get(i));
|
|
|
|
+ assertNull(hashMap.get(iDifferent));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private TestAllTypesNano createMessageForHashCodeEqualsTest() {
|
|
|
|
+ TestAllTypesNano message = new TestAllTypesNano();
|
|
|
|
+ message.optionalInt32 = 5;
|
|
|
|
+ message.optionalInt64 = 777;
|
|
|
|
+ message.optionalFloat = 1.0f;
|
|
|
|
+ message.optionalDouble = 2.0;
|
|
|
|
+ message.optionalBool = true;
|
|
|
|
+ message.optionalString = "Hello";
|
|
|
|
+ message.optionalBytes = new byte[] { 1, 2, 3 };
|
|
|
|
+ message.optionalNestedMessage = new TestAllTypesNano.NestedMessage();
|
|
|
|
+ message.optionalNestedMessage.bb = 27;
|
|
|
|
+ message.optionalNestedEnum = TestAllTypesNano.BAR;
|
|
|
|
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
|
|
|
|
+ message.repeatedInt64 = new long[] { 27L, 28L, 29L };
|
|
|
|
+ message.repeatedFloat = new float[] { 5.0f, 6.0f };
|
|
|
|
+ message.repeatedDouble = new double[] { 99.1, 22.5 };
|
|
|
|
+ message.repeatedBool = new boolean[] { true, false, true };
|
|
|
|
+ message.repeatedString = new String[] { "One", "Two" };
|
|
|
|
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
|
|
|
|
+ message.repeatedNestedMessage = new TestAllTypesNano.NestedMessage[] {
|
|
|
|
+ message.optionalNestedMessage,
|
|
|
|
+ message.optionalNestedMessage
|
|
|
|
+ };
|
|
|
|
+ message.repeatedNestedEnum = new int[] {
|
|
|
|
+ TestAllTypesNano.BAR,
|
|
|
|
+ TestAllTypesNano.BAZ
|
|
|
|
+ };
|
|
|
|
+ // We set the _nan fields to something other than nan, because equality
|
|
|
|
+ // is defined for nan such that Float.NaN != Float.NaN, which makes any
|
|
|
|
+ // instance of TestAllTypesNano unequal to any other instance unless
|
|
|
|
+ // these fields are set. This is also the behavior of the regular java
|
|
|
|
+ // generator when the value of a field is NaN.
|
|
|
|
+ message.defaultFloatNan = 1.0f;
|
|
|
|
+ message.defaultDoubleNan = 1.0;
|
|
|
|
+ return message;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private TestAllTypesNanoHas createMessageWithHasForHashCodeEqualsTest() {
|
|
|
|
+ TestAllTypesNanoHas message = new TestAllTypesNanoHas();
|
|
|
|
+ message.optionalInt32 = 5;
|
|
|
|
+ message.optionalString = "Hello";
|
|
|
|
+ message.optionalBytes = new byte[] { 1, 2, 3 };
|
|
|
|
+ message.optionalNestedMessage = new TestAllTypesNanoHas.NestedMessage();
|
|
|
|
+ message.optionalNestedMessage.bb = 27;
|
|
|
|
+ message.optionalNestedEnum = TestAllTypesNano.BAR;
|
|
|
|
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
|
|
|
|
+ message.repeatedString = new String[] { "One", "Two" };
|
|
|
|
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
|
|
|
|
+ message.repeatedNestedMessage = new TestAllTypesNanoHas.NestedMessage[] {
|
|
|
|
+ message.optionalNestedMessage,
|
|
|
|
+ message.optionalNestedMessage
|
|
|
|
+ };
|
|
|
|
+ message.repeatedNestedEnum = new int[] {
|
|
|
|
+ TestAllTypesNano.BAR,
|
|
|
|
+ TestAllTypesNano.BAZ
|
|
|
|
+ };
|
|
|
|
+ message.defaultFloatNan = 1.0f;
|
|
|
|
+ return message;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private TestNanoAccessors createMessageWithAccessorsForHashCodeEqualsTest() {
|
|
|
|
+ TestNanoAccessors message = new TestNanoAccessors()
|
|
|
|
+ .setOptionalInt32(5)
|
|
|
|
+ .setOptionalString("Hello")
|
|
|
|
+ .setOptionalBytes(new byte[] {1, 2, 3})
|
|
|
|
+ .setOptionalNestedMessage(new TestNanoAccessors.NestedMessage().setBb(27))
|
|
|
|
+ .setOptionalNestedEnum(TestNanoAccessors.BAR)
|
|
|
|
+ .setDefaultFloatNan(1.0f);
|
|
|
|
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
|
|
|
|
+ message.repeatedString = new String[] { "One", "Two" };
|
|
|
|
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
|
|
|
|
+ message.repeatedNestedMessage = new TestNanoAccessors.NestedMessage[] {
|
|
|
|
+ message.getOptionalNestedMessage(),
|
|
|
|
+ message.getOptionalNestedMessage()
|
|
|
|
+ };
|
|
|
|
+ message.repeatedNestedEnum = new int[] {
|
|
|
|
+ TestAllTypesNano.BAR,
|
|
|
|
+ TestAllTypesNano.BAZ
|
|
|
|
+ };
|
|
|
|
+ return message;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private NanoReferenceTypes.TestAllTypesNano createRefTypedMessageForHashCodeEqualsTest() {
|
|
|
|
+ NanoReferenceTypes.TestAllTypesNano message = new NanoReferenceTypes.TestAllTypesNano();
|
|
|
|
+ message.optionalInt32 = 5;
|
|
|
|
+ message.optionalInt64 = 777L;
|
|
|
|
+ message.optionalFloat = 1.0f;
|
|
|
|
+ message.optionalDouble = 2.0;
|
|
|
|
+ message.optionalBool = true;
|
|
|
|
+ message.optionalString = "Hello";
|
|
|
|
+ message.optionalBytes = new byte[] { 1, 2, 3 };
|
|
|
|
+ message.optionalNestedMessage =
|
|
|
|
+ new NanoReferenceTypes.TestAllTypesNano.NestedMessage();
|
|
|
|
+ message.optionalNestedMessage.foo = 27;
|
|
|
|
+ message.optionalNestedEnum = NanoReferenceTypes.TestAllTypesNano.BAR;
|
|
|
|
+ message.repeatedInt32 = new int[] { 5, 6, 7, 8 };
|
|
|
|
+ message.repeatedInt64 = new long[] { 27L, 28L, 29L };
|
|
|
|
+ message.repeatedFloat = new float[] { 5.0f, 6.0f };
|
|
|
|
+ message.repeatedDouble = new double[] { 99.1, 22.5 };
|
|
|
|
+ message.repeatedBool = new boolean[] { true, false, true };
|
|
|
|
+ message.repeatedString = new String[] { "One", "Two" };
|
|
|
|
+ message.repeatedBytes = new byte[][] { { 2, 7 }, { 2, 7 } };
|
|
|
|
+ message.repeatedNestedMessage =
|
|
|
|
+ new NanoReferenceTypes.TestAllTypesNano.NestedMessage[] {
|
|
|
|
+ message.optionalNestedMessage,
|
|
|
|
+ message.optionalNestedMessage
|
|
|
|
+ };
|
|
|
|
+ message.repeatedNestedEnum = new int[] {
|
|
|
|
+ NanoReferenceTypes.TestAllTypesNano.BAR,
|
|
|
|
+ NanoReferenceTypes.TestAllTypesNano.BAZ
|
|
|
|
+ };
|
|
|
|
+ return message;
|
|
|
|
+ }
|
|
|
|
+
|
|
public void testNullRepeatedFields() throws Exception {
|
|
public void testNullRepeatedFields() throws Exception {
|
|
// Check that serialization after explicitly setting a repeated field
|
|
// Check that serialization after explicitly setting a repeated field
|
|
// to null doesn't NPE.
|
|
// to null doesn't NPE.
|