Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / chrome / test / data / webui / mock_controller.js
blob62587184f3eb488e94952e9917d8c2b6188c321a
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6  * Create a mock function that records function calls and validates against
7  * expectations.
8  * @constructor.
9  */
10 function MockMethod() {
11   var fn = function() {
12     var args = Array.prototype.slice.call(arguments);
13     var callbacks =
14         args.filter(function(arg) { return (typeof arg == 'function'); });
16     if (callbacks.length > 1) {
17       console.error('Only support mocking function with at most one callback.');
18       return;
19     }
21     fn.recordCall(args);
22     if (callbacks.length == 1) {
23       callbacks[0].apply(undefined, fn.callbackData);
24       return;
25     }
26     return fn.returnValue;
27   };
29   /**
30    * List of signatures for fucntion calls.
31    * @type {!Array.<!Array>}
32    * @private
33    */
34   fn.calls_ = [];
36   /**
37    * List of expected call signatures.
38    * @type {!Array.<!Array>}
39    * @private
40    */
41   fn.expectations_ = [];
43   /**
44    * Value returned from call to function.
45    * @type {*}
46    */
47   fn.returnValue = undefined;
49   /**
50    * List of arguments for callback function.
51    * @type {!Array.<!Array>}
52    */
53   fn.callbackData = [];
55   fn.__proto__ = MockMethod.prototype;
56   return fn;
59 MockMethod.prototype = {
60   /**
61    * Adds an expected call signature.
62    * @param {...}  var_args Expected arguments for the function call.
63    */
64   addExpectation: function() {
65     var args = Array.prototype.slice.call(arguments);
66     this.expectations_.push(args.filter(this.notFunction_));
67   },
69   /**
70    * Adds a call signature.
71    * @param {!Array} args.
72    */
73   recordCall: function(args) {
74     this.calls_.push(args.filter(this.notFunction_));
75   },
77   /**
78    * Verifies that the function is called the expected number of times and with
79    * the correct signature for each call.
80    */
81   verifyMock: function() {
82     var errorMessage =  'Number of method calls did not match expectation.';
83     if (this.functionName)
84       errorMessage = 'Error in ' + this.functionName + ':\n' + errorMessage;
85     assertEquals(this.expectations_.length,
86                  this.calls_.length,
87                  errorMessage);
88     for (var i = 0; i < this.expectations_.length; i++) {
89       this.validateCall(i, this.expectations_[i], this.calls_[i]);
90     }
91   },
93   /**
94    * Verifies that the observed function arguments match expectations.
95    * Override if strict equality is not required.
96    * @param {number} index Canonical index of the function call. Unused in the
97    *     base implementation, but provides context that may be useful for
98    *     overrides.
99    * @param {!Array} expected The expected arguments.
100    * @parma {!Array} observed The observed arguments.
101    */
102   validateCall: function(index, expected, observed) {
103     assertDeepEquals(expected, observed);
104   },
106   /**
107    * Test if arg is a function.
108    * @param {*} arg The argument to test.
109    * @return True if arg is not function type.
110    */
111   notFunction_: function(arg) {
112     return typeof arg != 'function';
113   }
117  * Controller for mocking methods. Tracks calls to mocked methods and verifies
118  * that call signatures match expectations.
119  * @constructor.
120  */
121 function MockController() {
122   /**
123    * Original functions implementations, which are restored when |reset| is
124    * called.
125    * @type {!Array.<!Object>}
126    * @private
127    */
128   this.overrides_ = [];
130   /**
131    * List of registered mocks.
132    * @type {!Array.<!MockMethod>}
133    * @private
134    */
135   this.mocks_ = [];
138 MockController.prototype = {
139   /**
140    * Creates a mock function.
141    * @param {Object=} opt_parent Optional parent object for the function.
142    * @param {string=} opt_functionName Optional name of the function being
143    *     mocked. If the parent and function name are both provided, the
144    *     mock is automatically substituted for the original and replaced on
145    *     reset.
146    */
147   createFunctionMock: function(opt_parent, opt_functionName) {
148     var fn = new MockMethod();
150     // Register mock.
151     if (opt_parent && opt_functionName) {
152       this.overrides_.push({
153         parent: opt_parent,
154         functionName: opt_functionName,
155         originalFunction: opt_parent[opt_functionName]
156       });
157       opt_parent[opt_functionName] = fn;
158       fn.functionName = opt_functionName;
159     }
160     this.mocks_.push(fn);
162     return fn;
163   },
165   /**
166    * Validates all mocked methods. An exception is thrown if the
167    * expected and actual calls to a mocked function to not align.
168    */
169   verifyMocks: function() {
170     for (var i = 0; i < this.mocks_.length; i++) {
171       this.mocks_[i].verifyMock();
172     }
173   },
175   /**
176    * Discard mocks reestoring default behavior.
177    */
178   reset: function() {
179     for (var i = 0; i < this.overrides_.length; i++) {
180       var override = this.overrides_[i];
181       override.parent[override.functionName] = override.originalFunction;
182     }
183   },