From eb4797313c294a70e62e5cfa8f5f8ce478d1643f Mon Sep 17 00:00:00 2001 From: psyko-gh Date: Sat, 31 Aug 2024 01:41:28 +0200 Subject: [PATCH] test: added more tests --- .../rules/__tests__/testPredicateBuilders.ts | 77 ++++++++++ src/lib/rules/__tests__/testRules.ts | 135 ++++++++++++++++++ src/lib/rules/predicate/and.ts | 2 + src/lib/rules/predicate/not.ts | 4 +- src/lib/rules/predicate/or.ts | 2 + src/lib/rules/predicate/watchproviders.ts | 2 +- 6 files changed, 220 insertions(+), 2 deletions(-) diff --git a/src/lib/rules/__tests__/testPredicateBuilders.ts b/src/lib/rules/__tests__/testPredicateBuilders.ts index 2072642..3c8bd7d 100644 --- a/src/lib/rules/__tests__/testPredicateBuilders.ts +++ b/src/lib/rules/__tests__/testPredicateBuilders.ts @@ -15,6 +15,9 @@ import { ScorePredicate } from '@core/lib/rules/predicate/score'; import { StatusPredicate } from '@core/lib/rules/predicate/status'; import { VoteCountPredicate } from '@core/lib/rules/predicate/voteCount'; import { WatchprovidersPredicate } from '@core/lib/rules/predicate/watchproviders'; +import { AndPredicate } from '@core/lib/rules/predicate/and'; +import { NotPredicate } from '@core/lib/rules/predicate/not'; +import { OrPredicate } from '@core/lib/rules/predicate/or'; const from = (data: string) => { const options = yaml.load(data) as PredicateOption; @@ -199,3 +202,77 @@ describe('WatchProvidersPredicateBuilder', () => { `).toEqual(new WatchprovidersPredicate({ terms: ['Platform 1', 'Platform 2'], region: 'us' })); }); }); + +describe('OrPredicateBuilder', () => { + it('should match', async () => { + expectPredicate(` + or: + - voteCount: greater than 1000 + - score: above 7 + `).toEqual(new OrPredicate([new VoteCountPredicate({ operator: 'gt', threshold: 1000 }), new ScorePredicate({ operator: 'gt', threshold: 7 })])); + }); + + it('should not match', async () => { + expectPredicate(` + and: + - voteCount: greater than 1000 + - score: above 7 + `).not.toEqual(new OrPredicate([new VoteCountPredicate({ operator: 'gt', threshold: 1000 }), new ScorePredicate({ operator: 'gt', threshold: 7 })])); + }); + + it('should not match', async () => { + expectPredicate(` + not: + - voteCount: greater than 1000 + - score: above 7 + `).not.toEqual(new OrPredicate([new VoteCountPredicate({ operator: 'gt', threshold: 1000 }), new ScorePredicate({ operator: 'gt', threshold: 7 })])); + }); +}); + +describe('AndPredicateBuilder', () => { + it('should match', async () => { + expectPredicate(` + and: + - voteCount: greater than 1000 + - score: above 7 + `).toEqual(new AndPredicate([new VoteCountPredicate({ operator: 'gt', threshold: 1000 }), new ScorePredicate({ operator: 'gt', threshold: 7 })])); + }); + it('should match', async () => { + expectPredicate(` + not: + - voteCount: greater than 1000 + - score: above 7 + `).not.toEqual(new AndPredicate([new VoteCountPredicate({ operator: 'gt', threshold: 1000 }), new ScorePredicate({ operator: 'gt', threshold: 7 })])); + }); + it('should match', async () => { + expectPredicate(` + or: + - voteCount: greater than 1000 + - score: above 7 + `).not.toEqual(new AndPredicate([new VoteCountPredicate({ operator: 'gt', threshold: 1000 }), new ScorePredicate({ operator: 'gt', threshold: 7 })])); + }); +}); + +describe('NotPredicateBuilder', () => { + it('should match', async () => { + expectPredicate(` + not: + - voteCount: greater than 1000 + - score: above 7 + `).toEqual(new NotPredicate([new VoteCountPredicate({ operator: 'gt', threshold: 1000 }), new ScorePredicate({ operator: 'gt', threshold: 7 })])); + }); + it('should match', async () => { + expectPredicate(` + and: + - voteCount: greater than 1000 + - score: above 7 + `).not.toEqual(new NotPredicate([new VoteCountPredicate({ operator: 'gt', threshold: 1000 }), new ScorePredicate({ operator: 'gt', threshold: 7 })])); + }); + it('should match', async () => { + expectPredicate(` + or: + - voteCount: greater than 1000 + - score: above 7 + `).not.toEqual(new NotPredicate([new VoteCountPredicate({ operator: 'gt', threshold: 1000 }), new ScorePredicate({ operator: 'gt', threshold: 7 })])); + }); +}); diff --git a/src/lib/rules/__tests__/testRules.ts b/src/lib/rules/__tests__/testRules.ts index 79cb1e9..011c562 100644 --- a/src/lib/rules/__tests__/testRules.ts +++ b/src/lib/rules/__tests__/testRules.ts @@ -15,6 +15,10 @@ import { RuntimePredicate } from '@core/lib/rules/predicate/runtime'; import { OriginalLanguagePredicate } from '@core/lib/rules/predicate/originalLanguage'; import { StatusPredicate } from '@core/lib/rules/predicate/status'; import { fromHumanReadableDuration } from '@core/lib/rules/predicate/time'; +import { ProductionCompanyPredicate } from '@core/lib/rules/predicate/productionCompany'; +import { NotPredicate } from '@core/lib/rules/predicate/not'; +import { ReleasedPredicate } from '@core/lib/rules/predicate/released'; +import { WatchprovidersPredicate } from '@core/lib/rules/predicate/watchproviders'; const movie = movieJson as MovieDetails; const testRule = (predicate: Predicate | Predicate[]) => new Rule('test rule', Array.isArray(predicate) ? predicate : [predicate], 'accept'); @@ -307,3 +311,134 @@ describe('status predicate', () => { assertRuleDoesntMatch(testRule(new StatusPredicate({ terms: ['canceled', 'post production'] })), movie); }); }); + +describe('productionCompany predicate', () => { + it('should match', async () => { + assertRuleMatches(testRule(new ProductionCompanyPredicate({ terms: ['20th Century Fox'] })), movie); + assertRuleMatches(testRule(new ProductionCompanyPredicate({ terms: ['20th Century Fox', 'Bobcat studios'] })), movie); + }); + + it('should not match', async () => { + assertRuleDoesntMatch(testRule(new ProductionCompanyPredicate({ terms: ['Bobcat studios'] })), movie); + assertRuleDoesntMatch(testRule(new ProductionCompanyPredicate({ terms: ['Bobcat studios', '11th Century Fox'] })), movie); + }); +}); + +describe('not predicate', () => { + it('should match', async () => { + assertRuleMatches(testRule(new NotPredicate([new RuntimePredicate({ operator: 'gt', threshold: 3 * 60 * 60 })])), movie); + assertRuleMatches(testRule(new NotPredicate([new RuntimePredicate({ operator: 'lt', threshold: 2 * 60 * 60 })])), movie); + assertRuleMatches( + testRule( + new NotPredicate([ + new RuntimePredicate({ operator: 'lt', threshold: 2 * 60 * 60 }), + new ProductionCompanyPredicate({ terms: ['12th Century Fox'] }), + ]) + ), + movie + ); + }); + + it('should not match', async () => { + assertRuleDoesntMatch(testRule(new NotPredicate([new RuntimePredicate({ operator: 'lt', threshold: 3 * 60 * 60 })])), movie); + assertRuleDoesntMatch(testRule(new NotPredicate([new RuntimePredicate({ operator: 'gt', threshold: 2 * 60 * 60 })])), movie); + assertRuleDoesntMatch( + testRule( + new NotPredicate([ + new RuntimePredicate({ operator: 'lt', threshold: 2 * 60 * 60 }), + new ProductionCompanyPredicate({ terms: ['20th Century Fox'] }), + ]) + ), + movie + ); + }); +}); + +describe('or predicate', () => { + it('should match', async () => { + assertRuleMatches( + testRule( + new OrPredicate([ + new StatusPredicate({ terms: ['released'] }), + new OriginalLanguagePredicate({ terms: ['en'] }), + new CastPredicate({ terms: ['Sigourney Weaver', 'Jessica Alba'], excludeVoice: false }), + ]) + ), + movie + ); + + assertRuleMatches( + testRule( + new OrPredicate([ + new StatusPredicate({ terms: ['canceled'] }), + new OriginalLanguagePredicate({ terms: ['de'] }), + new CastPredicate({ terms: ['Sigourney Weaver', 'Jessica Alba'], excludeVoice: false }), + ]) + ), + movie + ); + }); + + it('should not match', async () => { + assertRuleDoesntMatch( + testRule( + new OrPredicate([ + new StatusPredicate({ terms: ['canceled'] }), + new OriginalLanguagePredicate({ terms: ['de'] }), + new CastPredicate({ terms: ['Jessica Alba'], excludeVoice: false }), + ]) + ), + movie + ); + }); +}); + +describe('and predicate', () => { + it('should match', async () => { + assertRuleMatches( + testRule( + new AndPredicate([ + new StatusPredicate({ terms: ['released'] }), + new OriginalLanguagePredicate({ terms: ['en'] }), + new CastPredicate({ terms: ['Sigourney Weaver', 'Jessica Alba'], excludeVoice: false }), + ]) + ), + movie + ); + }); + + it('should not match', async () => { + assertRuleDoesntMatch( + testRule( + new AndPredicate([ + new StatusPredicate({ terms: ['canceled'] }), // Movie is not cancelled + new OriginalLanguagePredicate({ terms: ['en'] }), + new CastPredicate({ terms: ['Sigourney Weaver', 'Jessica Alba'], excludeVoice: false }), + ]) + ), + movie + ); + }); +}); + +describe('released predicate', () => { + it('should match', async () => { + assertRuleMatches(testRule(new ReleasedPredicate({ value: true })), movie); + // assertRuleMatches(testRule(new ReleasedPredicate({ value: true })), { ...movie, status: 'test' }); + }); + + it('should not match', async () => { + assertRuleDoesntMatch(testRule(new ReleasedPredicate({ value: false })), movie); + // assertRuleDoesntMatch(testRule(new ReleasedPredicate({ value: false })), { ...movie, status: 'test' }); + }); +}); + +describe('watchProviders predicate', () => { + it('should match', async () => { + assertRuleMatches(testRule(new WatchprovidersPredicate({ region: 'CA', terms: ['Disney Plus', 'Crave'] })), movie); + }); + + it('should not match', async () => { + assertRuleDoesntMatch(testRule(new WatchprovidersPredicate({ region: 'CA', terms: ['Platform 1', 'Platform 2'] })), movie); + }); +}); diff --git a/src/lib/rules/predicate/and.ts b/src/lib/rules/predicate/and.ts index 3f8686c..4933454 100644 --- a/src/lib/rules/predicate/and.ts +++ b/src/lib/rules/predicate/and.ts @@ -5,6 +5,8 @@ import { AndFilterOptions } from '@core/lib/rules/interfaces'; import type { PredicateFactoryClass } from '@core/lib/rules/factory'; export class AndPredicate extends GroupPredicate { + private readonly type: string = 'and'; + constructor(children: Predicate[]) { super(children); } diff --git a/src/lib/rules/predicate/not.ts b/src/lib/rules/predicate/not.ts index 53b4c19..1e01265 100644 --- a/src/lib/rules/predicate/not.ts +++ b/src/lib/rules/predicate/not.ts @@ -5,12 +5,14 @@ import { NotFilterOptions } from '@core/lib/rules/interfaces'; import type { PredicateFactoryClass } from '@core/lib/rules/factory'; export class NotPredicate extends GroupPredicate { + private readonly type: string = 'not'; + constructor(children: Predicate[]) { super(children); } matches(movie: MovieDetails): boolean { - return !this.children.every((p) => p.matches(movie)); + return this.children.every((p) => !p.matches(movie)); } } diff --git a/src/lib/rules/predicate/or.ts b/src/lib/rules/predicate/or.ts index b215039..ccc7d33 100644 --- a/src/lib/rules/predicate/or.ts +++ b/src/lib/rules/predicate/or.ts @@ -5,6 +5,8 @@ import { OrFilterOptions } from '@core/lib/rules/interfaces'; import type { PredicateFactoryClass } from '@core/lib/rules/factory'; export class OrPredicate extends GroupPredicate { + private readonly type: string = 'or'; + constructor(children: Predicate[]) { super(children); } diff --git a/src/lib/rules/predicate/watchproviders.ts b/src/lib/rules/predicate/watchproviders.ts index 746cf0d..3601a58 100644 --- a/src/lib/rules/predicate/watchproviders.ts +++ b/src/lib/rules/predicate/watchproviders.ts @@ -21,7 +21,7 @@ export class WatchprovidersPredicate extends TagsPredicate { } const tags: string[] = []; for (const region of movie.watchProviders) { - if (region.iso_3166_1.toLowerCase() === this.region) { + if (region.iso_3166_1.toLowerCase() === this.region.toLowerCase()) { if (region.flatrate) { tags.push(...region.flatrate.map((r) => r.name)); }