@@ -10,7 +10,9 @@ import tests.contract.collectionBehavior
1010import tests.contract.compare
1111import tests.contract.mapBehavior
1212import tests.contract.setBehavior
13+ import tests.remove
1314import tests.stress.IntWrapper
15+ import tests.stress.ObjectWrapper
1416import kotlin.test.*
1517
1618class ImmutableHashMapTest : ImmutableMapTest () {
@@ -285,17 +287,35 @@ abstract class ImmutableMapTest {
285287 @Test fun noOperation () {
286288 immutableMapOf<String , String >().toPersistentMap().testNoOperation({ clear() }, { clear() })
287289
288- val instance = Any ()
289- val instance2 = Any ()
290-
291- val map = immutableMapOf(" x" to instance, null to " x" ).toPersistentMap()
292- with (map) {
293- testNoOperation({ remove(" y" ) }, { remove(" y" ) })
294- testNoOperation({ remove(" x" , instance2) }, { remove(" x" , instance2) })
295- testNoOperation({ put(" x" , instance) }, { put(" x" , instance) })
296- testNoOperation({ putAll(this ) }, { putAll(this ) })
297- testNoOperation({ putAll(emptyMap()) }, { putAll(emptyMap()) })
298- }
290+ val key = ObjectWrapper (" x" , " x" .hashCode())
291+ val equalKey = ObjectWrapper (" x" , " x" .hashCode()) // equalKey == key && equalKey !== key
292+ val notEqualKey = ObjectWrapper (" y" , " x" .hashCode()) // notEqualKey != key && notEqualKey.hashCode == key.hashCode
293+ val value = ObjectWrapper (1 , 1 )
294+ val equalValue = ObjectWrapper (1 , 1 ) // equalValue == value && equalValue !== value
295+ val notEqualValue = ObjectWrapper (2 , 2 ) // notEqualValue != value
296+
297+ /*
298+ To avoid changes to a persistent map:
299+ * remove(key):
300+ no key in map is equal (==) to the given key
301+ * remove(key, value):
302+ the above, or the value for the found key is not equal (!=) to the given value
303+ * put(key, value):
304+ map has a key equal (==) to the given key, and the value for the found key is the same (===) as the given value
305+ */
306+ val map = immutableMapOf(key to value, null to " x" ).toPersistentMap()
307+
308+ map.testNoOperation({ remove(notEqualKey) }, { remove(notEqualKey) })
309+ map.testNotNoOperation({ remove(equalKey) }, { remove(equalKey) })
310+
311+ map.testNoOperation({ remove(key, notEqualValue) }, { remove(key, notEqualValue) })
312+ map.testNotNoOperation({ remove(key, equalValue) }, { remove(key, equalValue) })
313+
314+ map.testNoOperation({ put(equalKey, value) }, { put(equalKey, value) })
315+ map.testNotNoOperation({ put(equalKey, equalValue) }, { put(equalKey, equalValue) })
316+
317+ map.testNoOperation({ putAll(this ) }, { putAll(this ) })
318+ map.testNoOperation({ putAll(emptyMap()) }, { putAll(emptyMap()) })
299319 }
300320
301321 fun <K , V > PersistentMap <K , V >.testNoOperation (persistent : PersistentMap <K , V >.() -> PersistentMap <K , V >, mutating : MutableMap <K , V >.() -> Unit ) {
@@ -306,6 +326,14 @@ abstract class ImmutableMapTest {
306326 assertSame(this , buildResult)
307327 }
308328
329+ fun <K , V > PersistentMap <K , V >.testNotNoOperation (persistent : PersistentMap <K , V >.() -> PersistentMap <K , V >, mutating : MutableMap <K , V >.() -> Unit ) {
330+ val result = this .persistent()
331+ val buildResult = this .mutate(mutating)
332+ // Ensure mutating operations do not return the same instance
333+ assertNotSame(this , result)
334+ assertNotSame(this , buildResult)
335+ }
336+
309337
310338 @Test
311339 fun covariantTyping () {
0 commit comments