Skip to content

Commit

Permalink
Add check for circular dependency
Browse files Browse the repository at this point in the history
  • Loading branch information
Ymaril committed Mar 13, 2023
1 parent 21b7880 commit d5790e0
Show file tree
Hide file tree
Showing 11 changed files with 149 additions and 90 deletions.
29 changes: 28 additions & 1 deletion src/Given.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ export default class Given<T extends Record<string, any>> {
public add<
K extends keyof Partial<T>,
D extends keyof Partial<T>
>(key: K, func: (...args: T[D][]) => T[K] | Promise<T[K]>, dependencies: D[] = []) {
>(key: K, func: (given: Record<D, T[D]>) => (T[K] | Promise<T[K]>), dependencies: D[] = []) {
if(this.isCircularDependency(key, dependencies.filter(d => key as any !== d as any)))
throw `letGiven '${String(key)}' circular dependency`;

if(!this.data[key])
this.data[key] = [];

Expand All @@ -28,6 +31,30 @@ export default class Given<T extends Record<string, any>> {
});
}

private isCircularDependency(checkedKey: keyof Partial<T>, currentDependencies: Array<keyof Partial<T>>) {
if(currentDependencies.includes(checkedKey))
return true;

for(let dependency of currentDependencies) {
if(this.isCircularDependency(checkedKey, this.getAllDependencies(dependency))) {
return true;
}
}

return false;
}

private getAllDependencies(key: keyof Partial<T>) {
if(!this.data[key])
return [];

return this.data[key].reduce((acc, currentValue) => {
return acc.concat(
currentValue.dependencies.filter(el => !acc.includes(el) && el !== key)
);
}, [] as Array<keyof Partial<T>>)
}

public async get(key: keyof Partial<T>, level?: number) {
if(typeof level === 'undefined')
level = this.data[key].length - 1;
Expand Down
106 changes: 17 additions & 89 deletions tests/dev/jasmine/given.test.ts
Original file line number Diff line number Diff line change
@@ -1,104 +1,32 @@
import useGiven from "../../../src/jasmine";
import Given from "../../../src/Given";

const { letGiven, it, fit, xit } = useGiven<{
interface letGiven {
five: number;
six: number;
}>();
}

describe("Example", () => {
letGiven('five', () => 5);

it("simple test", ({ five }) => {
expect(five).toEqual(5);
});

xit("skipped", ({ five }) => {
expect(five).toEqual(5);
});

describe("nested", () => {
letGiven('six', () => 6);

it("simple test", ({ five, six }) => {
expect(five).toEqual(5);
expect(six).toEqual(6);
});
});

it("where not defined", ({ six }) => {
expect(six).toEqual(undefined);
});

describe("overriding", () => {
letGiven('five', () => 6)

it("correct", ({ five }) => {
expect(five).not.toEqual(5);
})
});

describe("dependencies given", () => {
letGiven('six', async ({ five }) => five + 1, ['five']);
const given = new Given<letGiven>();

it("correct", ({ six }) => {
expect(six).toEqual(6);
});

describe("changed in nested describe", () => {
letGiven('five', () => 10);

it("correct used new value", ({ six }) => {
expect(six).toEqual(11);
});
});
describe("Example", () => {
beforeEach(() => {
given.add('five', () => 5);
});

describe("super", () => {
letGiven('five', ({ five }) => five + 5, ['five']);

it("success", ({ five }) => {
expect(five).toEqual(10);
});

describe("nested", () => {
letGiven('five', ({ five }) => five - 2, ['five']);

it("success", ({ five }) => {
expect(five).toEqual(8);
});
it("simple test", async () => {
const { five } = await given.loadValues();

describe("depend from another given", () => {
letGiven('six', () => 6);
letGiven('five', ({ five, six }) => five + six, ['five', 'six']);

it("success", ({ five }) => {
expect(five).toEqual(14);
});
});
});
expect(five).toEqual(5);
});

describe("specify dependencies", () => {
letGiven('six', ({ five }) => five + 1, ['five'])

it("correct", ({ six }) => {
expect(six).toEqual(6);
describe("circular dependency", () => {
beforeEach(() => {
given.add('five', ({ six }) => six + 5, ['six']);
});

describe("with async", () => {
letGiven('six', async ({ five }) => five + 2, ['five']);

it("correct", ({ six }) => {
expect(six).toEqual(7);
});
});

describe("changed in nested describe", () => {
letGiven('five', () => 10);

it("correct used new value", ({ six }) => {
expect(six).toEqual(11);
});
it("throw error", () => {
expect(() => {
given.add('six', ({ five }) => five + 5, ['five'])
}).toThrow("letGiven 'six' circular dependency");
});
});
});
104 changes: 104 additions & 0 deletions tests/dev/jasmine/letGiven.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import useGiven from "../../../src/jasmine";

const { letGiven, it, fit, xit } = useGiven<{
five: number;
six: number;
}>();

describe("Example", () => {
letGiven('five', () => 5);

it("simple test", ({ five }) => {
expect(five).toEqual(5);
});

xit("skipped", ({ five }) => {
expect(five).toEqual(5);
});

describe("nested", () => {
letGiven('six', () => 6);

it("simple test", ({ five, six }) => {
expect(five).toEqual(5);
expect(six).toEqual(6);
});
});

it("where not defined", ({ six }) => {
expect(six).toEqual(undefined);
});

describe("overriding", () => {
letGiven('five', () => 6)

it("correct", ({ five }) => {
expect(five).not.toEqual(5);
})
});

describe("dependencies given", () => {
letGiven('six', async ({ five }) => five + 1, ['five']);

it("correct", ({ six }) => {
expect(six).toEqual(6);
});

describe("changed in nested describe", () => {
letGiven('five', () => 10);

it("correct used new value", ({ six }) => {
expect(six).toEqual(11);
});
});
});

describe("super", () => {
letGiven('five', ({ five }) => five + 5, ['five']);

it("success", ({ five }) => {
expect(five).toEqual(10);
});

describe("nested", () => {
letGiven('five', ({ five }) => five - 2, ['five']);

it("success", ({ five }) => {
expect(five).toEqual(8);
});

describe("depend from another given", () => {
letGiven('six', () => 6);
letGiven('five', ({ five, six }) => five + six, ['five', 'six']);

it("success", ({ five }) => {
expect(five).toEqual(14);
});
});
});
});

describe("specify dependencies", () => {
letGiven('six', ({ five }) => five + 1, ['five'])

it("correct", ({ six }) => {
expect(six).toEqual(6);
});

describe("with async", () => {
letGiven('six', async ({ five }) => five + 2, ['five']);

it("correct", ({ six }) => {
expect(six).toEqual(7);
});
});

describe("changed in nested describe", () => {
letGiven('five', () => 10);

it("correct used new value", ({ six }) => {
expect(six).toEqual(11);
});
});
});
});
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit d5790e0

Please sign in to comment.