Skip to content

Commit aae0dfa

Browse files
author
vishalup29
committed
Issue #1754 Implement equals/hashCode for EvaluationContext and add tests.
Signed-off-by: vishalup29 <vishalupadhyay977@gmail.com>
1 parent 595a0db commit aae0dfa

File tree

4 files changed

+93
-0
lines changed

4 files changed

+93
-0
lines changed

src/main/java/dev/openfeature/sdk/ImmutableContext.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,38 @@ public EvaluationContext merge(EvaluationContext overridingContext) {
9696
return new ImmutableContext(attributes);
9797
}
9898

99+
/**
100+
* Equality for EvaluationContext implementations is defined in terms of their resolved
101+
* attribute maps. Two contexts are considered equal if their {@link #asMap()} representations
102+
* contain the same key/value pairs, regardless of how the context was constructed or layered.
103+
*
104+
* @param o the object to compare with this context
105+
* @return true if the other object is an EvaluationContext whose resolved attributes match
106+
*/
107+
@Override
108+
public boolean equals(Object o) {
109+
if (this == o) {
110+
return true;
111+
}
112+
if (!(o instanceof EvaluationContext)) {
113+
return false;
114+
}
115+
EvaluationContext that = (EvaluationContext) o;
116+
return this.asMap().equals(that.asMap());
117+
}
118+
119+
/**
120+
* Computes a hash code consistent with {@link #equals(Object)} by delegating to the
121+
* hash code of this context's resolved attribute map. This ensures that contexts with
122+
* identical effective attributes will have the same hash code.
123+
*
124+
* @return the hash code derived from this context's attribute map
125+
*/
126+
@Override
127+
public int hashCode() {
128+
return asMap().hashCode();
129+
}
130+
99131
@SuppressWarnings("all")
100132
private static class DelegateExclusions {
101133
@ExcludeFromGeneratedCoverageReport

src/main/java/dev/openfeature/sdk/LayeredEvaluationContext.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,24 @@ public Map<String, Object> asObjectMap() {
251251
return map;
252252
}
253253

254+
@Override
255+
public boolean equals(Object o) {
256+
if (this == o) {
257+
return true;
258+
}
259+
if (!(o instanceof EvaluationContext)) {
260+
return false;
261+
}
262+
263+
EvaluationContext that = (EvaluationContext) o;
264+
return this.asMap().equals(that.asMap());
265+
}
266+
267+
@Override
268+
public int hashCode() {
269+
return asMap().hashCode();
270+
}
271+
254272
void putHookContext(EvaluationContext context) {
255273
if (context == null || context.isEmpty()) {
256274
return;

src/test/java/dev/openfeature/sdk/ImmutableContextTest.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,22 @@ void mergeShouldObtainKeysFromOverridingContextWhenExistingContextIsEmpty() {
148148
assertEquals(new java.util.HashSet<>(java.util.Arrays.asList("key1", "key2")), merge.keySet());
149149
}
150150

151+
@DisplayName("Two ImmutableContext objects with identical attributes are considered equal")
152+
@Test
153+
void testImmutableContextEquality() {
154+
Map<String, Value> map1 = new HashMap<>();
155+
map1.put("key", new Value("value"));
156+
157+
Map<String, Value> map2 = new HashMap<>();
158+
map2.put("key", new Value("value"));
159+
160+
ImmutableContext a = new ImmutableContext(null, map1);
161+
ImmutableContext b = new ImmutableContext(null, map2);
162+
163+
assertEquals(a, b);
164+
assertEquals(a.hashCode(), b.hashCode());
165+
}
166+
151167
@DisplayName("Two different MutableContext objects with the different contents are not considered equal")
152168
@Test
153169
void unequalImmutableContextsAreNotEqual() {

src/test/java/dev/openfeature/sdk/LayeredEvaluationContextTest.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,5 +397,32 @@ void mergesCorrectlyWhenOtherHasNoTargetingKey() {
397397
merged.asMap());
398398
assertEquals(invocationContext.getTargetingKey(), merged.getTargetingKey());
399399
}
400+
401+
@Test
402+
void testLayeredContextEquality() {
403+
Map<String, Value> baseMap = Map.of("k", new Value("v"));
404+
Map<String, Value> layerMap = Map.of("x", new Value("y"));
405+
406+
EvaluationContext base = new MutableContext(null, baseMap);
407+
EvaluationContext layer = new MutableContext(null, layerMap);
408+
409+
LayeredEvaluationContext l1 = new LayeredEvaluationContext(base, layer, null, null);
410+
LayeredEvaluationContext l2 = new LayeredEvaluationContext(base, layer, null, null);
411+
412+
assertEquals(l1, l2);
413+
assertEquals(l1.hashCode(), l2.hashCode());
414+
}
415+
416+
@Test
417+
void testMixedContextEquality() {
418+
Map<String, Value> map = Map.of("foo", new Value("bar"));
419+
420+
EvaluationContext base = new MutableContext(null, map);
421+
LayeredEvaluationContext layered = new LayeredEvaluationContext(null, null, null, base);
422+
423+
assertEquals(base, layered);
424+
assertEquals(layered, base);
425+
assertEquals(base.hashCode(), layered.hashCode());
426+
}
400427
}
401428
}

0 commit comments

Comments
 (0)