utils_test.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833
  1. // Copyright 2009 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. goog.provide('goog.uri.utilsTest');
  15. goog.setTestOnly('goog.uri.utilsTest');
  16. goog.require('goog.functions');
  17. goog.require('goog.string');
  18. goog.require('goog.testing.jsunit');
  19. goog.require('goog.uri.utils');
  20. var utils = goog.uri.utils;
  21. function setUpPage() {
  22. goog.string.getRandomString = goog.functions.constant('RANDOM');
  23. }
  24. function tearDown() {}
  25. function testSplit() {
  26. var uri = 'http://www.google.com:80/path%20path+path?q=query&hl=en#fragment';
  27. assertEquals('http', utils.getScheme(uri));
  28. assertNull(utils.getUserInfoEncoded(uri));
  29. assertNull(utils.getUserInfo(uri));
  30. assertEquals('www.google.com', utils.getDomainEncoded(uri));
  31. assertEquals('www.google.com', utils.getDomain(uri));
  32. assertEquals(80, utils.getPort(uri));
  33. assertEquals('/path%20path+path', utils.getPathEncoded(uri));
  34. assertEquals('/path path+path', utils.getPath(uri));
  35. assertEquals('q=query&hl=en', utils.getQueryData(uri));
  36. assertEquals('fragment', utils.getFragmentEncoded(uri));
  37. assertEquals('fragment', utils.getFragment(uri));
  38. assertEquals(
  39. utils.getDomain('http://[2607:f8b0:4006:802::1006]'),
  40. '[2607:f8b0:4006:802::1006]');
  41. assertEquals(
  42. utils.getDomain('http://[2607:f8b0:4006:802::1006]:80'),
  43. '[2607:f8b0:4006:802::1006]');
  44. assertEquals(utils.getPort('http://[2607:f8b0:4006:802::1006]:80'), 80);
  45. assertEquals(utils.getDomain('http://[2607]:80/?q=]'), '[2607]');
  46. assertEquals(utils.getDomain('http://!!!'), '!!!');
  47. assertNull(utils.getPath('http://!!!'));
  48. assertNull(utils.getScheme('www.x.com:80'));
  49. assertEquals(
  50. 'Query data with no fragment identifier', 'foo=bar&baz=bin',
  51. utils.getQueryData('http://google.com?foo=bar&baz=bin'));
  52. }
  53. function testSplitWithNewline() {
  54. var uri = 'http://www.google.com:80/path%20path+path?q=query#frag\nment';
  55. assertEquals('http', utils.getScheme(uri));
  56. assertNull(utils.getUserInfoEncoded(uri));
  57. assertNull(utils.getUserInfo(uri));
  58. assertEquals('www.google.com', utils.getDomainEncoded(uri));
  59. assertEquals('www.google.com', utils.getDomain(uri));
  60. assertEquals(80, utils.getPort(uri));
  61. assertEquals('/path%20path+path', utils.getPathEncoded(uri));
  62. assertEquals('/path path+path', utils.getPath(uri));
  63. assertEquals('q=query', utils.getQueryData(uri));
  64. assertEquals('frag\nment', utils.getFragmentEncoded(uri));
  65. assertEquals('frag\nment', utils.getFragment(uri));
  66. }
  67. function testMailtoUri() {
  68. var uri = 'mailto:joe+random@hominid.com';
  69. assertNull(utils.getDomain(uri));
  70. assertEquals('mailto', utils.getScheme(uri));
  71. assertEquals('joe+random@hominid.com', utils.getPath(uri));
  72. }
  73. function testSplitRelativeUri() {
  74. var uri = '/path%20path+path?q=query&hl=en#fragment';
  75. assertNull(utils.getScheme(uri));
  76. assertNull(utils.getDomain(uri));
  77. assertNull(utils.getDomainEncoded(uri));
  78. assertNull(utils.getPort(uri));
  79. assertEquals('/path%20path+path', utils.getPathEncoded(uri));
  80. assertEquals('/path path+path', utils.getPath(uri));
  81. assertEquals('q=query&hl=en', utils.getQueryData(uri));
  82. assertEquals('fragment', utils.getFragmentEncoded(uri));
  83. assertEquals('fragment', utils.getFragment(uri));
  84. }
  85. function testSplitBadAuthority() {
  86. // This URL has a syntax error per the RFC (port number must be digits, and
  87. // host cannot contain a colon except in [...]). This test is solely to
  88. // 'document' the current behavior, which may affect application handling
  89. // of erroneous URLs.
  90. assertEquals(utils.getDomain('http://host:port/'), 'host:port');
  91. assertNull(utils.getPort('http://host:port/'));
  92. }
  93. function testSplitIntoHostAndPath() {
  94. // Splitting into host and path takes care of one of the major use cases
  95. // of resolve, without implementing a generic algorithm that undoubtedly
  96. // requires a huge footprint.
  97. var uri = 'http://www.google.com:80/path%20path+path?q=query&hl=en#fragment';
  98. assertEquals('http://www.google.com:80', goog.uri.utils.getHost(uri));
  99. assertEquals(
  100. '/path%20path+path?q=query&hl=en#fragment',
  101. goog.uri.utils.getPathAndAfter(uri));
  102. var uri2 = 'http://www.google.com/calendar';
  103. assertEquals(
  104. 'should handle missing fields', 'http://www.google.com',
  105. goog.uri.utils.getHost(uri2));
  106. assertEquals(
  107. 'should handle missing fields', '/calendar',
  108. goog.uri.utils.getPathAndAfter(uri2));
  109. }
  110. function testGetOrigin() {
  111. var uri =
  112. 'http://foo:pw@www.google.com:80/path%20path+path?q=query&hl=en#fragment';
  113. assertEquals('http://www.google.com:80', goog.uri.utils.getOrigin(uri));
  114. }
  115. function testRelativeUrisHaveNoPath() {
  116. assertNull(utils.getPathEncoded('?hello'));
  117. }
  118. function testReservedCharacters() {
  119. var o = '%6F';
  120. var uri = 'http://www.g' + o + 'ogle.com%40/xxx%2feee/ccc';
  121. assertEquals(
  122. 'Should not decode reserved characters in path', '/xxx%2feee/ccc',
  123. goog.uri.utils.getPath(uri));
  124. assertEquals(
  125. 'Should not decode reserved characters in domain', 'www.google.com%40',
  126. goog.uri.utils.getDomain(uri));
  127. }
  128. function testSetFragmentEncoded() {
  129. var expected = 'http://www.google.com/path#bar';
  130. assertEquals(
  131. expected,
  132. utils.setFragmentEncoded('http://www.google.com/path#foo', 'bar'));
  133. assertEquals(
  134. expected, utils.setFragmentEncoded('http://www.google.com/path', 'bar'));
  135. assertEquals(
  136. 'http://www.google.com/path',
  137. utils.setFragmentEncoded('http://www.google.com/path', ''));
  138. assertEquals(
  139. 'http://www.google.com/path',
  140. utils.setFragmentEncoded('http://www.google.com/path', null));
  141. }
  142. function testGetParamValue() {
  143. assertEquals(
  144. 'v1',
  145. utils.getParamValue('/path?key=v1&c=d&keywithsuffix=v3&key=v2', 'key'));
  146. assertEquals(
  147. 'v1',
  148. utils.getParamValue('/path?kEY=v1&c=d&keywithsuffix=v3&key=v2', 'kEY'));
  149. }
  150. function testGetParamValues() {
  151. assertArrayEquals(
  152. 'should ignore confusing suffixes', ['v1', 'v2'],
  153. utils.getParamValues(
  154. '/path?a=b&key=v1&c=d&key=v2&keywithsuffix=v3', 'key'));
  155. assertArrayEquals(
  156. 'should be case sensitive', ['v2'],
  157. utils.getParamValues(
  158. '/path?a=b&keY=v1&c=d&KEy=v2&keywithsuffix=v3', 'KEy'));
  159. assertArrayEquals(
  160. 'should work for the first parameter', ['v1', 'v2'],
  161. utils.getParamValues('/path?key=v1&c=d&key=v2&keywithsuffix=v3', 'key'));
  162. assertArrayEquals(
  163. 'should work for the last parameter', ['v1', 'v2'],
  164. utils.getParamValues('/path?key=v1&c=d&keywithsuffix=v3&key=v2', 'key'));
  165. assertArrayEquals(
  166. ['1'], utils.getParamValues('http://foo.com?q=1#?q=2&q=3', 'q'));
  167. }
  168. function testGetParamValueAllowsEqualInValues() {
  169. assertEquals(
  170. 'equals signs can appear unencoded', 'v1=v2',
  171. utils.getParamValue('/path?key=v1=v2', 'key'));
  172. assertArrayEquals(
  173. ['v1=v2=v3'], utils.getParamValues('/path?key=v1=v2=v3', 'key'));
  174. }
  175. function testGetParamValueNoSuchKey() {
  176. var uri = '/path?key=v1&c=d&keywithsuffix=v3&key=v2';
  177. assertNull(utils.getParamValue(uri, 'nosuchkey'));
  178. assertArrayEquals([], utils.getParamValues(uri, 'nosuchkey'));
  179. assertFalse(utils.hasParam(uri, 'nosuchkey'));
  180. assertNull(utils.getParamValue('q=1', 'q'));
  181. assertEquals('1', utils.getParamValue('?q=1', 'q'));
  182. }
  183. function testGetParamValueEmptyAndMissingValueStrings() {
  184. assertEquals('', utils.getParamValue('/path?key&bar', 'key'));
  185. assertEquals('', utils.getParamValue('/path?foo=bar&key', 'key'));
  186. assertEquals('', utils.getParamValue('/path?key', 'key'));
  187. assertEquals('', utils.getParamValue('/path?key=', 'key'));
  188. assertArrayEquals([''], utils.getParamValues('/path?key', 'key'));
  189. assertArrayEquals([''], utils.getParamValues('/path?key&bar', 'key'));
  190. assertArrayEquals([''], utils.getParamValues('/path?foo=bar&key', 'key'));
  191. assertArrayEquals([''], utils.getParamValues('/path?foo=bar&key=', 'key'));
  192. assertArrayEquals(
  193. ['', '', '', 'j', ''],
  194. utils.getParamValues('/path?key&key&key=&key=j&key', 'key'));
  195. assertArrayEquals(
  196. ['', '', '', '', ''],
  197. utils.getParamValues('/pathqqq?q&qq&q&q=&q&q', 'q'));
  198. assertTrue(utils.hasParam('/path?key=', 'key'));
  199. }
  200. function testGetParamValueDecoding() {
  201. assertEquals(
  202. 'plus should be supported as alias of space', 'foo bar baz',
  203. utils.getParamValue('/path?key=foo+bar%20baz', 'key'));
  204. assertArrayEquals(
  205. ['foo bar baz'],
  206. utils.getParamValues('/path?key=foo%20bar%20baz', 'key'));
  207. }
  208. function testGetParamIgnoresParamsInFragmentIdentifiers() {
  209. assertFalse(utils.hasParam('/path?bah#a&key=foo', 'key'));
  210. assertEquals(null, utils.getParamValue('/path?bah#a&key=bar', 'key'));
  211. assertArrayEquals([], utils.getParamValues('/path?bah#a&key=bar', 'key'));
  212. }
  213. function testGetParamIgnoresExcludesFragmentFromParameterValue() {
  214. // Make sure the '#' doesn't get included anywhere, for parameter values
  215. // of different lengths.
  216. assertEquals(
  217. 'foo', utils.getParamValue('/path?key=foo#key=bar&key=baz', 'key'));
  218. assertArrayEquals(
  219. ['foo'], utils.getParamValues('/path?key=foo#key=bar&key=baz', 'key'));
  220. assertEquals('', utils.getParamValue('/path?key#key=bar&key=baz', 'key'));
  221. assertArrayEquals(
  222. [''], utils.getParamValues('/path?key#key=bar&key=baz', 'key'));
  223. assertEquals('x', utils.getParamValue('/path?key=x#key=bar&key=baz', 'key'));
  224. assertArrayEquals(
  225. ['x'], utils.getParamValues('/path?key=x#key=bar&key=baz', 'key'));
  226. // Simply make sure hasParam doesn't die in this case.
  227. assertTrue(utils.hasParam('/path?key=foo#key=bar&key=baz', 'key'));
  228. assertTrue(utils.hasParam('/path?key=foo#key&key=baz', 'key'));
  229. }
  230. function testSameDomainPathsDiffer() {
  231. var uri1 = 'http://www.google.com/a';
  232. var uri2 = 'http://www.google.com/b';
  233. assertTrue(goog.uri.utils.haveSameDomain(uri1, uri2));
  234. assertTrue(goog.uri.utils.haveSameDomain(uri2, uri1));
  235. }
  236. function testSameDomainSchemesDiffer() {
  237. var uri1 = 'http://www.google.com';
  238. var uri2 = 'https://www.google.com';
  239. assertFalse(goog.uri.utils.haveSameDomain(uri1, uri2));
  240. assertFalse(goog.uri.utils.haveSameDomain(uri2, uri1));
  241. }
  242. function testSameDomainPortsDiffer() {
  243. var uri1 = 'http://www.google.com:1234/a';
  244. var uri2 = 'http://www.google.com/b';
  245. var uri3 = 'http://www.google.com:2345/b';
  246. assertFalse(goog.uri.utils.haveSameDomain(uri1, uri2));
  247. assertFalse(goog.uri.utils.haveSameDomain(uri2, uri1));
  248. assertFalse(goog.uri.utils.haveSameDomain(uri1, uri3));
  249. }
  250. function testSameDomainDomainsDiffer() {
  251. var uri1 = '/a';
  252. var uri2 = 'http://www.google.com/b';
  253. assertFalse(goog.uri.utils.haveSameDomain(uri1, uri2));
  254. assertFalse(goog.uri.utils.haveSameDomain(uri2, uri1));
  255. }
  256. function testSameDomainSubDomainDiffers() {
  257. var uri1 = 'http://www.google.com/a';
  258. var uri2 = 'http://mail.google.com/b';
  259. assertFalse(goog.uri.utils.haveSameDomain(uri1, uri2));
  260. assertFalse(goog.uri.utils.haveSameDomain(uri2, uri1));
  261. }
  262. function testSameDomainNoDomain() {
  263. var uri1 = '/a';
  264. var uri2 = '/b';
  265. assertTrue(goog.uri.utils.haveSameDomain(uri1, uri2));
  266. assertTrue(goog.uri.utils.haveSameDomain(uri2, uri1));
  267. }
  268. /**
  269. * Simple class with a constant toString.
  270. * @param {string} stringValue The result of toString.
  271. * @constructor
  272. */
  273. function HasString(stringValue) {
  274. this.value_ = stringValue;
  275. }
  276. /** @override */
  277. HasString.prototype.toString = function() {
  278. return this.value_;
  279. };
  280. function testBuildFromEncodedParts() {
  281. assertEquals(
  282. 'should handle full URL',
  283. 'http://foo@www.google.com:80/path?q=query#fragment',
  284. utils.buildFromEncodedParts(
  285. 'http', 'foo', 'www.google.com', 80, '/path', 'q=query', 'fragment'));
  286. assertEquals(
  287. 'should handle unspecified parameters', '/search',
  288. utils.buildFromEncodedParts(null, null, undefined, null, '/search'));
  289. assertEquals(
  290. 'should handle params of non-primitive types',
  291. 'http://foo@www.google.com:80/path?q=query#fragment',
  292. utils.buildFromEncodedParts(
  293. new HasString('http'), new HasString('foo'),
  294. new HasString('www.google.com'), new HasString('80'),
  295. new HasString('/path'), new HasString('q=query'),
  296. new HasString('fragment')));
  297. }
  298. function testAppendParam() {
  299. assertEquals(
  300. 'http://foo.com?q=1', utils.appendParam('http://foo.com', 'q', 1));
  301. assertEquals(
  302. 'http://foo.com?q=1#preserve',
  303. utils.appendParam('http://foo.com#preserve', 'q', 1));
  304. assertEquals(
  305. 'should tolerate a lone question mark', 'http://foo.com?q=1',
  306. utils.appendParam('http://foo.com?', 'q', 1));
  307. assertEquals(
  308. 'http://foo.com?q=1&r=2',
  309. utils.appendParam('http://foo.com?q=1', 'r', 2));
  310. assertEquals(
  311. 'http://foo.com?q=1&r=2&s=3#preserve',
  312. utils.appendParam('http://foo.com?q=1&r=2#preserve', 's', 3));
  313. assertEquals('?q=1#preserve', utils.appendParam('#preserve', 'q', 1));
  314. }
  315. function testBuildQueryData() {
  316. assertEquals(
  317. 'q=1&r=2&s=3&s=4', utils.buildQueryData(['q', 1, 'r', 2, 's', [3, 4]]));
  318. assertEquals('', utils.buildQueryData([]));
  319. }
  320. function testAppendParams() {
  321. assertEquals('http://foo.com', utils.appendParams('http://foo.com'));
  322. assertEquals(
  323. 'http://foo.com?q=1&r=2&s=3&s=4#preserve',
  324. utils.appendParams(
  325. 'http://foo.com#preserve', 'q', 1, 'r', 2, 's', [3, 4]));
  326. assertEquals(
  327. 'http://foo.com?a=1&q=1&r=2&s=3&s=4#preserve',
  328. utils.appendParams(
  329. 'http://foo.com?a=1#preserve', 'q', 1, 'r', 2, 's', [3, 4]));
  330. assertEquals(
  331. 'http://foo.com?q=1&r=2&s=3&s=4#preserve',
  332. utils.appendParams(
  333. 'http://foo.com?#preserve', 'q', 1, 'r', 2, 's', [3, 4]));
  334. assertEquals(
  335. '?q=1&r=2&s=3&s=4#preserve',
  336. utils.appendParams('#preserve', 'q', 1, 'r', 2, 's', [3, 4]));
  337. assertEquals(
  338. 'A question mark must not be appended if there are no ' +
  339. 'parameters, otherwise repeated appends will be broken.',
  340. 'http://foo.com#test', utils.appendParams('http://foo.com#test'));
  341. assertEquals(
  342. 'If a ? is already in the URL, it should be preserved when appending ' +
  343. '0 params',
  344. 'http://foo.com?#test', utils.appendParams('http://foo.com?#test'));
  345. assertEquals(
  346. 'should handle objects with to-string', 'http://foo.com?q=a&r=b',
  347. utils.appendParams(
  348. 'http://foo.com', 'q', new HasString('a'), 'r',
  349. [new HasString('b')]));
  350. assertThrows(
  351. 'appendParams should fail with an odd number of arguments.',
  352. function() { utils.appendParams('http://foo.com', 'a', 1, 'b'); });
  353. }
  354. function testValuelessParam() {
  355. assertEquals('http://foo.com?q', utils.appendParam('http://foo.com', 'q'));
  356. assertEquals(
  357. 'http://foo.com?q',
  358. utils.appendParam('http://foo.com', 'q', null /* opt_value */));
  359. assertEquals(
  360. 'http://foo.com?q#preserve',
  361. utils.appendParam('http://foo.com#preserve', 'q'));
  362. assertEquals(
  363. 'should tolerate a lone question mark', 'http://foo.com?q',
  364. utils.appendParam('http://foo.com?', 'q'));
  365. assertEquals(
  366. 'http://foo.com?q=1&r', utils.appendParam('http://foo.com?q=1', 'r'));
  367. assertEquals(
  368. 'http://foo.com?q=1&r=2&s#preserve',
  369. utils.appendParam('http://foo.com?q=1&r=2#preserve', 's'));
  370. assertTrue(utils.hasParam('http://foo.com?q=1&r=2&s#preserve', 's'));
  371. }
  372. function testAppendParamsAsArray() {
  373. assertEquals(
  374. 'http://foo.com?q=1&r=2&s=3&s=4#preserve',
  375. utils.appendParams(
  376. 'http://foo.com#preserve', ['q', 1, 'r', 2, 's', [3, 4]]));
  377. assertEquals(
  378. 'http://foo.com?q=1&s=3&s=4#preserve',
  379. utils.appendParams(
  380. 'http://foo.com#preserve', ['q', 1, 'r', null, 's', [3, 4]]));
  381. assertEquals(
  382. 'http://foo.com?q=1&s=3&s=4#preserve',
  383. utils.appendParams(
  384. 'http://foo.com#preserve', ['q', 1, 'r', undefined, 's', [3, 4]]));
  385. assertEquals(
  386. 'http://foo.com?q=1&r=2&s=3&s=4&s=null&s=undefined#preserve',
  387. utils.appendParams(
  388. 'http://foo.com#preserve',
  389. ['q', 1, 'r', 2, 's', [3, new HasString('4'), null, undefined]]));
  390. }
  391. function testAppendParamEscapes() {
  392. assertEquals(
  393. 'http://foo.com?h=a%20b',
  394. utils.appendParams('http://foo.com', 'h', 'a b'));
  395. assertEquals('h=a%20b', utils.buildQueryData(['h', 'a b']));
  396. assertEquals('h=a%20b', utils.buildQueryDataFromMap({'h': 'a b'}));
  397. }
  398. function testAppendParamsFromMap() {
  399. var uri = utils.appendParamsFromMap(
  400. 'http://www.foo.com',
  401. {'a': 1, 'b': 'bob', 'c': [1, 2, new HasString('3')]});
  402. assertArrayEquals(['1'], utils.getParamValues(uri, 'a'));
  403. assertArrayEquals(['bob'], utils.getParamValues(uri, 'b'));
  404. assertArrayEquals(['1', '2', '3'], utils.getParamValues(uri, 'c'));
  405. }
  406. function testBuildQueryDataFromMap() {
  407. assertEquals('a=1', utils.buildQueryDataFromMap({'a': 1}));
  408. var uri = 'foo.com?' +
  409. utils.buildQueryDataFromMap(
  410. {'a': 1, 'b': 'bob', 'c': [1, 2, new HasString('3')]});
  411. assertArrayEquals(['1'], utils.getParamValues(uri, 'a'));
  412. assertArrayEquals(['bob'], utils.getParamValues(uri, 'b'));
  413. assertArrayEquals(['1', '2', '3'], utils.getParamValues(uri, 'c'));
  414. }
  415. function testMultiParamSkipsNullParams() {
  416. // For the multi-param functions, null and undefined keys should be
  417. // skipped, but null within a parameter array should still be appended.
  418. assertEquals(
  419. 'buildQueryDataFromMap', 'a=null',
  420. utils.buildQueryDataFromMap({'a': [null], 'b': null, 'c': undefined}));
  421. assertEquals(
  422. 'buildQueryData', 'a=null',
  423. utils.buildQueryData(['a', [null], 'b', null, 'c', undefined]));
  424. assertEquals(
  425. 'appendParams', 'foo.com?a=null',
  426. utils.appendParams('foo.com', 'a', [null], 'b', null, 'c', undefined));
  427. assertEquals(
  428. 'empty strings should NOT be skipped', 'foo.com?a&b',
  429. utils.appendParams('foo.com', 'a', [''], 'b', ''));
  430. }
  431. function testRemoveParam() {
  432. assertEquals(
  433. 'remove middle', 'http://foo.com?q=1&s=3',
  434. utils.removeParam('http://foo.com?q=1&r=2&s=3', 'r'));
  435. assertEquals(
  436. 'remove first', 'http://foo.com?r=2&s=3',
  437. utils.removeParam('http://foo.com?q=1&r=2&s=3', 'q'));
  438. assertEquals(
  439. 'remove last', 'http://foo.com?q=1&r=2',
  440. utils.removeParam('http://foo.com?q=1&r=2&s=3', 's'));
  441. assertEquals(
  442. 'remove only param', 'http://foo.com',
  443. utils.removeParam('http://foo.com?q=1', 'q'));
  444. }
  445. function testRemoveParamWithFragment() {
  446. assertEquals(
  447. 'remove middle', 'http://foo.com?q=1&s=3#?r=1&r=1',
  448. utils.removeParam('http://foo.com?q=1&r=2&s=3#?r=1&r=1', 'r'));
  449. assertEquals(
  450. 'remove first', 'http://foo.com?r=2&s=3#?q=1&q=1',
  451. utils.removeParam('http://foo.com?q=1&r=2&s=3#?q=1&q=1', 'q'));
  452. assertEquals(
  453. 'remove only param', 'http://foo.com#?q=1&q=1',
  454. utils.removeParam('http://foo.com?q=1#?q=1&q=1', 'q'));
  455. assertEquals(
  456. 'remove last', 'http://foo.com?q=1&r=2#?s=1&s=1',
  457. utils.removeParam('http://foo.com?q=1&r=2&s=3#?s=1&s=1', 's'));
  458. }
  459. function testRemoveNonExistent() {
  460. assertEquals(
  461. 'remove key not present', 'http://foo.com?q=1',
  462. utils.removeParam('http://foo.com?q=1', 'nosuchkey'));
  463. assertEquals(
  464. 'remove key not present', 'http://foo.com#q=1',
  465. utils.removeParam('http://foo.com#q=1', 'q'));
  466. assertEquals(
  467. 'remove key from empty string', '', utils.removeParam('', 'nosuchkey'));
  468. }
  469. function testRemoveMultiple() {
  470. assertEquals(
  471. 'remove four of the same', 'http://foo.com',
  472. utils.removeParam('http://foo.com?q=1&q=2&q=3&q=4', 'q'));
  473. assertEquals(
  474. 'remove four of the same with another one in the middle',
  475. 'http://foo.com?a=99',
  476. utils.removeParam('http://foo.com?q=1&q=2&a=99&q=3&q=4', 'q'));
  477. }
  478. function testSetParam() {
  479. assertEquals(
  480. 'middle, no fragment', 'http://foo.com?q=1&s=3&r=999',
  481. utils.setParam('http://foo.com?q=1&r=2&s=3', 'r', 999));
  482. assertEquals(
  483. 'middle', 'http://foo.com?q=1&s=3&r=999#?r=1&r=1',
  484. utils.setParam('http://foo.com?q=1&r=2&s=3#?r=1&r=1', 'r', 999));
  485. assertEquals(
  486. 'first', 'http://foo.com?r=2&s=3&q=999#?q=1&q=1',
  487. utils.setParam('http://foo.com?q=1&r=2&s=3#?q=1&q=1', 'q', 999));
  488. assertEquals(
  489. 'only param', 'http://foo.com?q=999#?q=1&q=1',
  490. utils.setParam('http://foo.com?q=1#?q=1&q=1', 'q', 999));
  491. assertEquals(
  492. 'last', 'http://foo.com?q=1&r=2&s=999#?s=1&s=1',
  493. utils.setParam('http://foo.com?q=1&r=2&s=3#?s=1&s=1', 's', 999));
  494. assertEquals(
  495. 'multiple', 'http://foo.com?s=999#?s=1&s=1',
  496. utils.setParam('http://foo.com?s=1&s=2&s=3#?s=1&s=1', 's', 999));
  497. assertEquals(
  498. 'none', 'http://foo.com?r=1&s=999#?s=1&s=1',
  499. utils.setParam('http://foo.com?r=1#?s=1&s=1', 's', 999));
  500. }
  501. function testSetParamsFromMap() {
  502. // These helper assertions are needed because the input is an Object and
  503. // we cannot gaurauntee an order.
  504. function assertQueryEquals(message, expected, actual) {
  505. var expectedQuery = goog.uri.utils.getQueryData(expected);
  506. var actualQuery = goog.uri.utils.getQueryData(actual);
  507. assertEquals(
  508. 'Unmatched param count. ' + message, expectedQuery.split('&').length,
  509. actualQuery.split('&').length);
  510. // Build a map of all of the params for actual.
  511. var actualParams = {};
  512. goog.uri.utils.parseQueryData(actualQuery, function(key, value) {
  513. if (actualParams[key]) {
  514. actualParams[key].push(value);
  515. } else {
  516. actualParams[key] = [value];
  517. }
  518. });
  519. for (key in actualParams) {
  520. var expectedParams = goog.uri.utils.getParamValues(actual, key);
  521. assertArrayEquals(
  522. 'Unmatched param ' + key + ', ' + message, expectedParams.sort(),
  523. actualParams[key].sort());
  524. }
  525. }
  526. function assertUriEquals(message, expected, actual) {
  527. message = ' for expected URI: "' + expected + '", actual: "' + actual + '"';
  528. var expectedComps = utils.split(expected);
  529. var actualComps = utils.split(actual);
  530. for (var i = 1; i < expectedComps.length; i++) {
  531. if (i === goog.uri.utils.ComponentIndex.QUERY_DATA) {
  532. assertQueryEquals(message, expected, actual);
  533. } else {
  534. assertEquals(message, expectedComps[i], actualComps[i]);
  535. }
  536. }
  537. }
  538. assertEquals(
  539. 'remove some params', 'http://foo.com/bar?b=2#b=5',
  540. goog.uri.utils.setParamsFromMap(
  541. 'http://foo.com/bar?a=1&b=2&c=3#b=5', {a: null, c: undefined}));
  542. assertEquals(
  543. 'remove all params', 'http://foo.com#b=5',
  544. goog.uri.utils.setParamsFromMap(
  545. 'http://foo.com?a=1&b=2&c=3#b=5', {a: null, b: null, c: undefined}));
  546. assertEquals(
  547. 'update one param', 'http://foo.com?b=2&c=3&a=999#b=5',
  548. goog.uri.utils.setParamsFromMap(
  549. 'http://foo.com?a=1&b=2&c=3#b=5', {a: 999}));
  550. assertEquals(
  551. 'remove one param, update one param', 'http://foo.com?b=2&a=999',
  552. goog.uri.utils.setParamsFromMap(
  553. 'http://foo.com?a=1&b=2&c=3', {a: 999, c: null}));
  554. assertEquals(
  555. 'multiple params unmodified', 'http://foo.com?b=2&b=20&b&a=999',
  556. goog.uri.utils.setParamsFromMap(
  557. 'http://foo.com?a=1&b=2&b=20&b', {a: 999}));
  558. assertEquals(
  559. 'update multiple values', 'http://foo.com?a=1&c=3&b=5&b&b=10',
  560. goog.uri.utils.setParamsFromMap(
  561. 'http://foo.com?a=1&b=2&c=3', {b: [5, '', 10]}));
  562. // Tests that update/add multiple params must use assertUriEquals.
  563. assertUriEquals(
  564. 'add from blank query', 'http://foo.com?a=100&b=200#hash',
  565. goog.uri.utils.setParamsFromMap('http://foo.com#hash', {a: 100, b: 200}));
  566. assertUriEquals(
  567. 'replace multiple params', 'http://foo.com?d=4&a=100&b=200&c=300',
  568. goog.uri.utils.setParamsFromMap(
  569. 'http://foo.com?a=1&b=2&b=20&c=3&d=4', {a: 100, b: 200, c: 300}));
  570. // update 1, remove b, keep c as is, add d.
  571. assertUriEquals(
  572. 'add, remove and update', 'http://foo.com?a=100&c=3&d=400',
  573. goog.uri.utils.setParamsFromMap(
  574. 'http://foo.com?a=1&b=2&b=20&c=3', {a: 100, b: null, d: 400}));
  575. }
  576. function testModifyQueryParams() {
  577. var uri = 'http://foo.com?a=A&a=A2&b=B&b=B2&c=C';
  578. uri = utils.appendParam(uri, 'd', 'D');
  579. assertEquals('http://foo.com?a=A&a=A2&b=B&b=B2&c=C&d=D', uri);
  580. uri = utils.removeParam(uri, 'd');
  581. uri = utils.appendParam(uri, 'd', 'D2');
  582. assertEquals('http://foo.com?a=A&a=A2&b=B&b=B2&c=C&d=D2', uri);
  583. uri = utils.removeParam(uri, 'a');
  584. uri = utils.appendParam(uri, 'a', 'A3');
  585. assertEquals('http://foo.com?b=B&b=B2&c=C&d=D2&a=A3', uri);
  586. uri = utils.removeParam(uri, 'a');
  587. uri = utils.appendParam(uri, 'a', 'A4');
  588. assertEquals('A4', utils.getParamValue(uri, 'a'));
  589. }
  590. function testBrowserEncoding() {
  591. // Sanity check borrowed from old code to ensure that encodeURIComponent
  592. // is good enough. Entire test should be safe to delete.
  593. var allowedInFragment = /[A-Za-z0-9\-\._~!$&'()*+,;=:@/?]/g;
  594. var sb = [];
  595. for (var i = 33; i < 500; i++) { // arbitrarily use first 500 chars.
  596. sb.push(String.fromCharCode(i));
  597. }
  598. var testString = sb.join('');
  599. var encodedStr = encodeURIComponent(testString);
  600. // Strip all percent encoded characters, as they're ok.
  601. encodedStr = encodedStr.replace(/%[0-9A-F][0-9A-F]/g, '');
  602. // Remove allowed characters.
  603. encodedStr = encodedStr.replace(allowedInFragment, '');
  604. // Only illegal characters should remain, which is a fail.
  605. assertEquals('String should be empty', 0, encodedStr.length);
  606. }
  607. function testAppendPath() {
  608. var uri = 'http://www.foo.com';
  609. var expected = uri + '/dummy';
  610. assertEquals(
  611. 'Path has no trailing "/", adding with leading "/" failed', expected,
  612. goog.uri.utils.appendPath(uri, '/dummy'));
  613. assertEquals(
  614. 'Path has no trailing "/", adding with no leading "/" failed', expected,
  615. goog.uri.utils.appendPath(uri, 'dummy'));
  616. uri = uri + '/';
  617. assertEquals(
  618. 'Path has trailing "/", adding with leading "/" failed', expected,
  619. goog.uri.utils.appendPath(uri, '/dummy'));
  620. assertEquals(
  621. 'Path has trailing "/", adding with no leading "/" failed', expected,
  622. goog.uri.utils.appendPath(uri, 'dummy'));
  623. }
  624. function testMakeUnique() {
  625. assertEquals(
  626. 'http://www.google.com?zx=RANDOM#blob',
  627. goog.uri.utils.makeUnique('http://www.google.com#blob'));
  628. assertEquals(
  629. 'http://www.google.com?a=1&b=2&zx=RANDOM#blob',
  630. goog.uri.utils.makeUnique('http://www.google.com?zx=9&a=1&b=2#blob'));
  631. }
  632. function testParseQuery() {
  633. var result = [];
  634. goog.uri.utils.parseQueryData(
  635. 'foo=bar&no&empty=&tricky%3D%26=%3D%26&=nothing&=&',
  636. function(name, value) { result.push(name, value); });
  637. assertArrayEquals(
  638. [
  639. 'foo', 'bar', 'no', '', 'empty', '', 'tricky%3D%26', '=&', '',
  640. 'nothing', '', '', '', ''
  641. ],
  642. result);
  643. // Go thought buildQueryData and parseQueryData and see if we get the same
  644. // result.
  645. var result2 = [];
  646. goog.uri.utils.parseQueryData(
  647. goog.uri.utils.buildQueryData(result),
  648. function(name, value) { result2.push(name, value); });
  649. assertArrayEquals(result, result2);
  650. goog.uri.utils.parseQueryData(
  651. '', goog.partial(fail, 'Empty string should not run callback'));
  652. }
  653. function testSetPath() {
  654. assertEquals(
  655. 'http://www.google.com/bar',
  656. goog.uri.utils.setPath('http://www.google.com', 'bar'));
  657. assertEquals(
  658. 'http://www.google.com/bar',
  659. goog.uri.utils.setPath('http://www.google.com', '/bar'));
  660. assertEquals(
  661. 'http://www.google.com/bar/',
  662. goog.uri.utils.setPath('http://www.google.com', 'bar/'));
  663. assertEquals(
  664. 'http://www.google.com/bar/',
  665. goog.uri.utils.setPath('http://www.google.com', '/bar/'));
  666. assertEquals(
  667. 'http://www.google.com/bar?q=t',
  668. goog.uri.utils.setPath('http://www.google.com/?q=t', '/bar'));
  669. assertEquals(
  670. 'http://www.google.com/bar?q=t',
  671. goog.uri.utils.setPath('http://www.google.com/?q=t', 'bar'));
  672. assertEquals(
  673. 'http://www.google.com/bar/?q=t',
  674. goog.uri.utils.setPath('http://www.google.com/?q=t', 'bar/'));
  675. assertEquals(
  676. 'http://www.google.com/bar/?q=t',
  677. goog.uri.utils.setPath('http://www.google.com/?q=t', '/bar/'));
  678. assertEquals(
  679. 'http://www.google.com/bar?q=t',
  680. goog.uri.utils.setPath('http://www.google.com/foo?q=t', 'bar'));
  681. assertEquals(
  682. 'http://www.google.com/bar?q=t',
  683. goog.uri.utils.setPath('http://www.google.com/foo?q=t', '/bar'));
  684. assertEquals(
  685. 'https://www.google.com/bar?q=t&q1=y',
  686. goog.uri.utils.setPath('https://www.google.com/foo?q=t&q1=y', 'bar'));
  687. assertEquals(
  688. 'https://www.google.com:8113/bar?q=t&q1=y',
  689. goog.uri.utils.setPath('https://www.google.com:8113?q=t&q1=y', 'bar'));
  690. assertEquals(
  691. 'https://www.google.com:8113/foo/bar?q=t&q1=y',
  692. goog.uri.utils.setPath(
  693. 'https://www.google.com:8113/foobar?q=t&q1=y', 'foo/bar'));
  694. assertEquals(
  695. 'https://www.google.com:8113/foo/bar?q=t&q1=y',
  696. goog.uri.utils.setPath(
  697. 'https://www.google.com:8113/foobar?q=t&q1=y', '/foo/bar'));
  698. assertEquals(
  699. 'https://www.google.com:8113/foo/bar/?q=t&q1=y',
  700. goog.uri.utils.setPath(
  701. 'https://www.google.com:8113/foobar?q=t&q1=y', 'foo/bar/'));
  702. assertEquals(
  703. 'https://www.google.com:8113/foo/bar/?q=t&q1=y',
  704. goog.uri.utils.setPath(
  705. 'https://www.google.com:8113/foobar?q=t&q1=y', '/foo/bar/'));
  706. assertEquals(
  707. 'https://www.google.com:8113/?q=t&q1=y',
  708. goog.uri.utils.setPath(
  709. 'https://www.google.com:8113/foobar?q=t&q1=y', ''));
  710. }