// 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.objectTest'); goog.setTestOnly('goog.objectTest'); goog.require('goog.functions'); goog.require('goog.object'); goog.require('goog.testing.jsunit'); function stringifyObject(m) { var keys = goog.object.getKeys(m); var s = ''; for (var i = 0; i < keys.length; i++) { s += keys[i] + goog.object.get(m, keys[i]); } return s; } function getObject() { return { a: 0, b: 1, c: 2, d: 3 }; } function testKeys() { var m = getObject(); assertEquals('getKeys, The keys should be a,b,c', 'a,b,c,d', goog.object.getKeys(m).join(',')); } function testValues() { var m = getObject(); assertEquals('getValues, The values should be 0,1,2', '0,1,2,3', goog.object.getValues(m).join(',')); } function testGetAnyKey() { var m = getObject(); assertTrue('getAnyKey, The key should be a,b,c or d', goog.object.getAnyKey(m) in m); assertUndefined('getAnyKey, The key should be undefined', goog.object.getAnyKey({})); } function testGetAnyValue() { var m = getObject(); assertTrue('getAnyValue, The value should be 0,1,2 or 3', goog.object.containsValue(m, goog.object.getAnyValue(m))); assertUndefined('getAnyValue, The value should be undefined', goog.object.getAnyValue({})); } function testContainsKey() { var m = getObject(); assertTrue("containsKey, Should contain the 'a' key", goog.object.containsKey(m, 'a')); assertFalse("containsKey, Should not contain the 'e' key", goog.object.containsKey(m, 'e')); } function testContainsValue() { var m = getObject(); assertTrue('containsValue, Should contain the value 0', goog.object.containsValue(m, 0)); assertFalse('containsValue, Should not contain the value 4', goog.object.containsValue(m, 4)); assertTrue('isEmpty, The map should not be empty', !goog.object.isEmpty(m)); } function testFindKey() { var dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}; var key = goog.object.findKey(dict, function(v, k, d) { assertEquals('valid 3rd argument', dict, d); assertTrue('valid 1st argument', goog.object.containsValue(d, v)); assertTrue('valid 2nd argument', k in d); return v % 3 == 0; }); assertEquals('key "c" found', 'c', key); var pred = function(value) { return value > 5; }; assertUndefined('no match', goog.object.findKey(dict, pred)); } function testFindValue() { var dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}; var value = goog.object.findValue(dict, function(v, k, d) { assertEquals('valid 3rd argument', dict, d); assertTrue('valid 1st argument', goog.object.containsValue(d, v)); assertTrue('valid 2nd argument', k in d); return k.toUpperCase() == 'C'; }); assertEquals('value 3 found', 3, value); var pred = function(value, key) { return key > 'd'; }; assertUndefined('no match', goog.object.findValue(dict, pred)); } function testClear() { var m = getObject(); goog.object.clear(m); assertTrue('cleared so it should be empty', goog.object.isEmpty(m)); assertFalse("cleared so it should not contain 'a' key", goog.object.containsKey(m, 'a')); } function testClone() { var m = getObject(); var m2 = goog.object.clone(m); assertFalse('clone so it should not be empty', goog.object.isEmpty(m2)); assertTrue("clone so it should contain 'c' key", goog.object.containsKey(m2, 'c')); } function testUnsafeClonePrimitive() { assertEquals('cloning a primitive should return an equal primitive', 5, goog.object.unsafeClone(5)); } function testUnsafeCloneObjectThatHasACloneMethod() { var original = { name: 'original', clone: goog.functions.constant({name: 'clone'}) }; var clone = goog.object.unsafeClone(original); assertEquals('original', original.name); assertEquals('clone', clone.name); } function testUnsafeCloneFlatObject() { var original = {a: 1, b: 2, c: 3}; var clone = goog.object.unsafeClone(original); assertNotEquals(original, clone); assertObjectEquals(original, clone); } function testUnsafeCloneDeepObject() { var original = { a: 1, b: {c: 2, d: 3}, e: {f: {g: 4, h: 5}} }; var clone = goog.object.unsafeClone(original); assertNotEquals(original, clone); assertNotEquals(original.b, clone.b); assertNotEquals(original.e, clone.e); assertEquals(1, clone.a); assertEquals(2, clone.b.c); assertEquals(3, clone.b.d); assertEquals(4, clone.e.f.g); assertEquals(5, clone.e.f.h); } function testUnsafeCloneFunctions() { var original = { f: goog.functions.constant('hi') }; var clone = goog.object.unsafeClone(original); assertNotEquals(original, clone); assertEquals('hi', clone.f()); assertEquals(original.f, clone.f); } function testForEach() { var m = getObject(); var s = ''; goog.object.forEach(m, function(val, key, m2) { assertNotUndefined(key); assertEquals(m, m2); s += key + val; }); assertEquals(s, 'a0b1c2d3'); } function testFilter() { var m = getObject(); var m2 = goog.object.filter(m, function(val, key, m3) { assertNotUndefined(key); assertEquals(m, m3); return val > 1; }); assertEquals(stringifyObject(m2), 'c2d3'); } function testMap() { var m = getObject(); var m2 = goog.object.map(m, function(val, key, m3) { assertNotUndefined(key); assertEquals(m, m3); return val * val; }); assertEquals(stringifyObject(m2), 'a0b1c4d9'); } function testSome() { var m = getObject(); var b = goog.object.some(m, function(val, key, m2) { assertNotUndefined(key); assertEquals(m, m2); return val > 1; }); assertTrue(b); var b = goog.object.some(m, function(val, key, m2) { assertNotUndefined(key); assertEquals(m, m2); return val > 100; }); assertFalse(b); } function testEvery() { var m = getObject(); var b = goog.object.every(m, function(val, key, m2) { assertNotUndefined(key); assertEquals(m, m2); return val >= 0; }); assertTrue(b); b = goog.object.every(m, function(val, key, m2) { assertNotUndefined(key); assertEquals(m, m2); return val > 1; }); assertFalse(b); } function testContains() { var m = getObject(); assertTrue(goog.object.contains(m, 3)); assertFalse(goog.object.contains(m, 4)); } function testObjectProperties() { var m = {}; goog.object.set(m, 'toString', 'once'); goog.object.set(m, 'valueOf', 'upon'); goog.object.set(m, 'eval', 'a'); goog.object.set(m, 'toSource', 'midnight'); goog.object.set(m, 'prototype', 'dreary'); goog.object.set(m, 'hasOwnProperty', 'dark'); assertEquals(goog.object.get(m, 'toString'), 'once'); assertEquals(goog.object.get(m, 'valueOf'), 'upon'); assertEquals(goog.object.get(m, 'eval'), 'a'); assertEquals(goog.object.get(m, 'toSource'), 'midnight'); assertEquals(goog.object.get(m, 'prototype'), 'dreary'); assertEquals(goog.object.get(m, 'hasOwnProperty'), 'dark'); } function testSetDefault() { var dict = {}; assertEquals(1, goog.object.setIfUndefined(dict, 'a', 1)); assertEquals(1, dict['a']); assertEquals(1, goog.object.setIfUndefined(dict, 'a', 2)); assertEquals(1, dict['a']); } function testTranspose() { var m = getObject(); var b = goog.object.transpose(m); assertEquals('a', b[0]); assertEquals('b', b[1]); assertEquals('c', b[2]); assertEquals('d', b[3]); } function testExtend() { var o = {}; var o2 = {a: 0, b: 1}; goog.object.extend(o, o2); assertEquals(0, o.a); assertEquals(1, o.b); assertTrue('a' in o); assertTrue('b' in o); o2 = {c: 2}; goog.object.extend(o, o2); assertEquals(2, o.c); assertTrue('c' in o); o2 = {c: 3}; goog.object.extend(o, o2); assertEquals(3, o.c); assertTrue('c' in o); o = {}; o2 = {c: 2}; var o3 = {c: 3}; goog.object.extend(o, o2, o3); assertEquals(3, o.c); assertTrue('c' in o); o = {}; o2 = {a: 0, b: 1}; o3 = {c: 2, d: 3}; goog.object.extend(o, o2, o3); assertEquals(0, o.a); assertEquals(1, o.b); assertEquals(2, o.c); assertEquals(3, o.d); assertTrue('a' in o); assertTrue('b' in o); assertTrue('c' in o); assertTrue('d' in o); o = {}; o2 = { 'constructor': 0, 'hasOwnProperty': 1, 'isPrototypeOf': 2, 'propertyIsEnumerable': 3, 'toLocaleString': 4, 'toString': 5, 'valueOf': 6 }; goog.object.extend(o, o2); assertEquals(0, o['constructor']); assertEquals(1, o['hasOwnProperty']); assertEquals(2, o['isPrototypeOf']); assertEquals(3, o['propertyIsEnumerable']); assertEquals(4, o['toLocaleString']); assertEquals(5, o['toString']); assertEquals(6, o['valueOf']); assertTrue('constructor' in o); assertTrue('hasOwnProperty' in o); assertTrue('isPrototypeOf' in o); assertTrue('propertyIsEnumerable' in o); assertTrue('toLocaleString' in o); assertTrue('toString' in o); assertTrue('valueOf' in o); } function testCreate() { assertObjectEquals('With multiple arguments', {a: 0, b: 1}, goog.object.create('a', 0, 'b', 1)); assertObjectEquals('With an array argument', {a: 0, b: 1}, goog.object.create(['a', 0, 'b', 1])); assertObjectEquals('With no arguments', {}, goog.object.create()); assertObjectEquals('With an ampty array argument', {}, goog.object.create([])); assertThrows('Should throw due to uneven arguments', function() { goog.object.create('a'); }); assertThrows('Should throw due to uneven arguments', function() { goog.object.create('a', 0, 'b'); }); assertThrows('Should throw due to uneven length array', function() { goog.object.create(['a']); }); assertThrows('Should throw due to uneven length array', function() { goog.object.create(['a', 0, 'b']); }); } function testCreateSet() { assertObjectEquals('With multiple arguments', {a: true, b: true}, goog.object.createSet('a', 'b')); assertObjectEquals('With an array argument', {a: true, b: true}, goog.object.createSet(['a', 'b'])); assertObjectEquals('With no arguments', {}, goog.object.createSet()); assertObjectEquals('With an ampty array argument', {}, goog.object.createSet([])); } function createTestDeepObject() { var obj = {}; obj.a = {}; obj.a.b = {}; obj.a.b.c = {}; obj.a.b.c.fooArr = [5, 6, 7, 8]; obj.a.b.c.knownNull = null; return obj; } function testGetValueByKeys() { var obj = createTestDeepObject(); assertEquals(obj, goog.object.getValueByKeys(obj)); assertEquals(obj.a, goog.object.getValueByKeys(obj, 'a')); assertEquals(obj.a.b, goog.object.getValueByKeys(obj, 'a', 'b')); assertEquals(obj.a.b.c, goog.object.getValueByKeys(obj, 'a', 'b', 'c')); assertEquals(obj.a.b.c.d, goog.object.getValueByKeys(obj, 'a', 'b', 'c', 'd')); assertEquals(8, goog.object.getValueByKeys(obj, 'a', 'b', 'c', 'fooArr', 3)); assertNull(goog.object.getValueByKeys(obj, 'a', 'b', 'c', 'knownNull')); assertUndefined(goog.object.getValueByKeys(obj, 'e', 'f', 'g')); } function testGetValueByKeysArraySyntax() { var obj = createTestDeepObject(); assertEquals(obj, goog.object.getValueByKeys(obj, [])); assertEquals(obj.a, goog.object.getValueByKeys(obj, ['a'])); assertEquals(obj.a.b, goog.object.getValueByKeys(obj, ['a', 'b'])); assertEquals(obj.a.b.c, goog.object.getValueByKeys(obj, ['a', 'b', 'c'])); assertEquals(obj.a.b.c.d, goog.object.getValueByKeys(obj, ['a', 'b', 'c', 'd'])); assertEquals(8, goog.object.getValueByKeys(obj, ['a', 'b', 'c', 'fooArr', 3])); assertNull(goog.object.getValueByKeys(obj, ['a', 'b', 'c', 'knownNull'])); assertUndefined(goog.object.getValueByKeys(obj, 'e', 'f', 'g')); } function testImmutableView() { if (!Object.isFrozen) return; var x = {propA: 3}; var y = goog.object.createImmutableView(x); x.propA = 4; x.propB = 6; y.propA = 5; y.propB = 7; assertEquals(4, x.propA); assertEquals(6, x.propB); assertFalse(goog.object.isImmutableView(x)); assertEquals(4, y.propA); assertEquals(6, y.propB); assertTrue(goog.object.isImmutableView(y)); assertFalse('x and y should be different references', x == y); assertTrue( 'createImmutableView should not create a new view of an immutable object', y == goog.object.createImmutableView(y)); } function testImmutableViewStrict() { 'use strict'; if (!Object.isFrozen) return; var x = {propA: 3}; var y = goog.object.createImmutableView(x); assertThrows(function() { y.propA = 4; }); assertThrows(function() { y.propB = 4; }); }