UNPKG

49.1 kBJavaScriptView Raw
1/**
2 * unit.mocha.js
3 *
4 * Unit tests with stubbing at every step in the call chain to assert
5 * expectations on both function call arguments and return values.
6 */
7
8var path = require('path')
9 , sinon = require('sinon')
10 , advisable = require(path.resolve(__dirname, '..', 'lib', 'advisable'));
11
12describe('advisable:unit', function () {
13
14 beforeEach(function () {
15 this.target = sinon.stub();
16 this.obj = {
17 target: this.target
18 };
19 });
20
21 describe('sync', function () {
22
23 beforeEach(function () {
24 advisable.sync.call(this.obj);
25 });
26
27 describe('when advisable methods are mixed in but not used', function () {
28
29 it('calls the target function with the passed arguments', function () {
30 this.obj.target(1, 2, 3);
31
32 this.target.should.have.been.calledWithExactly(1, 2, 3);
33 });
34
35 it('calls the target function with the correct context', function () {
36 this.obj.target(1, 2, 3);
37
38 this.target.lastCall.thisValue.should.equal(this.obj);
39 });
40
41 describe('when the target function throws', function () {
42
43 beforeEach(function () {
44 this.error = new Error('target-throws');
45 this.target.throws(this.error);
46 });
47
48 it('throws the errors', function () {
49 this.obj.target.should.throw(this.error);
50 });
51
52 });
53
54 describe('when the target function returns', function () {
55
56 beforeEach(function () {
57 this.retval = 'target-return';
58 this.target.returns(this.retval);
59 });
60
61 it('returns the target function return value', function () {
62 this.obj.target(1, 2, 3).should.equal(this.retval);
63 });
64
65 });
66
67 });
68
69 describe('.beforeSync', function () {
70
71 describe('when the mutate option is true', function () {
72
73 beforeEach(function () {
74 this.before = sinon.stub();
75 this.obj.beforeSync('target', this.before, { mutate: true });
76 });
77
78 describe('when the target method is invoked', function () {
79
80 it('invokes before advice with the passed arguments', function () {
81 this.obj.target(1, 2, 3);
82
83 this.before.should.have.been.calledWithExactly(1, 2, 3);
84 });
85
86 it('invokes before advice in the target object context', function () {
87 this.obj.target(1, 2, 3);
88
89 this.before.lastCall.thisValue.should.equal(this.obj);
90 });
91
92 describe('when the before advice throws', function () {
93
94 beforeEach(function () {
95 this.error = 'beforeSync-mutate-before-throws';
96 this.before.throws(this.error);
97 });
98
99 it('throws the error', function () {
100 this.obj.target.should.throw(this.error);
101 });
102
103 it('does not call the target method', function () {
104 try { this.obj.target(); } catch (e) {}
105
106 this.target.should.not.have.been.called;
107 });
108
109 });
110
111 describe('when the before advice returns', function () {
112
113 beforeEach(function () {
114 this.retval = [
115 'beforeSync-mutate-before-return-one'
116 , 'beforeSync-mutate-before-return-two'
117 ];
118 this.before.returns(this.retval);
119 });
120
121 it('invokes the target with the returned arguments', function () {
122 this.obj.target(1, 2, 3);
123
124 this.target.should.have.been.calledWithExactly(
125 this.retval[0]
126 , this.retval[1]
127 );
128 });
129
130 it('invokes the target in the target object context', function () {
131 this.obj.target(1, 2, 3);
132
133 this.target.lastCall.thisValue.should.equal(this.obj);
134 });
135
136 describe('when the target method throws', function () {
137
138 beforeEach(function () {
139 this.error = new Error('beforeSync-mutate-target-throws');
140 this.target.throws(this.error);
141 });
142
143 it('throws the error', function () {
144 this.obj.target.should.throw(this.error);
145 });
146
147 });
148
149 describe('when the target method returns', function () {
150
151 beforeEach(function () {
152 this.retval = 'beforeSync-mutate-target-return';
153 this.target.returns(this.retval);
154 });
155
156 it('returns the target method return value', function () {
157 this.obj.target(1, 2, 3).should.equal(this.retval);
158 });
159
160 });
161
162 });
163
164 });
165
166 });
167
168 describe('when the mutate option is not passed', function () {
169
170 beforeEach(function () {
171 this.before = sinon.stub();
172 this.obj.beforeSync('target', this.before);
173 });
174
175 describe('when the target method is invoked', function () {
176
177 it('invokes before advice with the passed arguments', function () {
178 this.obj.target(1, 2, 3);
179
180 this.before.should.have.been.calledWithExactly(1, 2, 3);
181 });
182
183 it('invokes before advice in the target object context', function () {
184 this.obj.target(1, 2, 3);
185
186 this.before.lastCall.thisValue.should.equal(this.obj);
187 });
188
189 describe('when the before advice throws', function () {
190
191 beforeEach(function () {
192 this.error = 'beforeSync-before-throws';
193 this.before.throws(this.error);
194 });
195
196 it('throws the error', function () {
197 this.obj.target.should.throw(this.error);
198 });
199
200 it('does not call the target method', function () {
201 try { this.obj.target(); } catch (e) {}
202
203 this.target.should.not.have.been.called;
204 });
205
206 });
207
208 describe('when the before advice returns', function () {
209
210 beforeEach(function () {
211 this.retval = [
212 'beforeSync-before-return-one'
213 , 'beforeSync-before-return-two'
214 ];
215 this.before.returns(this.retval);
216 });
217
218 it('invokes the target with the original arguments', function () {
219 this.obj.target(1, 2, 3);
220
221 this.target.should.have.been.calledWithExactly(1, 2, 3);
222 });
223
224 it('invokes the target in the target object context', function () {
225 this.obj.target(1, 2, 3);
226
227 this.target.lastCall.thisValue.should.equal(this.obj);
228 });
229
230 describe('when the target method throws', function () {
231
232 beforeEach(function () {
233 this.error = new Error('beforeSync-target-throws');
234 this.target.throws(this.error);
235 });
236
237 it('throws the error', function () {
238 this.obj.target.should.throw(this.error);
239 });
240
241 });
242
243 describe('when the target method returns', function () {
244
245 beforeEach(function () {
246 this.retval = 'beforeSync-target-return';
247 this.target.returns(this.retval);
248 });
249
250 it('returns the target method return value', function () {
251 this.obj.target(1, 2, 3).should.equal(this.retval);
252 });
253
254 });
255
256 });
257
258 });
259
260 });
261
262 });
263
264 describe('.afterSync', function () {
265
266 describe('when the mutate option is true', function () {
267
268 beforeEach(function () {
269 this.after = sinon.stub();
270 this.obj.afterSync('target', this.after, { mutate: true });
271 });
272
273 describe('when the target method is invoked', function () {
274
275 it('invokes the target with the passed arguments', function () {
276 this.obj.target(1, 2, 3);
277
278 this.target.should.have.been.calledWithExactly(1, 2, 3);
279 });
280
281 it('invokes the target in the target object context', function () {
282 this.obj.target(1, 2, 3);
283
284 this.target.lastCall.thisValue.should.equal(this.obj);
285 });
286
287 describe('when the target method throws', function () {
288
289 beforeEach(function () {
290 this.error = 'afterSync-mutate-target-throws';
291 this.target.throws(this.error);
292 });
293
294 it('throws the error', function () {
295 this.obj.target.should.throw(this.error);
296 });
297
298 it('does not call the after advice', function () {
299 try { this.obj.target(); } catch (e) {}
300
301 this.after.should.not.have.been.called;
302 });
303
304 });
305
306 describe('when the target method returns', function () {
307
308 beforeEach(function () {
309 this.retval = 'afterSync-mutate-target-return';
310 this.target.returns(this.retval);
311 });
312
313 it('invokes the after advice with the return value', function () {
314 this.obj.target(1, 2, 3);
315
316 this.after.should.have.been.calledWithExactly(this.retval);
317 });
318
319 it('invokes the advice in the target object context', function () {
320 this.obj.target(1, 2, 3);
321
322 this.after.lastCall.thisValue.should.equal(this.obj);
323 });
324
325 describe('when the advising method throws', function () {
326
327 beforeEach(function () {
328 this.error = new Error('afterSync-mutate-after-throws');
329 this.after.throws(this.error);
330 });
331
332 it('throws the error', function () {
333 this.obj.target.should.throw(this.error);
334 });
335
336 });
337
338 describe('when the advising method returns', function () {
339
340 beforeEach(function () {
341 this.retval = 'afterSync-mutate-target-return';
342 this.after.returns(this.retval);
343 });
344
345 it('returns the advising method return value', function () {
346 this.obj.target(1, 2, 3).should.equal(this.retval);
347 });
348
349 });
350
351 });
352
353 });
354
355 });
356
357 describe('when the mutate option is not passed', function () {
358
359 beforeEach(function () {
360 this.after = sinon.stub();
361 this.obj.afterSync('target', this.after);
362 });
363
364 describe('when the target method is invoked', function () {
365
366 it('invokes the target with the passed arguments', function () {
367 this.obj.target(1, 2, 3);
368
369 this.target.should.have.been.calledWithExactly(1, 2, 3);
370 });
371
372 it('invokes the target in the target object context', function () {
373 this.obj.target(1, 2, 3);
374
375 this.target.lastCall.thisValue.should.equal(this.obj);
376 });
377
378 describe('when the target method throws', function () {
379
380 beforeEach(function () {
381 this.error = 'afterSync-mutate-target-throws';
382 this.target.throws(this.error);
383 });
384
385 it('throws the error', function () {
386 this.obj.target.should.throw(this.error);
387 });
388
389 it('does not call the advising method', function () {
390 try { this.obj.target(); } catch (e) {}
391
392 this.after.should.not.have.been.called;
393 });
394
395 });
396
397 describe('when the target method returns', function () {
398
399 beforeEach(function () {
400 this.retval = 'afterSync-target-return';
401 this.target.returns(this.retval);
402 });
403
404 it('invokes the advice with the original arguments', function () {
405 this.obj.target(1, 2, 3);
406
407 this.after.should.have.been.calledWithExactly(1, 2, 3);
408 });
409
410 it('invokes the advice in the target object context', function () {
411 this.obj.target(1, 2, 3);
412
413 this.after.lastCall.thisValue.should.equal(this.obj);
414 });
415
416 describe('when the advising method throws', function () {
417
418 beforeEach(function () {
419 this.error = new Error('afterSync-after-throws');
420 this.after.throws(this.error);
421 });
422
423 it('throws the error', function () {
424 this.obj.target.should.throw(this.error);
425 });
426
427 });
428
429 describe('when the advising method returns', function () {
430
431 beforeEach(function () {
432 this.afterRetval = 'afterSync-after-return';
433 this.after.returns(this.afterRetval);
434 });
435
436 it('returns the advising method return value', function () {
437 this.obj.target(1, 2, 3).should.equal(this.retval);
438 });
439
440 });
441
442 });
443
444 });
445
446 });
447
448 });
449
450 describe('.aroundSync', function () {
451
452 describe('when the mutate option is true', function () {
453
454 beforeEach(function () {
455 this.before = sinon.stub();
456 this.after = sinon.stub();
457 this.obj.aroundSync(
458 'target'
459 , this.before
460 , this.after
461 , { mutate: true });
462 });
463
464 describe('when the target method is invoked', function () {
465
466 it('invokes before advice with the passed arguments', function () {
467 this.obj.target(1, 2, 3);
468
469 this.before.should.have.been.calledWithExactly(1, 2, 3);
470 });
471
472 it('invokes before advice in the target object contest', function () {
473 this.obj.target(1, 2, 3);
474
475 this.before.lastCall.thisValue.should.equal(this.obj);
476 });
477
478 describe('when the before advice throws', function () {
479
480 beforeEach(function () {
481 this.error = 'aroundSync-mutate-before-throws';
482 this.before.throws(this.error);
483 });
484
485 it('throws the error', function () {
486 this.obj.target.should.throw(this.error);
487 });
488
489 it('does not call the target method', function () {
490 try { this.obj.target(); } catch (e) {}
491
492 this.target.should.not.have.been.called;
493 });
494
495 it('does not call the after advice', function () {
496 try { this.obj.target(); } catch (e) {}
497
498 this.after.should.not.have.been.called;
499 });
500
501 });
502
503 describe('when the before advice returns', function () {
504
505 beforeEach(function () {
506 this.retval = [
507 'aroundSync-mutate-before-return-one'
508 , 'aroundSync-mutate-before-return-two'
509 ];
510 this.before.returns(this.retval);
511 });
512
513 it('invokes the target with the returned arguments', function () {
514 this.obj.target(1, 2, 3);
515
516 this.target.should.have.been.calledWithExactly(
517 this.retval[0]
518 , this.retval[1]
519 );
520 });
521
522 it('invokes the target in the target context', function () {
523 this.obj.target(1, 2, 3);
524
525 this.target.lastCall.thisValue.should.equal(this.obj);
526 });
527
528 describe('when the target method throws', function () {
529
530 beforeEach(function () {
531 this.error = new Error('aroundSync-mutate-target-throws');
532 this.target.throws(this.error);
533 });
534
535 it('throws the error', function () {
536 this.obj.target.should.throw(this.error);
537 });
538
539 it('does not call the after advice', function () {
540 try { this.obj.target(); } catch (e) {}
541
542 this.after.should.not.have.been.called;
543 });
544
545 });
546
547 describe('when the target method returns', function () {
548
549 beforeEach(function () {
550 this.retval = 'aroundSync-mutate-target-return';
551 this.target.returns(this.retval);
552 });
553
554 it('invokes after advice with target return value', function () {
555 this.obj.target(1, 2, 3);
556
557 this.after.should.have.been.calledWithExactly(this.retval);
558 });
559
560 it('invokes the advice in the target context', function () {
561 this.obj.target(1, 2, 3);
562
563 this.after.lastCall.thisValue.should.equal(this.obj);
564 });
565
566 describe('when the after advice throws', function () {
567
568 beforeEach(function () {
569 this.error = new Error('aroundSync-mutate-after-throws');
570 this.after.throws(this.error);
571 });
572
573 it('throws the error', function () {
574 this.obj.target.should.throw(this.error);
575 });
576
577 });
578
579 describe('when the after advice returns', function () {
580
581 beforeEach(function () {
582 this.retval = 'aroundSync-mutate-after-return';
583 this.after.returns(this.retval);
584 });
585
586 it('returns the after advice return value', function () {
587 this.obj.target(1, 2, 3).should.equal(this.retval);
588 });
589
590 });
591
592 });
593
594 });
595
596 });
597
598 });
599
600 describe('when the mutate option is not passed', function () {
601
602 beforeEach(function () {
603 this.before = sinon.stub();
604 this.after = sinon.stub();
605 this.obj.aroundSync('target', this.before, this.after);
606 });
607
608 describe('when the target method is invoked', function () {
609
610 it('invokes before advice with the passed arguments', function () {
611 this.obj.target(1, 2, 3);
612
613 this.before.should.have.been.calledWithExactly(1, 2, 3);
614 });
615
616 it('invokes before advice in the target context', function () {
617 this.obj.target(1, 2, 3);
618
619 this.before.lastCall.thisValue.should.equal(this.obj);
620 });
621
622 describe('when the before advice throws', function () {
623
624 beforeEach(function () {
625 this.error = 'aroundSync-before-throws';
626 this.before.throws(this.error);
627 });
628
629 it('throws the error', function () {
630 this.obj.target.should.throw(this.error);
631 });
632
633 it('does not call the target method', function () {
634 try { this.obj.target(); } catch (e) {}
635
636 this.target.should.not.have.been.called;
637 });
638
639 it('does not call the after advice', function () {
640 try { this.obj.target(); } catch (e) {}
641
642 this.after.should.not.have.been.called;
643 });
644
645 });
646
647 describe('when the before advice returns', function () {
648
649 beforeEach(function () {
650 this.retval = [
651 'aroundSync-before-return-one'
652 , 'aroundSync-before-return-two'
653 ];
654 this.before.returns(this.retval);
655 });
656
657 it('invokes the target with the original arguments', function () {
658 this.obj.target(1, 2, 3);
659
660 this.target.should.have.been.calledWithExactly(1, 2, 3);
661 });
662
663 it('invokes the target in the target context', function () {
664 this.obj.target(1, 2, 3);
665
666 this.target.lastCall.thisValue.should.equal(this.obj);
667 });
668
669 describe('when the target method throws', function () {
670
671 beforeEach(function () {
672 this.error = new Error('aroundSync-target-throws');
673 this.target.throws(this.error);
674 });
675
676 it('throws the error', function () {
677 this.obj.target.should.throw(this.error);
678 });
679
680 it('does not call the after advice', function () {
681 try { this.obj.target(); } catch (e) {}
682
683 this.after.should.not.have.been.called;
684 });
685
686 });
687
688 describe('when the target method returns', function () {
689
690 beforeEach(function () {
691 this.retval = 'aroundSync-target-return';
692 this.target.returns(this.retval);
693 });
694
695 it('invokes after advice with original arguments', function () {
696 this.obj.target(1, 2, 3);
697
698 this.after.should.have.been.calledWithExactly(1, 2, 3);
699 });
700
701 it('invokes after advice in the target context', function () {
702 this.obj.target(1, 2, 3);
703
704 this.after.lastCall.thisValue.should.equal(this.obj);
705 });
706
707 describe('when the after advice throws', function () {
708
709 beforeEach(function () {
710 this.error = new Error('aroundSync-after-throws');
711 this.after.throws(this.error);
712 });
713
714 it('throws the error', function () {
715 this.obj.target.should.throw(this.error);
716 });
717
718 });
719
720 describe('when the after advice returns', function () {
721
722 beforeEach(function () {
723 this.afterRetval = 'aroundSync-after-return';
724 this.after.returns(this.retval);
725 });
726
727 it('returns the target method return value', function () {
728 this.obj.target(1, 2, 3).should.equal(this.retval);
729 });
730
731 });
732
733 });
734
735 });
736
737 });
738
739 });
740
741 });
742
743 });
744
745 describe('async', function () {
746
747 beforeEach(function () {
748 advisable.async.call(this.obj);
749 });
750
751 describe('when advisable methods are mixed in but not used', function () {
752
753 describe('when the target function is invoked', function () {
754
755 it('calls the target function with the passed arguments', function () {
756 var callback = function () {};
757
758 this.obj.target(1, 2, 3, callback);
759
760 this.target.should.have.been.calledWithExactly(1, 2, 3, callback);
761 });
762
763 it('calls the target function in the target context', function () {
764 this.obj.target(1, 2, 3, function () {});
765
766 this.target.lastCall.thisValue.should.equal(this.obj);
767 });
768
769 describe('when the target function errors', function () {
770
771 beforeEach(function () {
772 this.error = new Error('target-errors');
773 this.target.yields(this.error);
774 });
775
776 it('calls back with the error', function (done) {
777 this.obj.target(1, 2, 3, function (err, result) {
778 err.should.equal(this.error);
779 done();
780 }.bind(this));
781 });
782
783 });
784
785 describe('when the target function succeeds', function () {
786
787 beforeEach(function () {
788 this.retval = 'target-result';
789 this.target.yields(null, this.retval);
790 });
791
792 it('calls back with the results', function (done) {
793 this.obj.target(1, 2, 3, function (err, result) {
794 result.should.equal(this.retval);
795 done();
796 }.bind(this));
797 });
798
799 });
800
801 });
802
803 });
804
805 describe('.before', function () {
806
807 describe('when the mutate option is true', function () {
808
809 beforeEach(function () {
810 this.before = sinon.stub();
811 this.obj.before('target', this.before, { mutate: true });
812 });
813
814 describe('when the target method is invoked', function () {
815
816 it('invokes before advice with the passed arguments', function () {
817 this.obj.target(1, 2, 3, function () {});
818
819 this.before.should.have.been.calledWithExactly(
820 1
821 , 2
822 , 3
823 , sinon.match.func
824 );
825 });
826
827 it('invokes before advice in the target context', function () {
828 this.obj.target(1, 2, 3, function () {});
829
830 this.before.lastCall.thisValue.should.equal(this.obj);
831 });
832
833 describe('when the before advice errors', function () {
834
835 beforeEach(function () {
836 this.error = new Error('before-mutate-before-errors');
837 this.before.yields(this.error);
838 });
839
840 it('calls back with the error', function (done) {
841 this.obj.target(1, 2, 3, function (err, result) {
842 err.should.equal(this.error);
843 done();
844 }.bind(this));
845 });
846
847 it('does not call the target method', function (done) {
848 this.obj.target(1, 2, 3, function (err, result) {
849 this.target.should.not.have.been.called;
850 done();
851 }.bind(this));
852 });
853
854 });
855
856 describe('when the before advice succeeds', function () {
857
858 beforeEach(function () {
859 this.resultOne = 'before-mutate-before-result-one';
860 this.resultTwo = 'before-mutate-before-result-two';
861 this.resultThree = 'before-mutate-before-result-three';
862 this.before.yields(
863 null
864 , this.resultOne
865 , this.resultTwo
866 , this.resultThree
867 );
868 });
869
870 it('invokes the target with the advice results', function () {
871 this.obj.target(1, 2, 3, function () {});
872
873 this.target.should.have.been.calledWithExactly(
874 this.resultOne
875 , this.resultTwo
876 , this.resultThree
877 , sinon.match.func
878 );
879 });
880
881 it('invokes the target in the target context', function () {
882 this.obj.target(1, 2, 3, function () {});
883
884 this.target.lastCall.thisValue.should.equal(this.obj);
885 });
886
887 describe('when the target method errors', function () {
888
889 beforeEach(function () {
890 this.error = new Error('before-mutate-target-errors');
891 this.target.yields(this.error);
892 });
893
894 it('calls back with the error', function (done) {
895 this.obj.target(1, 2, 3, function (err, result) {
896 err.should.equal(this.error);
897 done();
898 }.bind(this));
899 });
900
901 });
902
903 describe('when the target method succeeds', function () {
904
905 beforeEach(function () {
906 this.result = 'before-mutate-target-result';
907 this.target.yields(null, this.result);
908 });
909
910 it('calls back with the target method results', function (done) {
911 this.obj.target(1, 2, 3, function (err, result) {
912 result.should.equal(this.result);
913 done();
914 }.bind(this));
915 });
916
917 });
918
919 });
920
921 });
922
923 });
924
925 describe('when the mutate option is not passed', function () {
926
927 beforeEach(function () {
928 this.before = sinon.stub();
929 this.obj.before('target', this.before);
930 });
931
932 describe('when the target method is invoked', function () {
933
934 it('invokes before advice with the passed arguments', function () {
935 this.obj.target(1, 2, 3, function () {});
936
937 this.before.should.have.been.calledWithExactly(
938 1
939 , 2
940 , 3
941 , sinon.match.func
942 );
943 });
944
945 it('invokes before advice in the target context', function () {
946 this.obj.target(1, 2, 3, function () {});
947
948 this.before.lastCall.thisValue.should.equal(this.obj);
949 });
950
951 describe('when the before advice errors', function () {
952
953 beforeEach(function () {
954 this.error = 'before-before-errors';
955 this.before.yields(this.error);
956 });
957
958 it('calls back with the error', function (done) {
959 this.obj.target(1, 2, 3, function (err, result) {
960 err.should.equal(this.error);
961 done();
962 }.bind(this));
963 });
964
965 });
966
967 describe('when the before advice succeeds', function () {
968
969 beforeEach(function () {
970 this.resultOne = 'before-before-result-one';
971 this.resultTwo = 'before-before-result-two';
972 this.resultThree = 'before-before-result-three';
973 this.before.yields(
974 null
975 , this.resultOne
976 , this.resultTwo
977 , this.resultThree
978 );
979 });
980
981 it('invokes the target with the original arguments', function () {
982 this.obj.target(1, 2, 3, function () {});
983
984 this.target.should.have.been.calledWithExactly(
985 1
986 , 2
987 , 3
988 , sinon.match.func
989 );
990 });
991
992 it('invokes the target in the target context', function () {
993 this.obj.target(1, 2, 3, function () {});
994
995 this.target.lastCall.thisValue.should.equal(this.obj);
996 });
997
998 describe('when the target method errors', function () {
999
1000 beforeEach(function () {
1001 this.error = new Error('before-target-errors');
1002 this.target.yields(this.error);
1003 });
1004
1005 it('calls back with the error', function (done) {
1006 this.obj.target(1, 2, 3, function (err, result) {
1007 err.should.equal(this.error);
1008 done();
1009 }.bind(this));
1010 });
1011
1012 });
1013
1014 describe('when the target method succeeds', function () {
1015
1016 beforeEach(function () {
1017 this.result = 'before-target-result';
1018 this.target.yields(null, this.result);
1019 });
1020
1021 it('calls back with the target method results', function (done) {
1022 this.obj.target(1, 2, 3, function (err, result) {
1023 result.should.equal(this.result);
1024 done();
1025 }.bind(this));
1026 });
1027
1028 });
1029
1030 });
1031
1032 });
1033
1034 });
1035
1036 });
1037
1038 describe('.after', function () {
1039
1040 describe('when the mutate option is true', function () {
1041
1042 beforeEach(function () {
1043 this.after = sinon.stub();
1044 this.obj.after('target', this.after, { mutate: true });
1045 });
1046
1047 describe('when the target method is invoked', function () {
1048
1049 it('invokes the target with the passed arguments', function () {
1050 this.obj.target(1, 2, 3, function () {});
1051
1052 this.target.should.have.been.calledWithExactly(
1053 1
1054 , 2
1055 , 3
1056 , sinon.match.func
1057 );
1058 });
1059
1060 it('invokes the target method in the target context', function () {
1061 this.obj.target(1, 2, 3, function () {});
1062
1063 this.target.lastCall.thisValue.should.equal(this.obj);
1064 });
1065
1066 describe('when the target method errors', function () {
1067
1068 beforeEach(function () {
1069 this.error = 'after-mutate-target-errors';
1070 this.target.yields(this.error);
1071 });
1072
1073 it('calls back with the error', function (done) {
1074 this.obj.target(1, 2, 3, function (err, result) {
1075 err.should.equal(this.error);
1076 done();
1077 }.bind(this));
1078 });
1079
1080 it('does not call the after advice', function (done) {
1081 this.obj.target(1, 2, 3, function (err, result) {
1082 this.after.should.not.have.been.called;
1083 done();
1084 }.bind(this));
1085 });
1086
1087 });
1088
1089 describe('when the target method succeeds', function () {
1090
1091 beforeEach(function () {
1092 this.result = 'after-mutate-target-result';
1093 this.target.yields(null, this.result);
1094 });
1095
1096 it('invokes after advice with the target results', function () {
1097 this.obj.target(1, 2, 3, function () {});
1098
1099 this.after.should.have.been.calledWithExactly(
1100 this.result
1101 , sinon.match.func
1102 );
1103 });
1104
1105 it('invokes after advice in the target context', function () {
1106 this.obj.target(1, 2, 3, function () {});
1107
1108 this.after.lastCall.thisValue.should.equal(this.obj);
1109 });
1110
1111 describe('when the advising method errors', function () {
1112
1113 beforeEach(function () {
1114 this.error = new Error('after-mutate-after-errors');
1115 this.target.yields(this.error);
1116 });
1117
1118 it('calls back with the error', function (done) {
1119 this.obj.target(1, 2, 3, function (err, result) {
1120 err.should.equal(this.error);
1121 done();
1122 }.bind(this));
1123 });
1124
1125 });
1126
1127 describe('when the advising method succeeds', function () {
1128
1129 beforeEach(function () {
1130 this.afterResult = 'after-mutate-after-result';
1131 this.after.yields(null, this.afterResult);
1132 });
1133
1134 it('calls back with the the advice results', function (done) {
1135 this.obj.target(1, 2, 3, function (err, result) {
1136 result.should.equal(this.afterResult);
1137 done();
1138 }.bind(this));
1139 });
1140
1141 });
1142
1143 });
1144
1145 });
1146
1147 });
1148
1149 describe('when the mutate option is not passed', function () {
1150
1151 beforeEach(function () {
1152 this.after = sinon.stub();
1153 this.obj.after('target', this.after);
1154 });
1155
1156 describe('when the target method is invoked', function () {
1157
1158 it('invokes the target method with the passed arguments', function () {
1159 this.obj.target(1, 2, 3, function () {});
1160
1161 this.target.should.have.been.calledWithExactly(
1162 1
1163 , 2
1164 , 3
1165 , sinon.match.func
1166 );
1167 });
1168
1169 it('invokes the target method in the target context', function () {
1170 this.obj.target(1, 2, 3, function () {});
1171
1172 this.target.lastCall.thisValue.should.equal(this.obj);
1173 });
1174
1175 describe('when the target method errors', function () {
1176
1177 beforeEach(function () {
1178 this.error = 'after-target-errors';
1179 this.target.yields(this.error);
1180 });
1181
1182 it('calls back with the error', function (done) {
1183 this.obj.target(1, 2, 3, function (err, result) {
1184 err.should.equal(this.error);
1185 done();
1186 }.bind(this));
1187 });
1188
1189 it('does not call the after advice', function (done) {
1190 this.obj.target(1, 2, 3, function (err, result) {
1191 this.after.should.not.have.been.called;
1192 done();
1193 }.bind(this));
1194 });
1195
1196 });
1197
1198 describe('when the target method succeeds', function () {
1199
1200 beforeEach(function () {
1201 this.result = 'after-target-result';
1202 this.target.yields(null, this.result);
1203 });
1204
1205 it('invokes the advice with the original arguments', function () {
1206 this.obj.target(1, 2, 3, function () {});
1207
1208 this.after.should.have.been.calledWithExactly(
1209 1
1210 , 2
1211 , 3
1212 , sinon.match.func
1213 );
1214 });
1215
1216 it('invokes after advice in the target context', function () {
1217 this.obj.target(1, 2, 3, function () {});
1218
1219 this.after.lastCall.thisValue.should.equal(this.obj);
1220 });
1221
1222 describe('when the advising method errors', function () {
1223
1224 beforeEach(function () {
1225 this.error = new Error('after-after-errors');
1226 this.target.yields(this.error);
1227 });
1228
1229 it('calls back with the error', function (done) {
1230 this.obj.target(1, 2, 3, function (err, result) {
1231 err.should.equal(this.error);
1232 done();
1233 }.bind(this));
1234 });
1235
1236 });
1237
1238 describe('when the advising method succeeds', function () {
1239
1240 beforeEach(function () {
1241 this.afterResult = 'after-after-result';
1242 this.after.yields(null, this.afterResult);
1243 });
1244
1245 it('calls back with the target method results', function (done) {
1246 this.obj.target(1, 2, 3, function (err, result) {
1247 result.should.equal(this.result);
1248 done();
1249 }.bind(this));
1250 });
1251
1252 });
1253
1254 });
1255
1256 });
1257
1258 });
1259
1260 });
1261
1262 describe('.around', function () {
1263
1264 describe('when the mutate option is true', function () {
1265
1266 beforeEach(function () {
1267 this.before = sinon.stub();
1268 this.after = sinon.stub();
1269 this.obj.around('target', this.before, this.after, { mutate: true });
1270 });
1271
1272 describe('when the target method is invoked', function () {
1273
1274 it('invokes before advice with the passed arguments', function () {
1275 this.obj.target(1, 2, 3, function () {});
1276
1277 this.before.should.have.been.calledWithExactly(
1278 1
1279 , 2
1280 , 3
1281 , sinon.match.func
1282 );
1283 });
1284
1285 it('invokes before advice in the target context', function () {
1286 this.obj.target(1, 2, 3, function () {});
1287
1288 this.before.lastCall.thisValue.should.equal(this.obj);
1289 });
1290
1291 describe('when the before advice errors', function () {
1292
1293 beforeEach(function () {
1294 this.error = new Error('around-mutate-before-errors');
1295 this.before.yields(this.error);
1296 });
1297
1298 it('calls back with the error', function (done) {
1299 this.obj.target(1, 2, 3, function (err, result) {
1300 err.should.equal(this.error);
1301 done();
1302 }.bind(this));
1303 });
1304
1305 it('does not call the target method', function (done) {
1306 this.obj.target(1, 2, 3, function (err, result) {
1307 this.target.should.not.have.been.called;
1308 done();
1309 }.bind(this));
1310 });
1311
1312 it('does not call the after advice', function (done) {
1313 this.obj.target(1, 2, 3, function (err, result) {
1314 this.after.should.not.have.been.called;
1315 done();
1316 }.bind(this));
1317 });
1318
1319 });
1320
1321 describe('when the before advice succeeds', function () {
1322
1323 beforeEach(function () {
1324 this.resultOne = 'around-before-mutate-result-one';
1325 this.resultTwo = 'around-before-mutate-result-two';
1326 this.resultThree = 'around-before-mutate-result-three';
1327 this.before.yields(
1328 null
1329 , this.resultOne
1330 , this.resultTwo
1331 , this.resultThree
1332 );
1333 });
1334
1335 it('invokes the target with the before results', function () {
1336 this.obj.target(1, 2, 3, function () {});
1337
1338 this.target.should.have.been.calledWithExactly(
1339 this.resultOne
1340 , this.resultTwo
1341 , this.resultThree
1342 , sinon.match.func
1343 );
1344 });
1345
1346 it('invokes the target in the target context', function () {
1347 this.obj.target(1, 2, 3, function () {});
1348
1349 this.target.lastCall.thisValue.should.equal(this.obj);
1350 });
1351
1352 describe('when the target method errors', function () {
1353
1354 beforeEach(function () {
1355 this.error = new Error('around-mutate-target-errors');
1356 this.target.yields(this.error);
1357 });
1358
1359 it('calls back with the error', function (done) {
1360 this.obj.target(1, 2, 3, function (err, result) {
1361 err.should.equal(this.error);
1362 done();
1363 }.bind(this));
1364 });
1365
1366 it('does not call the after advice', function (done) {
1367 this.obj.target(1, 2, 3, function (err, result) {
1368 this.after.should.not.have.been.called;
1369 done();
1370 }.bind(this));
1371 });
1372
1373 });
1374
1375 describe('when the target method succeeds', function () {
1376
1377 beforeEach(function () {
1378 this.result = 'around-mutate-target-result';
1379 this.target.yields(null, this.result);
1380 });
1381
1382 it('invokes the after advice with target results', function () {
1383 this.obj.target(1, 2, 3, function () {});
1384
1385 this.after.should.have.been.calledWithExactly(
1386 this.result
1387 , sinon.match.func
1388 );
1389 });
1390
1391 it('invokes after advice in the target context', function () {
1392 this.obj.target(1, 2, 3, function () {});
1393
1394 this.after.lastCall.thisValue.should.equal(this.obj);
1395 });
1396
1397 describe('when the after advice errors', function () {
1398
1399 beforeEach(function () {
1400 this.error = new Error('around-mutate-after-errors');
1401 this.after.yields(this.error);
1402 });
1403
1404 it('calls back with the error', function (done) {
1405 this.obj.target(1, 2, 3, function (err, result) {
1406 err.should.equal(this.error);
1407 done();
1408 }.bind(this));
1409 });
1410
1411 });
1412
1413 describe('when the after advice succeeds', function () {
1414
1415 beforeEach(function () {
1416 this.afterResults = [
1417 'around-mutate-after-result-one'
1418 , 'around-mutate-after-result-two'
1419 ];
1420 this.after.yields(
1421 null
1422 , this.afterResults[0]
1423 , this.afterResults[1]
1424 );
1425 });
1426
1427 it('calls back with the after results', function (done) {
1428 this.obj.target(1, 2, 3, function (err, r1, r2) {
1429 [ r1, r2 ].should.deep.equal(this.afterResults);
1430 done();
1431 }.bind(this));
1432 });
1433
1434 });
1435
1436 });
1437
1438 });
1439
1440 });
1441
1442 });
1443
1444 describe('when the mutate option is not passed', function () {
1445
1446 beforeEach(function () {
1447 this.before = sinon.stub();
1448 this.after = sinon.stub();
1449 this.obj.around('target', this.before, this.after);
1450 });
1451
1452 describe('when the target method is invoked', function () {
1453
1454 it('invokes before advice with the passed arguments', function () {
1455 this.obj.target(1, 2, 3, function () {});
1456
1457 this.before.should.have.been.calledWithExactly(
1458 1
1459 , 2
1460 , 3
1461 , sinon.match.func
1462 );
1463 });
1464
1465 it('invokes before advice in the target context', function () {
1466 this.obj.target(1, 2, 3, function () {});
1467
1468 this.before.lastCall.thisValue.should.equal(this.obj);
1469 });
1470
1471 describe('when the before advice errors', function () {
1472
1473 beforeEach(function () {
1474 this.error = new Error('around-before-errors');
1475 this.before.yields(this.error);
1476 });
1477
1478 it('calls back with the error', function (done) {
1479 this.obj.target(1, 2, 3, function (err, result) {
1480 err.should.equal(this.error);
1481 done();
1482 }.bind(this));
1483 });
1484
1485 it('does not call the target method', function (done) {
1486 this.obj.target(1, 2, 3, function (err, result) {
1487 this.target.should.not.have.been.called;
1488 done();
1489 }.bind(this));
1490 });
1491
1492 it('does not call the after advice', function (done) {
1493 this.obj.target(1, 2, 3, function (err, result) {
1494 this.after.should.not.have.been.called;
1495 done();
1496 }.bind(this));
1497 });
1498
1499 });
1500
1501 describe('when the before advice succeeds', function () {
1502
1503 beforeEach(function () {
1504 this.resultOne = 'around-before-mutate-result-one';
1505 this.resultTwo = 'around-before-mutate-result-two';
1506 this.resultThree = 'around-before-mutate-result-three';
1507 this.before.yields(
1508 null
1509 , this.resultOne
1510 , this.resultTwo
1511 , this.resultThree
1512 );
1513 });
1514
1515 it('invokes the target with the original arguments', function () {
1516 this.obj.target(1, 2, 3, function () {});
1517
1518 this.target.should.have.been.calledWithExactly(
1519 1
1520 , 2
1521 , 3
1522 , sinon.match.func
1523 );
1524 });
1525
1526 it('invokes the target in the target context', function () {
1527 this.obj.target(1, 2, 3, function () {});
1528
1529 this.target.lastCall.thisValue.should.equal(this.obj);
1530 });
1531
1532 describe('when the target method errors', function () {
1533
1534 beforeEach(function () {
1535 this.error = new Error('around-target-errors');
1536 this.target.yields(this.error);
1537 });
1538
1539 it('calls back with the error', function (done) {
1540 this.obj.target(1, 2, 3, function (err, result) {
1541 err.should.equal(this.error);
1542 done();
1543 }.bind(this));
1544 });
1545
1546 it('does not call the after advice', function (done) {
1547 this.obj.target(1, 2, 3, function (err, result) {
1548 this.after.should.not.have.been.called;
1549 done();
1550 }.bind(this));
1551 });
1552
1553 });
1554
1555 describe('when the target method succeeds', function () {
1556
1557 beforeEach(function () {
1558 this.result = 'around-target-result';
1559 this.target.yields(null, this.result);
1560 });
1561
1562 it('invokes after advice with original arguments', function () {
1563 this.obj.target(1, 2, 3, function () {});
1564
1565 this.after.should.have.been.calledWithExactly(
1566 1
1567 , 2
1568 , 3
1569 , sinon.match.func
1570 );
1571 });
1572
1573 it('invokes after advice in the target context', function () {
1574 this.obj.target(1, 2, 3, function () {});
1575
1576 this.after.lastCall.thisValue.should.equal(this.obj);
1577 });
1578
1579 describe('when the after advice errors', function () {
1580
1581 beforeEach(function () {
1582 this.error = new Error('around-after-errors');
1583 this.after.yields(this.error);
1584 });
1585
1586 it('calls back with the error', function (done) {
1587 this.obj.target(1, 2, 3, function (err, result) {
1588 err.should.equal(this.error);
1589 done();
1590 }.bind(this));
1591 });
1592
1593 });
1594
1595 describe('when the after advice succeeds', function () {
1596
1597 beforeEach(function () {
1598 this.afterResults = [
1599 'around-after-result-one'
1600 , 'around-after-result-two'
1601 ];
1602 this.after.yields(
1603 null
1604 , this.afterResults[0]
1605 , this.afterResults[1]
1606 );
1607 });
1608
1609 it('calls back with the target results', function (done) {
1610 this.obj.target(1, 2, 3, function (err, result) {
1611 result.should.equal(this.result);
1612 done();
1613 }.bind(this));
1614 });
1615
1616 });
1617
1618 });
1619
1620 });
1621
1622 });
1623
1624 });
1625
1626 });
1627
1628 });
1629
1630});