/* * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ package test.collections.js import kotlin.test.* import test.collections.* import test.collections.behaviors.* class ComplexMapJsTest : MapJsTest() { // Helper function with generic parameter to force to use ComlpexHashMap fun > doTest() { HashMap() HashMap(3) HashMap(3, 0.5f) @Suppress("UNCHECKED_CAST") val map = HashMap(createTestMap() as HashMap) assertEquals(KEYS.toNormalizedList(), map.keys.toNormalizedList() as List) assertEquals(VALUES.toNormalizedList(), map.values.toNormalizedList()) } @Test override fun constructors() { doTest() } override fun > Collection.toNormalizedList(): List = this.sorted() // hashMapOf returns ComlpexHashMap because it is Generic override fun emptyMutableMap(): MutableMap = genericHashMapOf() override fun emptyMutableMapWithNullableKeyValue(): MutableMap = genericHashMapOf() } class PrimitiveMapJsTest : MapJsTest() { @Test override fun constructors() { HashMap() HashMap(3) HashMap(3, 0.5f) val map = HashMap(createTestMap()) assertEquals(KEYS.toNormalizedList(), map.keys.toNormalizedList()) assertEquals(VALUES.toNormalizedList(), map.values.toNormalizedList()) } override fun > Collection.toNormalizedList(): List = this.sorted() override fun emptyMutableMap(): MutableMap = stringMapOf() override fun emptyMutableMapWithNullableKeyValue(): MutableMap = HashMap() @Test fun compareBehavior() { val specialJsStringMap = stringMapOf() specialJsStringMap.put("k1", "v1") compare(genericHashMapOf("k1" to "v1"), specialJsStringMap) { mapBehavior() } val specialJsNumberMap = HashMap(4) specialJsNumberMap.put(5, "v5") compare(genericHashMapOf(5 to "v5"), specialJsNumberMap) { mapBehavior() } } @Test fun putNull() { val map = stringMapOf("k" to null) assertEquals(1, map.size) map.put("k", null) assertEquals(1, map.size) map["k"] = null assertEquals(1, map.size) map.remove("k") assertEquals(0, map.size) } } class LinkedHashMapJsTest : MapJsTest() { @Test override fun constructors() { LinkedHashMap() LinkedHashMap(3) LinkedHashMap(3, 0.5f) val map = LinkedHashMap(createTestMap()) assertEquals(KEYS.toNormalizedList(), map.keys.toNormalizedList()) assertEquals(VALUES.toNormalizedList(), map.values.toNormalizedList()) } override fun > Collection.toNormalizedList(): List = this.toList() override fun emptyMutableMap(): MutableMap = LinkedHashMap() override fun emptyMutableMapWithNullableKeyValue(): MutableMap = LinkedHashMap() } class LinkedPrimitiveMapJsTest : MapJsTest() { @Test override fun constructors() { val map = createTestMap() assertEquals(KEYS.toNormalizedList(), map.keys.toNormalizedList()) assertEquals(VALUES.toNormalizedList(), map.values.toNormalizedList()) } override fun > Collection.toNormalizedList(): List = this.toList() override fun emptyMutableMap(): MutableMap = linkedStringMapOf() override fun emptyMutableMapWithNullableKeyValue(): MutableMap = LinkedHashMap() } abstract class MapJsTest { val KEYS = listOf("zero", "one", "two", "three") val VALUES = arrayOf(0, 1, 2, 3).toList() val SPECIAL_NAMES = arrayOf( "__proto__", "constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable" ) @Test fun getOrElse() { val data = emptyMap() val a = data.getOrElse("foo") { 2 } assertEquals(2, a) val b = data.getOrElse("foo") { 3 } assertEquals(3, b) assertEquals(0, data.size) } @Test fun getOrPut() { val data = emptyMutableMap() val a = data.getOrPut("foo") { 2 } assertEquals(2, a) val b = data.getOrPut("foo") { 3 } assertEquals(2, b) assertEquals(1, data.size) } @Test fun emptyMapGet() { val map = emptyMap() assertEquals(null, map.get("foo"), """failed on map.get("foo")""") assertEquals(null, map["bar"], """failed on map["bar"]""") } @Test fun mapGet() { val map = createTestMap() for (i in KEYS.indices) { assertEquals(VALUES[i], map.get(KEYS[i]), """failed on map.get(KEYS[$i])""") assertEquals(VALUES[i], map[KEYS[i]], """failed on map[KEYS[$i]]""") } assertEquals(null, map.get("foo")) } @Test fun mapPut() { val map = emptyMutableMap() map.put("foo", 1) assertEquals(1, map["foo"]) assertEquals(null, map["bar"]) map["bar"] = 2 assertEquals(1, map["foo"]) assertEquals(2, map["bar"]) map["foo"] = 0 assertEquals(0, map["foo"]) assertEquals(2, map["bar"]) } @Test fun sizeAndEmptyForEmptyMap() { val data = emptyMap() assertTrue(data.isEmpty()) assertTrue(data.none()) assertEquals(0, data.size) assertEquals(0, data.size) } @Test fun sizeAndEmpty() { val data = createTestMap() assertFalse(data.isEmpty()) assertFalse(data.none()) assertEquals(KEYS.size, data.size) } // #KT-3035 @Test fun emptyMapValues() { val emptyMap = emptyMap() assertTrue(emptyMap.values.isEmpty()) } @Test fun mapValues() { val map = createTestMap() assertEquals(VALUES.toNormalizedList(), map.values.toNormalizedList()) } @Test fun mapKeySet() { val map = createTestMap() assertEquals(KEYS.toNormalizedList(), map.keys.toNormalizedList()) } @Test fun mapEntrySet() { val map = createTestMap() val actualKeys = ArrayList() val actualValues = ArrayList() for (e in map.entries) { actualKeys.add(e.key) actualValues.add(e.value) } assertEquals(KEYS.toNormalizedList(), actualKeys.toNormalizedList()) assertEquals(VALUES.toNormalizedList(), actualValues.toNormalizedList()) } @Test fun mapContainsKey() { val map = createTestMap() assertTrue(map.containsKey(KEYS[0]) && map.containsKey(KEYS[1]) && map.containsKey(KEYS[2]) && map.containsKey(KEYS[3])) assertFalse(map.containsKey("foo") || map.containsKey(1 as Any)) } @Test fun mapContainsValue() { val map = createTestMap() assertTrue(map.containsValue(VALUES[0]) && map.containsValue(VALUES[1]) && map.containsValue(VALUES[2]) && map.containsValue(VALUES[3])) assertFalse(map.containsValue("four" as Any) || map.containsValue(5)) } @Test fun mapPutAll() { val map = createTestMap() val newMap = emptyMutableMap() newMap.putAll(map) assertEquals(KEYS.size, newMap.size) } @Test fun mapPutAllFromCustomMap() { val newMap = emptyMutableMap() newMap.putAll(ConstMap) assertEquals(ConstMap.entries.single().toPair(), newMap.entries.single().toPair()) } @Test fun mapRemove() { val map = createTestMutableMap() val last = KEYS.size - 1 val first = 0 val mid = KEYS.size / 2 assertEquals(KEYS.size, map.size) assertEquals(null, map.remove("foo")) assertEquals(VALUES[mid], map.remove(KEYS[mid])) assertEquals(null, map.remove(KEYS[mid])) assertEquals(VALUES[last], map.remove(KEYS[last])) assertEquals(VALUES[first], map.remove(KEYS[first])) assertEquals(KEYS.size - 3, map.size) } @Test fun mapClear() { val map = createTestMutableMap() assertFalse(map.isEmpty()) map.clear() assertTrue(map.isEmpty()) } @Test fun nullAsKey() { val map = emptyMutableMapWithNullableKeyValue() assertTrue(map.isEmpty()) map.put(null, 23) assertFalse(map.isEmpty()) assertTrue(map.containsKey(null)) assertEquals(23, map[null]) assertEquals(23, map.remove(null)) assertTrue(map.isEmpty()) assertEquals(null, map[null]) } @Test fun nullAsValue() { val map = emptyMutableMapWithNullableKeyValue() val KEY = "Key" assertTrue(map.isEmpty()) map.put(KEY, null) assertFalse(map.isEmpty()) assertEquals(null, map[KEY]) assertTrue(map.containsValue(null)) assertEquals(null, map.remove(KEY)) assertTrue(map.isEmpty()) } @Test fun setViaIndexOperators() { val map = HashMap() assertTrue{ map.isEmpty() } assertEquals(map.size, 0) map["name"] = "James" assertTrue{ !map.isEmpty() } assertEquals(map.size, 1) assertEquals("James", map["name"]) } @Test fun createUsingPairs() { val map = mapOf(Pair("a", 1), Pair("b", 2)) assertEquals(2, map.size) assertEquals(1, map.get("a")) assertEquals(2, map.get("b")) } @Test fun createUsingTo() { val map = mapOf("a" to 1, "b" to 2) assertEquals(2, map.size) assertEquals(1, map.get("a")) assertEquals(2, map.get("b")) } @Test fun mapIteratorImplicitly() { val map = createTestMap() val actualKeys = ArrayList() val actualValues = ArrayList() for (e in map) { actualKeys.add(e.key) actualValues.add(e.value) } assertEquals(KEYS.toNormalizedList(), actualKeys.toNormalizedList()) assertEquals(VALUES.toNormalizedList(), actualValues.toNormalizedList()) } @Test fun mapIteratorExplicitly() { val map = createTestMap() val actualKeys = ArrayList() val actualValues = ArrayList() val iterator = map.iterator() for (e in iterator) { actualKeys.add(e.key) actualValues.add(e.value) } assertEquals(KEYS.toNormalizedList(), actualKeys.toNormalizedList()) assertEquals(VALUES.toNormalizedList(), actualValues.toNormalizedList()) } @Test fun mapMutableIterator() { val map = createTestMutableMap() map.keys.removeAll { it == KEYS[0] } map.entries.removeAll { it.key == KEYS[1] } map.values.removeAll { it == VALUES[3] } assertEquals(1, map.size, "Expected 1 entry to remain in map, but got: $map") } @Test fun mapCollectionPropertiesAreViews() { val map = createTestMutableMap() assertTrue(map.size >= 3) val keys = map.keys val values = map.values val entries = map.entries val (key, value) = map.entries.first() map.remove(key) assertFalse(key in keys, "remove from map") assertFalse(value in values) assertFalse(entries.any { it.key == key }) map.put(key, value) assertTrue(key in keys, "put to map") assertTrue(value in values) assertTrue(entries.any { it.key == key }) keys -= key assertFalse(key in map, "remove from keys") assertFalse(value in values) assertFalse(entries.any { it.key == key }) val (key2, value2) = map.entries.first() values -= value2 assertFalse(key2 in map, "remove from values") assertFalse(map.containsValue(value2)) assertFalse(entries.any { it.value == value2 }) val entry = map.entries.first() entries -= entry assertFalse(entry.key in map, "remove from entries") assertFalse(entry.key in keys) assertFalse(entry.value in values) val entry2 = map.entries.first() entry2.setValue(100) assertEquals(100, map[entry2.key], "set value via entry") } @Test fun mapCollectionPropertiesDoNotSupportAdd() { val map = createTestMutableMap() val entry = map.entries.first() val (key, value) = entry assertFailsWith { map.entries += entry } assertFailsWith { map.keys += key } assertFailsWith { map.values += value } } @Test fun specialNamesNotContainsInEmptyMap() { val map = emptyMap() for (key in SPECIAL_NAMES) { assertFalse(map.containsKey(key), "unexpected key: $key") } } @Test fun specialNamesNotContainsInNonEmptyMap() { val map = createTestMap() for (key in SPECIAL_NAMES) { assertFalse(map.containsKey(key), "unexpected key: $key") } } @Test fun putAndGetSpecialNamesToMap() { val map = createTestMutableMap() var value = 0 for (key in SPECIAL_NAMES) { assertFalse(map.containsKey(key), "unexpected key: $key") map.put(key, value) assertTrue(map.containsKey(key), "key not found: $key") val actualValue = map.get(key) assertEquals(value, actualValue, "wrong value fo key: $key") map.remove(key) assertFalse(map.containsKey(key), "unexpected key after remove: $key") value += 3 } } @Test abstract fun constructors() /* test fun createLinkedMap() { val map = linkedMapOf("c" to 3, "b" to 2, "a" to 1) assertEquals(1, map.get("a")) assertEquals(2, map.get("b")) assertEquals(3, map.get("c")) assertEquals(arrayList("c", "b", "a"), map.keySet().toList()) } test fun iterate() { val map = TreeMap() map["beverage"] = "beer" map["location"] = "Mells" map["name"] = "James" val list = arrayList() for (e in map) { println("key = ${e.getKey()}, value = ${e.getValue()}") list.add(e.getKey()) list.add(e.getValue()) } assertEquals(6, list.size()) assertEquals("beverage,beer,location,Mells,name,James", list.joinToString(",")) } test fun iterateWithProperties() { val map = TreeMap() map["beverage"] = "beer" map["location"] = "Mells" map["name"] = "James" val list = arrayList() for (e in map) { println("key = ${e.key}, value = ${e.value}") list.add(e.key) list.add(e.value) } assertEquals(6, list.size()) assertEquals("beverage,beer,location,Mells,name,James", list.joinToString(",")) } test fun map() { val m1 = TreeMap() m1["beverage"] = "beer" m1["location"] = "Mells" val list = m1.map{ it.value + " rocks" } println("Got new list $list") assertEquals(arrayList("beer rocks", "Mells rocks"), list) } test fun mapValues() { val m1 = TreeMap() m1["beverage"] = "beer" m1["location"] = "Mells" val m2 = m1.mapValues{ it.value + "2" } println("Got new map $m2") assertEquals(arrayList("beer2", "Mells2"), m2.values().toList()) } test fun createSortedMap() { val map = sortedMapOf("c" to 3, "b" to 2, "a" to 1) assertEquals(1, map.get("a")) assertEquals(2, map.get("b")) assertEquals(3, map.get("c")) assertEquals(arrayList("a", "b", "c"), map.keySet()!!.toList()) } test fun toSortedMap() { val map = hashMapOf("c" to 3, "b" to 2, "a" to 1) val sorted = map.toSortedMap() assertEquals(1, sorted.get("a")) assertEquals(2, sorted.get("b")) assertEquals(3, sorted.get("c")) assertEquals(arrayList("a", "b", "c"), sorted.keySet()!!.toList()) } test fun toSortedMapWithComparator() { val map = hashMapOf("c" to 3, "bc" to 2, "bd" to 4, "abc" to 1) val c = comparator{ a, b -> val answer = a.length() - b.length() if (answer == 0) a.compareTo(b) else answer } val sorted = map.toSortedMap(c) assertEquals(arrayList("c", "bc", "bd", "abc"), sorted.keySet()!!.toList()) assertEquals(1, sorted.get("abc")) assertEquals(2, sorted.get("bc")) assertEquals(3, sorted.get("c")) } test fun compilerBug() { val map = TreeMap() map["beverage"] = "beer" map["location"] = "Mells" map["name"] = "James" var list = arrayList() for (e in map) { println("key = ${e.getKey()}, value = ${e.getValue()}") list += e.getKey() list += e.getValue() } assertEquals(6, list.size()) assertEquals("beverage,beer,location,Mells,name,James", list.joinToString(",")) println("==== worked! $list") } */ private object ConstMap : Map { override val entries: Set> get() = setOf(object : Map.Entry { override val key: String get() = "key" override val value: Int get() = 42 }) override val keys: Set get() = setOf("key") override val size: Int get() = 1 override val values = listOf(42) override fun containsKey(key: String) = key == "key" override fun containsValue(value: Int) = value == 42 override fun get(key: String) = if (key == "key") 42 else null override fun isEmpty() = false } // Helpers abstract fun > Collection.toNormalizedList(): List fun emptyMap(): Map = emptyMutableMap() abstract fun emptyMutableMap(): MutableMap abstract fun emptyMutableMapWithNullableKeyValue(): MutableMap fun createTestMap(): Map = createTestMutableMap() fun createTestMutableMap(): MutableMap { val map = emptyMutableMap() for (i in KEYS.indices) { map.put(KEYS[i], VALUES[i]) } return map } fun genericHashMapOf(vararg values: Pair) = hashMapOf(*values) }