1496 lines
42 KiB
JavaScript
1496 lines
42 KiB
JavaScript
// 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.
|
|
|
|
|
|
/**
|
|
* @fileoverview Unit tests for Closure's base.js.
|
|
*
|
|
* @nocompile
|
|
*/
|
|
|
|
goog.provide('goog.baseTest');
|
|
|
|
goog.setTestOnly('goog.baseTest');
|
|
|
|
// Used to test dynamic loading works, see testRequire*
|
|
goog.require('goog.Timer');
|
|
goog.require('goog.functions');
|
|
goog.require('goog.testing.PropertyReplacer');
|
|
goog.require('goog.testing.jsunit');
|
|
goog.require('goog.testing.recordFunction');
|
|
goog.require('goog.userAgent');
|
|
|
|
goog.require('goog.test_module');
|
|
var earlyTestModuleGet = goog.module.get('goog.test_module');
|
|
|
|
function getFramedVars(name) {
|
|
var w = window.frames[name];
|
|
var doc = w.document;
|
|
doc.open();
|
|
doc.write('<script>' +
|
|
'var a = [0, 1, 2];' +
|
|
'var o = {a: 0, b: 1};' +
|
|
'var n = 42;' +
|
|
'var b = true;' +
|
|
'var s = "string";' +
|
|
'var nv = null;' +
|
|
'var u = undefined;' +
|
|
'var fv = function(){};' +
|
|
'</' + 'script>');
|
|
doc.close();
|
|
return {
|
|
'array': w.a,
|
|
'object': w.o,
|
|
'number': w.n,
|
|
'boolean': w.b,
|
|
'string': w.s,
|
|
'functionVar': w.fv,
|
|
'nullVar': w.nv,
|
|
'undefinedVar': w.u
|
|
};
|
|
}
|
|
|
|
var framedVars = getFramedVars('f1');
|
|
var framedVars2 = getFramedVars('f2');
|
|
// remove iframe
|
|
var iframeElement = document.getElementById('f2');
|
|
iframeElement.parentNode.removeChild(iframeElement);
|
|
var stubs = new goog.testing.PropertyReplacer();
|
|
var originalGoogBind = goog.bind;
|
|
|
|
function tearDown() {
|
|
goog.setCssNameMapping(undefined);
|
|
stubs.reset();
|
|
goog.bind = originalGoogBind;
|
|
}
|
|
|
|
function testLibrary() {
|
|
assertNotUndefined("'goog' not loaded", goog);
|
|
}
|
|
|
|
function testDefine() {
|
|
goog.define('SOME_DEFINE', 123); // overridden by 456
|
|
assertEquals(SOME_DEFINE, 456);
|
|
|
|
goog.define('SOME_OTHER_DEFINE', 123); // not overridden
|
|
assertEquals(SOME_OTHER_DEFINE, 123);
|
|
|
|
goog.provide('ns');
|
|
|
|
goog.define('ns.SOME_DEFINE', 123); // overridden by 456
|
|
assertEquals(SOME_DEFINE, 456);
|
|
|
|
goog.define('ns.SOME_OTHER_DEFINE', 123); // not overridden
|
|
assertEquals(SOME_OTHER_DEFINE, 123);
|
|
}
|
|
|
|
function testProvide() {
|
|
goog.provide('goog.test.name.space');
|
|
assertNotUndefined('provide failed: goog.test', goog.test);
|
|
assertNotUndefined('provide failed: goog.test.name', goog.test.name);
|
|
assertNotUndefined('provide failed: goog.test.name.space',
|
|
goog.test.name.space);
|
|
|
|
// ensure that providing 'goog.test.name' doesn't throw an exception
|
|
goog.provide('goog.test');
|
|
goog.provide('goog.test.name');
|
|
|
|
delete goog.test;
|
|
}
|
|
|
|
function testProvideStrictness() {
|
|
goog.provide('goog.xy');
|
|
assertProvideFails('goog.xy');
|
|
|
|
goog.provide('goog.xy.z');
|
|
assertProvideFails('goog.xy');
|
|
|
|
window['goog']['xyz'] = 'Bob';
|
|
assertProvideFails('goog.xyz');
|
|
|
|
delete goog.xy;
|
|
delete goog.xyz;
|
|
}
|
|
|
|
function assertProvideFails(namespace) {
|
|
assertThrows('goog.provide(' + namespace + ') should have failed',
|
|
goog.partial(goog.provide, namespace));
|
|
}
|
|
|
|
function testIsProvided() {
|
|
goog.provide('goog.explicit');
|
|
assertTrue(goog.isProvided_('goog.explicit'));
|
|
goog.provide('goog.implicit.explicit');
|
|
assertFalse(goog.isProvided_('goog.implicit'));
|
|
assertTrue(goog.isProvided_('goog.implicit.explicit'));
|
|
}
|
|
|
|
function testGlobalize() {
|
|
var a = {a: 1, b: 2, c: 3};
|
|
var b = {};
|
|
goog.globalize(a, b);
|
|
assertNotUndefined('Globalize to arbitrary object', b.a);
|
|
assertNotUndefined('Globalize to arbitrary object', b.b);
|
|
assertNotUndefined('Globalize to arbitrary object', b.c);
|
|
}
|
|
|
|
function testExportSymbol() {
|
|
var date = new Date();
|
|
|
|
assertTrue(typeof nodots == 'undefined');
|
|
goog.exportSymbol('nodots', date);
|
|
assertEquals(date, nodots);
|
|
nodots = undefined;
|
|
|
|
assertTrue(typeof gotcher == 'undefined');
|
|
goog.exportSymbol('gotcher.dots.right.Here', date);
|
|
assertEquals(date, gotcher.dots.right.Here);
|
|
gotcher = undefined;
|
|
|
|
goog.provide('an.existing.path');
|
|
assertNotNull(an.existing.path);
|
|
goog.exportSymbol('an.existing.path', date);
|
|
assertEquals(date, an.existing.path);
|
|
an = undefined;
|
|
|
|
var foo = {foo: 'foo'};
|
|
var bar = {bar: 'bar'};
|
|
var baz = {baz: 'baz'};
|
|
goog.exportSymbol('one.two.three.Four', foo);
|
|
goog.exportSymbol('one.two.three.five', bar);
|
|
goog.exportSymbol('one.two.six', baz);
|
|
assertEquals(foo, one.two.three.Four);
|
|
assertEquals(bar, one.two.three.five);
|
|
assertEquals(baz, one.two.six);
|
|
|
|
var win = {};
|
|
var fooBar = {foo: 'foo', bar: 'bar'};
|
|
goog.exportSymbol('one.two.four', fooBar, win);
|
|
assertEquals(fooBar, win.one.two.four);
|
|
assertTrue('four' in win.one.two);
|
|
assertFalse('four' in one.two);
|
|
one = undefined;
|
|
}
|
|
|
|
goog.exportSymbol('exceptionTest', function() {
|
|
throw Error('ERROR');
|
|
});
|
|
|
|
function testExportSymbolExceptions() {
|
|
var e = assertThrows('Exception wasn\'t thrown by exported function',
|
|
exceptionTest);
|
|
assertEquals('Unexpected error thrown', 'ERROR', e.message);
|
|
}
|
|
|
|
//=== tests for Require logic ===
|
|
|
|
function testRequireClosure() {
|
|
assertNotUndefined('goog.Timer should be available', goog.Timer);
|
|
assertNotUndefined(
|
|
'goog.events.EventTarget should be available',
|
|
/** @suppress {missingRequire} */ goog.events.EventTarget);
|
|
}
|
|
|
|
function testRequireWithExternalDuplicate() {
|
|
// Do a provide without going via goog.require. Then goog.require it
|
|
// indirectly and ensure it doesn't cause a duplicate script.
|
|
goog.addDependency('dup.js', ['dup.base'], []);
|
|
goog.addDependency('dup-child.js', ['dup.base.child'], ['dup.base']);
|
|
goog.provide('dup.base');
|
|
|
|
stubs.set(goog, 'isDocumentFinishedLoading_', false);
|
|
stubs.set(goog.global, 'CLOSURE_IMPORT_SCRIPT', function(src) {
|
|
if (src == goog.basePath + 'dup.js') {
|
|
fail('Duplicate script written!');
|
|
} else if (src == goog.basePath + 'dup-child.js') {
|
|
// Allow expected script.
|
|
return true;
|
|
} else {
|
|
// Avoid affecting other state.
|
|
return false;
|
|
}
|
|
});
|
|
|
|
// To differentiate this call from the real one.
|
|
var require = goog.require;
|
|
require('dup.base.child');
|
|
}
|
|
|
|
//=== tests for language enhancements ===
|
|
|
|
function testTypeOf() {
|
|
assertEquals('array', goog.typeOf([]));
|
|
assertEquals('string', goog.typeOf('string'));
|
|
assertEquals('number', goog.typeOf(123));
|
|
assertEquals('null', goog.typeOf(null));
|
|
assertEquals('undefined', goog.typeOf(undefined));
|
|
assertEquals('object', goog.typeOf({}));
|
|
assertEquals('function', goog.typeOf(function() {}));
|
|
|
|
// Make sure that NodeList is not treated as an array... NodeLists should
|
|
// be of type object but Safari incorrectly reports it as function so a not
|
|
// equals test will have to suffice here.
|
|
assertNotEquals('array', goog.typeOf(document.getElementsByName('*')));
|
|
assertNotEquals('function', goog.typeOf(document.getElementsByName('*')));
|
|
assertEquals('object', goog.typeOf(document.getElementsByName('*')));
|
|
}
|
|
|
|
function testTypeOfFramed() {
|
|
assertEquals('array', goog.typeOf(framedVars.array));
|
|
assertEquals('string', goog.typeOf(framedVars.string));
|
|
assertEquals('number', goog.typeOf(framedVars.number));
|
|
assertEquals('null', goog.typeOf(framedVars.nullVar));
|
|
assertEquals('undefined', goog.typeOf(framedVars.undefinedVar));
|
|
assertEquals('object', goog.typeOf(framedVars.object));
|
|
assertEquals('function', goog.typeOf(framedVars.functionVar));
|
|
|
|
// Opera throws when trying to do cross frame typeof on node lists.
|
|
// IE behaves very strange when it comes to DOM nodes on disconnected frames.
|
|
}
|
|
|
|
function testTypeOfFramed2() {
|
|
assertEquals('array', goog.typeOf(framedVars2.array));
|
|
assertEquals('string', goog.typeOf(framedVars2.string));
|
|
assertEquals('number', goog.typeOf(framedVars2.number));
|
|
assertEquals('null', goog.typeOf(framedVars2.nullVar));
|
|
assertEquals('undefined', goog.typeOf(framedVars2.undefinedVar));
|
|
assertEquals('object', goog.typeOf(framedVars2.object));
|
|
assertEquals('function', goog.typeOf(framedVars2.functionVar));
|
|
|
|
// Opera throws when trying to do cross frame typeof on node lists.
|
|
// IE behaves very strange when it comes to DOM nodes on disconnected frames.
|
|
}
|
|
|
|
function testIsDef() {
|
|
var defined = 'foo';
|
|
var nullVar = null;
|
|
var notDefined;
|
|
|
|
assertTrue('defined should be defined', goog.isDef(defined));
|
|
assertTrue('null should be defined', goog.isDef(nullVar));
|
|
assertFalse('undefined should not be defined', goog.isDef(notDefined));
|
|
}
|
|
|
|
function testIsDefAndNotNull() {
|
|
assertTrue('string is defined and non-null', goog.isDefAndNotNull(''));
|
|
assertTrue('object is defined and non-null', goog.isDefAndNotNull({}));
|
|
assertTrue('function is defined and non-null',
|
|
goog.isDefAndNotNull(goog.nullFunction));
|
|
assertTrue('zero is defined and non-null',
|
|
goog.isDefAndNotNull(0));
|
|
assertFalse('null', goog.isDefAndNotNull(null));
|
|
assertFalse('undefined', goog.isDefAndNotNull(undefined));
|
|
}
|
|
|
|
function testIsNull() {
|
|
var notNull = 'foo';
|
|
var nullVar = null;
|
|
var notDefined;
|
|
|
|
assertFalse('defined should not be null', goog.isNull(notNull));
|
|
assertTrue('null should be null', goog.isNull(nullVar));
|
|
assertFalse('undefined should not be null', goog.isNull(notDefined));
|
|
}
|
|
|
|
function testIsArray() {
|
|
var array = [1, 2, 3];
|
|
var arrayWithLengthSet = [1, 2, 3];
|
|
arrayWithLengthSet.length = 2;
|
|
var objWithArrayFunctions = {slice: function() {}, length: 0};
|
|
var object = {a: 1, b: 2, c: 3};
|
|
var nullVar = null;
|
|
var notDefined;
|
|
var elem = document.getElementById('elem');
|
|
var text = document.getElementById('text').firstChild;
|
|
var impostor = document.body.getElementsByTagName('BOGUS');
|
|
impostor.push = Array.prototype.push;
|
|
impostor.pop = Array.prototype.pop;
|
|
impostor.slice = Array.prototype.slice;
|
|
impostor.splice = Array.prototype.splice;
|
|
|
|
assertTrue('array should be an array', goog.isArray(array));
|
|
assertTrue('arrayWithLengthSet should be an array',
|
|
goog.isArray(arrayWithLengthSet));
|
|
assertFalse('object with array functions should not be an array unless ' +
|
|
'length is not enumerable', goog.isArray(objWithArrayFunctions));
|
|
assertFalse('object should not be an array', goog.isArray(object));
|
|
assertFalse('null should not be an array', goog.isArray(nullVar));
|
|
assertFalse('undefined should not be an array', goog.isArray(notDefined));
|
|
assertFalse('NodeList should not be an array', goog.isArray(elem.childNodes));
|
|
assertFalse('TextNode should not be an array', goog.isArray(text));
|
|
assertTrue('Array of nodes should be an array',
|
|
goog.isArray([elem.firstChild, elem.lastChild]));
|
|
assertFalse('An impostor should not be an array', goog.isArray(impostor));
|
|
}
|
|
|
|
function testTypeOfAcrossWindow() {
|
|
if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('10') &&
|
|
!goog.userAgent.isVersionOrHigher('11')) {
|
|
// TODO(johnlenz): This test is flaky on IE10 (passing 90+% of the time).
|
|
// When it flakes the values are undefined which appears to indicate the
|
|
// script did not run in the opened window and not a failure of the logic
|
|
// we are trying to test.
|
|
return;
|
|
}
|
|
|
|
var w = window.open('', 'blank');
|
|
if (w) {
|
|
try {
|
|
var d = w.document;
|
|
d.open();
|
|
d.write('<script>function fun(){};' +
|
|
'var arr = [];' +
|
|
'var x = 42;' +
|
|
'var s = "";' +
|
|
'var b = true;' +
|
|
'var obj = {length: 0, splice: {}, call: {}};' +
|
|
'</' + 'script>');
|
|
d.close();
|
|
|
|
assertEquals('function', goog.typeOf(w.fun));
|
|
assertEquals('array', goog.typeOf(w.arr));
|
|
assertEquals('number', goog.typeOf(w.x));
|
|
assertEquals('string', goog.typeOf(w.s));
|
|
assertEquals('boolean', goog.typeOf(w.b));
|
|
assertEquals('object', goog.typeOf(w.obj));
|
|
} finally {
|
|
w.close();
|
|
}
|
|
}
|
|
}
|
|
|
|
function testIsArrayLike() {
|
|
var array = [1, 2, 3];
|
|
var objectWithNumericLength = {length: 2};
|
|
var objectWithNonNumericLength = {length: 'a'};
|
|
var object = {a: 1, b: 2};
|
|
var nullVar = null;
|
|
var notDefined;
|
|
var elem = document.getElementById('elem');
|
|
var text = document.getElementById('text').firstChild;
|
|
|
|
assertTrue('array should be array-like', goog.isArrayLike(array));
|
|
assertTrue('obj w/numeric length should be array-like',
|
|
goog.isArrayLike(objectWithNumericLength));
|
|
assertFalse('obj w/non-numeric length should not be array-like',
|
|
goog.isArrayLike(objectWithNonNumericLength));
|
|
assertFalse('object should not be array-like', goog.isArrayLike(object));
|
|
assertFalse('null should not be array-like', goog.isArrayLike(nullVar));
|
|
assertFalse('undefined should not be array-like',
|
|
goog.isArrayLike(notDefined));
|
|
assertTrue('NodeList should be array-like',
|
|
goog.isArrayLike(elem.childNodes));
|
|
// TODO(attila): Fix isArrayLike to return false for text nodes!
|
|
// assertFalse('TextNode should not be array-like', goog.isArrayLike(text));
|
|
assertTrue('Array of nodes should be array-like',
|
|
goog.isArrayLike([elem.firstChild, elem.lastChild]));
|
|
}
|
|
|
|
|
|
// Use mock date in testIsDateLike() rather than a real goog.date.Date to
|
|
// minimize dependencies in this unit test.
|
|
function MockGoogDate() {}
|
|
|
|
MockGoogDate.prototype.getFullYear = function() {
|
|
return 2007;
|
|
};
|
|
|
|
|
|
function testIsDateLike() {
|
|
var jsDate = new Date();
|
|
var googDate = new MockGoogDate();
|
|
var string = 'foo';
|
|
var number = 1;
|
|
var nullVar = null;
|
|
var notDefined;
|
|
|
|
assertTrue('js Date should be date-like', goog.isDateLike(jsDate));
|
|
assertTrue('goog Date should be date-like', goog.isDateLike(googDate));
|
|
assertFalse('string should not be date-like', goog.isDateLike(string));
|
|
assertFalse('number should not be date-like', goog.isDateLike(number));
|
|
assertFalse('nullVar should not be date-like', goog.isDateLike(nullVar));
|
|
assertFalse('undefined should not be date-like', goog.isDateLike(notDefined));
|
|
}
|
|
|
|
function testIsString() {
|
|
var string = 'foo';
|
|
var number = 2;
|
|
var nullVar = null;
|
|
var notDefined;
|
|
|
|
assertTrue('string should be a string', goog.isString(string));
|
|
assertFalse('number should not be a string', goog.isString(number));
|
|
assertFalse('null should not be a string', goog.isString(nullVar));
|
|
assertFalse('undefined should not be a string', goog.isString(notDefined));
|
|
}
|
|
|
|
function testIsBoolean() {
|
|
var b = true;
|
|
var s = 'true';
|
|
var num = 1;
|
|
var nullVar = null;
|
|
var notDefined;
|
|
|
|
assertTrue('boolean should be a boolean', goog.isBoolean(b));
|
|
assertFalse('string should not be a boolean', goog.isBoolean(s));
|
|
assertFalse('number should not be a boolean', goog.isBoolean(num));
|
|
assertFalse('null should not be a boolean', goog.isBoolean(nullVar));
|
|
assertFalse('undefined should not be a boolean', goog.isBoolean(notDefined));
|
|
}
|
|
|
|
function testIsNumber() {
|
|
var number = 1;
|
|
var string = '1';
|
|
var nullVar = null;
|
|
var notDefined;
|
|
|
|
assertTrue('number should be a number', goog.isNumber(number));
|
|
assertFalse('string should not be a number', goog.isNumber(string));
|
|
assertFalse('null should not be a number', goog.isNumber(nullVar));
|
|
assertFalse('undefined should not be a number', goog.isNumber(notDefined));
|
|
}
|
|
|
|
function testIsFunction() {
|
|
var func = function() { return 1; };
|
|
var object = {a: 1, b: 2};
|
|
var nullVar = null;
|
|
var notDefined;
|
|
|
|
assertTrue('function should be a function', goog.isFunction(func));
|
|
assertFalse('object should not be a function', goog.isFunction(object));
|
|
assertFalse('null should not be a function', goog.isFunction(nullVar));
|
|
assertFalse('undefined should not be a function',
|
|
goog.isFunction(notDefined));
|
|
}
|
|
|
|
function testIsObject() {
|
|
var object = {a: 1, b: 2};
|
|
var string = 'b';
|
|
var nullVar = null;
|
|
var notDefined;
|
|
var array = [0, 1, 2];
|
|
var fun = function() {};
|
|
|
|
assertTrue('object should be an object', goog.isObject(object));
|
|
assertTrue('array should be an object', goog.isObject(array));
|
|
assertTrue('function should be an object', goog.isObject(fun));
|
|
assertFalse('string should not be an object', goog.isObject(string));
|
|
assertFalse('null should not be an object', goog.isObject(nullVar));
|
|
assertFalse('undefined should not be an object', goog.isObject(notDefined));
|
|
}
|
|
|
|
|
|
//=== tests for unique ID methods ===
|
|
|
|
function testGetUid() {
|
|
var a = {};
|
|
var b = {};
|
|
var c = {};
|
|
|
|
var uid1 = goog.getUid(a);
|
|
var uid2 = goog.getUid(b);
|
|
var uid3 = goog.getUid(c);
|
|
|
|
assertNotEquals('Unique IDs must be unique', uid1, uid2);
|
|
assertNotEquals('Unique IDs must be unique', uid1, uid3);
|
|
assertNotEquals('Unique IDs must be unique', uid2, uid3);
|
|
}
|
|
|
|
function testHasUid() {
|
|
var a = {};
|
|
|
|
assertFalse(goog.hasUid(a));
|
|
assertFalse(goog.UID_PROPERTY_ in a);
|
|
|
|
var uid = goog.getUid(a);
|
|
assertTrue(goog.hasUid(a));
|
|
assertEquals(uid, goog.getUid(a));
|
|
}
|
|
|
|
function testRemoveUidFromPlainObject() {
|
|
var a = {};
|
|
var uid = goog.getUid(a);
|
|
goog.removeUid(a);
|
|
assertNotEquals("An object's old and new unique IDs should be different",
|
|
uid, goog.getUid(a));
|
|
}
|
|
|
|
function testRemoveUidFromObjectWithoutUid() {
|
|
var a = {};
|
|
// Removing a unique ID should not fail even if it did not exist
|
|
goog.removeUid(a);
|
|
}
|
|
|
|
function testRemoveUidFromNode() {
|
|
var node = document.createElement('div');
|
|
var nodeUid = goog.getUid(node);
|
|
goog.removeUid(node);
|
|
assertNotEquals("A node's old and new unique IDs should be different",
|
|
nodeUid, goog.getUid(node));
|
|
}
|
|
|
|
function testConstructorUid() {
|
|
function BaseClass() {};
|
|
function SubClass() {};
|
|
goog.inherits(SubClass, BaseClass);
|
|
|
|
var baseClassUid = goog.getUid(BaseClass);
|
|
var subClassUid = goog.getUid(SubClass);
|
|
|
|
assertTrue('Unique ID of BaseClass must be a number',
|
|
typeof baseClassUid == 'number');
|
|
assertTrue('Unique ID of SubClass must be a number',
|
|
typeof subClassUid == 'number');
|
|
assertNotEquals('Unique IDs of BaseClass and SubClass must differ',
|
|
baseClassUid, subClassUid);
|
|
assertNotEquals('Unique IDs of BaseClass and SubClass instances must differ',
|
|
goog.getUid(new BaseClass), goog.getUid(new SubClass));
|
|
|
|
assertEquals('Unique IDs of BaseClass.prototype and SubClass.prototype ' +
|
|
'should differ, but to keep the implementation simple, we do not ' +
|
|
'handle this edge case.',
|
|
goog.getUid(BaseClass.prototype), goog.getUid(SubClass.prototype));
|
|
}
|
|
|
|
|
|
/**
|
|
* Tests against Chrome bug where the re-created element will have the uid
|
|
* property set but undefined. See bug 1252508.
|
|
*/
|
|
function testUidNotUndefinedOnReusedElement() {
|
|
var div = document.createElement('DIV');
|
|
document.body.appendChild(div);
|
|
div.innerHTML = '<form id="form"></form>';
|
|
var span = div.getElementsByTagName('FORM')[0];
|
|
goog.getUid(span);
|
|
|
|
div.innerHTML = '<form id="form"></form>';
|
|
var span2 = div.getElementsByTagName('FORM')[0];
|
|
assertNotUndefined(goog.getUid(span2));
|
|
}
|
|
|
|
function testWindowUid() {
|
|
var uid = goog.getUid(window);
|
|
assertTrue('window unique id is a number', goog.isNumber(uid));
|
|
assertEquals('returns the same id second time', uid, goog.getUid(window));
|
|
goog.removeUid(window);
|
|
assertNotEquals('generates new id after the old one is removed',
|
|
goog.getUid(window));
|
|
}
|
|
|
|
//=== tests for clone method ===
|
|
|
|
function testClonePrimitive() {
|
|
assertEquals('cloning a primitive should return an equal primitive',
|
|
5, goog.cloneObject(5));
|
|
}
|
|
|
|
function testCloneObjectThatHasACloneMethod() {
|
|
var original = {
|
|
name: 'original',
|
|
clone: function() { return { name: 'clone' }; }
|
|
};
|
|
|
|
var clone = goog.cloneObject(original);
|
|
assertEquals('original', original.name);
|
|
assertEquals('clone', clone.name);
|
|
}
|
|
|
|
function testCloneFlatObject() {
|
|
var original = {a: 1, b: 2, c: 3};
|
|
var clone = goog.cloneObject(original);
|
|
assertNotEquals(original, clone);
|
|
assertEquals(1, clone.a);
|
|
assertEquals(2, clone.b);
|
|
assertEquals(3, clone.c);
|
|
}
|
|
|
|
function testCloneDeepObject() {
|
|
var original = {
|
|
a: 1,
|
|
b: {c: 2, d: 3},
|
|
e: {f: {g: 4, h: 5}}
|
|
};
|
|
var clone = goog.cloneObject(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 testCloneFunctions() {
|
|
var original = {
|
|
f: function() {
|
|
return 'hi';
|
|
}
|
|
};
|
|
var clone = goog.cloneObject(original);
|
|
|
|
assertNotEquals(original, clone);
|
|
assertEquals('hi', clone.f());
|
|
assertEquals(original.f, clone.f);
|
|
}
|
|
|
|
|
|
//=== tests for bind() and friends ===
|
|
|
|
// Function.prototype.bind and Function.prototype.partial are purposefullly
|
|
// not defined in open sourced Closure. These functions sniff for their
|
|
// presence.
|
|
|
|
var foo = 'global';
|
|
var obj = {foo: 'obj'};
|
|
|
|
function getFoo(arg1, arg2) {
|
|
return {foo: this.foo, arg1: arg1, arg2: arg2};
|
|
}
|
|
|
|
function testBindWithoutObj() {
|
|
if (Function.prototype.bind) {
|
|
assertEquals(foo, getFoo.bind()().foo);
|
|
}
|
|
}
|
|
|
|
function testBindWithObj() {
|
|
if (Function.prototype.bind) {
|
|
assertEquals(obj.foo, getFoo.bind(obj)().foo);
|
|
}
|
|
}
|
|
|
|
function testBindWithNullObj() {
|
|
if (Function.prototype.bind) {
|
|
assertEquals(foo, getFoo.bind()().foo);
|
|
}
|
|
}
|
|
|
|
function testBindStaticArgs() {
|
|
if (Function.prototype.bind) {
|
|
var fooprime = getFoo.bind(obj, 'hot', 'dog');
|
|
var res = fooprime();
|
|
assertEquals(obj.foo, res.foo);
|
|
assertEquals('hot', res.arg1);
|
|
assertEquals('dog', res.arg2);
|
|
}
|
|
}
|
|
|
|
function testBindDynArgs() {
|
|
if (Function.prototype.bind) {
|
|
var res = getFoo.bind(obj)('hot', 'dog');
|
|
assertEquals(obj.foo, res.foo);
|
|
assertEquals('hot', res.arg1);
|
|
assertEquals('dog', res.arg2);
|
|
}
|
|
}
|
|
|
|
function testBindCurriedArgs() {
|
|
if (Function.prototype.bind) {
|
|
var res = getFoo.bind(obj, 'hot')('dog');
|
|
assertEquals(obj.foo, res.foo);
|
|
assertEquals('hot', res.arg1);
|
|
assertEquals('dog', res.arg2);
|
|
}
|
|
}
|
|
|
|
function testBindDoubleBind() {
|
|
var getFooP = goog.bind(getFoo, obj, 'hot');
|
|
var getFooP2 = goog.bind(getFooP, null, 'dog');
|
|
|
|
var res = getFooP2();
|
|
assertEquals("res.arg1 should be 'hot'", 'hot', res.arg1);
|
|
assertEquals("res.arg2 should be 'dog'", 'dog', res.arg2);
|
|
}
|
|
|
|
function testBindWithCall() {
|
|
var obj = {};
|
|
var obj2 = {};
|
|
var f = function() {
|
|
assertEquals('this should be bound to obj', obj, this);
|
|
};
|
|
var b = goog.bind(f, obj);
|
|
b.call(null);
|
|
b.call(obj2);
|
|
}
|
|
|
|
function testBindJs() {
|
|
assertEquals(1, goog.bindJs_(add, {valueOf: function() { return 1; }})());
|
|
assertEquals(3, goog.bindJs_(add, null, 1, 2)());
|
|
}
|
|
|
|
function testBindNative() {
|
|
if (Function.prototype.bind &&
|
|
Function.prototype.bind.toString().indexOf('native code') != -1) {
|
|
assertEquals(
|
|
1, goog.bindNative_(add, {valueOf: function() { return 1; }})());
|
|
assertEquals(3, goog.bindNative_(add, null, 1, 2)());
|
|
|
|
assertThrows(function() {
|
|
goog.bindNative_(null, null);
|
|
});
|
|
}
|
|
}
|
|
|
|
function testBindDefault() {
|
|
assertEquals(
|
|
1, goog.bind(add, {valueOf: function() { return 1; }})());
|
|
assertEquals(3, goog.bind(add, null, 1, 2)());
|
|
}
|
|
|
|
function add(var_args) {
|
|
var sum = Number(this) || 0;
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
sum += arguments[i];
|
|
}
|
|
return sum;
|
|
}
|
|
|
|
function testPartial() {
|
|
var f = function(x, y) {
|
|
return x + y;
|
|
};
|
|
var g = goog.partial(f, 1);
|
|
assertEquals(3, g(2));
|
|
|
|
var h = goog.partial(f, 1, 2);
|
|
assertEquals(3, h());
|
|
|
|
var i = goog.partial(f);
|
|
assertEquals(3, i(1, 2));
|
|
}
|
|
|
|
function testPartialUsesGlobal() {
|
|
var f = function(x, y) {
|
|
assertEquals(goog.global, this);
|
|
return x + y;
|
|
};
|
|
var g = goog.partial(f, 1);
|
|
var h = goog.partial(g, 2);
|
|
assertEquals(3, h());
|
|
}
|
|
|
|
function testPartialWithCall() {
|
|
var obj = {};
|
|
var f = function(x, y) {
|
|
assertEquals(obj, this);
|
|
return x + y;
|
|
};
|
|
var g = goog.partial(f, 1);
|
|
var h = goog.partial(g, 2);
|
|
assertEquals(3, h.call(obj));
|
|
}
|
|
|
|
function testPartialAndBind() {
|
|
// This ensures that this "survives" through a partial.
|
|
var p = goog.partial(getFoo, 'hot');
|
|
var b = goog.bind(p, obj, 'dog');
|
|
|
|
var res = b();
|
|
assertEquals(obj.foo, res.foo);
|
|
assertEquals('hot', res.arg1);
|
|
assertEquals('dog', res.arg2);
|
|
}
|
|
|
|
function testBindAndPartial() {
|
|
// This ensures that this "survives" through a partial.
|
|
var b = goog.bind(getFoo, obj, 'hot');
|
|
var p = goog.partial(b, 'dog');
|
|
|
|
var res = p();
|
|
assertEquals(obj.foo, res.foo);
|
|
assertEquals('hot', res.arg1);
|
|
assertEquals('dog', res.arg2);
|
|
}
|
|
|
|
function testPartialMultipleCalls() {
|
|
var f = goog.testing.recordFunction();
|
|
|
|
var a = goog.partial(f, 'foo');
|
|
var b = goog.partial(a, 'bar');
|
|
|
|
a();
|
|
a();
|
|
b();
|
|
b();
|
|
|
|
assertEquals(4, f.getCallCount());
|
|
|
|
var calls = f.getCalls();
|
|
assertArrayEquals(['foo'], calls[0].getArguments());
|
|
assertArrayEquals(['foo'], calls[1].getArguments());
|
|
assertArrayEquals(['foo', 'bar'], calls[2].getArguments());
|
|
assertArrayEquals(['foo', 'bar'], calls[3].getArguments());
|
|
}
|
|
|
|
|
|
function testGlobalEval() {
|
|
goog.globalEval('var foofoofoo = 125;');
|
|
assertEquals('Var should be globally assigned', 125, goog.global.foofoofoo);
|
|
var foofoofoo = 128;
|
|
assertEquals('Global should not have changed', 125, goog.global.foofoofoo);
|
|
|
|
// NOTE(user): foofoofoo would normally be available in the function scope,
|
|
// via the scope chain, but the JsUnit framework seems to do something weird
|
|
// which makes it not work.
|
|
}
|
|
|
|
function testGlobalEvalWithHtml() {
|
|
// Make sure we don't trip on HTML markup in the code
|
|
goog.global.evalTestResult = 'failed';
|
|
goog.global.evalTest = function(arg) {
|
|
goog.global.evalTestResult = arg;
|
|
};
|
|
|
|
goog.globalEval('evalTest("<test>")');
|
|
|
|
assertEquals('Should be able to evaluate strings with HTML in',
|
|
'<test>', goog.global.evalTestResult);
|
|
}
|
|
|
|
|
|
//=== tests for inherits ===
|
|
|
|
function testInherits() {
|
|
function Foo() {};
|
|
function Bar() {};
|
|
goog.inherits(Bar, Foo);
|
|
var bar = new Bar();
|
|
|
|
assert('object should be instance of constructor',
|
|
bar instanceof Bar);
|
|
assert('object should be instance of base constructor',
|
|
bar instanceof Foo);
|
|
}
|
|
|
|
function testInherits_constructor() {
|
|
function Foo() {};
|
|
function Bar() {};
|
|
goog.inherits(Bar, Foo);
|
|
var bar = new Bar();
|
|
|
|
assertEquals('constructor property should match constructor function',
|
|
Bar, bar.constructor);
|
|
assertEquals('Superclass constructor should match constructor function',
|
|
Foo, Bar.superClass_.constructor);
|
|
}
|
|
|
|
|
|
//=== tests for makeSingleton ===
|
|
function testMakeSingleton() {
|
|
function Foo() {};
|
|
goog.addSingletonGetter(Foo);
|
|
|
|
assertNotNull('Should add get instance function', Foo.getInstance);
|
|
|
|
var x = Foo.getInstance();
|
|
assertNotNull('Should successfully create an object', x);
|
|
|
|
var y = Foo.getInstance();
|
|
assertEquals('Should return the same object', x, y);
|
|
|
|
delete Foo.instance_;
|
|
|
|
var z = Foo.getInstance();
|
|
assertNotNull('Should work after clearing for testing', z);
|
|
|
|
assertNotEquals('Should return a different object after clearing for testing',
|
|
x, z);
|
|
}
|
|
|
|
|
|
//=== tests for now ===
|
|
|
|
function testNow() {
|
|
var toleranceMilliseconds = 20; // 10 ms was not enough for IE7.
|
|
var now1 = new Date().getTime();
|
|
var now2 = goog.now();
|
|
assertTrue(Math.abs(now1 - now2) < toleranceMilliseconds);
|
|
}
|
|
|
|
|
|
//=== test non-html context ===
|
|
|
|
function testInHtmlDocument() {
|
|
var savedGoogGlobal = goog.global;
|
|
try {
|
|
goog.global = {};
|
|
assertFalse(goog.inHtmlDocument_());
|
|
goog.global.document = {};
|
|
assertFalse(goog.inHtmlDocument_());
|
|
goog.global.document.write = function() {};
|
|
assertTrue(goog.inHtmlDocument_());
|
|
} finally {
|
|
// Restore context to respect other tests.
|
|
goog.global = savedGoogGlobal;
|
|
}
|
|
}
|
|
|
|
function testLoadInNonHtmlNotThrows() {
|
|
var savedGoogGlobal = goog.global;
|
|
try {
|
|
goog.global = {};
|
|
goog.global.document = {};
|
|
assertFalse(goog.inHtmlDocument_());
|
|
// The goog code which is executed at load.
|
|
goog.findBasePath_();
|
|
goog.writeScriptTag_(goog.basePath + 'deps.js');
|
|
} finally {
|
|
// Restore context to respect other tests.
|
|
goog.global = savedGoogGlobal;
|
|
}
|
|
}
|
|
|
|
function testLoadBaseWithQueryParamOk() {
|
|
var savedGoogGlobal = goog.global;
|
|
try {
|
|
goog.global = {};
|
|
goog.global.document = {
|
|
write: goog.nullFunction,
|
|
getElementsByTagName: goog.functions.constant(
|
|
[{src: '/path/to/base.js?zx=5'}])
|
|
};
|
|
assertTrue(goog.inHtmlDocument_());
|
|
goog.findBasePath_();
|
|
assertEquals('/path/to/', goog.basePath);
|
|
} finally {
|
|
// Restore context to respect other tests.
|
|
goog.global = savedGoogGlobal;
|
|
}
|
|
}
|
|
|
|
//=== tests for getmsg ===
|
|
function testGetMsgWithDollarSigns() {
|
|
var msg = goog.getMsg('{$amount} per minute',
|
|
{amount: '$0.15'});
|
|
assertEquals('$0.15 per minute', msg);
|
|
msg = goog.getMsg('{$amount} per minute',
|
|
{amount: '$0.$1$5'});
|
|
assertEquals('$0.$1$5 per minute', msg);
|
|
|
|
msg = goog.getMsg('This is a {$rate} sale!',
|
|
{rate: '$$$$$$$$$$10'});
|
|
assertEquals('This is a $$$$$$$$$$10 sale!', msg);
|
|
msg = goog.getMsg('{$name}! Hamburgers: {$hCost}, Hotdogs: {$dCost}.', {
|
|
name: 'Burger Bob',
|
|
hCost: '$0.50',
|
|
dCost: '$100'
|
|
});
|
|
assertEquals('Burger Bob! Hamburgers: $0.50, Hotdogs: $100.', msg);
|
|
}
|
|
|
|
|
|
function testGetMsgWithPlaceholders() {
|
|
var msg = goog.getMsg('{$a} has {$b}', {a: '{$b}', b: 1});
|
|
assertEquals('{$b} has 1', msg);
|
|
|
|
msg = goog.getMsg('{$a}{$b}', {b: ''});
|
|
assertEquals('{$a}', msg);
|
|
}
|
|
|
|
|
|
//=== miscellaneous tests ===
|
|
|
|
function testIdentity() {
|
|
assertEquals(3, goog.identityFunction(3));
|
|
assertEquals(3, goog.identityFunction(3, 4));
|
|
assertEquals(null, goog.identityFunction(null));
|
|
assertTrue(goog.identityFunction() === undefined);
|
|
}
|
|
|
|
function testGetObjectByName() {
|
|
var m = {
|
|
'undefined': undefined,
|
|
'null': null,
|
|
emptyString: '',
|
|
'false': false,
|
|
'true': true,
|
|
zero: 0,
|
|
one: 1,
|
|
two: {
|
|
three: 3,
|
|
four: {
|
|
five: 5
|
|
}
|
|
},
|
|
'six|seven': '6|7',
|
|
'eight.nine': 8.9
|
|
};
|
|
goog.global.m = m;
|
|
|
|
assertNull(goog.getObjectByName('m.undefined'));
|
|
assertNull(goog.getObjectByName('m.null'));
|
|
assertEquals(goog.getObjectByName('m.emptyString'), '');
|
|
assertEquals(goog.getObjectByName('m.false'), false);
|
|
assertEquals(goog.getObjectByName('m.true'), true);
|
|
assertEquals(goog.getObjectByName('m.zero'), 0);
|
|
assertEquals(goog.getObjectByName('m.one'), 1);
|
|
assertEquals(goog.getObjectByName('m.two.three'), 3);
|
|
assertEquals(goog.getObjectByName('m.two.four.five'), 5);
|
|
assertEquals(goog.getObjectByName('m.six|seven'), '6|7');
|
|
assertNull(goog.getObjectByName('m.eight.nine'));
|
|
assertNull(goog.getObjectByName('m.notThere'));
|
|
|
|
assertEquals(goog.getObjectByName('one', m), 1);
|
|
assertEquals(goog.getObjectByName('two.three', m), 3);
|
|
assertEquals(goog.getObjectByName('two.four.five', m), 5);
|
|
assertEquals(goog.getObjectByName('six|seven', m), '6|7');
|
|
assertNull(goog.getObjectByName('eight.nine', m));
|
|
assertNull(goog.getObjectByName('notThere', m));
|
|
}
|
|
|
|
|
|
function testGetCssName() {
|
|
assertEquals('classname', goog.getCssName('classname'));
|
|
assertEquals('random-classname', goog.getCssName('random-classname'));
|
|
assertEquals('control-modifier', goog.getCssName('control', 'modifier'));
|
|
|
|
goog.setCssNameMapping({
|
|
'goog': 'a',
|
|
'disabled': 'b'
|
|
}, 'BY_PART');
|
|
var g = goog.getCssName('goog');
|
|
assertEquals('a', g);
|
|
assertEquals('a-b', goog.getCssName(g, 'disabled'));
|
|
assertEquals('a-b', goog.getCssName('goog-disabled'));
|
|
assertEquals('a-button', goog.getCssName('goog-button'));
|
|
|
|
goog.setCssNameMapping({
|
|
'goog-button': 'a',
|
|
'active': 'b'
|
|
}, 'BY_WHOLE');
|
|
|
|
g = goog.getCssName('goog-button');
|
|
assertEquals('a', g);
|
|
assertEquals('a-b', goog.getCssName(g, 'active'));
|
|
assertEquals('goog-disabled', goog.getCssName('goog-disabled'));
|
|
}
|
|
|
|
function testAddDependency() {
|
|
stubs.set(goog, 'writeScriptTag_', goog.nullFunction);
|
|
stubs.set(goog, 'isDocumentFinishedLoading_', false);
|
|
|
|
goog.addDependency(
|
|
'foo.js',
|
|
['testDep.foo'],
|
|
['testDep.bar']);
|
|
|
|
goog.provide('testDep.bar');
|
|
|
|
// To differentiate this call from the real one.
|
|
var require = goog.require;
|
|
|
|
// this used to throw an exception
|
|
require('testDep.foo');
|
|
|
|
assertTrue(goog.isObject(testDep.bar));
|
|
|
|
// Unset provided namespace so the test can be re-run.
|
|
testDep = undefined;
|
|
}
|
|
|
|
function testBaseMethod() {
|
|
function A() {}
|
|
A.prototype.foo = function(x, y) {
|
|
return x + y;
|
|
};
|
|
|
|
function B() {}
|
|
goog.inherits(B, A);
|
|
B.prototype.foo = function(x, y) {
|
|
return 2 + goog.base(this, 'foo', x, y);
|
|
};
|
|
|
|
function C() {}
|
|
goog.inherits(C, B);
|
|
C.prototype.foo = function(x, y) {
|
|
return 4 + goog.base(this, 'foo', x, y);
|
|
};
|
|
|
|
var d = new C();
|
|
d.foo = function(x, y) {
|
|
return 8 + goog.base(this, 'foo', x, y);
|
|
};
|
|
|
|
assertEquals(15, d.foo(1, 0));
|
|
assertEquals(16, d.foo(1, 1));
|
|
assertEquals(16, d.foo(2, 0));
|
|
assertEquals(7, (new C()).foo(1, 0));
|
|
assertEquals(3, (new B()).foo(1, 0));
|
|
assertThrows(function() {
|
|
goog.base(d, 'foo', 1, 0);
|
|
});
|
|
|
|
delete B.prototype.foo;
|
|
assertEquals(13, d.foo(1, 0));
|
|
|
|
delete C.prototype.foo;
|
|
assertEquals(9, d.foo(1, 0));
|
|
}
|
|
|
|
function testBaseMethodAndBaseCtor() {
|
|
// This will fail on FF4.0 if the following bug is not fixed:
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=586482
|
|
function A(x, y) {
|
|
this.foo(x, y);
|
|
}
|
|
A.prototype.foo = function(x, y) {
|
|
this.bar = x + y;
|
|
};
|
|
|
|
function B(x, y) {
|
|
goog.base(this, x, y);
|
|
}
|
|
goog.inherits(B, A);
|
|
B.prototype.foo = function(x, y) {
|
|
goog.base(this, 'foo', x, y);
|
|
this.bar = this.bar * 2;
|
|
};
|
|
|
|
assertEquals(14, new B(3, 4).bar);
|
|
}
|
|
|
|
function testBaseClass() {
|
|
function A(x, y) {
|
|
this.foo = x + y;
|
|
}
|
|
|
|
function B(x, y) {
|
|
goog.base(this, x, y);
|
|
this.foo += 2;
|
|
}
|
|
goog.inherits(B, A);
|
|
|
|
function C(x, y) {
|
|
goog.base(this, x, y);
|
|
this.foo += 4;
|
|
}
|
|
goog.inherits(C, B);
|
|
|
|
function D(x, y) {
|
|
goog.base(this, x, y);
|
|
this.foo += 8;
|
|
}
|
|
goog.inherits(D, C);
|
|
|
|
assertEquals(15, (new D(1, 0)).foo);
|
|
assertEquals(16, (new D(1, 1)).foo);
|
|
assertEquals(16, (new D(2, 0)).foo);
|
|
assertEquals(7, (new C(1, 0)).foo);
|
|
assertEquals(3, (new B(1, 0)).foo);
|
|
}
|
|
|
|
function testClassBaseOnMethod() {
|
|
function A() {}
|
|
A.prototype.foo = function(x, y) {
|
|
return x + y;
|
|
};
|
|
|
|
function B() {}
|
|
goog.inherits(B, A);
|
|
B.prototype.foo = function(x, y) {
|
|
return 2 + B.base(this, 'foo', x, y);
|
|
};
|
|
|
|
function C() {}
|
|
goog.inherits(C, B);
|
|
C.prototype.foo = function(x, y) {
|
|
return 4 + C.base(this, 'foo', x, y);
|
|
};
|
|
|
|
var d = new C();
|
|
assertEquals(7, d.foo(1, 0));
|
|
assertEquals(8, d.foo(1, 1));
|
|
assertEquals(8, d.foo(2, 0));
|
|
assertEquals(3, (new B()).foo(1, 0));
|
|
|
|
delete B.prototype.foo;
|
|
assertEquals(5, d.foo(1, 0));
|
|
|
|
delete C.prototype.foo;
|
|
assertEquals(1, d.foo(1, 0));
|
|
}
|
|
|
|
function testClassBaseOnConstructor() {
|
|
function A(x, y) {
|
|
this.foo = x + y;
|
|
}
|
|
|
|
function B(x, y) {
|
|
B.base(this, 'constructor', x, y);
|
|
this.foo += 2;
|
|
}
|
|
goog.inherits(B, A);
|
|
|
|
function C(x, y) {
|
|
C.base(this, 'constructor', x, y);
|
|
this.foo += 4;
|
|
}
|
|
goog.inherits(C, B);
|
|
|
|
function D(x, y) {
|
|
D.base(this, 'constructor', x, y);
|
|
this.foo += 8;
|
|
}
|
|
goog.inherits(D, C);
|
|
|
|
assertEquals(15, (new D(1, 0)).foo);
|
|
assertEquals(16, (new D(1, 1)).foo);
|
|
assertEquals(16, (new D(2, 0)).foo);
|
|
assertEquals(7, (new C(1, 0)).foo);
|
|
assertEquals(3, (new B(1, 0)).foo);
|
|
}
|
|
|
|
function testClassBaseOnMethodAndBaseCtor() {
|
|
function A(x, y) {
|
|
this.foo(x, y);
|
|
}
|
|
A.prototype.foo = function(x, y) {
|
|
this.bar = x + y;
|
|
};
|
|
|
|
function B(x, y) {
|
|
B.base(this, 'constructor', x, y);
|
|
}
|
|
goog.inherits(B, A);
|
|
B.prototype.foo = function(x, y) {
|
|
B.base(this, 'foo', x, y);
|
|
this.bar = this.bar * 2;
|
|
};
|
|
|
|
assertEquals(14, new B(3, 4).bar);
|
|
}
|
|
|
|
function testGoogRequireCheck() {
|
|
stubs.set(goog, 'ENABLE_DEBUG_LOADER', false);
|
|
stubs.set(goog, 'useStrictRequires', true);
|
|
stubs.set(goog, 'implicitNamespaces_', {});
|
|
|
|
// Aliased so that build tools do not mistake this for an actual call.
|
|
var require = goog.require;
|
|
assertThrows('Requiring non-required namespace should fail',
|
|
function() {
|
|
require('far.out');
|
|
});
|
|
|
|
assertUndefined(goog.global.far);
|
|
assertEvaluatesToFalse(goog.getObjectByName('far.out'));
|
|
assertObjectEquals({}, goog.implicitNamespaces_);
|
|
assertFalse(goog.isProvided_('far.out'));
|
|
|
|
goog.provide('far.out');
|
|
|
|
assertNotUndefined(far.out);
|
|
assertEvaluatesToTrue(goog.getObjectByName('far.out'));
|
|
assertObjectEquals({'far': true}, goog.implicitNamespaces_);
|
|
assertTrue(goog.isProvided_('far.out'));
|
|
|
|
goog.global.far.out = 42;
|
|
assertEquals(42, goog.getObjectByName('far.out'));
|
|
assertTrue(goog.isProvided_('far.out'));
|
|
|
|
// Empty string should be allowed.
|
|
goog.global.far.out = '';
|
|
assertEquals('', goog.getObjectByName('far.out'));
|
|
assertTrue(goog.isProvided_('far.out'));
|
|
|
|
// Null or undefined are not allowed.
|
|
goog.global.far.out = null;
|
|
assertNull(goog.getObjectByName('far.out'));
|
|
assertFalse(goog.isProvided_('far.out'));
|
|
|
|
goog.global.far.out = undefined;
|
|
assertNull(goog.getObjectByName('far.out'));
|
|
assertFalse(goog.isProvided_('far.out'));
|
|
|
|
stubs.reset();
|
|
delete far;
|
|
}
|
|
|
|
function testLateRequireProtection() {
|
|
if (!document.readyState) return;
|
|
var e = assertThrows(function() {
|
|
// To differentiate this call from the real one.
|
|
var require = goog.require;
|
|
require('goog.ui.Component');
|
|
});
|
|
|
|
assertContains('after document load', e.message);
|
|
}
|
|
|
|
function testDefineClass() {
|
|
var Base = goog.defineClass(null, {
|
|
constructor: function(foo) {
|
|
this.foo = foo;
|
|
},
|
|
statics: {
|
|
x: 42
|
|
},
|
|
frobnicate: function() {
|
|
return this.foo + this.foo;
|
|
}
|
|
});
|
|
var Derived = goog.defineClass(Base, {
|
|
constructor: function() {
|
|
Derived.base(this, 'constructor', 'bar');
|
|
},
|
|
frozzle: function(foo) {
|
|
this.foo = foo;
|
|
}
|
|
});
|
|
|
|
assertEquals(42, Base.x);
|
|
var der = new Derived();
|
|
assertEquals('barbar', der.frobnicate());
|
|
der.frozzle('qux');
|
|
assertEquals('quxqux', der.frobnicate());
|
|
}
|
|
|
|
function testDefineClass_interface() {
|
|
var Interface = goog.defineClass(null, {
|
|
statics: {
|
|
foo: 'bar'
|
|
},
|
|
qux: function() {}
|
|
});
|
|
assertEquals('bar', Interface.foo);
|
|
assertThrows(function() { new Interface(); });
|
|
}
|
|
|
|
function testDefineClass_seals() {
|
|
if (!(Object.seal instanceof Function)) return; // IE<9 doesn't have seal
|
|
var A = goog.defineClass(null, {
|
|
constructor: function() {}
|
|
});
|
|
var a = new A();
|
|
try {
|
|
a.foo = 'bar';
|
|
} catch (expectedInStrictModeOnly) { /* ignored */ }
|
|
assertEquals(undefined, a.foo);
|
|
}
|
|
|
|
function testDefineClass_unsealable() {
|
|
var LegacyBase = function() {};
|
|
LegacyBase.prototype.foo = null;
|
|
LegacyBase.prototype.setFoo = function(foo) {
|
|
this.foo = foo;
|
|
};
|
|
goog.tagUnsealableClass(LegacyBase);
|
|
|
|
var Derived = goog.defineClass(LegacyBase, {
|
|
constructor: function() {}
|
|
});
|
|
|
|
var der = new Derived();
|
|
der.setFoo('bar');
|
|
assertEquals('bar', der.foo);
|
|
}
|
|
|
|
// Validate the behavior of goog.module when used from traditional files.
|
|
function testGoogModuleGet() {
|
|
// assert that goog.module doesn't modify the global namespace
|
|
assertUndefined('module failed to protect global namespace: ' +
|
|
'goog.test_module_dep', goog.test_module_dep);
|
|
|
|
// assert that goog.module with goog.module.declareLegacyNamespace is present.
|
|
assertNotUndefined('module failed to declare global namespace: ' +
|
|
'goog.test_module', goog.test_module);
|
|
|
|
// assert that a require'd goog.module is available immediately after the
|
|
// goog.require call.
|
|
assertNotUndefined('module failed to protect global namespace: ' +
|
|
'goog.test_module_dep', earlyTestModuleGet);
|
|
|
|
|
|
// assert that an non-existent module request doesn't throw and returns null.
|
|
assertEquals(null, goog.module.get('unrequired.module.id'));
|
|
|
|
// Validate the module exports
|
|
var testModuleExports = goog.module.get('goog.test_module');
|
|
assertTrue(goog.isFunction(testModuleExports));
|
|
|
|
// Validate that the module exports object has not changed
|
|
assertEquals(earlyTestModuleGet, testModuleExports);
|
|
}
|
|
|
|
function testNormalizePath() {
|
|
assertEquals('foo/path.js', goog.normalizePath_('./foo/./path.js'));
|
|
assertEquals('foo/path.js', goog.normalizePath_('bar/../foo/path.js'));
|
|
assertEquals('bar/path.js', goog.normalizePath_('bar/foo/../path.js'));
|
|
assertEquals('path.js', goog.normalizePath_('bar/foo/../../path.js'));
|
|
|
|
assertEquals('../foo/path.js', goog.normalizePath_('../foo/path.js'));
|
|
assertEquals('../../foo/path.js', goog.normalizePath_('../../foo/path.js'));
|
|
assertEquals('../path.js', goog.normalizePath_('../foo/../path.js'));
|
|
assertEquals('../../path.js', goog.normalizePath_('../foo/../../path.js'));
|
|
|
|
assertEquals('/../foo/path.js', goog.normalizePath_('/../foo/path.js'));
|
|
assertEquals('/path.js', goog.normalizePath_('/foo/../path.js'));
|
|
assertEquals('/foo/path.js', goog.normalizePath_('/./foo/path.js'));
|
|
|
|
assertEquals('//../foo/path.js', goog.normalizePath_('//../foo/path.js'));
|
|
assertEquals('//path.js', goog.normalizePath_('//foo/../path.js'));
|
|
assertEquals('//foo/path.js', goog.normalizePath_('//./foo/path.js'));
|
|
|
|
assertEquals('http://../x/y.js', goog.normalizePath_('http://../x/y.js'));
|
|
assertEquals('http://path.js', goog.normalizePath_('http://foo/../path.js'));
|
|
assertEquals('http://x/path.js', goog.normalizePath_('http://./x/path.js'));
|
|
|
|
var expected = '../../../../../../../javascript/apps/xid/xid.js';
|
|
var original = '../testing/../../../../../../../' +
|
|
'closure/goog/../apps/xid/xid.js';
|
|
assertEquals(expected, goog.normalizePath_(original));
|
|
}
|
|
|
|
|
|
function testGoogModuleNames() {
|
|
// avoid usage checks
|
|
var module = goog.module;
|
|
|
|
function assertInvalidId(id) {
|
|
var err = assertThrows(function() {
|
|
module(id);
|
|
});
|
|
assertEquals('Invalid module identifier', err.message);
|
|
}
|
|
|
|
function assertValidId(id) {
|
|
// This is a cheesy check, but we validate that we don't get an invalid
|
|
// namespace warning, but instead get a module isn't loaded correctly
|
|
// error.
|
|
var err = assertThrows(function() {
|
|
module(id);
|
|
});
|
|
assertTrue(err.message.indexOf('has been loaded incorrectly') != -1);
|
|
}
|
|
|
|
assertInvalidId('/somepath/module.js');
|
|
assertInvalidId('./module.js');
|
|
assertInvalidId('1');
|
|
|
|
assertValidId('a');
|
|
assertValidId('a.b');
|
|
assertValidId('a.b.c');
|
|
assertValidId('aB.Cd.eF');
|
|
assertValidId('a1.0E.Fg');
|
|
|
|
assertValidId('_');
|
|
assertValidId('$');
|
|
assertValidId('_$');
|
|
assertValidId('$_');
|
|
}
|