| // Copyright 2006 The Closure Library Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS-IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| goog.provide('goog.structs.MapTest'); |
| goog.setTestOnly('goog.structs.MapTest'); |
| |
| goog.require('goog.iter'); |
| goog.require('goog.structs'); |
| goog.require('goog.structs.Map'); |
| goog.require('goog.testing.jsunit'); |
| |
| function stringifyMap(m) { |
| var keys = goog.structs.getKeys(m); |
| var s = ''; |
| for (var i = 0; i < keys.length; i++) { |
| s += keys[i] + m[keys[i]]; |
| } |
| return s; |
| } |
| |
| function getMap() { |
| var m = new goog.structs.Map; |
| m.set('a', 0); |
| m.set('b', 1); |
| m.set('c', 2); |
| m.set('d', 3); |
| return m; |
| } |
| |
| function testGetCount() { |
| var m = getMap(); |
| assertEquals('count, should be 4', m.getCount(), 4); |
| m.remove('d'); |
| assertEquals('count, should be 3', m.getCount(), 3); |
| } |
| |
| function testKeys() { |
| var m = getMap(); |
| assertEquals('getKeys, The keys should be a,b,c', m.getKeys().join(','), |
| 'a,b,c,d'); |
| } |
| |
| function testValues() { |
| var m = getMap(); |
| assertEquals('getValues, The values should be 0,1,2', |
| m.getValues().join(','), '0,1,2,3'); |
| } |
| |
| function testContainsKey() { |
| var m = getMap(); |
| assertTrue("containsKey, Should contain the 'a' key", m.containsKey('a')); |
| assertFalse("containsKey, Should not contain the 'e' key", |
| m.containsKey('e')); |
| } |
| |
| function testClear() { |
| var m = getMap(); |
| m.clear(); |
| assertTrue('cleared so it should be empty', m.isEmpty()); |
| assertTrue("cleared so it should not contain 'a' key", !m.containsKey('a')); |
| } |
| |
| function testAddAll() { |
| var m = new goog.structs.Map; |
| m.addAll({a: 0, b: 1, c: 2, d: 3}); |
| assertTrue('addAll so it should not be empty', !m.isEmpty()); |
| assertTrue("addAll so it should contain 'c' key", m.containsKey('c')); |
| |
| var m2 = new goog.structs.Map; |
| m2.addAll(m); |
| assertTrue('addAll so it should not be empty', !m2.isEmpty()); |
| assertTrue("addAll so it should contain 'c' key", m2.containsKey('c')); |
| } |
| |
| function testConstructor() { |
| var m = getMap(); |
| var m2 = new goog.structs.Map(m); |
| assertTrue('constr with Map so it should not be empty', !m2.isEmpty()); |
| assertTrue("constr with Map so it should contain 'c' key", |
| m2.containsKey('c')); |
| } |
| |
| |
| function testConstructorWithVarArgs() { |
| var m = new goog.structs.Map('a', 1); |
| assertTrue('constr with var_args so it should not be empty', !m.isEmpty()); |
| assertEquals('constr with var_args', 1, m.get('a')); |
| |
| m = new goog.structs.Map('a', 1, 'b', 2); |
| assertTrue('constr with var_args so it should not be empty', !m.isEmpty()); |
| assertEquals('constr with var_args', 1, m.get('a')); |
| assertEquals('constr with var_args', 2, m.get('b')); |
| |
| assertThrows('Odd number of arguments is not allowed', function() { |
| var m = new goog.structs.Map('a', 1, 'b'); |
| }); |
| } |
| |
| function testClone() { |
| var m = getMap(); |
| var m2 = m.clone(); |
| assertTrue('clone so it should not be empty', !m2.isEmpty()); |
| assertTrue("clone so it should contain 'c' key", m2.containsKey('c')); |
| } |
| |
| |
| function testRemove() { |
| var m = new goog.structs.Map(); |
| for (var i = 0; i < 1000; i++) { |
| m.set(i, 'foo'); |
| } |
| |
| for (var i = 0; i < 1000; i++) { |
| assertTrue(m.keys_.length <= 2 * m.getCount()); |
| m.remove(i); |
| } |
| assertTrue(m.isEmpty()); |
| assertEquals('', m.getKeys().join('')); |
| } |
| |
| |
| function testForEach() { |
| var m = getMap(); |
| var s = ''; |
| goog.structs.forEach(m, function(val, key, m2) { |
| assertNotUndefined(key); |
| assertEquals(m, m2); |
| s += key + val; |
| }); |
| assertEquals(s, 'a0b1c2d3'); |
| } |
| |
| function testFilter() { |
| var m = getMap(); |
| |
| var m2 = goog.structs.filter(m, function(val, key, m3) { |
| assertNotUndefined(key); |
| assertEquals(m, m3); |
| return val > 1; |
| }); |
| assertEquals(stringifyMap(m2), 'c2d3'); |
| } |
| |
| |
| function testMap() { |
| var m = getMap(); |
| var m2 = goog.structs.map(m, function(val, key, m3) { |
| assertNotUndefined(key); |
| assertEquals(m, m3); |
| return val * val; |
| }); |
| assertEquals(stringifyMap(m2), 'a0b1c4d9'); |
| } |
| |
| function testSome() { |
| var m = getMap(); |
| var b = goog.structs.some(m, function(val, key, m2) { |
| assertNotUndefined(key); |
| assertEquals(m, m2); |
| return val > 1; |
| }); |
| assertTrue(b); |
| var b = goog.structs.some(m, function(val, key, m2) { |
| assertNotUndefined(key); |
| assertEquals(m, m2); |
| return val > 100; |
| }); |
| assertFalse(b); |
| } |
| |
| function testEvery() { |
| var m = getMap(); |
| var b = goog.structs.every(m, function(val, key, m2) { |
| assertNotUndefined(key); |
| assertEquals(m, m2); |
| return val >= 0; |
| }); |
| assertTrue(b); |
| b = goog.structs.every(m, function(val, key, m2) { |
| assertNotUndefined(key); |
| assertEquals(m, m2); |
| return val > 1; |
| }); |
| assertFalse(b); |
| } |
| |
| function testContainsValue() { |
| var m = getMap(); |
| assertTrue(m.containsValue(3)); |
| assertFalse(m.containsValue(4)); |
| } |
| |
| function testObjectProperties() { |
| var m = new goog.structs.Map; |
| |
| assertEquals(m.get('toString'), undefined); |
| assertEquals(m.get('valueOf'), undefined); |
| assertEquals(m.get('eval'), undefined); |
| assertEquals(m.get('toSource'), undefined); |
| assertEquals(m.get('prototype'), undefined); |
| assertEquals(m.get(':foo'), undefined); |
| |
| m.set('toString', 'once'); |
| m.set('valueOf', 'upon'); |
| m.set('eval', 'a'); |
| m.set('toSource', 'midnight'); |
| m.set('prototype', 'dreary'); |
| m.set('hasOwnProperty', 'dark'); |
| m.set(':foo', 'happy'); |
| |
| assertEquals(m.get('toString'), 'once'); |
| assertEquals(m.get('valueOf'), 'upon'); |
| assertEquals(m.get('eval'), 'a'); |
| assertEquals(m.get('toSource'), 'midnight'); |
| assertEquals(m.get('prototype'), 'dreary'); |
| assertEquals(m.get('hasOwnProperty'), 'dark'); |
| assertEquals(m.get(':foo'), 'happy'); |
| |
| var keys = m.getKeys().join(','); |
| assertEquals(keys, |
| 'toString,valueOf,eval,toSource,prototype,hasOwnProperty,:foo'); |
| |
| var values = m.getValues().join(','); |
| assertEquals(values, 'once,upon,a,midnight,dreary,dark,happy'); |
| } |
| |
| function testDuplicateKeys() { |
| var m = new goog.structs.Map; |
| |
| m.set('a', 1); |
| m.set('b', 2); |
| m.set('c', 3); |
| m.set('d', 4); |
| m.set('e', 5); |
| m.set('f', 6); |
| assertEquals(6, m.getKeys().length); |
| m.set('foo', 1); |
| assertEquals(7, m.getKeys().length); |
| m.remove('foo'); |
| assertEquals(6, m.getKeys().length); |
| m.set('foo', 2); |
| assertEquals(7, m.getKeys().length); |
| m.remove('foo'); |
| m.set('foo', 3); |
| m.remove('foo'); |
| m.set('foo', 4); |
| assertEquals(7, m.getKeys().length); |
| } |
| |
| function testGetKeyIterator() { |
| var m = new goog.structs.Map; |
| m.set('a', 1); |
| m.set('b', 2); |
| m.set('c', 3); |
| m.set('d', 4); |
| m.set('e', 5); |
| |
| var iter = m.getKeyIterator(); |
| assertEquals('Should contain the keys', 'abcde', goog.iter.join(iter, '')); |
| |
| m.remove('b'); |
| m.remove('d'); |
| iter = m.getKeyIterator(); |
| assertEquals('Should not contain the removed keys', |
| 'ace', goog.iter.join(iter, '')); |
| } |
| |
| function testGetValueIterator() { |
| var m = new goog.structs.Map; |
| m.set('a', 1); |
| m.set('b', 2); |
| m.set('c', 3); |
| m.set('d', 4); |
| m.set('e', 5); |
| |
| var iter = m.getValueIterator(); |
| assertEquals('Should contain the values', '12345', goog.iter.join(iter, '')); |
| |
| m.remove('b'); |
| m.remove('d'); |
| iter = m.getValueIterator(); |
| assertEquals('Should not contain the removed keys', |
| '135', goog.iter.join(iter, '')); |
| } |
| |
| function testDefaultIterator() { |
| // The default iterator should behave like the value iterator |
| |
| var m = new goog.structs.Map; |
| m.set('a', 1); |
| m.set('b', 2); |
| m.set('c', 3); |
| m.set('d', 4); |
| m.set('e', 5); |
| |
| assertEquals('Should contain the values', '12345', goog.iter.join(m, '')); |
| |
| m.remove('b'); |
| m.remove('d'); |
| assertEquals('Should not contain the removed keys', |
| '135', goog.iter.join(m, '')); |
| } |
| |
| function testMutatedIterator() { |
| var message = 'The map has changed since the iterator was created'; |
| |
| var m = new goog.structs.Map; |
| m.set('a', 1); |
| m.set('b', 2); |
| m.set('c', 3); |
| m.set('d', 4); |
| |
| var iter = m.getValueIterator(); |
| m.set('e', 5); |
| var ex = assertThrows('Expected an exception since the map has changed', |
| function() { |
| iter.next(); |
| }); |
| assertEquals(message, ex.message); |
| |
| m = new goog.structs.Map; |
| m.set('a', 1); |
| m.set('b', 2); |
| m.set('c', 3); |
| m.set('d', 4); |
| |
| iter = m.getValueIterator(); |
| m.remove('d'); |
| var ex = assertThrows('Expected an exception since the map has changed', |
| function() { |
| iter.next(); |
| }); |
| assertEquals(message, ex.message); |
| |
| m = new goog.structs.Map; |
| m.set('a', 1); |
| m.set('b', 2); |
| m.set('c', 3); |
| m.set('d', 4); |
| |
| iter = m.getValueIterator(); |
| m.set('d', 5); |
| iter.next(); |
| // Changing an existing value is OK. |
| iter.next(); |
| } |
| |
| function testTranspose() { |
| var m = new goog.structs.Map; |
| m.set('a', 1); |
| m.set('b', 2); |
| m.set('c', 3); |
| m.set('d', 4); |
| m.set('e', 5); |
| |
| var transposed = m.transpose(); |
| assertEquals('Should contain the keys', 'abcde', |
| goog.iter.join(transposed, '')); |
| } |
| |
| function testToObject() { |
| Object.prototype.b = 0; |
| try { |
| var map = new goog.structs.Map(); |
| map.set('a', 0); |
| var obj = map.toObject(); |
| assertTrue('object representation has key "a"', obj.hasOwnProperty('a')); |
| assertFalse('object representation does not have key "b"', |
| obj.hasOwnProperty('b')); |
| assertEquals('value for key "a"', 0, obj['a']); |
| } finally { |
| delete Object.prototype.b; |
| } |
| } |
| |
| function testEqualsWithSameObject() { |
| var map1 = getMap(); |
| assertTrue('maps are the same object', map1.equals(map1)); |
| } |
| |
| function testEqualsWithDifferentSizeMaps() { |
| var map1 = getMap(); |
| var map2 = new goog.structs.Map(); |
| |
| assertFalse('maps are different sizes', map1.equals(map2)); |
| } |
| |
| function testEqualsWithDefaultEqualityFn() { |
| var map1 = new goog.structs.Map(); |
| var map2 = new goog.structs.Map(); |
| |
| assertTrue('maps are both empty', map1.equals(map2)); |
| |
| map1 = getMap(); |
| map2 = getMap(); |
| assertTrue('maps are the same', map1.equals(map2)); |
| |
| map2.set('d', '3'); |
| assertFalse('maps have 3 and \'3\'', map1.equals(map2)); |
| } |
| |
| function testEqualsWithCustomEqualityFn() { |
| var map1 = new goog.structs.Map(); |
| var map2 = new goog.structs.Map(); |
| |
| map1.set('a', 0); |
| map1.set('b', 1); |
| |
| map2.set('a', '0'); |
| map2.set('b', '1'); |
| |
| var equalsFn = function(a, b) { return a == b }; |
| |
| assertTrue('maps are equal with ==', map1.equals(map2, equalsFn)); |
| } |