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) {
|
function hashObject(obj) {
|
||||||
|
if (obj == null) return "";
|
||||||
|
|
||||||
var hashCode;
|
var hashCode;
|
||||||
if (typeof obj == "string") {
|
if (typeof obj == "string") {
|
||||||
return obj;
|
return obj;
|
||||||
@@ -97,23 +99,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function equals_fixedValueNoEquals(fixedValue, variableValue) {
|
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);
|
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
|
* @constructor
|
||||||
* @param {string} hash
|
* @param {string} hash
|
||||||
@@ -167,7 +157,7 @@
|
|||||||
|
|
||||||
Bucket.prototype = {
|
Bucket.prototype = {
|
||||||
getEqualityFunction: function (searchValue) {
|
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),
|
getEntryForKey: createBucketSearcher(ENTRY),
|
||||||
@@ -178,7 +168,7 @@
|
|||||||
var result = this.getEntryAndIndexForKey(key);
|
var result = this.getEntryAndIndexForKey(key);
|
||||||
if (result) {
|
if (result) {
|
||||||
arrayRemoveAt(this.entries, result[0]);
|
arrayRemoveAt(this.entries, result[0]);
|
||||||
return result[1];
|
return result;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
@@ -253,8 +243,6 @@
|
|||||||
var equalityFunction = (typeof equalityFunctionParam == FUNCTION) ? equalityFunctionParam : null;
|
var equalityFunction = (typeof equalityFunctionParam == FUNCTION) ? equalityFunctionParam : null;
|
||||||
|
|
||||||
this.put_wn2jw4$ = function (key, value) {
|
this.put_wn2jw4$ = function (key, value) {
|
||||||
checkKey(key);
|
|
||||||
checkValue(value);
|
|
||||||
var hash = hashingFunction(key), bucket, bucketEntry, oldValue = null;
|
var hash = hashingFunction(key), bucket, bucketEntry, oldValue = null;
|
||||||
|
|
||||||
// Check if a bucket exists for the bucket key
|
// Check if a bucket exists for the bucket key
|
||||||
@@ -282,8 +270,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.get_za3rmp$ = function (key) {
|
this.get_za3rmp$ = function (key) {
|
||||||
checkKey(key);
|
|
||||||
|
|
||||||
var hash = hashingFunction(key);
|
var hash = hashingFunction(key);
|
||||||
|
|
||||||
// Check if a bucket exists for the bucket key
|
// Check if a bucket exists for the bucket key
|
||||||
@@ -300,7 +286,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.containsKey_za3rmp$ = function (key) {
|
this.containsKey_za3rmp$ = function (key) {
|
||||||
checkKey(key);
|
|
||||||
var bucketKey = hashingFunction(key);
|
var bucketKey = hashingFunction(key);
|
||||||
|
|
||||||
// Check if a bucket exists for the bucket key
|
// Check if a bucket exists for the bucket key
|
||||||
@@ -310,7 +295,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.containsValue_za3rmp$ = function (value) {
|
this.containsValue_za3rmp$ = function (value) {
|
||||||
checkValue(value);
|
|
||||||
var i = buckets.length;
|
var i = buckets.length;
|
||||||
while (i--) {
|
while (i--) {
|
||||||
if (buckets[i].containsValue_za3rmp$(value)) {
|
if (buckets[i].containsValue_za3rmp$(value)) {
|
||||||
@@ -354,17 +338,17 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.remove_za3rmp$ = function (key) {
|
this.remove_za3rmp$ = function (key) {
|
||||||
checkKey(key);
|
var hash = hashingFunction(key), bucketIndex, oldValue = null, result = null;
|
||||||
|
|
||||||
var hash = hashingFunction(key), bucketIndex, oldValue = null;
|
|
||||||
|
|
||||||
// Check if a bucket exists for the bucket key
|
// Check if a bucket exists for the bucket key
|
||||||
var bucket = getBucketForHash(bucketsByHash, hash);
|
var bucket = getBucketForHash(bucketsByHash, hash);
|
||||||
|
|
||||||
if (bucket) {
|
if (bucket) {
|
||||||
// Remove entry from this bucket for this key
|
// Remove entry from this bucket for this key
|
||||||
oldValue = bucket.removeEntryForKey(key);
|
result = bucket.removeEntryForKey(key);
|
||||||
if (oldValue !== null) {
|
if (result !== null) {
|
||||||
|
oldValue = result[1];
|
||||||
|
|
||||||
// Entry was removed, so check if bucket is empty
|
// Entry was removed, so check if bucket is empty
|
||||||
if (!bucket.entries.length) {
|
if (!bucket.entries.length) {
|
||||||
// Bucket is empty, so remove it from the bucket collections
|
// 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()
|
override fun <T : kotlin.Comparable<T>> Collection<T>.toNormalizedList(): List<T> = this.toSortedList()
|
||||||
// hashMapOf returns ComlpexHashMap because it is Generic
|
// hashMapOf returns ComlpexHashMap because it is Generic
|
||||||
override fun emptyMutableMap(): MutableMap<String, Int> = hashMapOf()
|
override fun emptyMutableMap(): MutableMap<String, Int> = hashMapOf()
|
||||||
|
override fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?> = hashMapOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
class PrimitiveMapJsTest : MapJsTest() {
|
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 <T : kotlin.Comparable<T>> Collection<T>.toNormalizedList(): List<T> = this.toSortedList()
|
||||||
override fun emptyMutableMap(): MutableMap<String, Int> = HashMap()
|
override fun emptyMutableMap(): MutableMap<String, Int> = HashMap()
|
||||||
|
override fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?> = HashMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
class LinkedHashMapTest : MapJsTest() {
|
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 <T : kotlin.Comparable<T>> Collection<T>.toNormalizedList(): List<T> = this.toList()
|
||||||
override fun emptyMutableMap(): MutableMap<String, Int> = LinkedHashMap()
|
override fun emptyMutableMap(): MutableMap<String, Int> = LinkedHashMap()
|
||||||
|
override fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?> = LinkedHashMap()
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class MapJsTest {
|
abstract class MapJsTest {
|
||||||
@@ -224,6 +227,31 @@ abstract class MapJsTest {
|
|||||||
assertTrue(map.isEmpty())
|
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...
|
TODO fix bug with .set() on Map...
|
||||||
@@ -444,6 +472,8 @@ abstract class MapJsTest {
|
|||||||
|
|
||||||
abstract fun emptyMutableMap(): MutableMap<String, Int>
|
abstract fun emptyMutableMap(): MutableMap<String, Int>
|
||||||
|
|
||||||
|
abstract fun emptyMutableMapWithNullableKeyValue(): MutableMap<String?, Int?>
|
||||||
|
|
||||||
fun createTestMap(): Map<String, Int> = createTestMutableMap()
|
fun createTestMap(): Map<String, Int> = createTestMutableMap()
|
||||||
|
|
||||||
fun createTestMutableMap(): MutableMap<String, Int> {
|
fun createTestMutableMap(): MutableMap<String, Int> {
|
||||||
|
|||||||
@@ -22,10 +22,13 @@ class ComplexSetJsTest : SetJsTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// hashSetOf returns ComlpexHashSet because it is Generic
|
// 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() {
|
class PrimitiveSetJsTest : SetJsTest() {
|
||||||
|
override fun createEmptyMutableSet(): MutableSet<String> = HashSet()
|
||||||
|
override fun createEmptyMutableSetWithNullableValues(): MutableSet<String?> = HashSet()
|
||||||
test override fun constructors() {
|
test override fun constructors() {
|
||||||
HashSet<String>()
|
HashSet<String>()
|
||||||
HashSet<String>(3)
|
HashSet<String>(3)
|
||||||
@@ -35,11 +38,11 @@ class PrimitiveSetJsTest : SetJsTest() {
|
|||||||
|
|
||||||
assertEquals(data, set)
|
assertEquals(data, set)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createEmptyMutableSet(): MutableSet<String> = HashSet<String>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class LinkedHashSetTest : SetJsTest() {
|
class LinkedHashSetTest : SetJsTest() {
|
||||||
|
override fun createEmptyMutableSet(): MutableSet<String> = LinkedHashSet()
|
||||||
|
override fun createEmptyMutableSetWithNullableValues(): MutableSet<String?> = LinkedHashSet()
|
||||||
test override fun constructors() {
|
test override fun constructors() {
|
||||||
LinkedHashSet<String>()
|
LinkedHashSet<String>()
|
||||||
LinkedHashSet<String>(3)
|
LinkedHashSet<String>(3)
|
||||||
@@ -49,8 +52,6 @@ class LinkedHashSetTest : SetJsTest() {
|
|||||||
|
|
||||||
assertEquals(data, set)
|
assertEquals(data, set)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createEmptyMutableSet(): MutableSet<String> = LinkedHashSet<String>()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class SetJsTest {
|
abstract class SetJsTest {
|
||||||
@@ -187,8 +188,20 @@ abstract class SetJsTest {
|
|||||||
|
|
||||||
test abstract fun constructors()
|
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
|
//Helpers
|
||||||
abstract fun createEmptyMutableSet(): MutableSet<String>
|
abstract fun createEmptyMutableSet(): MutableSet<String>
|
||||||
|
abstract fun createEmptyMutableSetWithNullableValues(): MutableSet<String?>
|
||||||
|
|
||||||
fun createTestMutableSet(): MutableSet<String> {
|
fun createTestMutableSet(): MutableSet<String> {
|
||||||
val set = createEmptyMutableSet()
|
val set = createEmptyMutableSet()
|
||||||
|
|||||||
Reference in New Issue
Block a user