Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nested isObjectWith support #128

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ node_modules/
.tmp/
sauce.json
.vscode/
.idea
dist/
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
8
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
language: node_js

node_js:
- "node"
- 8

install:
- "npm install"

script:
- "gulp test:travis"
- "gulp test:travis"
6 changes: 3 additions & 3 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ gulp.task('test:mocha.es6', function () {

function runMocha(srcPath) {
return gulp.src(srcPath)
.pipe($.spawnMocha({
ui: 'bdd',
.pipe($.spawnMocha({
ui: 'bdd',
reporter: 'spec',
env: {'NODE_PATH': './.tmp/src'}
}))
Expand Down Expand Up @@ -289,5 +289,5 @@ gulp.task('release', ['default'], function (cb) {
});

gulp.task('test:travis', ['build'], function (cb) {
runSequence('test:sauce', 'test:mocha', 'test:mocha.es6', cb);
runSequence('test:mocha', 'test:mocha.es6', cb);
});
42 changes: 31 additions & 11 deletions src/Match/MatchObjectWith.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,44 @@
import * as _ from "lodash";
import { IMatch } from "./IMatch";
import { Consts } from "../Consts";
import { Utils } from "../Common/Utils";
import {IMatch} from "./IMatch";
import {Consts} from "../Consts";
import {Utils} from "../Common/Utils";

export class MatchObjectWith<T> implements IMatch {

readonly ___id = Consts.IMATCH_ID_VALUE;

private readonly _value: T;

constructor(value: T) {
this._value = <any>_.cloneDeep(value);
}

___matches(object: Object): boolean {
let match = false;
let partial = _.pick(object, _.keys(this._value));
if (_.isEqual(this._value, partial))
match = true;
return match;
___matches(object: Object, value?: Object): boolean {
const compare = (value || this._value) as any;
const compareKeys = _.keys(compare);
const partial = _.pick(object, compareKeys) as any;
const partialKeys = _.keys(partial);

if (compareKeys.length !== partialKeys.length) {
return false;
}

if (!partialKeys.length) {
return _.isEqual(object, value);
}

for (const key of partialKeys) {
const nested = partial[key];
if (_.isArray(nested) || _.isObject(nested)) {
if (!this.___matches(nested, compare[key])) {
return false;
}
} else if (!_.isEqual(nested, compare[key])) {
return false;
}
}

return true;
}

toString(): string {
Expand Down
120 changes: 120 additions & 0 deletions test/spec/Mock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,126 @@ describe("Mock", () => {
expect(mock.object.doString()).to.eq(undefined);
});

it("should not treat date objects as the same when using isObjectWith", () => {
const date1 = new Date(Date.now() - 1000000000);
const date2 = new Date(Date.now() - 1000000001);

const bar1nested = new TypeMoqTests.Bar();
bar1nested.anyValue = date1;
const bar1 = new TypeMoqTests.Bar();
bar1.nested = bar1nested;

const bar2nested = new TypeMoqTests.Bar();
bar2nested.anyValue = date2;

const bar2 = new TypeMoqTests.Bar();
bar2.nested = bar2nested;
const match = {nested: {anyValue: date1}};
const mock = Mock.ofType(TypeMoqTests.Doer);

mock.setup(x => x.doObject(It.isObjectWith(match))).returns(() => "At vero eos et accusamus et iusto odio dignissimos ducimus");

expect(mock.object.doObject(bar1)).to.eq("At vero eos et accusamus et iusto odio dignissimos ducimus");
expect(mock.object.doObject(bar2)).to.eq(undefined);

bar2nested.anyValue = date1;
expect(mock.object.doObject(bar2)).to.eq("At vero eos et accusamus et iusto odio dignissimos ducimus");

expect(mock.object.doObject(new Object())).to.eq(undefined);
expect(mock.object.doObject({ foo: 'nothing' })).to.eq(undefined);
expect(mock.object.doObject()).to.eq(undefined);
});

it("should match a method with partial nested object value params", () => {

const bar1nested = new TypeMoqTests.Bar();
bar1nested.anyValue = 42;
bar1nested.enumValue = TypeMoqTests.AnEnum.One;
const bar1 = new TypeMoqTests.Bar();
bar1.value = "Lorem ipsum dolor sit amet";
bar1.nested = bar1nested;

const bar2nested = new TypeMoqTests.Bar();
bar2nested.anyValue = 42;
bar2nested.enumValue = TypeMoqTests.AnEnum.Two;

const bar2 = new TypeMoqTests.Bar();
bar2.value = "Ut enim ad minim veniam";
bar2.nested = bar2nested;
const match = {nested: {enumValue: TypeMoqTests.AnEnum.One}};
const mock = Mock.ofType(TypeMoqTests.Doer);

mock.setup(x => x.doObject(It.isObjectWith(match))).returns(() => "At vero eos et accusamus et iusto odio dignissimos ducimus");

expect(mock.object.doObject(bar1)).to.eq("At vero eos et accusamus et iusto odio dignissimos ducimus");
expect(mock.object.doObject(bar2)).to.eq(undefined);

bar2nested.enumValue = TypeMoqTests.AnEnum.One;
expect(mock.object.doObject(bar2)).to.eq("At vero eos et accusamus et iusto odio dignissimos ducimus");

expect(mock.object.doObject(new Object())).to.eq(undefined);
expect(mock.object.doObject({ foo: 'nothing' })).to.eq(undefined);
expect(mock.object.doObject()).to.eq(undefined);
});

it("should match a method with partial nested object array value params", () => {

const bar1nested = new TypeMoqTests.Bar();
bar1nested.anyValue = 42;
bar1nested.enumValue = TypeMoqTests.AnEnum.One;
const bar1 = new TypeMoqTests.Bar();
bar1.value = "Lorem ipsum dolor sit amet";
bar1.nesteds = [bar1nested];

const bar2nested = new TypeMoqTests.Bar();
bar2nested.anyValue = 42;
bar2nested.enumValue = TypeMoqTests.AnEnum.Two;

const bar2 = new TypeMoqTests.Bar();
bar2.value = "Ut enim ad minim veniam";
bar2.nesteds = [bar2nested];
const match = {nesteds: [{enumValue: TypeMoqTests.AnEnum.One}]};
const mock = Mock.ofType(TypeMoqTests.Doer);

mock.setup(x => x.doObject(It.isObjectWith(match))).returns(() => "At vero eos et accusamus et iusto odio dignissimos ducimus");

expect(mock.object.doObject(bar1)).to.eq("At vero eos et accusamus et iusto odio dignissimos ducimus");
expect(mock.object.doObject(bar2)).to.eq(undefined);

bar2nested.enumValue = TypeMoqTests.AnEnum.One;
expect(mock.object.doObject(bar2)).to.eq("At vero eos et accusamus et iusto odio dignissimos ducimus");

expect(mock.object.doObject(new Object())).to.eq(undefined);
expect(mock.object.doObject({ foo: 'nothing' })).to.eq(undefined);
expect(mock.object.doObject()).to.eq(undefined);
});

it("should match a method with partial array value params", () => {

const bar1 = new TypeMoqTests.Bar();
bar1.value = "Lorem ipsum dolor sit amet";
bar1.anyValue = 42;
bar1.enumValue = TypeMoqTests.AnEnum.One;
const bar2 = new TypeMoqTests.Bar();
bar2.value = "Ut enim ad minim veniam";
bar2.enumValue = TypeMoqTests.AnEnum.Two;
const match = [{ anyValue: 42, enumValue: TypeMoqTests.AnEnum.One }];
const mock = Mock.ofType(TypeMoqTests.Doer);

mock.setup(x => x.doObject(It.isObjectWith(match))).returns(() => "At vero eos et accusamus et iusto odio dignissimos ducimus");

expect(mock.object.doObject([bar1])).to.eq("At vero eos et accusamus et iusto odio dignissimos ducimus");
expect(mock.object.doObject([bar2])).to.eq(undefined);

bar2.anyValue = 42;
bar2.enumValue = TypeMoqTests.AnEnum.One;
expect(mock.object.doObject([bar2])).to.eq("At vero eos et accusamus et iusto odio dignissimos ducimus");

expect(mock.object.doObject([new Object()])).to.eq(undefined);
expect(mock.object.doObject([{ foo: 'nothing' }])).to.eq(undefined);
expect(mock.object.doObject([])).to.eq(undefined);
});

it("should match a method with partial object value params", () => {

const bar1 = new TypeMoqTests.Bar();
Expand Down
4 changes: 4 additions & 0 deletions test/spec/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,16 @@ export module TypeMoqTests {
value: string = '';
anyValue: any = undefined;
enumValue: AnEnum;
nesteds?: Bar[];
nested?: Bar;
}

export interface IBar {
value: string;
anyValue: any;
enumValue: AnEnum;
nested?: IBar;
nesteds?: IBar[];
}

export interface IDo {
Expand Down