JS stdlib: allowed use null as key and value in Map implementations. Added tests for using null in Set and Map implementations.
This commit is contained in:
committed by
Ilya Ryzhenkov
parent
223a14a855
commit
14ab3c4de1
@@ -68,6 +68,8 @@
|
||||
};
|
||||
|
||||
function hashObject(obj) {
|
||||
if (obj == null) return "";
|
||||
|
||||
var hashCode;
|
||||
if (typeof obj == "string") {
|
||||
return obj;
|
||||
@@ -97,23 +99,11 @@
|
||||
}
|
||||
|
||||
function equals_fixedValueNoEquals(fixedValue, variableValue) {
|
||||
return (typeof variableValue.equals_za3rmp$ == FUNCTION) ?
|
||||
return (variableValue != null && typeof variableValue.equals_za3rmp$ == FUNCTION) ?
|
||||
// TODO: test this case
|
||||
variableValue.equals_za3rmp$(fixedValue) : (fixedValue === variableValue);
|
||||
}
|
||||
|
||||
function createKeyValCheck(kvStr) {
|
||||
return function (kv) {
|
||||
if (kv === null) {
|
||||
throw new Error("null is not a valid " + kvStr);
|
||||
}
|
||||
else if (typeof kv == "undefined") {
|
||||
throw new Error(kvStr + " must not be undefined");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var checkKey = createKeyValCheck("key"), checkValue = createKeyValCheck("value");
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* @param {string} hash
|
||||
@@ -167,7 +157,7 @@
|
||||
|
||||
Bucket.prototype = {
|
||||
getEqualityFunction: function (searchValue) {
|
||||
return (typeof searchValue.equals_za3rmp$ == FUNCTION) ? equals_fixedValueHasEquals : equals_fixedValueNoEquals;
|
||||
return (searchValue != null && typeof searchValue.equals_za3rmp$ == FUNCTION) ? equals_fixedValueHasEquals : equals_fixedValueNoEquals;
|
||||
},
|
||||
|
||||
getEntryForKey: createBucketSearcher(ENTRY),
|
||||
@@ -178,7 +168,7 @@
|
||||
var result = this.getEntryAndIndexForKey(key);
|
||||
if (result) {
|
||||
arrayRemoveAt(this.entries, result[0]);
|
||||
return result[1];
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -253,8 +243,6 @@
|
||||
var equalityFunction = (typeof equalityFunctionParam == FUNCTION) ? equalityFunctionParam : null;
|
||||
|
||||
this.put_wn2jw4$ = function (key, value) {
|
||||
checkKey(key);
|
||||
checkValue(value);
|
||||
var hash = hashingFunction(key), bucket, bucketEntry, oldValue = null;
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
@@ -282,8 +270,6 @@
|
||||
};
|
||||
|
||||
this.get_za3rmp$ = function (key) {
|
||||
checkKey(key);
|
||||
|
||||
var hash = hashingFunction(key);
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
@@ -300,7 +286,6 @@
|
||||
};
|
||||
|
||||
this.containsKey_za3rmp$ = function (key) {
|
||||
checkKey(key);
|
||||
var bucketKey = hashingFunction(key);
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
@@ -310,7 +295,6 @@
|
||||
};
|
||||
|
||||
this.containsValue_za3rmp$ = function (value) {
|
||||
checkValue(value);
|
||||
var i = buckets.length;
|
||||
while (i--) {
|
||||
if (buckets[i].containsValue_za3rmp$(value)) {
|
||||
@@ -354,17 +338,17 @@
|
||||
};
|
||||
|
||||
this.remove_za3rmp$ = function (key) {
|
||||
checkKey(key);
|
||||
|
||||
var hash = hashingFunction(key), bucketIndex, oldValue = null;
|
||||
var hash = hashingFunction(key), bucketIndex, oldValue = null, result = null;
|
||||
|
||||
// Check if a bucket exists for the bucket key
|
||||
var bucket = getBucketForHash(bucketsByHash, hash);
|
||||
|
||||
if (bucket) {
|
||||
// Remove entry from this bucket for this key
|
||||
oldValue = bucket.removeEntryForKey(key);
|
||||
if (oldValue !== null) {
|
||||
result = bucket.removeEntryForKey(key);
|
||||
if (result !== null) {
|
||||
oldValue = result[1];
|
||||
|
||||
// Entry was removed, so check if bucket is empty
|
||||
if (!bucket.entries.length) {
|
||||
// Bucket is empty, so remove it from the bucket collections
|
||||
|
||||
@@ -23,6 +23,7 @@ class ComplexMapJsTest : MapJsTest() {
|
||||
override fun <T : kotlin.Comparable<T>> Collection<T>.toNormalizedList(): List<T> = this.toSortedList()
|
||||
// hashMapOf returns ComlpexHashMap because it is Generic
|
||||
override fun emptyMutableMap(): MutableMap<String, Int> = hashMapOf()
|
||||
override fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?> = hashMapOf()
|
||||
}
|
||||
|
||||
class PrimitiveMapJsTest : MapJsTest() {
|
||||
@@ -39,6 +40,7 @@ class PrimitiveMapJsTest : MapJsTest() {
|
||||
|
||||
override fun <T : kotlin.Comparable<T>> Collection<T>.toNormalizedList(): List<T> = this.toSortedList()
|
||||
override fun emptyMutableMap(): MutableMap<String, Int> = HashMap()
|
||||
override fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?> = HashMap()
|
||||
}
|
||||
|
||||
class LinkedHashMapTest : MapJsTest() {
|
||||
@@ -55,6 +57,7 @@ class LinkedHashMapTest : MapJsTest() {
|
||||
|
||||
override fun <T : kotlin.Comparable<T>> Collection<T>.toNormalizedList(): List<T> = this.toList()
|
||||
override fun emptyMutableMap(): MutableMap<String, Int> = LinkedHashMap()
|
||||
override fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?> = LinkedHashMap()
|
||||
}
|
||||
|
||||
abstract class MapJsTest {
|
||||
@@ -224,6 +227,31 @@ abstract class MapJsTest {
|
||||
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())
|
||||
}
|
||||
/*
|
||||
|
||||
TODO fix bug with .set() on Map...
|
||||
@@ -444,6 +472,8 @@ abstract class MapJsTest {
|
||||
|
||||
abstract fun emptyMutableMap(): MutableMap<String, Int>
|
||||
|
||||
abstract fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?>
|
||||
|
||||
fun createTestMap(): Map<String, Int> = createTestMutableMap()
|
||||
|
||||
fun createTestMutableMap(): MutableMap<String, Int> {
|
||||
|
||||
@@ -22,10 +22,13 @@ class ComplexSetJsTest : SetJsTest() {
|
||||
}
|
||||
|
||||
// hashSetOf returns ComlpexHashSet because it is Generic
|
||||
override fun createEmptyMutableSet(): MutableSet<String> = hashSetOf<String>()
|
||||
override fun createEmptyMutableSet(): MutableSet<String> = hashSetOf()
|
||||
override fun createEmptyMutableSetWithNullableValues(): MutableSet<String?> = hashSetOf()
|
||||
}
|
||||
|
||||
class PrimitiveSetJsTest : SetJsTest() {
|
||||
override fun createEmptyMutableSet(): MutableSet<String> = HashSet()
|
||||
override fun createEmptyMutableSetWithNullableValues(): MutableSet<String?> = HashSet()
|
||||
test override fun constructors() {
|
||||
HashSet<String>()
|
||||
HashSet<String>(3)
|
||||
@@ -35,11 +38,11 @@ class PrimitiveSetJsTest : SetJsTest() {
|
||||
|
||||
assertEquals(data, set)
|
||||
}
|
||||
|
||||
override fun createEmptyMutableSet(): MutableSet<String> = HashSet<String>()
|
||||
}
|
||||
|
||||
class LinkedHashSetTest : SetJsTest() {
|
||||
override fun createEmptyMutableSet(): MutableSet<String> = LinkedHashSet()
|
||||
override fun createEmptyMutableSetWithNullableValues(): MutableSet<String?> = LinkedHashSet()
|
||||
test override fun constructors() {
|
||||
LinkedHashSet<String>()
|
||||
LinkedHashSet<String>(3)
|
||||
@@ -49,8 +52,6 @@ class LinkedHashSetTest : SetJsTest() {
|
||||
|
||||
assertEquals(data, set)
|
||||
}
|
||||
|
||||
override fun createEmptyMutableSet(): MutableSet<String> = LinkedHashSet<String>()
|
||||
}
|
||||
|
||||
abstract class SetJsTest {
|
||||
@@ -187,8 +188,20 @@ abstract class SetJsTest {
|
||||
|
||||
test abstract fun constructors()
|
||||
|
||||
Test fun nullAsValue() {
|
||||
val set = createEmptyMutableSetWithNullableValues()
|
||||
|
||||
assertTrue(set.isEmpty(), "Set should be empty")
|
||||
set.add(null)
|
||||
assertFalse(set.isEmpty(), "Set should not be empty")
|
||||
assertTrue(set.contains(null), "Set should contains null")
|
||||
assertTrue(set.remove(null), "Expected true when remove null")
|
||||
assertTrue(set.isEmpty(), "Set should be empty")
|
||||
}
|
||||
|
||||
//Helpers
|
||||
abstract fun createEmptyMutableSet(): MutableSet<String>
|
||||
abstract fun createEmptyMutableSetWithNullableValues(): MutableSet<String?>
|
||||
|
||||
fun createTestMutableSet(): MutableSet<String> {
|
||||
val set = createEmptyMutableSet()
|
||||
|
||||
Reference in New Issue
Block a user