base_test.js 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907
  1. // Copyright 2006 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Unit tests for Closure's base.js.
  16. */
  17. goog.provide('goog.baseTest');
  18. goog.setTestOnly('goog.baseTest');
  19. goog.require('goog.Promise');
  20. // Used to test dynamic loading works, see testRequire*
  21. goog.require('goog.Timer');
  22. goog.require('goog.dom');
  23. goog.require('goog.dom.TagName');
  24. goog.require('goog.functions');
  25. goog.require('goog.object');
  26. goog.require('goog.test_module');
  27. goog.require('goog.testing.PropertyReplacer');
  28. goog.require('goog.testing.jsunit');
  29. goog.require('goog.testing.recordFunction');
  30. goog.require('goog.userAgent');
  31. var earlyTestModuleGet = goog.module.get('goog.test_module');
  32. /**
  33. * @param {?} name
  34. * @return {?}
  35. */
  36. function getFramedVars(name) {
  37. var w = window.frames[name];
  38. var doc = w.document;
  39. doc.open();
  40. doc.write(
  41. '<script>' +
  42. 'var a = [0, 1, 2];' +
  43. 'var o = {a: 0, b: 1};' +
  44. 'var n = 42;' +
  45. 'var b = true;' +
  46. 'var s = "string";' +
  47. 'var nv = null;' +
  48. 'var u = undefined;' +
  49. 'var fv = function(){};' +
  50. '</' +
  51. 'script>');
  52. doc.close();
  53. return {
  54. 'array': w.a,
  55. 'object': w.o,
  56. 'number': w.n,
  57. 'boolean': w.b,
  58. 'string': w.s,
  59. 'functionVar': w.fv,
  60. 'nullVar': w.nv,
  61. 'undefinedVar': w.u
  62. };
  63. }
  64. var framedVars = getFramedVars('f1');
  65. var framedVars2 = getFramedVars('f2');
  66. // remove iframe
  67. var iframeElement = document.getElementById('f2');
  68. iframeElement.parentNode.removeChild(iframeElement);
  69. var stubs = new goog.testing.PropertyReplacer();
  70. var originalGoogBind = goog.bind;
  71. function tearDown() {
  72. goog.setCssNameMapping(undefined);
  73. stubs.reset();
  74. goog.bind = originalGoogBind;
  75. }
  76. function testLibrary() {
  77. assertNotUndefined('\'goog\' not loaded', goog);
  78. }
  79. function testDefine() {
  80. goog.define('SOME_DEFINE', 123); // overridden by 456
  81. assertEquals(SOME_DEFINE, 456);
  82. goog.define('SOME_OTHER_DEFINE', 123); // not overridden
  83. assertEquals(SOME_OTHER_DEFINE, 123);
  84. // alias to avoid the being picked up by the deps scanner.
  85. var provide = goog.provide;
  86. provide('ns');
  87. goog.define('ns.SOME_DEFINE', 123); // overridden by 456
  88. assertEquals(SOME_DEFINE, 456);
  89. goog.define('ns.SOME_OTHER_DEFINE', 123); // not overridden
  90. assertEquals(SOME_OTHER_DEFINE, 123);
  91. }
  92. function testProvide() {
  93. // alias to avoid the being picked up by the deps scanner.
  94. var provide = goog.provide;
  95. provide('goog.test.name.space');
  96. assertNotUndefined('provide failed: goog.test', goog.test);
  97. assertNotUndefined('provide failed: goog.test.name', goog.test.name);
  98. assertNotUndefined(
  99. 'provide failed: goog.test.name.space', goog.test.name.space);
  100. // ensure that providing 'goog.test.name' doesn't throw an exception
  101. provide('goog.test');
  102. provide('goog.test.name');
  103. delete goog.test;
  104. }
  105. // "watch" is a native member of Object.prototype on Firefox
  106. // Ensure it can still be added as a namespace
  107. function testProvideWatch() {
  108. // alias to avoid the being picked up by the deps scanner.
  109. var provide = goog.provide;
  110. provide('goog.yoddle.watch');
  111. assertNotUndefined('provide failed: goog.yoddle.watch', goog.yoddle.watch);
  112. delete goog.yoddle;
  113. }
  114. // Namespaces should not conflict with elements added to the window based on
  115. // their id
  116. function testConflictingSymbolAndId() {
  117. // Create a div with a given id
  118. var divElement = document.createElement('div');
  119. divElement.id = 'clashingname';
  120. document.body.appendChild(divElement);
  121. // The object at window.clashingname is the element with that id
  122. assertEquals(window.clashingname, divElement);
  123. // Export a symbol to a sub-namespace of that id
  124. var symbolObject = {};
  125. goog.exportSymbol('clashingname.symbolname', symbolObject);
  126. // The symbol has been added...
  127. assertEquals(window.clashingname.symbolname, symbolObject);
  128. // ...and has not affected the original div
  129. assertEquals(window.clashingname, divElement);
  130. }
  131. function testProvideStrictness() {
  132. // alias to avoid the being picked up by the deps scanner.
  133. var provide = goog.provide;
  134. provide('goog.xy');
  135. assertProvideFails('goog.xy');
  136. provide('goog.xy.z');
  137. assertProvideFails('goog.xy');
  138. window['goog']['xyz'] = 'Bob';
  139. assertProvideFails('goog.xyz');
  140. delete goog.xy;
  141. delete goog.xyz;
  142. }
  143. /** @param {?} namespace */
  144. function assertProvideFails(namespace) {
  145. assertThrows(
  146. 'goog.provide(' + namespace + ') should have failed',
  147. goog.partial(goog.provide, namespace));
  148. }
  149. function testIsProvided() {
  150. // alias to avoid the being picked up by the deps scanner.
  151. var provide = goog.provide;
  152. provide('goog.explicit');
  153. assertTrue(goog.isProvided_('goog.explicit'));
  154. provide('goog.implicit.explicit');
  155. assertFalse(goog.isProvided_('goog.implicit'));
  156. assertTrue(goog.isProvided_('goog.implicit.explicit'));
  157. }
  158. function testGlobalize() {
  159. var a = {a: 1, b: 2, c: 3};
  160. var b = {};
  161. goog.globalize(a, b);
  162. assertNotUndefined('Globalize to arbitrary object', b.a);
  163. assertNotUndefined('Globalize to arbitrary object', b.b);
  164. assertNotUndefined('Globalize to arbitrary object', b.c);
  165. }
  166. function testExportSymbol() {
  167. var date = new Date();
  168. // alias to avoid the being picked up by the deps scanner.
  169. var provide = goog.provide;
  170. assertTrue(typeof nodots == 'undefined');
  171. goog.exportSymbol('nodots', date);
  172. assertEquals(date, nodots);
  173. nodots = undefined;
  174. assertTrue(typeof gotcher == 'undefined');
  175. goog.exportSymbol('gotcher.dots.right.Here', date);
  176. assertEquals(date, gotcher.dots.right.Here);
  177. gotcher = undefined;
  178. provide('an.existing.path');
  179. assertNotNull(an.existing.path);
  180. goog.exportSymbol('an.existing.path', date);
  181. assertEquals(date, an.existing.path);
  182. an = undefined;
  183. var foo = {foo: 'foo'};
  184. var bar = {bar: 'bar'};
  185. var baz = {baz: 'baz'};
  186. goog.exportSymbol('one.two.three.Four', foo);
  187. goog.exportSymbol('one.two.three.five', bar);
  188. goog.exportSymbol('one.two.six', baz);
  189. assertEquals(foo, one.two.three.Four);
  190. assertEquals(bar, one.two.three.five);
  191. assertEquals(baz, one.two.six);
  192. var win = {};
  193. var fooBar = {foo: 'foo', bar: 'bar'};
  194. goog.exportSymbol('one.two.four', fooBar, win);
  195. assertEquals(fooBar, win.one.two.four);
  196. assertTrue('four' in win.one.two);
  197. assertFalse('four' in one.two);
  198. one = undefined;
  199. }
  200. goog.exportSymbol('exceptionTest', function() {
  201. throw Error('ERROR');
  202. });
  203. function testExportSymbolExceptions() {
  204. var inner = function() {
  205. // If exceptionTest wasn't exported using execScript, IE8 will throw "Object
  206. // doesn't support this property or method" instead.
  207. exceptionTest();
  208. };
  209. var e = assertThrows('Exception wasn\'t thrown by exported function', inner);
  210. assertEquals('Unexpected error thrown', 'ERROR', e.message);
  211. }
  212. //=== tests for Require logic ===
  213. function testRequireClosure() {
  214. assertNotUndefined('goog.Timer should be available', goog.Timer);
  215. /** @suppress {missingRequire} */
  216. assertNotUndefined(
  217. 'goog.events.EventTarget should be available', goog.events.EventTarget);
  218. }
  219. function testRequireWithExternalDuplicate() {
  220. // alias to avoid the being picked up by the deps scanner.
  221. var provide = goog.provide;
  222. // Do a provide without going via goog.require. Then goog.require it
  223. // indirectly and ensure it doesn't cause a duplicate script.
  224. goog.addDependency('dup.js', ['dup.base'], []);
  225. goog.addDependency('dup-child.js', ['dup.base.child'], ['dup.base']);
  226. provide('dup.base');
  227. stubs.set(goog, 'isDocumentFinishedLoading_', false);
  228. stubs.set(goog.global, 'CLOSURE_IMPORT_SCRIPT', function(src) {
  229. if (src == goog.basePath + 'dup.js') {
  230. fail('Duplicate script written!');
  231. } else if (src == goog.basePath + 'dup-child.js') {
  232. // Allow expected script.
  233. return true;
  234. } else {
  235. // Avoid affecting other state.
  236. return false;
  237. }
  238. });
  239. // To differentiate this call from the real one.
  240. var require = goog.require;
  241. require('dup.base.child');
  242. }
  243. //=== tests for language enhancements ===
  244. function testTypeOf() {
  245. assertEquals('array', goog.typeOf([]));
  246. assertEquals('string', goog.typeOf('string'));
  247. assertEquals('number', goog.typeOf(123));
  248. assertEquals('null', goog.typeOf(null));
  249. assertEquals('undefined', goog.typeOf(undefined));
  250. assertEquals('object', goog.typeOf({}));
  251. assertEquals('function', goog.typeOf(function() {}));
  252. // Make sure that NodeList is not treated as an array... NodeLists should
  253. // be of type object but Safari incorrectly reports it as function so a not
  254. // equals test will have to suffice here.
  255. assertNotEquals('array', goog.typeOf(document.getElementsByName('*')));
  256. assertNotEquals('function', goog.typeOf(document.getElementsByName('*')));
  257. assertEquals('object', goog.typeOf(document.getElementsByName('*')));
  258. }
  259. function testTypeOfFramed() {
  260. assertEquals('array', goog.typeOf(framedVars.array));
  261. assertEquals('string', goog.typeOf(framedVars.string));
  262. assertEquals('number', goog.typeOf(framedVars.number));
  263. assertEquals('null', goog.typeOf(framedVars.nullVar));
  264. assertEquals('undefined', goog.typeOf(framedVars.undefinedVar));
  265. assertEquals('object', goog.typeOf(framedVars.object));
  266. assertEquals('function', goog.typeOf(framedVars.functionVar));
  267. // Opera throws when trying to do cross frame typeof on node lists.
  268. // IE behaves very strange when it comes to DOM nodes on disconnected frames.
  269. }
  270. function testTypeOfFramed2() {
  271. assertEquals('array', goog.typeOf(framedVars2.array));
  272. assertEquals('string', goog.typeOf(framedVars2.string));
  273. assertEquals('number', goog.typeOf(framedVars2.number));
  274. assertEquals('null', goog.typeOf(framedVars2.nullVar));
  275. assertEquals('undefined', goog.typeOf(framedVars2.undefinedVar));
  276. assertEquals('object', goog.typeOf(framedVars2.object));
  277. assertEquals('function', goog.typeOf(framedVars2.functionVar));
  278. // Opera throws when trying to do cross frame typeof on node lists.
  279. // IE behaves very strange when it comes to DOM nodes on disconnected frames.
  280. }
  281. function testIsDef() {
  282. var defined = 'foo';
  283. var nullVar = null;
  284. var notDefined;
  285. assertTrue('defined should be defined', goog.isDef(defined));
  286. assertTrue('null should be defined', goog.isDef(nullVar));
  287. assertFalse('undefined should not be defined', goog.isDef(notDefined));
  288. }
  289. function testIsDefAndNotNull() {
  290. assertTrue('string is defined and non-null', goog.isDefAndNotNull(''));
  291. assertTrue('object is defined and non-null', goog.isDefAndNotNull({}));
  292. assertTrue(
  293. 'function is defined and non-null',
  294. goog.isDefAndNotNull(goog.nullFunction));
  295. assertTrue('zero is defined and non-null', goog.isDefAndNotNull(0));
  296. assertFalse('null', goog.isDefAndNotNull(null));
  297. assertFalse('undefined', goog.isDefAndNotNull(undefined));
  298. }
  299. function testIsNull() {
  300. var notNull = 'foo';
  301. var nullVar = null;
  302. var notDefined;
  303. assertFalse('defined should not be null', goog.isNull(notNull));
  304. assertTrue('null should be null', goog.isNull(nullVar));
  305. assertFalse('undefined should not be null', goog.isNull(notDefined));
  306. }
  307. function testIsArray() {
  308. var array = [1, 2, 3];
  309. var arrayWithLengthSet = [1, 2, 3];
  310. arrayWithLengthSet.length = 2;
  311. var objWithArrayFunctions = {slice: function() {}, length: 0};
  312. var object = {a: 1, b: 2, c: 3};
  313. var nullVar = null;
  314. var notDefined;
  315. var elem = document.getElementById('elem');
  316. var text = document.getElementById('text').firstChild;
  317. var impostor = document.body.getElementsByTagName('BOGUS');
  318. impostor.push = Array.prototype.push;
  319. impostor.pop = Array.prototype.pop;
  320. impostor.slice = Array.prototype.slice;
  321. impostor.splice = Array.prototype.splice;
  322. assertTrue('array should be an array', goog.isArray(array));
  323. assertTrue(
  324. 'arrayWithLengthSet should be an array',
  325. goog.isArray(arrayWithLengthSet));
  326. assertFalse(
  327. 'object with array functions should not be an array unless ' +
  328. 'length is not enumerable',
  329. goog.isArray(objWithArrayFunctions));
  330. assertFalse('object should not be an array', goog.isArray(object));
  331. assertFalse('null should not be an array', goog.isArray(nullVar));
  332. assertFalse('undefined should not be an array', goog.isArray(notDefined));
  333. assertFalse('NodeList should not be an array', goog.isArray(elem.childNodes));
  334. assertFalse('TextNode should not be an array', goog.isArray(text));
  335. assertTrue(
  336. 'Array of nodes should be an array',
  337. goog.isArray([elem.firstChild, elem.lastChild]));
  338. assertFalse('An impostor should not be an array', goog.isArray(impostor));
  339. }
  340. function testTypeOfAcrossWindow() {
  341. if (goog.userAgent.IE && goog.userAgent.isVersionOrHigher('10') &&
  342. !goog.userAgent.isVersionOrHigher('11')) {
  343. // TODO(johnlenz): This test is flaky on IE10 (passing 90+% of the time).
  344. // When it flakes the values are undefined which appears to indicate the
  345. // script did not run in the opened window and not a failure of the logic
  346. // we are trying to test.
  347. return;
  348. }
  349. var w = window.open('', 'blank');
  350. if (w) {
  351. try {
  352. var d = w.document;
  353. d.open();
  354. d.write(
  355. '<script>function fun(){};' +
  356. 'var arr = [];' +
  357. 'var x = 42;' +
  358. 'var s = "";' +
  359. 'var b = true;' +
  360. 'var obj = {length: 0, splice: {}, call: {}};' +
  361. '</' +
  362. 'script>');
  363. d.close();
  364. assertEquals('function', goog.typeOf(w.fun));
  365. assertEquals('array', goog.typeOf(w.arr));
  366. assertEquals('number', goog.typeOf(w.x));
  367. assertEquals('string', goog.typeOf(w.s));
  368. assertEquals('boolean', goog.typeOf(w.b));
  369. assertEquals('object', goog.typeOf(w.obj));
  370. } finally {
  371. w.close();
  372. }
  373. }
  374. }
  375. function testIsArrayLike() {
  376. var array = [1, 2, 3];
  377. var objectWithNumericLength = {length: 2};
  378. var objectWithNonNumericLength = {length: 'a'};
  379. var object = {a: 1, b: 2};
  380. var nullVar = null;
  381. var notDefined;
  382. var elem = document.getElementById('elem');
  383. var text = document.getElementById('text').firstChild;
  384. assertTrue('array should be array-like', goog.isArrayLike(array));
  385. assertTrue(
  386. 'obj w/numeric length should be array-like',
  387. goog.isArrayLike(objectWithNumericLength));
  388. assertFalse(
  389. 'obj w/non-numeric length should not be array-like',
  390. goog.isArrayLike(objectWithNonNumericLength));
  391. assertFalse('object should not be array-like', goog.isArrayLike(object));
  392. assertFalse('null should not be array-like', goog.isArrayLike(nullVar));
  393. assertFalse(
  394. 'undefined should not be array-like', goog.isArrayLike(notDefined));
  395. assertTrue(
  396. 'NodeList should be array-like', goog.isArrayLike(elem.childNodes));
  397. // TODO(attila): Fix isArrayLike to return false for text nodes!
  398. // assertFalse('TextNode should not be array-like', goog.isArrayLike(text));
  399. assertTrue(
  400. 'Array of nodes should be array-like',
  401. goog.isArrayLike([elem.firstChild, elem.lastChild]));
  402. }
  403. /**
  404. * Use mock date in testIsDateLike() rather than a real goog.date.Date to
  405. * minimize dependencies in this unit test.
  406. */
  407. function MockGoogDate() {}
  408. /** @return {number} */
  409. MockGoogDate.prototype.getFullYear = function() {
  410. return 2007;
  411. };
  412. function testIsDateLike() {
  413. var jsDate = new Date();
  414. var googDate = new MockGoogDate();
  415. var string = 'foo';
  416. var number = 1;
  417. var nullVar = null;
  418. var notDefined;
  419. assertTrue('js Date should be date-like', goog.isDateLike(jsDate));
  420. assertTrue('goog Date should be date-like', goog.isDateLike(googDate));
  421. assertFalse('string should not be date-like', goog.isDateLike(string));
  422. assertFalse('number should not be date-like', goog.isDateLike(number));
  423. assertFalse('nullVar should not be date-like', goog.isDateLike(nullVar));
  424. assertFalse('undefined should not be date-like', goog.isDateLike(notDefined));
  425. }
  426. function testIsString() {
  427. var string = 'foo';
  428. var number = 2;
  429. var nullVar = null;
  430. var notDefined;
  431. assertTrue('string should be a string', goog.isString(string));
  432. assertFalse('number should not be a string', goog.isString(number));
  433. assertFalse('null should not be a string', goog.isString(nullVar));
  434. assertFalse('undefined should not be a string', goog.isString(notDefined));
  435. }
  436. function testIsBoolean() {
  437. var b = true;
  438. var s = 'true';
  439. var num = 1;
  440. var nullVar = null;
  441. var notDefined;
  442. assertTrue('boolean should be a boolean', goog.isBoolean(b));
  443. assertFalse('string should not be a boolean', goog.isBoolean(s));
  444. assertFalse('number should not be a boolean', goog.isBoolean(num));
  445. assertFalse('null should not be a boolean', goog.isBoolean(nullVar));
  446. assertFalse('undefined should not be a boolean', goog.isBoolean(notDefined));
  447. }
  448. function testIsNumber() {
  449. var number = 1;
  450. var string = '1';
  451. var nullVar = null;
  452. var notDefined;
  453. assertTrue('number should be a number', goog.isNumber(number));
  454. assertFalse('string should not be a number', goog.isNumber(string));
  455. assertFalse('null should not be a number', goog.isNumber(nullVar));
  456. assertFalse('undefined should not be a number', goog.isNumber(notDefined));
  457. }
  458. function testIsFunction() {
  459. var func = function() {
  460. return 1;
  461. };
  462. var object = {a: 1, b: 2};
  463. var nullVar = null;
  464. var notDefined;
  465. assertTrue('function should be a function', goog.isFunction(func));
  466. assertFalse('object should not be a function', goog.isFunction(object));
  467. assertFalse('null should not be a function', goog.isFunction(nullVar));
  468. assertFalse(
  469. 'undefined should not be a function', goog.isFunction(notDefined));
  470. }
  471. function testIsObject() {
  472. var object = {a: 1, b: 2};
  473. var string = 'b';
  474. var nullVar = null;
  475. var notDefined;
  476. var array = [0, 1, 2];
  477. var fun = function() {};
  478. assertTrue('object should be an object', goog.isObject(object));
  479. assertTrue('array should be an object', goog.isObject(array));
  480. assertTrue('function should be an object', goog.isObject(fun));
  481. assertFalse('string should not be an object', goog.isObject(string));
  482. assertFalse('null should not be an object', goog.isObject(nullVar));
  483. assertFalse('undefined should not be an object', goog.isObject(notDefined));
  484. }
  485. //=== tests for unique ID methods ===
  486. function testGetUid() {
  487. var a = {};
  488. var b = {};
  489. var c = {};
  490. var uid1 = goog.getUid(a);
  491. var uid2 = goog.getUid(b);
  492. var uid3 = goog.getUid(c);
  493. assertNotEquals('Unique IDs must be unique', uid1, uid2);
  494. assertNotEquals('Unique IDs must be unique', uid1, uid3);
  495. assertNotEquals('Unique IDs must be unique', uid2, uid3);
  496. }
  497. function testHasUid() {
  498. var a = {};
  499. assertFalse(goog.hasUid(a));
  500. assertFalse(goog.UID_PROPERTY_ in a);
  501. var uid = goog.getUid(a);
  502. assertTrue(goog.hasUid(a));
  503. assertEquals(uid, goog.getUid(a));
  504. }
  505. function testRemoveUidFromPlainObject() {
  506. var a = {};
  507. var uid = goog.getUid(a);
  508. goog.removeUid(a);
  509. assertNotEquals(
  510. 'An object\'s old and new unique IDs should be different', uid,
  511. goog.getUid(a));
  512. }
  513. function testRemoveUidFromObjectWithoutUid() {
  514. var a = {};
  515. // Removing a unique ID should not fail even if it did not exist
  516. goog.removeUid(a);
  517. }
  518. function testRemoveUidFromNode() {
  519. var node = goog.dom.createElement(goog.dom.TagName.DIV);
  520. var nodeUid = goog.getUid(node);
  521. goog.removeUid(node);
  522. assertNotEquals(
  523. 'A node\'s old and new unique IDs should be different', nodeUid,
  524. goog.getUid(node));
  525. }
  526. function testConstructorUid() {
  527. function BaseClass() {}
  528. function SubClass() {}
  529. goog.inherits(SubClass, BaseClass);
  530. var baseClassUid = goog.getUid(BaseClass);
  531. var subClassUid = goog.getUid(SubClass);
  532. assertTrue(
  533. 'Unique ID of BaseClass must be a number',
  534. typeof baseClassUid == 'number');
  535. assertTrue(
  536. 'Unique ID of SubClass must be a number', typeof subClassUid == 'number');
  537. assertNotEquals(
  538. 'Unique IDs of BaseClass and SubClass must differ', baseClassUid,
  539. subClassUid);
  540. assertNotEquals(
  541. 'Unique IDs of BaseClass and SubClass instances must differ',
  542. goog.getUid(new BaseClass), goog.getUid(new SubClass));
  543. assertEquals(
  544. 'Unique IDs of BaseClass.prototype and SubClass.prototype ' +
  545. 'should differ, but to keep the implementation simple, we do not ' +
  546. 'handle this edge case.',
  547. goog.getUid(BaseClass.prototype), goog.getUid(SubClass.prototype));
  548. }
  549. /**
  550. * Tests against Chrome bug where the re-created element will have the uid
  551. * property set but undefined. See bug 1252508.
  552. */
  553. function testUidNotUndefinedOnReusedElement() {
  554. var div = goog.dom.createElement(goog.dom.TagName.DIV);
  555. document.body.appendChild(div);
  556. div.innerHTML = '<form id="form"></form>';
  557. var span = goog.dom.getElementsByTagName(goog.dom.TagName.FORM, div)[0];
  558. goog.getUid(span);
  559. div.innerHTML = '<form id="form"></form>';
  560. var span2 = goog.dom.getElementsByTagName(goog.dom.TagName.FORM, div)[0];
  561. assertNotUndefined(goog.getUid(span2));
  562. }
  563. function testWindowUid() {
  564. var uid = goog.getUid(window);
  565. assertTrue('window unique id is a number', goog.isNumber(uid));
  566. assertEquals('returns the same id second time', uid, goog.getUid(window));
  567. goog.removeUid(window);
  568. assertNotEquals(
  569. 'generates new id after the old one is removed', goog.getUid(window));
  570. }
  571. //=== tests for clone method ===
  572. function testClonePrimitive() {
  573. assertEquals(
  574. 'cloning a primitive should return an equal primitive', 5,
  575. goog.cloneObject(5));
  576. }
  577. function testCloneObjectThatHasACloneMethod() {
  578. var original = {
  579. name: 'original',
  580. clone: function() {
  581. return {name: 'clone'};
  582. }
  583. };
  584. var clone = goog.cloneObject(original);
  585. assertEquals('original', original.name);
  586. assertEquals('clone', clone.name);
  587. }
  588. function testCloneFlatObject() {
  589. var original = {a: 1, b: 2, c: 3};
  590. var clone = goog.cloneObject(original);
  591. assertNotEquals(original, clone);
  592. assertEquals(1, clone.a);
  593. assertEquals(2, clone.b);
  594. assertEquals(3, clone.c);
  595. }
  596. function testCloneDeepObject() {
  597. var original = {a: 1, b: {c: 2, d: 3}, e: {f: {g: 4, h: 5}}};
  598. var clone = goog.cloneObject(original);
  599. assertNotEquals(original, clone);
  600. assertNotEquals(original.b, clone.b);
  601. assertNotEquals(original.e, clone.e);
  602. assertEquals(1, clone.a);
  603. assertEquals(2, clone.b.c);
  604. assertEquals(3, clone.b.d);
  605. assertEquals(4, clone.e.f.g);
  606. assertEquals(5, clone.e.f.h);
  607. }
  608. function testCloneFunctions() {
  609. var original = {
  610. f: function() {
  611. return 'hi';
  612. }
  613. };
  614. var clone = goog.cloneObject(original);
  615. assertNotEquals(original, clone);
  616. assertEquals('hi', clone.f());
  617. assertEquals(original.f, clone.f);
  618. }
  619. //=== tests for bind() and friends ===
  620. // Function.prototype.bind and Function.prototype.partial are purposefullly
  621. // not defined in open sourced Closure. These functions sniff for their
  622. // presence.
  623. var foo = 'global';
  624. var obj = {foo: 'obj'};
  625. /**
  626. * @param {?} arg1
  627. * @param {?} arg2
  628. * @return {?}
  629. */
  630. function getFoo(arg1, arg2) {
  631. return {foo: this.foo, arg1: arg1, arg2: arg2};
  632. }
  633. function testBindWithoutObj() {
  634. if (Function.prototype.bind) {
  635. assertEquals(foo, getFoo.bind()().foo);
  636. }
  637. }
  638. function testBindWithObj() {
  639. if (Function.prototype.bind) {
  640. assertEquals(obj.foo, getFoo.bind(obj)().foo);
  641. }
  642. }
  643. function testBindWithNullObj() {
  644. if (Function.prototype.bind) {
  645. assertEquals(foo, getFoo.bind()().foo);
  646. }
  647. }
  648. function testBindStaticArgs() {
  649. if (Function.prototype.bind) {
  650. var fooprime = getFoo.bind(obj, 'hot', 'dog');
  651. var res = fooprime();
  652. assertEquals(obj.foo, res.foo);
  653. assertEquals('hot', res.arg1);
  654. assertEquals('dog', res.arg2);
  655. }
  656. }
  657. function testBindDynArgs() {
  658. if (Function.prototype.bind) {
  659. var res = getFoo.bind(obj)('hot', 'dog');
  660. assertEquals(obj.foo, res.foo);
  661. assertEquals('hot', res.arg1);
  662. assertEquals('dog', res.arg2);
  663. }
  664. }
  665. function testBindCurriedArgs() {
  666. if (Function.prototype.bind) {
  667. var res = getFoo.bind(obj, 'hot')('dog');
  668. assertEquals(obj.foo, res.foo);
  669. assertEquals('hot', res.arg1);
  670. assertEquals('dog', res.arg2);
  671. }
  672. }
  673. function testBindDoubleBind() {
  674. var getFooP = goog.bind(getFoo, obj, 'hot');
  675. var getFooP2 = goog.bind(getFooP, null, 'dog');
  676. var res = getFooP2();
  677. assertEquals('res.arg1 should be \'hot\'', 'hot', res.arg1);
  678. assertEquals('res.arg2 should be \'dog\'', 'dog', res.arg2);
  679. }
  680. function testBindWithCall() {
  681. var obj = {};
  682. var obj2 = {};
  683. var f = function() {
  684. assertEquals('this should be bound to obj', obj, this);
  685. };
  686. var b = goog.bind(f, obj);
  687. b.call(null);
  688. b.call(obj2);
  689. }
  690. function testBindJs() {
  691. assertEquals(1, goog.bindJs_(add, {
  692. valueOf: function() {
  693. return 1;
  694. }
  695. })());
  696. assertEquals(3, goog.bindJs_(add, null, 1, 2)());
  697. }
  698. function testBindNative() {
  699. if (Function.prototype.bind &&
  700. Function.prototype.bind.toString().indexOf('native code') != -1) {
  701. assertEquals(1, goog.bindNative_(add, {
  702. valueOf: function() {
  703. return 1;
  704. }
  705. })());
  706. assertEquals(3, goog.bindNative_(add, null, 1, 2)());
  707. assertThrows(function() {
  708. goog.bindNative_(null, null);
  709. });
  710. }
  711. }
  712. function testBindDefault() {
  713. assertEquals(1, goog.bind(add, {
  714. valueOf: function() {
  715. return 1;
  716. }
  717. })());
  718. assertEquals(3, goog.bind(add, null, 1, 2)());
  719. }
  720. /**
  721. * @param {...?} var_args
  722. * @return {?}
  723. */
  724. function add(var_args) {
  725. var sum = Number(this) || 0;
  726. for (var i = 0; i < arguments.length; i++) {
  727. sum += arguments[i];
  728. }
  729. return sum;
  730. }
  731. function testPartial() {
  732. var f = function(x, y) {
  733. return x + y;
  734. };
  735. var g = goog.partial(f, 1);
  736. assertEquals(3, g(2));
  737. var h = goog.partial(f, 1, 2);
  738. assertEquals(3, h());
  739. var i = goog.partial(f);
  740. assertEquals(3, i(1, 2));
  741. }
  742. function testPartialUsesGlobal() {
  743. var f = function(x, y) {
  744. assertEquals(goog.global, this);
  745. return x + y;
  746. };
  747. var g = goog.partial(f, 1);
  748. var h = goog.partial(g, 2);
  749. assertEquals(3, h());
  750. }
  751. function testPartialWithCall() {
  752. var obj = {};
  753. var f = function(x, y) {
  754. assertEquals(obj, this);
  755. return x + y;
  756. };
  757. var g = goog.partial(f, 1);
  758. var h = goog.partial(g, 2);
  759. assertEquals(3, h.call(obj));
  760. }
  761. function testPartialAndBind() {
  762. // This ensures that this "survives" through a partial.
  763. var p = goog.partial(getFoo, 'hot');
  764. var b = goog.bind(p, obj, 'dog');
  765. var res = b();
  766. assertEquals(obj.foo, res.foo);
  767. assertEquals('hot', res.arg1);
  768. assertEquals('dog', res.arg2);
  769. }
  770. function testBindAndPartial() {
  771. // This ensures that this "survives" through a partial.
  772. var b = goog.bind(getFoo, obj, 'hot');
  773. var p = goog.partial(b, 'dog');
  774. var res = p();
  775. assertEquals(obj.foo, res.foo);
  776. assertEquals('hot', res.arg1);
  777. assertEquals('dog', res.arg2);
  778. }
  779. function testPartialMultipleCalls() {
  780. var f = goog.testing.recordFunction();
  781. var a = goog.partial(f, 'foo');
  782. var b = goog.partial(a, 'bar');
  783. a();
  784. a();
  785. b();
  786. b();
  787. assertEquals(4, f.getCallCount());
  788. var calls = f.getCalls();
  789. assertArrayEquals(['foo'], calls[0].getArguments());
  790. assertArrayEquals(['foo'], calls[1].getArguments());
  791. assertArrayEquals(['foo', 'bar'], calls[2].getArguments());
  792. assertArrayEquals(['foo', 'bar'], calls[3].getArguments());
  793. }
  794. function testGlobalEval() {
  795. goog.globalEval('var foofoofoo = 125;');
  796. assertEquals('Var should be globally assigned', 125, goog.global.foofoofoo);
  797. var foofoofoo = 128;
  798. assertEquals('Global should not have changed', 125, goog.global.foofoofoo);
  799. // NOTE(user): foofoofoo would normally be available in the function scope,
  800. // via the scope chain, but the JsUnit framework seems to do something weird
  801. // which makes it not work.
  802. }
  803. function testGlobalEvalWithHtml() {
  804. // Make sure we don't trip on HTML markup in the code
  805. goog.global.evalTestResult = 'failed';
  806. goog.global.evalTest = function(arg) {
  807. goog.global.evalTestResult = arg;
  808. };
  809. goog.globalEval('evalTest("<test>")');
  810. assertEquals(
  811. 'Should be able to evaluate strings with HTML in', '<test>',
  812. goog.global.evalTestResult);
  813. }
  814. //=== tests for inherits ===
  815. function testInherits() {
  816. function Foo() {}
  817. function Bar() {}
  818. goog.inherits(Bar, Foo);
  819. var bar = new Bar();
  820. assert('object should be instance of constructor', bar instanceof Bar);
  821. assert('object should be instance of base constructor', bar instanceof Foo);
  822. }
  823. function testInherits_constructor() {
  824. function Foo() {}
  825. function Bar() {}
  826. goog.inherits(Bar, Foo);
  827. var bar = new Bar();
  828. assertEquals(
  829. 'constructor property should match constructor function', Bar,
  830. bar.constructor);
  831. assertEquals(
  832. 'Superclass constructor should match constructor function', Foo,
  833. Bar.superClass_.constructor);
  834. }
  835. //=== tests for makeSingleton ===
  836. function testMakeSingleton() {
  837. function Foo() {}
  838. goog.addSingletonGetter(Foo);
  839. assertNotNull('Should add get instance function', Foo.getInstance);
  840. var x = Foo.getInstance();
  841. assertNotNull('Should successfully create an object', x);
  842. var y = Foo.getInstance();
  843. assertEquals('Should return the same object', x, y);
  844. delete Foo.instance_;
  845. var z = Foo.getInstance();
  846. assertNotNull('Should work after clearing for testing', z);
  847. assertNotEquals(
  848. 'Should return a different object after clearing for testing', x, z);
  849. }
  850. //=== tests for now ===
  851. function testNow() {
  852. var toleranceMilliseconds = 20; // 10 ms was not enough for IE7.
  853. var now1 = new Date().getTime();
  854. var now2 = goog.now();
  855. assertTrue(Math.abs(now1 - now2) < toleranceMilliseconds);
  856. }
  857. //=== test non-html context ===
  858. function testInHtmlDocument() {
  859. var savedGoogGlobal = goog.global;
  860. try {
  861. goog.global = {};
  862. assertFalse(goog.inHtmlDocument_());
  863. goog.global.document = {};
  864. assertFalse(goog.inHtmlDocument_());
  865. goog.global.document.write = function() {};
  866. assertTrue(goog.inHtmlDocument_());
  867. } finally {
  868. // Restore context to respect other tests.
  869. goog.global = savedGoogGlobal;
  870. }
  871. }
  872. function testLoadInNonHtmlNotThrows() {
  873. var savedGoogGlobal = goog.global;
  874. try {
  875. goog.global = {};
  876. goog.global.document = {};
  877. assertFalse(goog.inHtmlDocument_());
  878. // The goog code which is executed at load.
  879. goog.findBasePath_();
  880. goog.writeScriptTag_(goog.basePath + 'deps.js');
  881. } finally {
  882. // Restore context to respect other tests.
  883. goog.global = savedGoogGlobal;
  884. }
  885. }
  886. function testLoadBaseWithQueryParamOk() {
  887. var savedGoogGlobal = goog.global;
  888. try {
  889. goog.global = {};
  890. goog.global.document = {
  891. write: goog.nullFunction,
  892. getElementsByTagName:
  893. goog.functions.constant([{src: '/path/to/base.js?zx=5'}])
  894. };
  895. assertTrue(goog.inHtmlDocument_());
  896. goog.findBasePath_();
  897. assertEquals('/path/to/', goog.basePath);
  898. } finally {
  899. // Restore context to respect other tests.
  900. goog.global = savedGoogGlobal;
  901. }
  902. }
  903. function testLoadBaseFromGlobalVariableOk() {
  904. var savedGoogGlobal = goog.global;
  905. try {
  906. goog.global = {};
  907. goog.global.document = {
  908. write: goog.nullFunction,
  909. getElementsByTagName:
  910. goog.functions.constant([{src: '/path/to/base.js?zx=5'}])
  911. };
  912. goog.global.CLOSURE_BASE_PATH = '/from/constant/';
  913. goog.findBasePath_();
  914. assertEquals(goog.global.CLOSURE_BASE_PATH, goog.basePath);
  915. } finally {
  916. // Restore context to respect other tests.
  917. goog.global = savedGoogGlobal;
  918. }
  919. }
  920. function testLoadBaseFromGlobalVariableDOMClobbered() {
  921. var savedGoogGlobal = goog.global;
  922. try {
  923. goog.global = {};
  924. goog.global.document = {
  925. write: goog.nullFunction,
  926. getElementsByTagName:
  927. goog.functions.constant([{src: '/path/to/base.js?zx=5'}])
  928. };
  929. // Make goog.global.CLOSURE_BASE_PATH an object with a toString, like
  930. // it would be if it were a DOM clobbered HTMLElement.
  931. goog.global.CLOSURE_BASE_PATH = {};
  932. goog.global.CLOSURE_BASE_PATH.toString = function() {
  933. return '/from/constant/';
  934. };
  935. goog.findBasePath_();
  936. assertEquals('/path/to/', goog.basePath);
  937. } finally {
  938. // Restore context to respect other tests.
  939. goog.global = savedGoogGlobal;
  940. }
  941. }
  942. function testLoadBaseFromCurrentScriptIgnoringOthers() {
  943. var savedGoogGlobal = goog.global;
  944. try {
  945. goog.global = {};
  946. goog.global.document = {
  947. write: goog.nullFunction,
  948. currentScript: {src: '/currentScript/base.js?zx=5'},
  949. getElementsByTagName:
  950. goog.functions.constant([{src: '/path/to/base.js?zx=5'}])
  951. };
  952. goog.findBasePath_();
  953. assertEquals('/currentScript/', goog.basePath);
  954. } finally {
  955. // Restore context to respect other tests.
  956. goog.global = savedGoogGlobal;
  957. }
  958. }
  959. //=== tests for getmsg ===
  960. function testGetMsgWithDollarSigns() {
  961. var msg = goog.getMsg('{$amount} per minute', {amount: '$0.15'});
  962. assertEquals('$0.15 per minute', msg);
  963. msg = goog.getMsg('{$amount} per minute', {amount: '$0.$1$5'});
  964. assertEquals('$0.$1$5 per minute', msg);
  965. msg = goog.getMsg('This is a {$rate} sale!', {rate: '$$$$$$$$$$10'});
  966. assertEquals('This is a $$$$$$$$$$10 sale!', msg);
  967. msg = goog.getMsg(
  968. '{$name}! Hamburgers: {$hCost}, Hotdogs: {$dCost}.',
  969. {name: 'Burger Bob', hCost: '$0.50', dCost: '$100'});
  970. assertEquals('Burger Bob! Hamburgers: $0.50, Hotdogs: $100.', msg);
  971. }
  972. function testGetMsgWithPlaceholders() {
  973. var msg = goog.getMsg('{$a} has {$b}', {a: '{$b}', b: 1});
  974. assertEquals('{$b} has 1', msg);
  975. msg = goog.getMsg('{$a}{$b}', {b: ''});
  976. assertEquals('{$a}', msg);
  977. }
  978. //=== miscellaneous tests ===
  979. function testGetObjectByName() {
  980. var m = {
  981. 'undefined': undefined,
  982. 'null': null,
  983. emptyString: '',
  984. 'false': false,
  985. 'true': true,
  986. zero: 0,
  987. one: 1,
  988. two: {three: 3, four: {five: 5}},
  989. 'six|seven': '6|7',
  990. 'eight.nine': 8.9
  991. };
  992. goog.global.m = m;
  993. assertNull(goog.getObjectByName('m.undefined'));
  994. assertNull(goog.getObjectByName('m.null'));
  995. assertEquals(goog.getObjectByName('m.emptyString'), '');
  996. assertEquals(goog.getObjectByName('m.false'), false);
  997. assertEquals(goog.getObjectByName('m.true'), true);
  998. assertEquals(goog.getObjectByName('m.zero'), 0);
  999. assertEquals(goog.getObjectByName('m.one'), 1);
  1000. assertEquals(goog.getObjectByName('m.two.three'), 3);
  1001. assertEquals(goog.getObjectByName('m.two.four.five'), 5);
  1002. assertEquals(goog.getObjectByName('m.six|seven'), '6|7');
  1003. assertNull(goog.getObjectByName('m.eight.nine'));
  1004. assertNull(goog.getObjectByName('m.notThere'));
  1005. assertEquals(goog.getObjectByName('one', m), 1);
  1006. assertEquals(goog.getObjectByName('two.three', m), 3);
  1007. assertEquals(goog.getObjectByName('two.four.five', m), 5);
  1008. assertEquals(goog.getObjectByName('six|seven', m), '6|7');
  1009. assertNull(goog.getObjectByName('eight.nine', m));
  1010. assertNull(goog.getObjectByName('notThere', m));
  1011. }
  1012. function testGetCssName() {
  1013. assertEquals('classname', goog.getCssName('classname'));
  1014. assertEquals('random-classname', goog.getCssName('random-classname'));
  1015. assertEquals('control-modifier', goog.getCssName('control', 'modifier'));
  1016. goog.setCssNameMapping({'goog': 'a', 'disabled': 'b'}, 'BY_PART');
  1017. var g = goog.getCssName('goog');
  1018. assertEquals('a', g);
  1019. assertEquals('a-b', goog.getCssName(g, 'disabled'));
  1020. assertEquals('a-b', goog.getCssName('goog-disabled'));
  1021. assertEquals('a-button', goog.getCssName('goog-button'));
  1022. goog.setCssNameMapping({'goog-button': 'a', 'active': 'b'}, 'BY_WHOLE');
  1023. g = goog.getCssName('goog-button');
  1024. assertEquals('a', g);
  1025. assertEquals('a-b', goog.getCssName(g, 'active'));
  1026. assertEquals('goog-disabled', goog.getCssName('goog-disabled'));
  1027. e = assertThrows(function() {
  1028. goog.getCssName('.name');
  1029. });
  1030. assertEquals(
  1031. 'className passed in goog.getCssName must not start with ".".' +
  1032. ' You passed: .name',
  1033. e.message);
  1034. assertNull(goog.getCssName(null));
  1035. }
  1036. function testGetCssName_nameMapFn() {
  1037. assertEquals('classname', goog.getCssName('classname'));
  1038. goog.global.CLOSURE_CSS_NAME_MAP_FN = function(classname) {
  1039. return classname + '!';
  1040. };
  1041. assertEquals('classname!', goog.getCssName('classname'));
  1042. }
  1043. function testAddDependency() {
  1044. stubs.set(goog, 'writeScriptTag_', goog.nullFunction);
  1045. goog.addDependency('foo.js', ['testDep.foo'], ['testDep.bar']);
  1046. // alias to avoid the being picked up by the deps scanner.
  1047. var provide = goog.provide;
  1048. provide('testDep.bar');
  1049. // To differentiate this call from the real one.
  1050. var require = goog.require;
  1051. // this used to throw an exception
  1052. require('testDep.foo');
  1053. assertTrue(goog.isObject(testDep.bar));
  1054. // Unset provided namespace so the test can be re-run.
  1055. testDep = undefined;
  1056. }
  1057. function testAddDependencyModule() {
  1058. var load = goog.testing.recordFunction();
  1059. stubs.set(goog, 'writeScriptTag_', load);
  1060. goog.addDependency('mod.js', ['testDep.mod'], [], true);
  1061. goog.addDependency('empty.js', ['testDep.empty'], [], {});
  1062. goog.addDependency('mod-goog.js', ['testDep.goog'], [], {'module': 'goog'});
  1063. // To differentiate this call from the real one.
  1064. var require = goog.require;
  1065. var assertModuleLoad = function(module, args) {
  1066. assertEquals(2, args.length);
  1067. assertEquals('', args[0]);
  1068. assertRegExp(
  1069. '^goog\\.retrieveAndExec_\\(".*/' + module + '", true, false\\);$',
  1070. args[1]);
  1071. };
  1072. require('testDep.mod');
  1073. assertEquals(1, load.getCallCount());
  1074. assertModuleLoad('mod.js', load.getCalls()[0].getArguments());
  1075. require('testDep.empty');
  1076. assertEquals(2, load.getCallCount());
  1077. assertEquals(2, load.getCalls()[1].getArguments().length);
  1078. assertRegExp('^.*/empty.js$', load.getCalls()[1].getArguments()[0]);
  1079. assertUndefined(load.getCalls()[1].getArguments()[1]);
  1080. require('testDep.goog');
  1081. assertEquals(3, load.getCallCount());
  1082. assertModuleLoad('mod-goog.js', load.getCalls()[2].getArguments());
  1083. // Unset provided namespace so the test can be re-run.
  1084. testDep = undefined;
  1085. }
  1086. function testAddDependencyEs6() {
  1087. var script = null;
  1088. var requireTranspilation = false;
  1089. stubs.set(goog, 'needsTranspile_', function() {
  1090. return requireTranspilation;
  1091. });
  1092. stubs.set(goog, 'writeScriptTag_', function(src, scriptText) {
  1093. if (script != null) {
  1094. throw new Error('Multiple scripts written');
  1095. }
  1096. script = scriptText;
  1097. });
  1098. goog.addDependency(
  1099. 'fancy.js', ['testDep.fancy'], [],
  1100. {'lang': 'es6-impl', 'module': 'goog'});
  1101. goog.addDependency('super.js', ['testDep.superFancy'], [], {'lang': 'es6'});
  1102. // To differentiate this call from the real one.
  1103. var require = goog.require;
  1104. requireTranspilation = false;
  1105. require('testDep.fancy');
  1106. assertRegExp(
  1107. /^goog\.retrieveAndExec_\(".*\/fancy\.js", true, false\);$/, script);
  1108. script = null;
  1109. requireTranspilation = true;
  1110. require('testDep.superFancy');
  1111. assertRegExp(
  1112. /^goog\.retrieveAndExec_\(".*\/super\.js", false, true\);$/, script);
  1113. // Unset provided namespace so the test can be re-run.
  1114. testDep = undefined;
  1115. }
  1116. function testBaseMethod() {
  1117. function A() {}
  1118. A.prototype.foo = function(x, y) {
  1119. return x + y;
  1120. };
  1121. function B() {}
  1122. goog.inherits(B, A);
  1123. B.prototype.foo = function(x, y) {
  1124. return 2 + goog.base(this, 'foo', x, y);
  1125. };
  1126. function C() {}
  1127. goog.inherits(C, B);
  1128. C.prototype.foo = function(x, y) {
  1129. return 4 + goog.base(this, 'foo', x, y);
  1130. };
  1131. var d = new C();
  1132. d.foo = function(x, y) {
  1133. return 8 + goog.base(this, 'foo', x, y);
  1134. };
  1135. assertEquals(15, d.foo(1, 0));
  1136. assertEquals(16, d.foo(1, 1));
  1137. assertEquals(16, d.foo(2, 0));
  1138. assertEquals(7, (new C()).foo(1, 0));
  1139. assertEquals(3, (new B()).foo(1, 0));
  1140. assertThrows(function() {
  1141. goog.base(d, 'foo', 1, 0);
  1142. });
  1143. delete B.prototype.foo;
  1144. assertEquals(13, d.foo(1, 0));
  1145. delete C.prototype.foo;
  1146. assertEquals(9, d.foo(1, 0));
  1147. }
  1148. function testBaseMethodAndBaseCtor() {
  1149. // This will fail on FF4.0 if the following bug is not fixed:
  1150. // https://bugzilla.mozilla.org/show_bug.cgi?id=586482
  1151. function A(x, y) {
  1152. this.foo(x, y);
  1153. }
  1154. A.prototype.foo = function(x, y) {
  1155. this.bar = x + y;
  1156. };
  1157. function B(x, y) {
  1158. goog.base(this, x, y);
  1159. }
  1160. goog.inherits(B, A);
  1161. B.prototype.foo = function(x, y) {
  1162. goog.base(this, 'foo', x, y);
  1163. this.bar = this.bar * 2;
  1164. };
  1165. assertEquals(14, new B(3, 4).bar);
  1166. }
  1167. function testBaseClass() {
  1168. function A(x, y) {
  1169. this.foo = x + y;
  1170. }
  1171. function B(x, y) {
  1172. goog.base(this, x, y);
  1173. this.foo += 2;
  1174. }
  1175. goog.inherits(B, A);
  1176. function C(x, y) {
  1177. goog.base(this, x, y);
  1178. this.foo += 4;
  1179. }
  1180. goog.inherits(C, B);
  1181. function D(x, y) {
  1182. goog.base(this, x, y);
  1183. this.foo += 8;
  1184. }
  1185. goog.inherits(D, C);
  1186. assertEquals(15, (new D(1, 0)).foo);
  1187. assertEquals(16, (new D(1, 1)).foo);
  1188. assertEquals(16, (new D(2, 0)).foo);
  1189. assertEquals(7, (new C(1, 0)).foo);
  1190. assertEquals(3, (new B(1, 0)).foo);
  1191. }
  1192. function testClassBaseOnMethod() {
  1193. function A() {}
  1194. A.prototype.foo = function(x, y) {
  1195. return x + y;
  1196. };
  1197. function B() {}
  1198. goog.inherits(B, A);
  1199. B.prototype.foo = function(x, y) {
  1200. return 2 + B.base(this, 'foo', x, y);
  1201. };
  1202. function C() {}
  1203. goog.inherits(C, B);
  1204. C.prototype.foo = function(x, y) {
  1205. return 4 + C.base(this, 'foo', x, y);
  1206. };
  1207. var d = new C();
  1208. assertEquals(7, d.foo(1, 0));
  1209. assertEquals(8, d.foo(1, 1));
  1210. assertEquals(8, d.foo(2, 0));
  1211. assertEquals(3, (new B()).foo(1, 0));
  1212. delete B.prototype.foo;
  1213. assertEquals(5, d.foo(1, 0));
  1214. delete C.prototype.foo;
  1215. assertEquals(1, d.foo(1, 0));
  1216. }
  1217. function testClassBaseOnConstructor() {
  1218. function A(x, y) {
  1219. this.foo = x + y;
  1220. }
  1221. function B(x, y) {
  1222. B.base(this, 'constructor', x, y);
  1223. this.foo += 2;
  1224. }
  1225. goog.inherits(B, A);
  1226. function C(x, y) {
  1227. C.base(this, 'constructor', x, y);
  1228. this.foo += 4;
  1229. }
  1230. goog.inherits(C, B);
  1231. function D(x, y) {
  1232. D.base(this, 'constructor', x, y);
  1233. this.foo += 8;
  1234. }
  1235. goog.inherits(D, C);
  1236. assertEquals(15, (new D(1, 0)).foo);
  1237. assertEquals(16, (new D(1, 1)).foo);
  1238. assertEquals(16, (new D(2, 0)).foo);
  1239. assertEquals(7, (new C(1, 0)).foo);
  1240. assertEquals(3, (new B(1, 0)).foo);
  1241. }
  1242. function testClassBaseOnMethodAndBaseCtor() {
  1243. function A(x, y) {
  1244. this.foo(x, y);
  1245. }
  1246. A.prototype.foo = function(x, y) {
  1247. this.bar = x + y;
  1248. };
  1249. function B(x, y) {
  1250. B.base(this, 'constructor', x, y);
  1251. }
  1252. goog.inherits(B, A);
  1253. B.prototype.foo = function(x, y) {
  1254. B.base(this, 'foo', x, y);
  1255. this.bar = this.bar * 2;
  1256. };
  1257. assertEquals(14, new B(3, 4).bar);
  1258. }
  1259. function testGoogRequireCheck() {
  1260. // alias to avoid the being picked up by the deps scanner.
  1261. var provide = goog.provide;
  1262. stubs.set(goog, 'ENABLE_DEBUG_LOADER', true);
  1263. stubs.set(goog, 'useStrictRequires', true);
  1264. stubs.set(goog, 'implicitNamespaces_', {});
  1265. // Aliased so that build tools do not mistake this for an actual call.
  1266. var require = goog.require;
  1267. assertThrows('Requiring non-required namespace should fail', function() {
  1268. require('far.outnotprovided');
  1269. });
  1270. assertUndefined(goog.global.far);
  1271. assertEvaluatesToFalse(goog.getObjectByName('far.out'));
  1272. assertObjectEquals({}, goog.implicitNamespaces_);
  1273. assertFalse(goog.isProvided_('far.out'));
  1274. provide('far.out');
  1275. assertNotUndefined(far.out);
  1276. assertEvaluatesToTrue(goog.getObjectByName('far.out'));
  1277. assertObjectEquals({'far': true}, goog.implicitNamespaces_);
  1278. assertTrue(goog.isProvided_('far.out'));
  1279. goog.global.far.out = 42;
  1280. assertEquals(42, goog.getObjectByName('far.out'));
  1281. assertTrue(goog.isProvided_('far.out'));
  1282. // Empty string should be allowed.
  1283. goog.global.far.out = '';
  1284. assertEquals('', goog.getObjectByName('far.out'));
  1285. assertTrue(goog.isProvided_('far.out'));
  1286. // Null or undefined are not allowed.
  1287. goog.global.far.out = null;
  1288. assertNull(goog.getObjectByName('far.out'));
  1289. assertFalse(goog.isProvided_('far.out'));
  1290. goog.global.far.out = undefined;
  1291. assertNull(goog.getObjectByName('far.out'));
  1292. assertFalse(goog.isProvided_('far.out'));
  1293. stubs.reset();
  1294. delete far;
  1295. }
  1296. /**
  1297. * @return {?}
  1298. */
  1299. function diables_testCspSafeGoogRequire() {
  1300. if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10')) {
  1301. return;
  1302. }
  1303. stubs.set(goog, 'ENABLE_CHROME_APP_SAFE_SCRIPT_LOADING', true);
  1304. // Aliased so that build tools do not mistake this for an actual call.
  1305. var require = goog.require;
  1306. require('goog.Uri');
  1307. // Set a timeout to allow the user agent to finish parsing this script block,
  1308. // thus allowing the appended script (via goog.require) to execute.
  1309. var ASYNC_TIMEOUT_MS = 1000;
  1310. var resolver = goog.Promise.withResolver();
  1311. window.setTimeout(function() {
  1312. assertNotUndefined(goog.Uri);
  1313. resolver.resolve();
  1314. stubs.reset();
  1315. }, ASYNC_TIMEOUT_MS);
  1316. return resolver.promise;
  1317. }
  1318. function testLateRequireProtection() {
  1319. if (!document.readyState) return;
  1320. var e = assertThrows(function() {
  1321. // To differentiate this call from the real one.
  1322. var require = goog.require;
  1323. require('goog.ui.Component');
  1324. });
  1325. assertContains('after document load', e.message);
  1326. }
  1327. function testDefineClass() {
  1328. var Base = goog.defineClass(null, {
  1329. constructor: function(foo) {
  1330. this.foo = foo;
  1331. },
  1332. statics: {x: 42},
  1333. frobnicate: function() {
  1334. return this.foo + this.foo;
  1335. }
  1336. });
  1337. var Derived = goog.defineClass(Base, {
  1338. constructor: function() {
  1339. Derived.base(this, 'constructor', 'bar');
  1340. },
  1341. frozzle: function(foo) {
  1342. this.foo = foo;
  1343. }
  1344. });
  1345. assertEquals(42, Base.x);
  1346. var der = new Derived();
  1347. assertEquals('barbar', der.frobnicate());
  1348. der.frozzle('qux');
  1349. assertEquals('quxqux', der.frobnicate());
  1350. }
  1351. function testDefineClass_interface() {
  1352. /** @interface */
  1353. var Interface =
  1354. goog.defineClass(null, {statics: {foo: 'bar'}, qux: function() {}});
  1355. assertEquals('bar', Interface.foo);
  1356. assertThrows(function() {
  1357. new Interface();
  1358. });
  1359. }
  1360. function testDefineClass_seals() {
  1361. if (!(Object.seal instanceof Function)) return; // IE<9 doesn't have seal
  1362. var A = goog.defineClass(null, {constructor: function() {}});
  1363. var a = new A();
  1364. try {
  1365. a.foo = 'bar';
  1366. } catch (expectedInStrictModeOnly) { /* ignored */
  1367. }
  1368. assertEquals(undefined, a.foo);
  1369. }
  1370. function testDefineClass_unsealable() {
  1371. var LegacyBase = function() {};
  1372. LegacyBase.prototype.foo = null;
  1373. LegacyBase.prototype.setFoo = function(foo) {
  1374. this.foo = foo;
  1375. };
  1376. goog.tagUnsealableClass(LegacyBase);
  1377. var Derived = goog.defineClass(LegacyBase, {constructor: function() {}});
  1378. var der = new Derived();
  1379. der.setFoo('bar');
  1380. assertEquals('bar', der.foo);
  1381. }
  1382. function testDefineClass_constructorIsNotWrappedWhenSealingIsDisabled() {
  1383. var org = goog.defineClass;
  1384. var ctr = null;
  1385. var replacement = function(superClass, def) {
  1386. ctr = def.constructor;
  1387. return org(superClass, def);
  1388. };
  1389. // copy all the properties
  1390. goog.object.extend(replacement, org);
  1391. replacement.SEAL_CLASS_INSTANCES = false;
  1392. stubs.replace(goog, 'defineClass', replacement);
  1393. var MyClass = goog.defineClass(null, {constructor: function() {}});
  1394. assertEquals('The constructor should not be wrapped.', ctr, MyClass);
  1395. }
  1396. function testDefineClass_unsealableConstructorIsWrapped() {
  1397. var LegacyBase = function() {};
  1398. LegacyBase.prototype.foo = null;
  1399. LegacyBase.prototype.setFoo = function(foo) {
  1400. this.foo = foo;
  1401. };
  1402. goog.tagUnsealableClass(LegacyBase);
  1403. var org = goog.defineClass;
  1404. var ctr = null;
  1405. var replacement = function(superClass, def) {
  1406. ctr = def.constructor;
  1407. return org(superClass, def);
  1408. };
  1409. // copy all the properties
  1410. goog.object.extend(replacement, org);
  1411. stubs.replace(goog, 'defineClass', replacement);
  1412. var Derived = goog.defineClass(LegacyBase, {constructor: function() {}});
  1413. assertNotEquals('The constructor should be wrapped.', ctr, Derived);
  1414. }
  1415. // Validate the behavior of goog.module when used from traditional files.
  1416. function testGoogModuleGet() {
  1417. // assert that goog.module doesn't modify the global namespace
  1418. assertUndefined(
  1419. 'module failed to protect global namespace: ' +
  1420. 'goog.test_module_dep',
  1421. goog.test_module_dep);
  1422. // assert that goog.module with goog.module.declareLegacyNamespace is present.
  1423. assertNotUndefined(
  1424. 'module failed to declare global namespace: ' +
  1425. 'goog.test_module',
  1426. goog.test_module);
  1427. // assert that a require'd goog.module is available immediately after the
  1428. // goog.require call.
  1429. assertNotUndefined(
  1430. 'module failed to protect global namespace: ' +
  1431. 'goog.test_module_dep',
  1432. earlyTestModuleGet);
  1433. // assert that an non-existent module request doesn't throw and returns null.
  1434. assertEquals(null, goog.module.get('unrequired.module.id'));
  1435. // Validate the module exports
  1436. var testModuleExports = goog.module.get('goog.test_module');
  1437. assertTrue(goog.isFunction(testModuleExports));
  1438. // Test that any escaping of </script> in test files is correct. Escape the
  1439. // / in </script> here so that any such code does not affect it here.
  1440. assertEquals('<\/script>', testModuleExports.CLOSING_SCRIPT_TAG);
  1441. // Validate that the module exports object has not changed
  1442. assertEquals(earlyTestModuleGet, testModuleExports);
  1443. }
  1444. // Validate the behavior of goog.module when used from traditional files.
  1445. function testGoogLoadModuleByUrl() {
  1446. if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('10')) {
  1447. // IE before 10 don't report an error.
  1448. return;
  1449. }
  1450. stubs.set(goog, 'loadFileSync_', function(src) {
  1451. return 'closure load file sync: ' + src;
  1452. });
  1453. // "goog.loadModuleByUrl" is not a general purpose code loader, it can
  1454. // not be used to late load code.
  1455. var err =
  1456. assertThrows('loadModuleFromUrl should not hide failures', function() {
  1457. goog.loadModuleFromUrl('bogus url');
  1458. });
  1459. assertContains('Cannot write "bogus url" after document load', err.message);
  1460. }
  1461. function testModuleExportSealed() {
  1462. if (goog.userAgent.IE && !goog.userAgent.isVersionOrHigher('9')) {
  1463. // IE before 9 don't support sealing objects
  1464. return;
  1465. }
  1466. goog.loadModule('goog.module("a.b.supplied"); exports.foo = {};');
  1467. var exports0 = goog.module.get('a.b.supplied');
  1468. assertTrue(Object.isSealed(exports0));
  1469. goog.loadModule('goog.module("a.b.object"); exports = {};');
  1470. var exports1 = goog.module.get('a.b.object');
  1471. assertTrue(Object.isSealed(exports1));
  1472. goog.loadModule('goog.module("a.b.fn"); exports = function() {};');
  1473. var exports2 = goog.module.get('a.b.fn');
  1474. assertFalse(Object.isSealed(exports2));
  1475. }
  1476. function testWorkaroundSafari10EvalBug0() {
  1477. // Validate the safari module loading workaround isn't triggered for
  1478. // browsers we know it isn't needed.
  1479. if (goog.userAgent.SAFARI) {
  1480. return;
  1481. }
  1482. assertFalse(goog.useSafari10Workaround());
  1483. }
  1484. function testWorkaroundSafari10EvalBug1() {
  1485. assertEquals(
  1486. '(function(){' + // no \n
  1487. 'goog.module(\'foo\');\n' +
  1488. '\n;})();\n',
  1489. goog.workaroundSafari10EvalBug(
  1490. 'goog.module(\'foo\');\n'));
  1491. }
  1492. function testWorkaroundSafari10EvalBug2() {
  1493. assertEquals(
  1494. '(function(){' + // no \n
  1495. 'goog.module(\'foo\');\n' +
  1496. 'alert("//# sourceMappingURL a.b.c.map")\n' +
  1497. 'alert("//# sourceURL a.b.c.js")\n' +
  1498. '\n;})();\n',
  1499. goog.workaroundSafari10EvalBug(
  1500. 'goog.module(\'foo\');\n' +
  1501. 'alert("//# sourceMappingURL a.b.c.map")\n' +
  1502. 'alert("//# sourceURL a.b.c.js")\n'));
  1503. }
  1504. function testGoogLoadModuleInSafari10() {
  1505. try {
  1506. eval('let es6 = 1');
  1507. } catch (e) {
  1508. // If ES6 block scope syntax isn't supported, don't run the rest of the
  1509. // test.
  1510. return;
  1511. }
  1512. goog.loadModule(
  1513. 'goog.module("a.safari.test");' +
  1514. 'let x = true;' +
  1515. 'function fn() { return x }' +
  1516. 'exports.fn = fn;');
  1517. var exports = goog.module.get('a.safari.test');
  1518. // Safari 10 will throw an exception if the module being loaded is eval'd
  1519. // without a containing function.
  1520. assertNotThrows(exports.fn);
  1521. }
  1522. function testLoadFileSync() {
  1523. var fileContents = goog.loadFileSync_('deps.js');
  1524. assertTrue(
  1525. 'goog.loadFileSync_ returns string', typeof fileContents === 'string');
  1526. assertTrue('goog.loadFileSync_ string length > 0', fileContents.length > 0);
  1527. stubs.set(goog.global, 'CLOSURE_LOAD_FILE_SYNC', function(src) {
  1528. return 'closure load file sync: ' + src;
  1529. });
  1530. assertEquals(
  1531. 'goog.CLOSURE_LOAD_FILE_SYNC override', goog.loadFileSync_('test url'),
  1532. 'closure load file sync: test url');
  1533. }
  1534. function testNormalizePath1() {
  1535. assertEquals('foo/path.js', goog.normalizePath_('./foo/./path.js'));
  1536. assertEquals('foo/path.js', goog.normalizePath_('bar/../foo/path.js'));
  1537. assertEquals('bar/path.js', goog.normalizePath_('bar/foo/../path.js'));
  1538. assertEquals('path.js', goog.normalizePath_('bar/foo/../../path.js'));
  1539. assertEquals('../foo/path.js', goog.normalizePath_('../foo/path.js'));
  1540. assertEquals('../../foo/path.js', goog.normalizePath_('../../foo/path.js'));
  1541. assertEquals('../path.js', goog.normalizePath_('../foo/../path.js'));
  1542. assertEquals('../../path.js', goog.normalizePath_('../foo/../../path.js'));
  1543. assertEquals('/../foo/path.js', goog.normalizePath_('/../foo/path.js'));
  1544. assertEquals('/path.js', goog.normalizePath_('/foo/../path.js'));
  1545. assertEquals('/foo/path.js', goog.normalizePath_('/./foo/path.js'));
  1546. assertEquals('//../foo/path.js', goog.normalizePath_('//../foo/path.js'));
  1547. assertEquals('//path.js', goog.normalizePath_('//foo/../path.js'));
  1548. assertEquals('//foo/path.js', goog.normalizePath_('//./foo/path.js'));
  1549. assertEquals('http://../x/y.js', goog.normalizePath_('http://../x/y.js'));
  1550. assertEquals('http://path.js', goog.normalizePath_('http://foo/../path.js'));
  1551. assertEquals('http://x/path.js', goog.normalizePath_('http://./x/path.js'));
  1552. }
  1553. function testGoogModuleNames() {
  1554. // avoid usage checks
  1555. var module = goog.module;
  1556. function assertInvalidId(id) {
  1557. var err = assertThrows(function() {
  1558. module(id);
  1559. });
  1560. assertEquals('Invalid module identifier', err.message);
  1561. }
  1562. function assertValidId(id) {
  1563. // This is a cheesy check, but we validate that we don't get an invalid
  1564. // namespace warning, but instead get a module isn't loaded correctly
  1565. // error.
  1566. var err = assertThrows(function() {
  1567. module(id);
  1568. });
  1569. assertTrue(err.message.indexOf('has been loaded incorrectly') != -1);
  1570. }
  1571. assertInvalidId('/somepath/module.js');
  1572. assertInvalidId('./module.js');
  1573. assertInvalidId('1');
  1574. assertValidId('a');
  1575. assertValidId('a.b');
  1576. assertValidId('a.b.c');
  1577. assertValidId('aB.Cd.eF');
  1578. assertValidId('a1.0E.Fg');
  1579. assertValidId('_');
  1580. assertValidId('$');
  1581. assertValidId('_$');
  1582. assertValidId('$_');
  1583. }