UNPKG

6.84 kBJavaScriptView Raw
1/**
2 * repeated.mocha.js
3 *
4 * Test cases where advised methods are invoked multiple times to ensure
5 * advice implementation does not have state-changing affects across
6 * multiple invocations.
7 */
8
9var path = require('path')
10 , advisable = require(path.resolve(__dirname, '..', 'lib', 'advisable'))
11 , Target;
12
13Target = function (v) {
14 this.v = v;
15};
16
17// asyncFunc adds the passed argument to the stored value
18Target.prototype.asyncFunc = function (a, callback) {
19 process.nextTick(function () {
20 callback(null, a + this.v);
21 }.bind(this));
22};
23
24describe('advisable:repeated', function () {
25
26 describe('async', function () {
27
28 // Returns a callback that takes two arguments (err, result), checks
29 // for error, and asserts against the expected result
30 function checkResult(expected, done) {
31 return function (err, result) {
32 if (err) return done(err);
33
34 result.should.equal(expected);
35 done();
36 };
37 }
38
39 // Returns a callback that takes one argument (err), checks for error,
40 // and asserts the targets stored value against the expected result.
41 // checkVal should be invoked in the test suite's context>
42 function checkVal(expected, done) {
43 return function (err) {
44 if (err) return done(err);
45
46 this.target.v.should.equal(expected);
47 done();
48 }.bind(this);
49 }
50
51 // Repeats this.target.asyncFunc n times with a passed value of zero
52 function repeat(n, callback) {
53 var chain;
54
55 chain = function (err, result) {
56 if (--n === 0) {
57 callback(err, result);
58 }
59 else {
60 this.target.asyncFunc(0, chain);
61 }
62 }.bind(this);
63
64 this.target.asyncFunc(0, chain);
65 }
66
67 beforeEach(function () {
68 this.target = new Target(0);
69 advisable.async.call(this.target);
70 });
71
72 describe('.before', function () {
73
74 describe('when the mutate option is true', function () {
75
76 beforeEach(function () {
77 this.target.before('asyncFunc', function (a, callback) {
78 this.v++;
79 callback(null, a + this.v);
80 }, { mutate: true });
81 });
82
83 [ 1, 2, 3, 4, 5 ].forEach(function (n) {
84
85 // before: inc to n
86 // target: call back with n + n = n * 2
87
88 it('passes results for ' + n + ' invocations', function (done) {
89 repeat.bind(this)(n, checkResult(n * 2, done));
90 });
91
92 it('maintains state for ' + n + ' invocations', function (done) {
93 repeat.bind(this)(n, checkVal.bind(this)(n, done));
94 });
95
96 });
97
98 });
99
100 describe('when the mutate option is not passed', function () {
101
102 beforeEach(function () {
103 this.target.before('asyncFunc', function (a, callback) {
104 this.v++;
105 callback();
106 });
107 });
108
109 [ 1, 2, 3, 4, 5 ].forEach(function (n) {
110
111 // before: inc to n
112 // target: call back with 0 + n
113
114 it('passes results for ' + n + ' invocations', function (done) {
115 repeat.bind(this)(n, checkResult(n, done));
116 });
117
118 it('maintains state for ' + n + ' invocations', function (done) {
119 repeat.bind(this)(n, checkVal.bind(this)(n, done));
120 });
121
122 });
123
124 });
125
126 });
127
128 describe('.after', function () {
129
130 describe('when the mutate option is true', function () {
131
132 beforeEach(function () {
133 this.target.after('asyncFunc', function (result, callback) {
134 this.v++;
135 callback(null, result + this.v);
136 }, { mutate: true });
137 });
138
139 [ 1, 2, 3, 4, 5 ].forEach(function (n) {
140
141 // target: call back with (n - 1)
142 // after: inc to n, call back with (n + n - 1) = (n * 2 - 1)
143
144 it('passes results for ' + n + ' invocations', function (done) {
145 repeat.bind(this)(n, checkResult(n * 2 - 1, done));
146 });
147
148 it('maintains state for ' + n + ' invocations', function (done) {
149 repeat.bind(this)(n, checkVal.bind(this)(n, done));
150 });
151
152 });
153
154 });
155
156 describe('when the mutate option is not passed', function () {
157
158 beforeEach(function () {
159 this.target.after('asyncFunc', function (result, callback) {
160 this.v++;
161 callback();
162 });
163 });
164
165 [ 1, 2, 3, 4, 5 ].forEach(function (n) {
166
167 // target: call back with (n - 1)
168 // after: inc to n
169
170 it('passes results for ' + n + ' invocations', function (done) {
171 repeat.bind(this)(n, checkResult(n - 1, done));
172 });
173
174 it('maintains state for ' + n + ' invocations', function (done) {
175 repeat.bind(this)(n, checkVal.bind(this)(n, done));
176 });
177
178 });
179
180 });
181
182 });
183
184 describe('.around', function () {
185
186 describe('when the mutate option is true', function () {
187
188 beforeEach(function () {
189 this.target.around(
190 'asyncFunc'
191 , function (a, callback) {
192 this.v++;
193 callback(null, a + this.v);
194 }
195 , function (result, callback) {
196 this.v++;
197 callback(null, result + this.v);
198 }
199 , { mutate: true }
200 );
201 });
202
203 [ 1, 2, 3, 4, 5 ].forEach(function (n) {
204
205 // before: inc to (2 * n - 1), call back with 0 + (2 * n - 1)
206 // target: call back with 2 * (2 * n - 1)
207 // after: inc to (2 * n), call back with (2 * n) + (2 * (2 * n - 1))
208
209 it('passes results for ' + n + ' invocations', function (done) {
210 repeat.bind(this)(n, checkResult(6 * n - 2, done));
211 });
212
213 it('maintains state for ' + n + ' invocations', function (done) {
214 repeat.bind(this)(n, checkVal.bind(this)(2 * n, done));
215 });
216
217 });
218
219 });
220
221 describe('when the mutate option is not passed', function () {
222
223 beforeEach(function () {
224 this.target.around(
225 'asyncFunc'
226 , function (a, callback) {
227 this.v++;
228 callback();
229 }
230 , function (a, callback) {
231 this.v++;
232 callback();
233 }
234 );
235 });
236
237 [ 1, 2, 3, 4, 5 ].forEach(function (n) {
238
239 // before: inc to (2 * n - 1)
240 // target: call back with (0 + (2 * n - 1))
241 // after: inc to (2 * n)
242
243 it('passes results for ' + n + ' invocations', function (done) {
244 repeat.bind(this)(n, checkResult(2 * n - 1, done));
245 });
246
247 it('maintains state for ' + n + ' invocations', function (done) {
248 repeat.bind(this)(n, checkVal.bind(this)(2 * n, done));
249 });
250
251 });
252
253 });
254
255 });
256
257 });
258
259});