functions_test.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736
  1. // Copyright 2008 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 goog.functions.
  16. */
  17. goog.provide('goog.functionsTest');
  18. goog.setTestOnly('goog.functionsTest');
  19. goog.require('goog.array');
  20. goog.require('goog.functions');
  21. goog.require('goog.testing.MockClock');
  22. goog.require('goog.testing.PropertyReplacer');
  23. goog.require('goog.testing.jsunit');
  24. goog.require('goog.testing.recordFunction');
  25. var fTrue = makeCallOrderLogger('fTrue', true);
  26. var gFalse = makeCallOrderLogger('gFalse', false);
  27. var hTrue = makeCallOrderLogger('hTrue', true);
  28. var stubs = new goog.testing.PropertyReplacer();
  29. function setUp() {
  30. callOrder = [];
  31. }
  32. function tearDown() {
  33. stubs.reset();
  34. }
  35. var foo = 'global';
  36. var obj = {foo: 'obj'};
  37. function getFoo(arg1, arg2) {
  38. return {foo: this.foo, arg1: arg1, arg2: arg2};
  39. }
  40. function testTrue() {
  41. assertTrue(goog.functions.TRUE());
  42. }
  43. function testFalse() {
  44. assertFalse(goog.functions.FALSE());
  45. }
  46. function testLock() {
  47. function add(var_args) {
  48. var result = 0;
  49. for (var i = 0; i < arguments.length; i++) {
  50. result += arguments[i];
  51. }
  52. return result;
  53. }
  54. assertEquals(6, add(1, 2, 3));
  55. assertEquals(0, goog.functions.lock(add)(1, 2, 3));
  56. assertEquals(3, goog.functions.lock(add, 2)(1, 2, 3));
  57. assertEquals(6, goog.partial(add, 1, 2)(3));
  58. assertEquals(3, goog.functions.lock(goog.partial(add, 1, 2))(3));
  59. }
  60. function testNth() {
  61. assertEquals(1, goog.functions.nth(0)(1));
  62. assertEquals(2, goog.functions.nth(1)(1, 2));
  63. assertEquals('a', goog.functions.nth(0)('a', 'b'));
  64. assertEquals(undefined, goog.functions.nth(0)());
  65. assertEquals(undefined, goog.functions.nth(1)(true));
  66. assertEquals(undefined, goog.functions.nth(-1)());
  67. }
  68. function testPartialRight() {
  69. var f = function(x, y) { return x / y; };
  70. var g = goog.functions.partialRight(f, 2);
  71. assertEquals(2, g(4));
  72. var h = goog.functions.partialRight(f, 4, 2);
  73. assertEquals(2, h());
  74. var i = goog.functions.partialRight(f);
  75. assertEquals(2, i(4, 2));
  76. }
  77. function testPartialRightUsesGlobal() {
  78. var f = function(x, y) {
  79. assertEquals(goog.global, this);
  80. return x / y;
  81. };
  82. var g = goog.functions.partialRight(f, 2);
  83. var h = goog.functions.partialRight(g, 4);
  84. assertEquals(2, h());
  85. }
  86. function testPartialRightWithCall() {
  87. var obj = {};
  88. var f = function(x, y) {
  89. assertEquals(obj, this);
  90. return x / y;
  91. };
  92. var g = goog.functions.partialRight(f, 2);
  93. var h = goog.functions.partialRight(g, 4);
  94. assertEquals(2, h.call(obj));
  95. }
  96. function testPartialRightAndBind() {
  97. // This ensures that this "survives" through a partialRight.
  98. var p = goog.functions.partialRight(getFoo, 'dog');
  99. var b = goog.bind(p, obj, 'hot');
  100. var res = b();
  101. assertEquals(obj.foo, res.foo);
  102. assertEquals('hot', res.arg1);
  103. assertEquals('dog', res.arg2);
  104. }
  105. function testBindAndPartialRight() {
  106. // This ensures that this "survives" through a partialRight.
  107. var b = goog.bind(getFoo, obj, 'hot');
  108. var p = goog.functions.partialRight(b, 'dog');
  109. var res = p();
  110. assertEquals(obj.foo, res.foo);
  111. assertEquals('hot', res.arg1);
  112. assertEquals('dog', res.arg2);
  113. }
  114. function testPartialRightMultipleCalls() {
  115. var f = goog.testing.recordFunction();
  116. var a = goog.functions.partialRight(f, 'foo');
  117. var b = goog.functions.partialRight(a, 'bar');
  118. a();
  119. a();
  120. b();
  121. b();
  122. assertEquals(4, f.getCallCount());
  123. var calls = f.getCalls();
  124. assertArrayEquals(['foo'], calls[0].getArguments());
  125. assertArrayEquals(['foo'], calls[1].getArguments());
  126. assertArrayEquals(['bar', 'foo'], calls[2].getArguments());
  127. assertArrayEquals(['bar', 'foo'], calls[3].getArguments());
  128. }
  129. function testIdentity() {
  130. assertEquals(3, goog.functions.identity(3));
  131. assertEquals(3, goog.functions.identity(3, 4, 5, 6));
  132. assertEquals('Hi there', goog.functions.identity('Hi there'));
  133. assertEquals(null, goog.functions.identity(null));
  134. assertEquals(undefined, goog.functions.identity());
  135. var arr = [1, 'b', null];
  136. assertEquals(arr, goog.functions.identity(arr));
  137. var obj = {a: 'ay', b: 'bee', c: 'see'};
  138. assertEquals(obj, goog.functions.identity(obj));
  139. }
  140. function testConstant() {
  141. assertEquals(3, goog.functions.constant(3)());
  142. assertEquals(undefined, goog.functions.constant()());
  143. }
  144. function testError() {
  145. var f = goog.functions.error('x');
  146. var e = assertThrows(
  147. 'A function created by goog.functions.error must throw an error', f);
  148. assertEquals('x', e.message);
  149. }
  150. function testFail() {
  151. var obj = {};
  152. var f = goog.functions.fail(obj);
  153. var e = assertThrows(
  154. 'A function created by goog.functions.raise must throw its input', f);
  155. assertEquals(obj, e);
  156. }
  157. function testCompose() {
  158. var add2 = function(x) { return x + 2; };
  159. var doubleValue = function(x) { return x * 2; };
  160. assertEquals(6, goog.functions.compose(doubleValue, add2)(1));
  161. assertEquals(4, goog.functions.compose(add2, doubleValue)(1));
  162. assertEquals(6, goog.functions.compose(add2, add2, doubleValue)(1));
  163. assertEquals(
  164. 12, goog.functions.compose(doubleValue, add2, add2, doubleValue)(1));
  165. assertUndefined(goog.functions.compose()(1));
  166. assertEquals(3, goog.functions.compose(add2)(1));
  167. var add2Numbers = function(x, y) { return x + y; };
  168. assertEquals(17, goog.functions.compose(add2Numbers)(10, 7));
  169. assertEquals(34, goog.functions.compose(doubleValue, add2Numbers)(10, 7));
  170. }
  171. function testAdd() {
  172. assertUndefined(goog.functions.sequence()());
  173. assertCallOrderAndReset([]);
  174. assert(goog.functions.sequence(fTrue)());
  175. assertCallOrderAndReset(['fTrue']);
  176. assertFalse(goog.functions.sequence(fTrue, gFalse)());
  177. assertCallOrderAndReset(['fTrue', 'gFalse']);
  178. assert(goog.functions.sequence(fTrue, gFalse, hTrue)());
  179. assertCallOrderAndReset(['fTrue', 'gFalse', 'hTrue']);
  180. assert(goog.functions.sequence(goog.functions.identity)(true));
  181. assertFalse(goog.functions.sequence(goog.functions.identity)(false));
  182. }
  183. function testAnd() {
  184. // the return value is unspecified for an empty and
  185. goog.functions.and()();
  186. assertCallOrderAndReset([]);
  187. assert(goog.functions.and(fTrue)());
  188. assertCallOrderAndReset(['fTrue']);
  189. assertFalse(goog.functions.and(fTrue, gFalse)());
  190. assertCallOrderAndReset(['fTrue', 'gFalse']);
  191. assertFalse(goog.functions.and(fTrue, gFalse, hTrue)());
  192. assertCallOrderAndReset(['fTrue', 'gFalse']);
  193. assert(goog.functions.and(goog.functions.identity)(true));
  194. assertFalse(goog.functions.and(goog.functions.identity)(false));
  195. }
  196. function testOr() {
  197. // the return value is unspecified for an empty or
  198. goog.functions.or()();
  199. assertCallOrderAndReset([]);
  200. assert(goog.functions.or(fTrue)());
  201. assertCallOrderAndReset(['fTrue']);
  202. assert(goog.functions.or(fTrue, gFalse)());
  203. assertCallOrderAndReset(['fTrue']);
  204. assert(goog.functions.or(fTrue, gFalse, hTrue)());
  205. assertCallOrderAndReset(['fTrue']);
  206. assert(goog.functions.or(goog.functions.identity)(true));
  207. assertFalse(goog.functions.or(goog.functions.identity)(false));
  208. }
  209. function testNot() {
  210. assertTrue(goog.functions.not(gFalse)());
  211. assertCallOrderAndReset(['gFalse']);
  212. assertTrue(goog.functions.not(goog.functions.identity)(false));
  213. assertFalse(goog.functions.not(goog.functions.identity)(true));
  214. var f = function(a, b) {
  215. assertEquals(1, a);
  216. assertEquals(2, b);
  217. return false;
  218. };
  219. assertTrue(goog.functions.not(f)(1, 2));
  220. }
  221. function testCreate(expectedArray) {
  222. var tempConstructor = function(a, b) {
  223. this.foo = a;
  224. this.bar = b;
  225. };
  226. var factory = goog.partial(goog.functions.create, tempConstructor, 'baz');
  227. var instance = factory('qux');
  228. assert(instance instanceof tempConstructor);
  229. assertEquals(instance.foo, 'baz');
  230. assertEquals(instance.bar, 'qux');
  231. }
  232. function testWithReturnValue() {
  233. var obj = {};
  234. var f = function(a, b) {
  235. assertEquals(obj, this);
  236. assertEquals(1, a);
  237. assertEquals(2, b);
  238. };
  239. assertTrue(goog.functions.withReturnValue(f, true).call(obj, 1, 2));
  240. assertFalse(goog.functions.withReturnValue(f, false).call(obj, 1, 2));
  241. }
  242. function testEqualTo() {
  243. assertTrue(goog.functions.equalTo(42)(42));
  244. assertFalse(goog.functions.equalTo(42)(13));
  245. assertFalse(goog.functions.equalTo(42)('a string'));
  246. assertFalse(goog.functions.equalTo(42)('42'));
  247. assertTrue(goog.functions.equalTo(42, true)('42'));
  248. assertTrue(goog.functions.equalTo(0)(0));
  249. assertFalse(goog.functions.equalTo(0)(''));
  250. assertFalse(goog.functions.equalTo(0)(1));
  251. assertTrue(goog.functions.equalTo(0, true)(0));
  252. assertTrue(goog.functions.equalTo(0, true)(''));
  253. assertFalse(goog.functions.equalTo(0, true)(1));
  254. }
  255. function makeCallOrderLogger(name, returnValue) {
  256. return function() {
  257. callOrder.push(name);
  258. return returnValue;
  259. };
  260. }
  261. function assertCallOrderAndReset(expectedArray) {
  262. assertArrayEquals(expectedArray, callOrder);
  263. callOrder = [];
  264. }
  265. function testCacheReturnValue() {
  266. var returnFive = function() { return 5; };
  267. var recordedReturnFive = goog.testing.recordFunction(returnFive);
  268. var cachedRecordedReturnFive =
  269. goog.functions.cacheReturnValue(recordedReturnFive);
  270. assertEquals(0, recordedReturnFive.getCallCount());
  271. assertEquals(5, cachedRecordedReturnFive());
  272. assertEquals(1, recordedReturnFive.getCallCount());
  273. assertEquals(5, cachedRecordedReturnFive());
  274. assertEquals(1, recordedReturnFive.getCallCount());
  275. }
  276. function testCacheReturnValueFlagEnabled() {
  277. var count = 0;
  278. var returnIncrementingInteger = function() {
  279. count++;
  280. return count;
  281. };
  282. var recordedFunction = goog.testing.recordFunction(returnIncrementingInteger);
  283. var cachedRecordedFunction =
  284. goog.functions.cacheReturnValue(recordedFunction);
  285. assertEquals(0, recordedFunction.getCallCount());
  286. assertEquals(1, cachedRecordedFunction());
  287. assertEquals(1, recordedFunction.getCallCount());
  288. assertEquals(1, cachedRecordedFunction());
  289. assertEquals(1, recordedFunction.getCallCount());
  290. assertEquals(1, cachedRecordedFunction());
  291. }
  292. function testCacheReturnValueFlagDisabled() {
  293. stubs.set(goog.functions, 'CACHE_RETURN_VALUE', false);
  294. var count = 0;
  295. var returnIncrementingInteger = function() {
  296. count++;
  297. return count;
  298. };
  299. var recordedFunction = goog.testing.recordFunction(returnIncrementingInteger);
  300. var cachedRecordedFunction =
  301. goog.functions.cacheReturnValue(recordedFunction);
  302. assertEquals(0, recordedFunction.getCallCount());
  303. assertEquals(1, cachedRecordedFunction());
  304. assertEquals(1, recordedFunction.getCallCount());
  305. assertEquals(2, cachedRecordedFunction());
  306. assertEquals(2, recordedFunction.getCallCount());
  307. assertEquals(3, cachedRecordedFunction());
  308. }
  309. function testOnce() {
  310. var recordedFunction = goog.testing.recordFunction();
  311. var f = goog.functions.once(recordedFunction);
  312. assertEquals(0, recordedFunction.getCallCount());
  313. f();
  314. assertEquals(1, recordedFunction.getCallCount());
  315. f();
  316. assertEquals(1, recordedFunction.getCallCount());
  317. }
  318. function testDebounce() {
  319. // Encoded sequences of commands to perform mapped to expected # of calls.
  320. // f: fire
  321. // w: wait (for the timer to elapse)
  322. assertAsyncDecoratorCommandSequenceCalls(goog.functions.debounce, {
  323. 'f': 0,
  324. 'ff': 0,
  325. 'fff': 0,
  326. 'fw': 1,
  327. 'ffw': 1,
  328. 'fffw': 1,
  329. 'fwffwf': 2,
  330. 'ffwwwffwwfwf': 3
  331. });
  332. }
  333. function testDebounceScopeBinding() {
  334. var interval = 500;
  335. var mockClock = new goog.testing.MockClock(true);
  336. var x = {'y': 0};
  337. goog.functions.debounce(function() { ++this['y']; }, interval, x)();
  338. assertEquals(0, x['y']);
  339. mockClock.tick(interval);
  340. assertEquals(1, x['y']);
  341. mockClock.uninstall();
  342. }
  343. function testDebounceArgumentBinding() {
  344. var interval = 500;
  345. var mockClock = new goog.testing.MockClock(true);
  346. var calls = 0;
  347. var debouncedFn = goog.functions.debounce(function(a, b, c) {
  348. ++calls;
  349. assertEquals(3, a);
  350. assertEquals('string', b);
  351. assertEquals(false, c);
  352. }, interval);
  353. debouncedFn(3, 'string', false);
  354. mockClock.tick(interval);
  355. assertEquals(1, calls);
  356. // goog.functions.debounce should always pass the last arguments passed to the
  357. // decorator into the decorated function, even if called multiple times.
  358. debouncedFn();
  359. mockClock.tick(interval / 2);
  360. debouncedFn(8, null, true);
  361. debouncedFn(3, 'string', false);
  362. mockClock.tick(interval);
  363. assertEquals(2, calls);
  364. mockClock.uninstall();
  365. }
  366. function testDebounceArgumentAndScopeBinding() {
  367. var interval = 500;
  368. var mockClock = new goog.testing.MockClock(true);
  369. var x = {'calls': 0};
  370. var debouncedFn = goog.functions.debounce(function(a, b, c) {
  371. ++this['calls'];
  372. assertEquals(3, a);
  373. assertEquals('string', b);
  374. assertEquals(false, c);
  375. }, interval, x);
  376. debouncedFn(3, 'string', false);
  377. mockClock.tick(interval);
  378. assertEquals(1, x['calls']);
  379. // goog.functions.debounce should always pass the last arguments passed to the
  380. // decorator into the decorated function, even if called multiple times.
  381. debouncedFn();
  382. mockClock.tick(interval / 2);
  383. debouncedFn(8, null, true);
  384. debouncedFn(3, 'string', false);
  385. mockClock.tick(interval);
  386. assertEquals(2, x['calls']);
  387. mockClock.uninstall();
  388. }
  389. function testThrottle() {
  390. // Encoded sequences of commands to perform mapped to expected # of calls.
  391. // f: fire
  392. // w: wait (for the timer to elapse)
  393. assertAsyncDecoratorCommandSequenceCalls(goog.functions.throttle, {
  394. 'f': 1,
  395. 'ff': 1,
  396. 'fff': 1,
  397. 'fw': 1,
  398. 'ffw': 2,
  399. 'fwf': 2,
  400. 'fffw': 2,
  401. 'fwfff': 2,
  402. 'fwfffw': 3,
  403. 'fwffwf': 3,
  404. 'ffwf': 2,
  405. 'ffwff': 2,
  406. 'ffwfw': 3,
  407. 'ffwffwf': 3,
  408. 'ffwffwff': 3,
  409. 'ffwffwffw': 4,
  410. 'ffwwwffwwfw': 5,
  411. 'ffwwwffwwfwf': 6
  412. });
  413. }
  414. function testThrottleScopeBinding() {
  415. var interval = 500;
  416. var mockClock = new goog.testing.MockClock(true);
  417. var x = {'y': 0};
  418. goog.functions.throttle(function() { ++this['y']; }, interval, x)();
  419. assertEquals(1, x['y']);
  420. mockClock.uninstall();
  421. }
  422. function testThrottleArgumentBinding() {
  423. var interval = 500;
  424. var mockClock = new goog.testing.MockClock(true);
  425. var calls = 0;
  426. var throttledFn = goog.functions.throttle(function(a, b, c) {
  427. ++calls;
  428. assertEquals(3, a);
  429. assertEquals('string', b);
  430. assertEquals(false, c);
  431. }, interval);
  432. throttledFn(3, 'string', false);
  433. assertEquals(1, calls);
  434. // goog.functions.throttle should always pass the last arguments passed to the
  435. // decorator into the decorated function, even if called multiple times.
  436. throttledFn();
  437. mockClock.tick(interval / 2);
  438. throttledFn(8, null, true);
  439. throttledFn(3, 'string', false);
  440. mockClock.tick(interval);
  441. assertEquals(2, calls);
  442. mockClock.uninstall();
  443. }
  444. function testThrottleArgumentAndScopeBinding() {
  445. var interval = 500;
  446. var mockClock = new goog.testing.MockClock(true);
  447. var x = {'calls': 0};
  448. var throttledFn = goog.functions.throttle(function(a, b, c) {
  449. ++this['calls'];
  450. assertEquals(3, a);
  451. assertEquals('string', b);
  452. assertEquals(false, c);
  453. }, interval, x);
  454. throttledFn(3, 'string', false);
  455. assertEquals(1, x['calls']);
  456. // goog.functions.throttle should always pass the last arguments passed to the
  457. // decorator into the decorated function, even if called multiple times.
  458. throttledFn();
  459. mockClock.tick(interval / 2);
  460. throttledFn(8, null, true);
  461. throttledFn(3, 'string', false);
  462. mockClock.tick(interval);
  463. assertEquals(2, x['calls']);
  464. mockClock.uninstall();
  465. }
  466. function testRateLimit() {
  467. // Encoded sequences of commands to perform mapped to expected # of calls.
  468. // f: fire
  469. // w: wait (for the timer to elapse)
  470. assertAsyncDecoratorCommandSequenceCalls(goog.functions.rateLimit, {
  471. 'f': 1,
  472. 'ff': 1,
  473. 'fff': 1,
  474. 'fw': 1,
  475. 'ffw': 1,
  476. 'fwf': 2,
  477. 'fffw': 1,
  478. 'fwfff': 2,
  479. 'fwfffw': 2,
  480. 'fwffwf': 3,
  481. 'ffwf': 2,
  482. 'ffwff': 2,
  483. 'ffwfw': 2,
  484. 'ffwffwf': 3,
  485. 'ffwffwff': 3,
  486. 'ffwffwffw': 3,
  487. 'ffwwwffwwfw': 3,
  488. 'ffwwwffwwfwf': 4
  489. });
  490. }
  491. function testRateLimitScopeBinding() {
  492. var interval = 500;
  493. var mockClock = new goog.testing.MockClock(true);
  494. var x = {'y': 0};
  495. goog.functions.rateLimit(function() {
  496. ++this['y'];
  497. }, interval, x)();
  498. assertEquals(1, x['y']);
  499. mockClock.uninstall();
  500. }
  501. function testRateLimitArgumentBinding() {
  502. var interval = 500;
  503. var mockClock = new goog.testing.MockClock(true);
  504. var calls = 0;
  505. var rateLimitedFn = goog.functions.rateLimit(function(a, b, c) {
  506. ++calls;
  507. assertEquals(3, a);
  508. assertEquals('string', b);
  509. assertEquals(false, c);
  510. }, interval);
  511. rateLimitedFn(3, 'string', false);
  512. assertEquals(1, calls);
  513. // goog.functions.rateLimit should always pass the first arguments passed to
  514. // the
  515. // decorator into the decorated function, even if called multiple times.
  516. rateLimitedFn();
  517. mockClock.tick(interval / 2);
  518. rateLimitedFn(8, null, true);
  519. mockClock.tick(interval);
  520. rateLimitedFn(3, 'string', false);
  521. assertEquals(2, calls);
  522. mockClock.uninstall();
  523. }
  524. function testRateLimitArgumentAndScopeBinding() {
  525. var interval = 500;
  526. var mockClock = new goog.testing.MockClock(true);
  527. var x = {'calls': 0};
  528. var rateLimitedFn = goog.functions.rateLimit(function(a, b, c) {
  529. ++this['calls'];
  530. assertEquals(3, a);
  531. assertEquals('string', b);
  532. assertEquals(false, c);
  533. }, interval, x);
  534. rateLimitedFn(3, 'string', false);
  535. assertEquals(1, x['calls']);
  536. // goog.functions.rateLimit should always pass the last arguments passed to
  537. // the
  538. // decorator into the decorated function, even if called multiple times.
  539. rateLimitedFn();
  540. mockClock.tick(interval / 2);
  541. rateLimitedFn(8, null, true);
  542. mockClock.tick(interval);
  543. rateLimitedFn(3, 'string', false);
  544. assertEquals(2, x['calls']);
  545. mockClock.uninstall();
  546. }
  547. /**
  548. * Wraps a {@code goog.testing.recordFunction} with the specified decorator and
  549. * executes a list of command sequences, asserting that in each case the
  550. * decorated function is called the expected number of times.
  551. * @param {function():*} decorator The async decorator to test.
  552. * @param {!Object.<string, number>} expectedCommandSequenceCalls An object
  553. * mapping string command sequences (where 'f' is 'fire' and 'w' is 'wait')
  554. * to the number times we expect a decorated function to be called during
  555. * the execution of those commands.
  556. */
  557. function assertAsyncDecoratorCommandSequenceCalls(
  558. decorator, expectedCommandSequenceCalls) {
  559. var interval = 500;
  560. var mockClock = new goog.testing.MockClock(true);
  561. for (var commandSequence in expectedCommandSequenceCalls) {
  562. var recordedFunction = goog.testing.recordFunction();
  563. var f = decorator(recordedFunction, interval);
  564. for (var i = 0; i < commandSequence.length; ++i) {
  565. switch (commandSequence[i]) {
  566. case 'f':
  567. f();
  568. break;
  569. case 'w':
  570. mockClock.tick(interval);
  571. break;
  572. }
  573. }
  574. var expectedCalls = expectedCommandSequenceCalls[commandSequence];
  575. assertEquals(
  576. 'Expected ' + expectedCalls + ' calls for command sequence "' +
  577. commandSequence + '" (' +
  578. goog.array
  579. .map(
  580. commandSequence,
  581. function(command) {
  582. switch (command) {
  583. case 'f':
  584. return 'fire';
  585. case 'w':
  586. return 'wait';
  587. }
  588. })
  589. .join(' -> ') +
  590. ')',
  591. expectedCalls, recordedFunction.getCallCount());
  592. }
  593. mockClock.uninstall();
  594. }