@fluffy-spoon/substitute
Advanced tools
Comparing version 1.76.0 to 1.80.0
@@ -11,3 +11,4 @@ declare class Dummy { | ||
foo(): string | undefined | null; | ||
bar(a: number, b?: number): number; | ||
} | ||
export {}; |
@@ -40,3 +40,3 @@ "use strict"; | ||
var ava_1 = require("ava"); | ||
var Index_1 = require("../src/Index"); | ||
var index_1 = require("../src/index"); | ||
var Utilities_1 = require("../src/Utilities"); | ||
@@ -76,2 +76,5 @@ var Dummy = /** @class */ (function () { | ||
}; | ||
Example.prototype.bar = function (a, b) { | ||
return a + b || 0; | ||
}; | ||
return Example; | ||
@@ -84,3 +87,3 @@ }()); | ||
instance = new Example(); | ||
substitute = Index_1.Substitute.for(); | ||
substitute = index_1.Substitute.for(); | ||
} | ||
@@ -91,4 +94,4 @@ ; | ||
substitute.c('blah', 'fuzz'); | ||
t.throws(function () { return substitute.received(1337).c('foo', 'bar'); }, "Expected 1337 calls to the method c with arguments ['foo', 'bar'], but received none of such calls.\nAll calls received to method c:\n-> 1 call with arguments ['blah', 'fuzz']"); | ||
t.throws(function () { return substitute.received(2117).c('foo', 'bar'); }, "Expected 2117 calls to the method c with arguments ['foo', 'bar'], but received none of such calls.\nAll calls received to method c:\n-> 1 call with arguments ['blah', 'fuzz']"); | ||
t.throws(function () { return substitute.received(1337).c('foo', 'bar'); }, "Expected 1337 calls to the method c with arguments ['foo', 'bar'], but received none of such calls.\nAll calls received to method c:\n-> call with arguments ['blah', 'fuzz']"); | ||
t.throws(function () { return substitute.received(2117).c('foo', 'bar'); }, "Expected 2117 calls to the method c with arguments ['foo', 'bar'], but received none of such calls.\nAll calls received to method c:\n-> call with arguments ['blah', 'fuzz']"); | ||
}); | ||
@@ -105,3 +108,3 @@ ava_1.default('class string field get returns', function (t) { | ||
initialize(); | ||
Index_1.Substitute.disableFor(substitute).received(2); | ||
index_1.Substitute.disableFor(substitute).received(2); | ||
t.throws(function () { return substitute.received(2).received(2); }); | ||
@@ -112,3 +115,3 @@ t.notThrows(function () { return substitute.received(1).received(2); }); | ||
initialize(); | ||
Index_1.Substitute.disableFor(substitute).received('foo'); | ||
index_1.Substitute.disableFor(substitute).received('foo'); | ||
t.notThrows(function () { return substitute.received(1).received('foo'); }); | ||
@@ -119,3 +122,3 @@ t.throws(function () { return substitute.received(2).received('foo'); }); | ||
initialize(); | ||
substitute.c(Index_1.Arg.all()).mimicks(instance.c); | ||
substitute.c(index_1.Arg.all()).mimicks(instance.c); | ||
t.deepEqual(substitute.c('a', 'b'), 'hello a world (b)'); | ||
@@ -141,9 +144,9 @@ }); | ||
t.notThrows(function () { return substitute.received().v = 'hello'; }); | ||
t.notThrows(function () { return substitute.received(5).v = Index_1.Arg.any(); }); | ||
t.notThrows(function () { return substitute.received().v = Index_1.Arg.any(); }); | ||
t.notThrows(function () { return substitute.received(5).v = index_1.Arg.any(); }); | ||
t.notThrows(function () { return substitute.received().v = index_1.Arg.any(); }); | ||
t.notThrows(function () { return substitute.received(2).v = 'hello'; }); | ||
t.notThrows(function () { return substitute.received(2).v = Index_1.Arg.is(function (x) { return x && x.indexOf('ll') > -1; }); }); | ||
t.throws(function () { return substitute.received(2).v = Index_1.Arg.any(); }); | ||
t.throws(function () { return substitute.received(1).v = Index_1.Arg.any(); }); | ||
t.throws(function () { return substitute.received(1).v = Index_1.Arg.is(function (x) { return x && x.indexOf('ll') > -1; }); }); | ||
t.notThrows(function () { return substitute.received(2).v = index_1.Arg.is(function (x) { return x && x.indexOf('ll') > -1; }); }); | ||
t.throws(function () { return substitute.received(2).v = index_1.Arg.any(); }); | ||
t.throws(function () { return substitute.received(1).v = index_1.Arg.any(); }); | ||
t.throws(function () { return substitute.received(1).v = index_1.Arg.is(function (x) { return x && x.indexOf('ll') > -1; }); }); | ||
t.throws(function () { return substitute.received(3).v = 'hello'; }); | ||
@@ -153,3 +156,3 @@ }); | ||
initialize(); | ||
substitute.c(Index_1.Arg.any(), "there").returns("blah", "haha"); | ||
substitute.c(index_1.Arg.any(), "there").returns("blah", "haha"); | ||
t.is(substitute.c("hi", "there"), 'blah'); | ||
@@ -179,3 +182,3 @@ t.is(substitute.c("his", "there"), 'haha'); | ||
initialize(); | ||
otherSubstitute = Index_1.Substitute.for(); | ||
otherSubstitute = index_1.Substitute.for(); | ||
substitute.returnPromise().returns(Promise.resolve(otherSubstitute)); | ||
@@ -223,3 +226,3 @@ _b = (_a = t).is; | ||
t.notThrows(function () { return substitute.received().c('hi', 'there'); }); | ||
t.throws(function () { return substitute.received(7).c('hi', 'there'); }, "Expected 7 calls to the method c with arguments ['hi', 'there'], but received 4 of such calls.\nAll calls received to method c:\n-> 4 calls with arguments ['hi', 'there']\n-> 1 call with arguments ['hi', 'the1re']"); | ||
t.throws(function () { return substitute.received(7).c('hi', 'there'); }, "Expected 7 calls to the method c with arguments ['hi', 'there'], but received 4 of such calls.\nAll calls received to method c:\n-> call with arguments ['hi', 'there']\n-> call with arguments ['hi', 'the1re']\n-> call with arguments ['hi', 'there']\n-> call with arguments ['hi', 'there']\n-> call with arguments ['hi', 'there']"); | ||
}); | ||
@@ -233,3 +236,3 @@ ava_1.default('received call matches after partial mocks using property instance mimicks', function (t) { | ||
t.notThrows(function () { return substitute.received(1).c('lala', 'bar'); }); | ||
t.throws(function () { return substitute.received(2).c('lala', 'bar'); }, "Expected 2 calls to the method c with arguments ['lala', 'bar'], but received 1 of such call.\nAll calls received to method c:\n-> 1 call with arguments ['lala', 'bar']"); | ||
t.throws(function () { return substitute.received(2).c('lala', 'bar'); }, "Expected 2 calls to the method c with arguments ['lala', 'bar'], but received 1 of such call.\nAll calls received to method c:\n-> call with arguments ['lala', 'bar']"); | ||
t.deepEqual(substitute.d, 1337); | ||
@@ -244,7 +247,31 @@ }); | ||
initialize(); | ||
t.true(Utilities_1.areArgumentsEqual(Index_1.Arg.any(), 'hi')); | ||
t.true(Utilities_1.areArgumentsEqual(Index_1.Arg.any('array'), ['foo', 'bar'])); | ||
t.true(Utilities_1.areArgumentsEqual(index_1.Arg.any(), 'hi')); | ||
t.true(Utilities_1.areArgumentsEqual(index_1.Arg.any('array'), ['foo', 'bar'])); | ||
t.false(Utilities_1.areArgumentsEqual(['foo', 'bar'], ['foo', 'bar'])); | ||
t.false(Utilities_1.areArgumentsEqual(Index_1.Arg.any('array'), 1337)); | ||
t.false(Utilities_1.areArgumentsEqual(index_1.Arg.any('array'), 1337)); | ||
}); | ||
ava_1.default('verifying with more arguments fails', function (t) { | ||
initialize(); | ||
substitute.bar(1); | ||
substitute.received().bar(1); | ||
t.throws(function () { return substitute.received().bar(1, 2); }); | ||
}); | ||
ava_1.default('verifying with less arguments fails', function (t) { | ||
initialize(); | ||
substitute.bar(1, 2); | ||
substitute.received().bar(1, 2); | ||
t.throws(function () { return substitute.received().bar(1); }); | ||
}); | ||
ava_1.default('return with more arguments is not matched fails', function (t) { | ||
initialize(); | ||
substitute.bar(1, 2).returns(3); | ||
t.is(3, substitute.bar(1, 2)); | ||
t.is(void 0, substitute.bar(1)); | ||
}); | ||
ava_1.default('return with less arguments is not matched', function (t) { | ||
initialize(); | ||
substitute.bar(1).returns(3); | ||
t.is(3, substitute.bar(1)); | ||
t.is(void 0, substitute.bar(1, 2)); | ||
}); | ||
//# sourceMappingURL=index.test.js.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var ava_1 = require("ava"); | ||
var Index_1 = require("../../src/Index"); | ||
var index_1 = require("../../src/index"); | ||
ava_1.default('issue 15: can call properties twice', function (t) { | ||
var baz = "baz"; | ||
var foo = Index_1.Substitute.for(); | ||
var foo = index_1.Substitute.for(); | ||
foo.bar.returns(baz); | ||
@@ -9,0 +9,0 @@ var call1 = foo.bar; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var ava_1 = require("ava"); | ||
var Index_1 = require("../../src/Index"); | ||
var index_1 = require("../../src/index"); | ||
ava_1.default('issue 18: receive with arg', function (t) { | ||
var mockedCalculator = Index_1.Substitute.for(); | ||
mockedCalculator.add(1, Index_1.Arg.is(function (input) { return input === 2; })).returns(4); | ||
var mockedCalculator = index_1.Substitute.for(); | ||
mockedCalculator.add(1, index_1.Arg.is(function (input) { return input === 2; })).returns(4); | ||
void mockedCalculator.add(1, 2); | ||
mockedCalculator.received(1).add(1, Index_1.Arg.is(function (input) { return input === 2; })); | ||
mockedCalculator.received(1).add(1, index_1.Arg.is(function (input) { return input === 2; })); | ||
t.pass(); | ||
}); | ||
//# sourceMappingURL=18.test.js.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var ava_1 = require("ava"); | ||
var Index_1 = require("../../src/Index"); | ||
ava_1.default('issue 23: mimick received should not call method', function (t) { | ||
var mockedCalculator = Index_1.Substitute.for(); | ||
var result = 0; | ||
mockedCalculator.add(Index_1.Arg.all()).mimicks(function (a, b) { | ||
return result = a + b; | ||
var index_1 = require("../../src/index"); | ||
ava_1.default("issue 23: mimick received should not call method", function (t) { | ||
var mockedCalculator = index_1.Substitute.for(); | ||
var calls = 0; | ||
mockedCalculator.add(index_1.Arg.all()).mimicks(function (a, b) { | ||
t.deepEqual(++calls, 1, 'mimick called twice'); | ||
return a + b; | ||
}); | ||
t.throws(function () { return mockedCalculator.received().add(Index_1.Arg.any(), Index_1.Arg.any()); }); | ||
t.is(result, 0); | ||
mockedCalculator.add(1, 1); // ok | ||
mockedCalculator.received(1).add(1, 1); // not ok, calls mimick func | ||
}); | ||
//# sourceMappingURL=23.test.js.map |
@@ -39,3 +39,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var Index_1 = require("../../src/Index"); | ||
var index_1 = require("../../src/index"); | ||
var ava_1 = require("ava"); | ||
@@ -74,3 +74,3 @@ var ClassA = /** @class */ (function () { | ||
return __generator(this, function (_a) { | ||
classBMock = Index_1.default.for(); | ||
classBMock = index_1.default.for(); | ||
classC = new ClassC(classBMock); | ||
@@ -77,0 +77,0 @@ t.not(classC, null); |
@@ -40,3 +40,3 @@ "use strict"; | ||
var ava_1 = require("ava"); | ||
var Index_1 = require("../../src/Index"); | ||
var index_1 = require("../../src/index"); | ||
var Example = /** @class */ (function () { | ||
@@ -56,3 +56,3 @@ function Example() { | ||
exports.Example = Example; | ||
var substitute = Index_1.Substitute.for(); | ||
var substitute = index_1.Substitute.for(); | ||
ava_1.default('issue 9: can record method with 0 arguments', function (t) { return __awaiter(_this, void 0, void 0, function () { | ||
@@ -59,0 +59,0 @@ function service() { |
export declare class Argument<T> { | ||
private description; | ||
private matchingFunction; | ||
encounteredValues: any[]; | ||
constructor(description: string, matchingFunction: (arg: T) => boolean); | ||
@@ -14,2 +13,3 @@ matches(arg: T): boolean; | ||
export declare class Arg { | ||
private static _all; | ||
static all(): AllArguments; | ||
@@ -16,0 +16,0 @@ static any(): Argument<any> & any; |
@@ -20,3 +20,2 @@ "use strict"; | ||
this.matchingFunction = matchingFunction; | ||
this.encounteredValues = []; | ||
} | ||
@@ -47,3 +46,3 @@ Argument.prototype.matches = function (arg) { | ||
Arg.all = function () { | ||
return new AllArguments(); | ||
return this._all = (this._all || new AllArguments()); | ||
}; | ||
@@ -50,0 +49,0 @@ Arg.any = function (type) { |
import { ContextState, PropertyKey } from "./ContextState"; | ||
import { Context } from "src/Context"; | ||
import { Call } from "../Utilities"; | ||
import { GetPropertyState } from "./GetPropertyState"; | ||
@@ -8,11 +9,12 @@ export declare class FunctionState implements ContextState { | ||
private mimicks; | ||
private _callCount; | ||
private _arguments; | ||
readonly arguments: any[]; | ||
private _calls; | ||
private _lastArgs?; | ||
readonly calls: Call[]; | ||
readonly callCount: number; | ||
readonly property: string | number | symbol; | ||
constructor(_getPropertyState: GetPropertyState, ...args: any[]); | ||
apply(context: Context, args: any[], matchingFunctionStates: FunctionState[]): any; | ||
constructor(_getPropertyState: GetPropertyState); | ||
private getCallCount; | ||
apply(context: Context, args: any[]): any; | ||
set(context: Context, property: PropertyKey, value: any): void; | ||
get(context: Context, property: PropertyKey): any; | ||
} |
"use strict"; | ||
var __values = (this && this.__values) || function (o) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0; | ||
if (m) return m.call(o); | ||
return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var Utilities_1 = require("../Utilities"); | ||
var Arguments_1 = require("../Arguments"); | ||
var Nothing = Symbol(); | ||
var FunctionState = /** @class */ (function () { | ||
function FunctionState(_getPropertyState) { | ||
var args = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
args[_i - 1] = arguments[_i]; | ||
} | ||
this._getPropertyState = _getPropertyState; | ||
this.returns = Nothing; | ||
this.returns = []; | ||
this.mimicks = null; | ||
this._arguments = args; | ||
this._callCount = 0; | ||
this._calls = []; | ||
} | ||
Object.defineProperty(FunctionState.prototype, "arguments", { | ||
Object.defineProperty(FunctionState.prototype, "calls", { | ||
get: function () { | ||
return this._arguments; | ||
return this._calls; | ||
}, | ||
@@ -37,3 +21,3 @@ enumerable: true, | ||
get: function () { | ||
return this._callCount; | ||
return this._calls.length; | ||
}, | ||
@@ -50,61 +34,31 @@ enumerable: true, | ||
}); | ||
FunctionState.prototype.apply = function (context, args, matchingFunctionStates) { | ||
var e_1, _a, e_2, _b; | ||
var callCount = this._callCount; | ||
FunctionState.prototype.getCallCount = function (args) { | ||
return this._calls.reduce(function (count, cargs) { return Utilities_1.areArgumentArraysEqual(cargs, args) ? count + 1 : count; }, 0); | ||
}; | ||
FunctionState.prototype.apply = function (context, args) { | ||
var hasExpectations = context.initialState.hasExpectations; | ||
if (!matchingFunctionStates) { | ||
matchingFunctionStates = this._getPropertyState | ||
.recordedFunctionStates | ||
.filter(function (x) { return Utilities_1.areArgumentArraysEqual(x.arguments, args); }); | ||
this._lastArgs = args; | ||
context.initialState.assertCallCountMatchesExpectations(this._calls, this.getCallCount(args), 'method', this.property, args); | ||
if (!hasExpectations) { | ||
this._calls.push(args); | ||
} | ||
if (hasExpectations) { | ||
callCount = matchingFunctionStates | ||
.map(function (x) { return x.callCount; }) | ||
.reduce(function (a, b) { return a + b; }, 0); | ||
} | ||
context.initialState.assertCallCountMatchesExpectations(this._getPropertyState.recordedFunctionStates, callCount, 'method', this.property, args); | ||
if (!hasExpectations) { | ||
this._callCount++; | ||
try { | ||
for (var matchingFunctionStates_1 = __values(matchingFunctionStates), matchingFunctionStates_1_1 = matchingFunctionStates_1.next(); !matchingFunctionStates_1_1.done; matchingFunctionStates_1_1 = matchingFunctionStates_1.next()) { | ||
var matchingFunctionState = matchingFunctionStates_1_1.value; | ||
try { | ||
for (var _c = __values(matchingFunctionState.arguments), _d = _c.next(); !_d.done; _d = _c.next()) { | ||
var argument = _d.value; | ||
if (!(argument instanceof Arguments_1.Argument)) | ||
continue; | ||
var indexOffset = matchingFunctionState | ||
.arguments | ||
.indexOf(argument); | ||
var myArg = args[indexOffset]; | ||
if (myArg instanceof Arguments_1.Argument) | ||
continue; | ||
argument.encounteredValues.push(myArg); | ||
} | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (_d && !_d.done && (_b = _c.return)) _b.call(_c); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
if (this.mimicks) | ||
return this.mimicks.apply(this.mimicks, args); | ||
if (!this.returns.length) | ||
return context.proxy; | ||
var returns = this.returns.find(function (r) { return Utilities_1.areArgumentArraysEqual(r.args, args); }); | ||
if (returns) { | ||
var returnValues = returns.returnValues; | ||
if (returnValues.length === 1) { | ||
return returnValues[0]; | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (matchingFunctionStates_1_1 && !matchingFunctionStates_1_1.done && (_a = matchingFunctionStates_1.return)) _a.call(matchingFunctionStates_1); | ||
if (returnValues.length > returns.returnIndex) { | ||
return returnValues[returns.returnIndex++]; | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
return void 0; // probably a test setup error, imho throwin is more helpful -- domasx2 | ||
//throw Error(`${String(this._getPropertyState.property)} with ${stringifyArguments(returns.args)} called ${returns.returnIndex + 1} times, but only ${returnValues.length} return values were set up`) | ||
} | ||
} | ||
if (this.mimicks) | ||
return this.mimicks.apply(this.mimicks, args); | ||
if (this.returns === Nothing) | ||
return context.proxy; | ||
var returnsArray = this.returns; | ||
if (returnsArray.length === 1) | ||
return returnsArray[0]; | ||
return returnsArray[this._callCount - 1]; | ||
return void 0; | ||
}; | ||
@@ -120,3 +74,3 @@ FunctionState.prototype.set = function (context, property, value) { | ||
_this.mimicks = input; | ||
_this._callCount--; | ||
_this._calls.pop(); | ||
context.state = context.initialState; | ||
@@ -126,4 +80,5 @@ }; | ||
if (property === 'returns') { | ||
if (this.returns !== Nothing) | ||
throw new Error('The return value for the function ' + this._getPropertyState.toString() + ' with ' + Utilities_1.stringifyArguments(this._arguments) + ' has already been set to ' + this.returns); | ||
if (this.returns.length) // I don't think this can happen -- domasx2 | ||
throw new Error('BUT HOW?'); | ||
//throw new Error('The return value for the function ' + this._getPropertyState.toString() + ' with ' + stringifyArguments(this._arguments) + ' has already been set to ' + this.returns); | ||
return function () { | ||
@@ -134,4 +89,20 @@ var returns = []; | ||
} | ||
_this.returns = returns; | ||
_this._callCount--; | ||
if (!_this._lastArgs) { | ||
throw new Error('Eh, there\'s a bug, no args recorded for this return :/'); | ||
} | ||
_this.returns.push({ | ||
returnValues: returns, | ||
returnIndex: 0, | ||
args: _this._lastArgs | ||
}); | ||
_this._calls.pop(); | ||
if (_this.callCount === 0) { | ||
// var indexOfSelf = this | ||
// ._getPropertyState | ||
// .recordedFunctionStates | ||
// .indexOf(this); | ||
// this._getPropertyState | ||
// .recordedFunctionStates | ||
// .splice(indexOfSelf, 1); | ||
} | ||
context.state = context.initialState; | ||
@@ -138,0 +109,0 @@ }; |
@@ -9,7 +9,7 @@ import { ContextState, PropertyKey } from "./ContextState"; | ||
private _callCount; | ||
private _recordedFunctionStates; | ||
private _functionState?; | ||
private readonly isFunction; | ||
readonly property: string | number | symbol; | ||
readonly callCount: number; | ||
readonly recordedFunctionStates: FunctionState[]; | ||
readonly functionState: FunctionState | undefined; | ||
constructor(_property: PropertyKey); | ||
@@ -16,0 +16,0 @@ apply(context: Context, args: any[]): any; |
"use strict"; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spread = (this && this.__spread) || function () { | ||
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); | ||
return ar; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var FunctionState_1 = require("./FunctionState"); | ||
var Utilities_1 = require("../Utilities"); | ||
var Nothing = Symbol(); | ||
@@ -31,3 +10,2 @@ var GetPropertyState = /** @class */ (function () { | ||
this.mimicks = null; | ||
this._recordedFunctionStates = []; | ||
this._callCount = 0; | ||
@@ -37,3 +15,3 @@ } | ||
get: function () { | ||
return this._recordedFunctionStates.length > 0; | ||
return !!this._functionState; | ||
}, | ||
@@ -57,5 +35,5 @@ enumerable: true, | ||
}); | ||
Object.defineProperty(GetPropertyState.prototype, "recordedFunctionStates", { | ||
Object.defineProperty(GetPropertyState.prototype, "functionState", { | ||
get: function () { | ||
return __spread(this._recordedFunctionStates); | ||
return this._functionState; | ||
}, | ||
@@ -67,10 +45,8 @@ enumerable: true, | ||
this._callCount = 0; | ||
var matchingFunctionStates = this._recordedFunctionStates.filter(function (x) { return Utilities_1.areArgumentArraysEqual(x.arguments, args); }); | ||
if (matchingFunctionStates.length > 0) { | ||
var matchingFunctionState = matchingFunctionStates[0]; | ||
return matchingFunctionState.apply(context, args, matchingFunctionStates); | ||
if (this.functionState) { | ||
return this.functionState.apply(context, args); | ||
} | ||
var functionState = new (FunctionState_1.FunctionState.bind.apply(FunctionState_1.FunctionState, __spread([void 0, this], args)))(); | ||
var functionState = new FunctionState_1.FunctionState(this); | ||
context.state = functionState; | ||
this._recordedFunctionStates.push(functionState); | ||
this._functionState = functionState; | ||
return context.apply(args); | ||
@@ -118,3 +94,4 @@ }; | ||
} | ||
context.initialState.assertCallCountMatchesExpectations(context.initialState.getPropertyStates, this.callCount, 'property', this.property, []); | ||
context.initialState.assertCallCountMatchesExpectations([[]], // I'm not sure what this was supposed to mean | ||
this.callCount, 'property', this.property, []); | ||
return context.proxy; | ||
@@ -121,0 +98,0 @@ }; |
@@ -67,3 +67,3 @@ "use strict"; | ||
return; | ||
throw new Error('Expected ' + expectedCount + ' call' + (expectedCount === 1 ? '' : 's') + ' to the ' + type + ' ' + property.toString() + ' with ' + Utilities_1.stringifyArguments(args) + ', but received ' + (callCount === 0 ? 'none' : callCount) + ' of such call' + (callCount === 1 ? '' : 's') + '.\nAll calls received to ' + type + ' ' + property.toString() + ':' + Utilities_1.stringifyCalls(calls)); | ||
throw new Error('Expected ' + (expectedCount === null ? '1 or more' : expectedCount) + ' call' + (expectedCount === 1 ? '' : 's') + ' to the ' + type + ' ' + property.toString() + ' with ' + Utilities_1.stringifyArguments(args) + ', but received ' + (callCount === 0 ? 'none' : callCount) + ' of such call' + (callCount === 1 ? '' : 's') + '.\nAll calls received to ' + type + ' ' + property.toString() + ':' + Utilities_1.stringifyCalls(calls)); | ||
}; | ||
@@ -70,0 +70,0 @@ InitialState.prototype.doesCallCountMatchExpectations = function (expectedCount, actualCount) { |
@@ -49,3 +49,4 @@ "use strict"; | ||
} | ||
context.initialState.assertCallCountMatchesExpectations(context.initialState.setPropertyStates, callCount, 'property', this.property, this.arguments); | ||
context.initialState.assertCallCountMatchesExpectations([[]], // not sure what this was supposed to do | ||
callCount, 'property', this.property, this.arguments); | ||
if (!hasExpectations) { | ||
@@ -52,0 +53,0 @@ this._callCount++; |
@@ -1,5 +0,2 @@ | ||
export declare type Call = { | ||
callCount: number; | ||
arguments?: any[]; | ||
}; | ||
export declare type Call = any[]; | ||
export declare function stringifyArguments(args: any[]): string; | ||
@@ -6,0 +3,0 @@ export declare function areArgumentArraysEqual(a: any[], b: any[]): boolean; |
@@ -22,3 +22,3 @@ "use strict"; | ||
function areArgumentArraysEqual(a, b) { | ||
for (var i = 0; i < Math.min(b.length, a.length); i++) { | ||
for (var i = 0; i < Math.max(b.length, a.length); i++) { // @TODO should be Math.max I think -- domasx2 | ||
if (!areArgumentsEqual(b[i], a[i])) | ||
@@ -32,3 +32,2 @@ return false; | ||
var e_1, _a; | ||
calls = calls.filter(function (x) { return x.callCount > 0; }); | ||
if (calls.length === 0) | ||
@@ -40,6 +39,3 @@ return ' (no calls)'; | ||
var call = calls_1_1.value; | ||
output += '\n-> ' + call.callCount + ' call'; | ||
output += call.callCount !== 1 ? 's' : ''; | ||
if (call.arguments) | ||
output += ' with ' + stringifyArguments(call.arguments); | ||
output += '\n-> call with ' + (call.length ? stringifyArguments(call) : '(no arguments)'); | ||
} | ||
@@ -59,35 +55,6 @@ } | ||
function areArgumentsEqual(a, b) { | ||
var e_2, _a, e_3, _b; | ||
if (a instanceof Arguments_1.AllArguments || b instanceof Arguments_1.AllArguments) | ||
return true; | ||
if (a instanceof Arguments_1.Argument && b instanceof Arguments_1.Argument) { | ||
try { | ||
for (var _c = __values(a.encounteredValues), _d = _c.next(); !_d.done; _d = _c.next()) { | ||
var encounteredValue = _d.value; | ||
if (!b.matches(encounteredValue)) | ||
return false; | ||
} | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (_d && !_d.done && (_a = _c.return)) _a.call(_c); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
try { | ||
for (var _e = __values(b.encounteredValues), _f = _e.next(); !_f.done; _f = _e.next()) { | ||
var encounteredValue = _f.value; | ||
if (!a.matches(encounteredValue)) | ||
return false; | ||
} | ||
} | ||
catch (e_3_1) { e_3 = { error: e_3_1 }; } | ||
finally { | ||
try { | ||
if (_f && !_f.done && (_b = _e.return)) _b.call(_e); | ||
} | ||
finally { if (e_3) throw e_3.error; } | ||
} | ||
return true; | ||
throw new Error("`Argument` should only be used to set up value or verify, not in the implementation."); | ||
} | ||
@@ -98,2 +65,3 @@ if (a instanceof Arguments_1.Argument) | ||
return b.matches(a); | ||
// I think this is surprising behaviour. null !== undefined, test lib should be strict about it -- domasx2 | ||
if ((typeof a === 'undefined' || a === null) && (typeof b === 'undefined' || b === null)) | ||
@@ -100,0 +68,0 @@ return true; |
{ | ||
"name": "@fluffy-spoon/substitute", | ||
"version": "1.76.0", | ||
"version": "1.80.0", | ||
"description": "An NSubstitute port to TypeScript called substitute.js.", | ||
@@ -17,3 +17,3 @@ "main": "dist/src/Index.js", | ||
"ts-node": "^7.0.1", | ||
"typescript": "^3.3.3333" | ||
"typescript": "^3.3.4000" | ||
}, | ||
@@ -20,0 +20,0 @@ "ava": { |
import test from 'ava'; | ||
import { Substitute, Arg } from '../src/Index'; | ||
import { Substitute, Arg } from '../src/index'; | ||
import { areArgumentsEqual } from '../src/Utilities'; | ||
@@ -35,3 +35,7 @@ import { OmitProxyMethods, ObjectSubstitute } from '../src/Transformations'; | ||
return 'stuff'; | ||
} | ||
} | ||
bar (a: number, b?: number): number{ | ||
return a + b || 0 | ||
} | ||
} | ||
@@ -55,3 +59,3 @@ | ||
All calls received to method c: | ||
-> 1 call with arguments ['blah', 'fuzz']`); | ||
-> call with arguments ['blah', 'fuzz']`); | ||
@@ -61,3 +65,3 @@ t.throws(() => substitute.received(2117).c('foo', 'bar'), | ||
All calls received to method c: | ||
-> 1 call with arguments ['blah', 'fuzz']`); | ||
-> call with arguments ['blah', 'fuzz']`); | ||
}); | ||
@@ -171,4 +175,3 @@ | ||
substitute.returnPromise().returns(Promise.resolve(otherSubstitute)); | ||
t.is(otherSubstitute, await substitute.returnPromise()); | ||
t.is(otherSubstitute, await substitute.returnPromise()); | ||
}); | ||
@@ -209,4 +212,7 @@ | ||
All calls received to method c: | ||
-> 4 calls with arguments ['hi', 'there'] | ||
-> 1 call with arguments ['hi', 'the1re']`); | ||
-> call with arguments ['hi', 'there'] | ||
-> call with arguments ['hi', 'the1re'] | ||
-> call with arguments ['hi', 'there'] | ||
-> call with arguments ['hi', 'there'] | ||
-> call with arguments ['hi', 'there']`); | ||
}); | ||
@@ -227,3 +233,3 @@ | ||
All calls received to method c: | ||
-> 1 call with arguments ['lala', 'bar']`); | ||
-> call with arguments ['lala', 'bar']`); | ||
@@ -249,2 +255,30 @@ t.deepEqual(substitute.d, 1337); | ||
t.false(areArgumentsEqual(Arg.any('array'), 1337)); | ||
}); | ||
}); | ||
test('verifying with more arguments fails', t => { | ||
initialize() | ||
substitute.bar(1) | ||
substitute.received().bar(1) | ||
t.throws(() => substitute.received().bar(1, 2)) | ||
}) | ||
test('verifying with less arguments fails', t => { | ||
initialize() | ||
substitute.bar(1, 2) | ||
substitute.received().bar(1, 2) | ||
t.throws(() => substitute.received().bar(1)) | ||
}) | ||
test('return with more arguments is not matched fails', t => { | ||
initialize() | ||
substitute.bar(1, 2).returns(3) | ||
t.is(3, substitute.bar(1, 2)) | ||
t.is(void 0, substitute.bar(1)) | ||
}) | ||
test('return with less arguments is not matched', t => { | ||
initialize() | ||
substitute.bar(1).returns(3) | ||
t.is(3, substitute.bar(1)) | ||
t.is(void 0, substitute.bar(1, 2)) | ||
}) |
import test from 'ava'; | ||
import { Substitute } from '../../src/Index'; | ||
import { Substitute } from '../../src/index'; | ||
@@ -5,0 +5,0 @@ export interface Example { |
import test from 'ava'; | ||
import { Substitute, Arg } from '../../src/Index'; | ||
import { Substitute, Arg } from '../../src/index'; | ||
@@ -5,0 +5,0 @@ interface CalculatorInterface { |
@@ -1,23 +0,25 @@ | ||
import test from 'ava'; | ||
import test from "ava"; | ||
import { Substitute, Arg } from '../../src/Index'; | ||
import { Substitute, Arg } from "../../src/index"; | ||
interface CalculatorInterface { | ||
add(a: number, b: number): number | ||
subtract(a: number, b: number): number | ||
divide(a: number, b: number): number | ||
isEnabled: boolean | ||
add(a: number, b: number): number; | ||
subtract(a: number, b: number): number; | ||
divide(a: number, b: number): number; | ||
isEnabled: boolean; | ||
} | ||
test('issue 23: mimick received should not call method', t => { | ||
const mockedCalculator = Substitute.for<CalculatorInterface>(); | ||
test("issue 23: mimick received should not call method", t => { | ||
const mockedCalculator = Substitute.for<CalculatorInterface>(); | ||
let result = 0; | ||
mockedCalculator.add(Arg.all()).mimicks((a, b) => { | ||
return result = a + b; | ||
}); | ||
let calls = 0 | ||
t.throws(() => mockedCalculator.received().add(Arg.any(), Arg.any())); | ||
mockedCalculator.add(Arg.all()).mimicks((a, b) => { | ||
t.deepEqual(++calls, 1, 'mimick called twice') | ||
return a + b; | ||
}); | ||
t.is(result, 0); | ||
}); | ||
mockedCalculator.add(1, 1); // ok | ||
mockedCalculator.received(1).add(1, 1) // not ok, calls mimick func | ||
}); |
@@ -1,2 +0,2 @@ | ||
import Substitute from "../../src/Index"; | ||
import Substitute from "../../src/index"; | ||
import test from 'ava'; | ||
@@ -3,0 +3,0 @@ |
import test from 'ava'; | ||
import { Substitute } from '../../src/Index'; | ||
import { Substitute } from '../../src/index'; | ||
import { ObjectSubstitute } from '../../src/Transformations'; | ||
@@ -5,0 +5,0 @@ |
export class Argument<T> { | ||
encounteredValues: any[]; | ||
@@ -7,5 +6,3 @@ constructor( | ||
private matchingFunction: (arg: T) => boolean | ||
) { | ||
this.encounteredValues = []; | ||
} | ||
){} | ||
@@ -32,4 +29,6 @@ matches(arg: T) { | ||
export class Arg { | ||
private static _all: AllArguments; | ||
static all() { | ||
return new AllArguments(); | ||
return this._all = (this._all || new AllArguments()); | ||
} | ||
@@ -36,0 +35,0 @@ |
import { ContextState, PropertyKey } from "./ContextState"; | ||
import { Context } from "src/Context"; | ||
import { stringifyArguments, stringifyCalls, areArgumentsEqual, areArgumentArraysEqual } from "../Utilities"; | ||
import { stringifyArguments, stringifyCalls, areArgumentsEqual, areArgumentArraysEqual, Call } from "../Utilities"; | ||
import { GetPropertyState } from "./GetPropertyState"; | ||
import { Argument } from "../Arguments"; | ||
import { Argument, Arg } from "../Arguments"; | ||
const Nothing = Symbol(); | ||
const Nothing = Symbol() | ||
interface ReturnMock { | ||
args: Call | ||
returnValues: any[] | Symbol // why symbol, what | ||
returnIndex: 0 | ||
} | ||
export class FunctionState implements ContextState { | ||
private returns: any[]|Symbol; | ||
private returns: ReturnMock[]; | ||
private mimicks: Function|null; | ||
private _callCount: number; | ||
private _arguments: any[]; | ||
private _calls: Call[]; // list of lists of arguments this was called with | ||
private _lastArgs?: Call // bit of a hack | ||
public get arguments() { | ||
return this._arguments; | ||
public get calls(): Call[] { | ||
return this._calls | ||
} | ||
public get callCount() { | ||
return this._callCount; | ||
return this._calls.length; | ||
} | ||
@@ -28,28 +34,19 @@ | ||
constructor(private _getPropertyState: GetPropertyState, ...args: any[]) { | ||
this.returns = Nothing; | ||
constructor(private _getPropertyState: GetPropertyState) { | ||
this.returns = []; | ||
this.mimicks = null; | ||
this._calls = []; | ||
} | ||
this._arguments = args; | ||
this._callCount = 0; | ||
private getCallCount(args: Call): number { | ||
return this._calls.reduce((count, cargs) => areArgumentArraysEqual(cargs, args) ? count + 1 : count, 0) | ||
} | ||
apply(context: Context, args: any[], matchingFunctionStates: FunctionState[]) { | ||
let callCount = this._callCount; | ||
apply(context: Context, args: any[]) { | ||
const hasExpectations = context.initialState.hasExpectations; | ||
if(!matchingFunctionStates) { | ||
matchingFunctionStates = this._getPropertyState | ||
.recordedFunctionStates | ||
.filter(x => areArgumentArraysEqual(x.arguments, args)); | ||
} | ||
this._lastArgs = args | ||
if(hasExpectations) { | ||
callCount = matchingFunctionStates | ||
.map(x => x.callCount) | ||
.reduce((a, b) => a + b, 0); | ||
} | ||
context.initialState.assertCallCountMatchesExpectations( | ||
this._getPropertyState.recordedFunctionStates, | ||
callCount, | ||
this._calls, | ||
this.getCallCount(args), | ||
'method', | ||
@@ -60,31 +57,27 @@ this.property, | ||
if(!hasExpectations) { | ||
this._callCount++; | ||
this._calls.push(args) | ||
} | ||
for(let matchingFunctionState of matchingFunctionStates) | ||
for(let argument of matchingFunctionState.arguments) { | ||
if(!(argument instanceof Argument)) | ||
continue; | ||
if (!hasExpectations) { | ||
if(this.mimicks) | ||
return this.mimicks.apply(this.mimicks, args); | ||
const indexOffset = matchingFunctionState | ||
.arguments | ||
.indexOf(argument); | ||
const myArg = args[indexOffset]; | ||
if(myArg instanceof Argument) | ||
continue; | ||
if(!this.returns.length) | ||
return context.proxy; | ||
const returns = this.returns.find(r => areArgumentArraysEqual(r.args, args)) | ||
argument.encounteredValues.push(myArg); | ||
if (returns) { | ||
const returnValues = returns.returnValues as any[] | ||
if (returnValues.length === 1) { | ||
return returnValues[0] | ||
} | ||
if (returnValues.length > returns.returnIndex) { | ||
return returnValues[returns.returnIndex++] | ||
} | ||
return void 0 // probably a test setup error, imho throwin is more helpful -- domasx2 | ||
//throw Error(`${String(this._getPropertyState.property)} with ${stringifyArguments(returns.args)} called ${returns.returnIndex + 1} times, but only ${returnValues.length} return values were set up`) | ||
} | ||
} | ||
if(this.mimicks) | ||
return this.mimicks.apply(this.mimicks, args); | ||
if(this.returns === Nothing) | ||
return context.proxy; | ||
var returnsArray = this.returns as any[]; | ||
if(returnsArray.length === 1) | ||
return returnsArray[0]; | ||
return returnsArray[this._callCount-1]; | ||
return void 0 | ||
} | ||
@@ -102,3 +95,3 @@ | ||
this.mimicks = input; | ||
this._callCount--; | ||
this._calls.pop() | ||
@@ -110,9 +103,27 @@ context.state = context.initialState; | ||
if(property === 'returns') { | ||
if(this.returns !== Nothing) | ||
throw new Error('The return value for the function ' + this._getPropertyState.toString() + ' with ' + stringifyArguments(this._arguments) + ' has already been set to ' + this.returns); | ||
if (this.returns.length) // I don't think this can happen -- domasx2 | ||
throw new Error('BUT HOW?') | ||
//throw new Error('The return value for the function ' + this._getPropertyState.toString() + ' with ' + stringifyArguments(this._arguments) + ' has already been set to ' + this.returns); | ||
return (...returns: any[]) => { | ||
this.returns = returns; | ||
this._callCount--; | ||
if (!this._lastArgs) { | ||
throw new Error('Eh, there\'s a bug, no args recorded for this return :/') | ||
} | ||
this.returns.push({ | ||
returnValues: returns, | ||
returnIndex: 0, | ||
args: this._lastArgs | ||
}) | ||
this._calls.pop() | ||
if(this.callCount === 0) { | ||
// var indexOfSelf = this | ||
// ._getPropertyState | ||
// .recordedFunctionStates | ||
// .indexOf(this); | ||
// this._getPropertyState | ||
// .recordedFunctionStates | ||
// .splice(indexOfSelf, 1); | ||
} | ||
context.state = context.initialState; | ||
@@ -119,0 +130,0 @@ }; |
@@ -5,2 +5,3 @@ import { ContextState, PropertyKey } from "./ContextState"; | ||
import { areArgumentsEqual, areArgumentArraysEqual } from "../Utilities"; | ||
import { Arg } from "../Arguments"; | ||
@@ -14,6 +15,6 @@ const Nothing = Symbol(); | ||
private _callCount: number; | ||
private _recordedFunctionStates: FunctionState[]; | ||
private _functionState?: FunctionState; | ||
private get isFunction() { | ||
return this._recordedFunctionStates.length > 0; | ||
private get isFunction(): boolean { | ||
return !!this._functionState | ||
} | ||
@@ -29,4 +30,4 @@ | ||
public get recordedFunctionStates() { | ||
return [...this._recordedFunctionStates]; | ||
public get functionState(): FunctionState | undefined { | ||
return this._functionState | ||
} | ||
@@ -37,4 +38,2 @@ | ||
this.mimicks = null; | ||
this._recordedFunctionStates = []; | ||
this._callCount = 0; | ||
@@ -46,16 +45,10 @@ } | ||
const matchingFunctionStates = this._recordedFunctionStates.filter(x => areArgumentArraysEqual(x.arguments, args)); | ||
if(matchingFunctionStates.length > 0) { | ||
const matchingFunctionState = matchingFunctionStates[0]; | ||
return matchingFunctionState.apply( | ||
context, | ||
args, | ||
matchingFunctionStates); | ||
if (this.functionState) { | ||
return this.functionState.apply(context, args); | ||
} | ||
var functionState = new FunctionState(this, ...args); | ||
var functionState = new FunctionState(this); | ||
context.state = functionState; | ||
this._functionState = functionState | ||
this._recordedFunctionStates.push(functionState); | ||
return context.apply(args); | ||
@@ -113,3 +106,3 @@ } | ||
context.initialState.assertCallCountMatchesExpectations( | ||
context.initialState.getPropertyStates, | ||
[[]], // I'm not sure what this was supposed to mean | ||
this.callCount, | ||
@@ -116,0 +109,0 @@ 'property', |
@@ -43,7 +43,6 @@ import { ContextState, PropertyKey } from "./ContextState"; | ||
this.clearExpectations(); | ||
if(this.doesCallCountMatchExpectations(expectedCount, callCount)) | ||
return; | ||
throw new Error('Expected ' + expectedCount + ' call' + (expectedCount === 1 ? '' : 's') + ' to the ' + type + ' ' + property.toString() + ' with ' + stringifyArguments(args) + ', but received ' + (callCount === 0 ? 'none' : callCount) + ' of such call' + (callCount === 1 ? '' : 's') + '.\nAll calls received to ' + type + ' ' + property.toString() + ':' + stringifyCalls(calls)); | ||
throw new Error('Expected ' + (expectedCount === null ? '1 or more' : expectedCount) + ' call' + (expectedCount === 1 ? '' : 's') + ' to the ' + type + ' ' + property.toString() + ' with ' + stringifyArguments(args) + ', but received ' + (callCount === 0 ? 'none' : callCount) + ' of such call' + (callCount === 1 ? '' : 's') + '.\nAll calls received to ' + type + ' ' + property.toString() + ':' + stringifyCalls(calls)); | ||
} | ||
@@ -96,3 +95,2 @@ | ||
return 'Substitute'; | ||
if(property.toString() === 'Symbol(util.inspect.custom)') | ||
@@ -99,0 +97,0 @@ return void 0; |
@@ -45,3 +45,3 @@ import { ContextState, PropertyKey } from "./ContextState"; | ||
context.initialState.assertCallCountMatchesExpectations( | ||
context.initialState.setPropertyStates, | ||
[[]], // not sure what this was supposed to do | ||
callCount, | ||
@@ -48,0 +48,0 @@ 'property', |
import { Argument, AllArguments } from "./Arguments"; | ||
import util = require('util') | ||
export type Call = {callCount: number, arguments?: any[]}; | ||
export type Call = any[] // list of args | ||
@@ -12,3 +12,3 @@ export function stringifyArguments(args: any[]) { | ||
export function areArgumentArraysEqual(a: any[], b: any[]) { | ||
for(var i=0;i<Math.min(b.length, a.length);i++) { | ||
for(var i=0;i<Math.max(b.length, a.length);i++) { // @TODO should be Math.max I think -- domasx2 | ||
if(!areArgumentsEqual(b[i], a[i])) | ||
@@ -22,3 +22,2 @@ return false; | ||
export function stringifyCalls(calls: Call[]) { | ||
calls = calls.filter(x => x.callCount > 0); | ||
@@ -30,7 +29,3 @@ if(calls.length === 0) | ||
for (let call of calls) { | ||
output += '\n-> ' + call.callCount + ' call'; | ||
output += call.callCount !== 1 ? 's' : ''; | ||
if(call.arguments) | ||
output += ' with ' + stringifyArguments(call.arguments); | ||
output += '\n-> call with ' + (call.length ? stringifyArguments(call) : '(no arguments)') | ||
} | ||
@@ -46,13 +41,3 @@ | ||
if(a instanceof Argument && b instanceof Argument) { | ||
for(let encounteredValue of a.encounteredValues) { | ||
if(!b.matches(encounteredValue)) | ||
return false; | ||
} | ||
for(let encounteredValue of b.encounteredValues) { | ||
if(!a.matches(encounteredValue)) | ||
return false; | ||
} | ||
return true; | ||
throw new Error("`Argument` should only be used to set up value or verify, not in the implementation.") | ||
} | ||
@@ -66,2 +51,3 @@ | ||
// I think this is surprising behaviour. null !== undefined, test lib should be strict about it -- domasx2 | ||
if ((typeof a === 'undefined' || a === null) && (typeof b === 'undefined' || b === null)) | ||
@@ -68,0 +54,0 @@ return true; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
176061
80
2340