stub.js 4.05 KB
Newer Older
Ketan's avatar
Ketan committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

(function ($, window) {
    "use strict";

    function wrapMethod(object, property, method, copyProperties) {
        if (!object) {
            throw new TypeError("Should wrap property of object");
        }

        if (typeof method != "function") {
            throw new TypeError("Method wrapper should be function");
        }

        var wrappedMethod = object[property],
            error;

        if ($.type(wrappedMethod) !== 'function') {
            error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
                property + " as function");
        }

        if (wrappedMethod.restore) {
            error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
        }

        if (error) {
            if (wrappedMethod._stack) {
                error.stack += '\n--------------\n' + wrappedMethod._stack;
            }
            throw error;
        }

        // IE 8 does not support hasOwnProperty.
        var owned = object.hasOwnProperty ?
            object.hasOwnProperty(property) :
            Object.prototype.hasOwnProperty.call(object, property);

        object[property] = method;
        method.displayName = property;
        // Stack trace which can be used to find what line of code the original method was created on.
        method._stack = (new Error('Stack Trace for original')).stack;

        method.restore = function () {
            if (!owned) {
                delete object[property];
            }
            if (object[property] === method) {
                object[property] = wrappedMethod;
            }
        };

        if (copyProperties) {
            for (var prop in wrappedMethod) {
                if (!Object.prototype.hasOwnProperty.call(method, prop)) {
                    method[prop] = wrappedMethod[prop];
                }
            }
        }

        return method;
    }

    function stub(object, property, func, copyProperties) {
        if (!!func && typeof func != "function") {
            throw new TypeError("Custom stub should be function");
        }

        var wrapper;

        if (func) {
            wrapper = func;
        } else {
            wrapper = stub.create();
        }

        if (!object && typeof property === "undefined") {
            return stub.create();
        }

        if (typeof property === "undefined" && typeof object == "object") {
            for (var prop in object) {
                if (typeof object[prop] === "function") {
                    stub(object, prop);
                }
            }

            return object;
        }

        return wrapMethod(object, property, wrapper, copyProperties);
    }

    $.extend(stub, (function () {
        var proto = {
            create: function create() {
                var functionStub = function () {
                    functionStub.callCount = functionStub.callCount ? functionStub.callCount + 1 : 1;
                    functionStub.lastCallArgs = arguments;
                    functionStub.callArgsStack.push(arguments);
                    if (functionStub.returnCallback && $.type(functionStub.returnCallback) === 'function') {
                        return functionStub.returnCallback.apply(functionStub.returnCallback, arguments);
                    } else if (functionStub.returnValue) {
                        return functionStub.returnValue;
                    }
                };
                $.extend(functionStub, stub);
                functionStub.reset();
                functionStub.displayName = "stub";
                return functionStub;
            },

            reset: function() {
                this.callCount = null;
                this.lastCallArgs = [];
                this.callArgsStack = [];
                this.returnValue = null;
                this.returnCallback = null;
            }
        };

        return proto;
    }()));

    window.jsunit = window.jsunit || {};
    $.extend(window.jsunit, {
        stub: stub
    });
})(jQuery, window);