123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667 |
- // 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.array');
- goog.require('goog.functions');
- goog.require('goog.object');
- goog.require('goog.testing.jsunit');
- goog.require('goog.testing.recordFunction');
- 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 testUnsafeCloneObjectThatHasACloneNonMethod() {
- var originalIndex = {red: [0, 4], clone: [1, 3, 5, 7], yellow: [2, 6]};
- var clone = goog.object.unsafeClone(originalIndex);
- assertArrayEquals([1, 3, 5, 7], originalIndex.clone);
- assertArrayEquals([1, 3, 5, 7], clone.clone);
- }
- 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 createRecordedGetFoo() {
- return goog.testing.recordFunction(goog.functions.constant('foo'));
- }
- function testSetWithReturnValueNotSet_KeyIsSet() {
- var f = createRecordedGetFoo();
- var obj = {};
- obj['key'] = 'bar';
- assertEquals('bar', goog.object.setWithReturnValueIfNotSet(obj, 'key', f));
- f.assertCallCount(0);
- }
- function testSetWithReturnValueNotSet_KeyIsNotSet() {
- var f = createRecordedGetFoo();
- var obj = {};
- assertEquals('foo', goog.object.setWithReturnValueIfNotSet(obj, 'key', f));
- f.assertCallCount(1);
- }
- function testSetWithReturnValueNotSet_KeySetValueIsUndefined() {
- var f = createRecordedGetFoo();
- var obj = {};
- obj['key'] = undefined;
- assertEquals(
- undefined, goog.object.setWithReturnValueIfNotSet(obj, 'key', f));
- f.assertCallCount(0);
- }
- 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';
- // IE9 supports isFrozen, but does not support strict mode. Exit early if we
- // are not actually running in strict mode.
- var isStrict = (function() { return !this; })();
- if (!Object.isFrozen || !isStrict) {
- return;
- }
- var x = {propA: 3};
- var y = goog.object.createImmutableView(x);
- assertThrows(function() { y.propA = 4; });
- assertThrows(function() { y.propB = 4; });
- }
- function testEmptyObjectsAreEqual() {
- assertTrue(goog.object.equals({}, {}));
- }
- function testObjectsWithDifferentKeysAreUnequal() {
- assertFalse(goog.object.equals({'a': 1}, {'b': 1}));
- }
- function testObjectsWithDifferentValuesAreUnequal() {
- assertFalse(goog.object.equals({'a': 1}, {'a': 2}));
- }
- function testObjectsWithSameKeysAndValuesAreEqual() {
- assertTrue(goog.object.equals({'a': 1}, {'a': 1}));
- }
- function testObjectsWithSameKeysInDifferentOrderAreEqual() {
- assertTrue(goog.object.equals({'a': 1, 'b': 2}, {'b': 2, 'a': 1}));
- }
- function testIs() {
- var object = {};
- assertTrue(goog.object.is(object, object));
- assertFalse(goog.object.is(object, {}));
- assertTrue(goog.object.is(NaN, NaN));
- assertTrue(goog.object.is(0, 0));
- assertTrue(goog.object.is(1, 1));
- assertTrue(goog.object.is(-1, -1));
- assertTrue(goog.object.is(123, 123));
- assertFalse(goog.object.is(0, -0));
- assertFalse(goog.object.is(-0, 0));
- assertFalse(goog.object.is(0, 1));
- assertTrue(goog.object.is(true, true));
- assertTrue(goog.object.is(false, false));
- assertFalse(goog.object.is(true, false));
- assertFalse(goog.object.is(false, true));
- assertTrue(goog.object.is('', ''));
- assertTrue(goog.object.is('a', 'a'));
- assertFalse(goog.object.is('', 'a'));
- assertFalse(goog.object.is('a', ''));
- assertFalse(goog.object.is('a', 'b'));
- assertFalse(goog.object.is(true, 'true'));
- assertFalse(goog.object.is('true', true));
- assertFalse(goog.object.is(false, 'false'));
- assertFalse(goog.object.is('false', false));
- assertFalse(goog.object.is(0, '0'));
- assertFalse(goog.object.is('0', 0));
- }
- function testGetAllPropertyNames_enumerableProperties() {
- var obj = {a: function() {}, b: 'b', c: function(x) {}};
- assertSameElements(['a', 'b', 'c'], goog.object.getAllPropertyNames(obj));
- }
- function testGetAllPropertyNames_nonEnumerableProperties() {
- var obj = {};
- try {
- Object.defineProperty(obj, 'foo', {value: 'bar', enumerable: false});
- } catch (ex) {
- // IE8 doesn't allow Object.defineProperty on non-DOM elements.
- if (ex.message == 'Object doesn\'t support this action') {
- return;
- }
- }
- var expected = goog.isDef(Object.getOwnPropertyNames) ? ['foo'] : [];
- assertSameElements(expected, goog.object.getAllPropertyNames(obj));
- }
- function testGetAllPropertyNames_inheritedProperties() {
- var parent = function() {};
- parent.prototype.a = null;
- var child = function() {};
- goog.inherits(child, parent);
- child.prototype.b = null;
- var expected = ['a', 'b'];
- if (goog.isDef(Object.getOwnPropertyNames)) {
- expected.push('constructor');
- }
- assertSameElements(
- expected, goog.object.getAllPropertyNames(child.prototype));
- }
- function testGetAllPropertyNames_es6ClassProperties() {
- // Create an ES6 class via eval so we can bail out if it's a syntax error in
- // browsers that don't support ES6 classes.
- try {
- eval(
- 'var Foo = class {' +
- ' a() {}' +
- '};' +
- 'Foo.prototype.b = null;' +
- 'var Bar = class extends Foo {' +
- ' c() {}' +
- ' static d() {}' +
- '};');
- } catch (e) {
- if (e instanceof SyntaxError) {
- return;
- }
- }
- assertSameElements(
- ['a', 'b', 'constructor'],
- goog.object.getAllPropertyNames(Foo.prototype));
- assertSameElements(
- ['a', 'b', 'c', 'constructor'],
- goog.object.getAllPropertyNames(Bar.prototype));
- var expectedBarProperties = ['d', 'prototype', 'length', 'name'];
- // Some versions of Firefox don't find the name property via
- // getOwnPropertyNames.
- if (!goog.array.contains(Object.getOwnPropertyNames(Bar), 'name')) {
- goog.array.remove(expectedBarProperties, 'name');
- }
- assertSameElements(
- expectedBarProperties, goog.object.getAllPropertyNames(Bar));
- }
- function testGetAllPropertyNames_includeObjectPrototype() {
- var obj = {a: function() {}, b: 'b', c: function(x) {}};
- // There's slightly different behavior depending on what APIs the browser
- // under test supports.
- var additionalProps = !!Object.getOwnPropertyNames ?
- Object.getOwnPropertyNames(Object.prototype) :
- [];
- // __proto__ is a bit special and should be excluded from the result set.
- goog.array.remove(additionalProps, '__proto__');
- assertSameElements(
- ['a', 'b', 'c'].concat(additionalProps),
- goog.object.getAllPropertyNames(obj, true));
- }
- function testGetAllPropertyNames_includeFunctionPrototype() {
- var obj = function() {};
- obj.a = function() {};
- // There's slightly different behavior depending on what APIs the browser
- // under test supports.
- var additionalProps = !!Object.getOwnPropertyNames ?
- Object.getOwnPropertyNames(Function.prototype).concat(['prototype']) :
- [];
- var expectedElements = ['a'].concat(additionalProps);
- goog.array.removeDuplicates(expectedElements);
- assertSameElements(
- expectedElements, goog.object.getAllPropertyNames(obj, false, true));
- }
|