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:
Zalim Bashorov
2014-06-23 21:39:33 +04:00
committed by Ilya Ryzhenkov
parent 223a14a855
commit 14ab3c4de1
3 changed files with 59 additions and 32 deletions
+11 -27
View File
@@ -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
+30
View File
@@ -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> {
+18 -5
View File
@@ -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()