diff --git a/components/context/build.gradle.kts b/components/context/build.gradle.kts index 4dca7fc3036..c737d9fefdd 100644 --- a/components/context/build.gradle.kts +++ b/components/context/build.gradle.kts @@ -7,3 +7,7 @@ apply(from = "$rootDir/gradle/java.gradle") jmh { version = "1.28" } + +val excludedClassesInstructionCoverage by extra { + listOf("datadog.context.ContextProviders") // covered by forked test +} diff --git a/components/context/src/main/java/datadog/context/ContextKey.java b/components/context/src/main/java/datadog/context/ContextKey.java index 41b79a42c52..41f09e914a5 100644 --- a/components/context/src/main/java/datadog/context/ContextKey.java +++ b/components/context/src/main/java/datadog/context/ContextKey.java @@ -29,16 +29,7 @@ public int hashCode() { return index; } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } else if (o == null || getClass() != o.getClass()) { - return false; - } else { - return index == ((ContextKey) o).index; - } - } + // we want identity equality, so no need to override equals() @Override public String toString() { diff --git a/components/context/src/test/java/datadog/context/ContextBinderTest.java b/components/context/src/test/java/datadog/context/ContextBinderTest.java index 6aabffba095..6e1b77026c7 100644 --- a/components/context/src/test/java/datadog/context/ContextBinderTest.java +++ b/components/context/src/test/java/datadog/context/ContextBinderTest.java @@ -17,6 +17,7 @@ void testAttachAndDetach() { assertEquals(context, Context.from(carrier)); // Detaching removes all context assertEquals(context, Context.detachFrom(carrier)); + assertEquals(root(), Context.detachFrom(carrier)); assertEquals(root(), Context.from(carrier)); } } diff --git a/components/context/src/test/java/datadog/context/ContextKeyTest.java b/components/context/src/test/java/datadog/context/ContextKeyTest.java index 8e65485f6c3..3ef6236c51e 100644 --- a/components/context/src/test/java/datadog/context/ContextKeyTest.java +++ b/components/context/src/test/java/datadog/context/ContextKeyTest.java @@ -1,9 +1,11 @@ package datadog.context; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -31,4 +33,26 @@ void testKeyNameCollision() { assertEquals(value, context.get(key1)); assertNull(context.get(key2)); } + + @SuppressWarnings({ + "EqualsWithItself", + "SimplifiableAssertion", + "ConstantValue", + "EqualsBetweenInconvertibleTypes" + }) + @Test + void testEqualsAndHashCode() { + ContextKey key1 = ContextKey.named("same-name"); + ContextKey key2 = ContextKey.named("same-name"); + // Test equals on self + assertTrue(key1.equals(key1)); + assertEquals(key1.hashCode(), key1.hashCode()); + // Test equals on null + assertFalse(key1.equals(null)); + // Test equals on different object type + assertFalse(key1.equals("value")); + // Test equals on different keys with the same name + assertFalse(key1.equals(key2)); + assertNotEquals(key1.hashCode(), key2.hashCode()); + } } diff --git a/components/context/src/test/java/datadog/context/ContextTest.java b/components/context/src/test/java/datadog/context/ContextTest.java index c1632163bb6..a7ea8f42b52 100644 --- a/components/context/src/test/java/datadog/context/ContextTest.java +++ b/components/context/src/test/java/datadog/context/ContextTest.java @@ -2,6 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -12,6 +13,8 @@ class ContextTest { static final ContextKey STRING_KEY = ContextKey.named("string-key"); static final ContextKey BOOLEAN_KEY = ContextKey.named("boolean-key"); + static final ContextKey FLOAT_KEY = ContextKey.named("float-key"); + static final ContextKey LONG_KEY = ContextKey.named("long-key"); // demonstrate how values can hide their context keys static class ValueWithKey implements ImplicitContextKeyed { @@ -86,19 +89,33 @@ void testEqualsAndHashCode() { Context context1 = empty.with(STRING_KEY, "value"); Context context2 = empty.with(STRING_KEY, "value "); Context context3 = empty.with(STRING_KEY, "value ".trim()); + Context context4 = empty.with(STRING_KEY, "value").with(BOOLEAN_KEY, true); // Test equals on self assertTrue(empty.equals(empty)); assertTrue(context1.equals(context1)); + assertTrue(context4.equals(context4)); // Test equals on null assertFalse(context1.equals(null)); + assertFalse(context4.equals(null)); // Test equals on different object type assertFalse(context1.equals("value")); + assertFalse(context4.equals("value")); // Test equals on different contexts with the same values assertTrue(context1.equals(context3)); assertEquals(context1.hashCode(), context3.hashCode()); // Test equals on different contexts assertFalse(context1.equals(empty)); + assertNotEquals(context1.hashCode(), empty.hashCode()); assertFalse(context1.equals(context2)); + assertNotEquals(context1.hashCode(), context2.hashCode()); + assertFalse(context1.equals(context4)); + assertNotEquals(context1.hashCode(), context4.hashCode()); + assertFalse(empty.equals(context1)); + assertNotEquals(empty.hashCode(), context1.hashCode()); + assertFalse(context2.equals(context1)); + assertNotEquals(context2.hashCode(), context1.hashCode()); + assertFalse(context4.equals(context1)); + assertNotEquals(context4.hashCode(), context1.hashCode()); } @Test @@ -110,4 +127,41 @@ void testImplicitKey() { assertNull(ValueWithKey.from(empty)); assertEquals(valueWithKey, ValueWithKey.from(context)); } + + @SuppressWarnings({"SimplifiableAssertion"}) + @Test + void testInflation() { + Context empty = Context.root(); + + Context one = empty.with(STRING_KEY, "unset").with(STRING_KEY, "one"); + Context two = one.with(BOOLEAN_KEY, false).with(BOOLEAN_KEY, true); + Context three = two.with(FLOAT_KEY, 0.0f).with(FLOAT_KEY, 3.3f); + + assertNull(empty.get(STRING_KEY)); + assertNull(empty.get(BOOLEAN_KEY)); + assertNull(empty.get(FLOAT_KEY)); + assertNull(empty.get(LONG_KEY)); + + assertEquals("one", one.get(STRING_KEY)); + assertNull(one.get(BOOLEAN_KEY)); + assertNull(one.get(FLOAT_KEY)); + assertNull(one.get(LONG_KEY)); + + assertEquals("one", two.get(STRING_KEY)); + assertEquals(true, two.get(BOOLEAN_KEY)); + assertNull(two.get(FLOAT_KEY)); + assertNull(two.get(LONG_KEY)); + + assertEquals("one", three.get(STRING_KEY)); + assertEquals(true, three.get(BOOLEAN_KEY)); + assertEquals(3.3f, three.get(FLOAT_KEY)); + assertNull(three.get(LONG_KEY)); + + assertFalse(empty.equals(one)); + assertFalse(one.equals(two)); + assertFalse(two.equals(three)); + assertNotEquals(one.hashCode(), empty.hashCode()); + assertNotEquals(two.hashCode(), one.hashCode()); + assertNotEquals(three.hashCode(), two.hashCode()); + } }