From a8740b8f6b5a0554f6cb0e0be9f0e99932932f2f Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 5 Apr 2023 20:30:21 -0700 Subject: [PATCH] Add camera manager range tests. --- src/camera-manager/range.ts | 2 +- tests/camera-manager/range.test.ts | 165 +++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 tests/camera-manager/range.test.ts diff --git a/src/camera-manager/range.ts b/src/camera-manager/range.ts index 8518b646..c358395b 100644 --- a/src/camera-manager/range.ts +++ b/src/camera-manager/range.ts @@ -36,7 +36,7 @@ export class MemoryRangeSet implements MemoryRangeSetInterface { } } -interface ExpiringRange extends Range { +export interface ExpiringRange extends Range { expires: Date; } diff --git a/tests/camera-manager/range.test.ts b/tests/camera-manager/range.test.ts new file mode 100644 index 00000000..8051baad --- /dev/null +++ b/tests/camera-manager/range.test.ts @@ -0,0 +1,165 @@ +import add from 'date-fns/add'; +import sub from 'date-fns/sub'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { + compressRanges, + DateRange, + ExpiringMemoryRangeSet, + ExpiringRange, + MemoryRangeSet, + rangesOverlap, +} from '../../src/camera-manager/range.js'; + +describe('MemoryRangeSet', () => { + const rangeSet = new MemoryRangeSet(); + const now = new Date(); + const range: DateRange = { + start: now, + end: add(now, { hours: 1 }), + }; + + beforeEach(() => { + rangeSet.clear(); + }); + + it('should have coverage when added', () => { + rangeSet.add(range); + expect(rangeSet.hasCoverage(range)).toBeTruthy(); + }); + it('should not have coverage when overlapping', () => { + rangeSet.add(range); + expect(rangeSet.hasCoverage({ ...range, end: add(now, { hours: 2 }) })).toBeFalsy(); + }); + it('should not have coverage when non-overlapping', () => { + rangeSet.add(range); + expect( + rangeSet.hasCoverage({ + start: add(now, { hours: 2 }), + end: add(now, { hours: 3 }), + }), + ).toBeFalsy(); + }); + + it('should be empty when cleared', () => { + rangeSet.add(range); + rangeSet.clear(); + expect(rangeSet.hasCoverage(range)).toBeFalsy(); + }); +}); + +describe('ExpiringMemoryRangeSet', () => { + const expiringRangeSet = new ExpiringMemoryRangeSet(); + const now = new Date(); + const expiringRange: ExpiringRange = { + start: now, + end: add(now, { hours: 1 }), + expires: add(now, { hours: 1 }), + }; + + beforeEach(() => { + expiringRangeSet.clear(); + }); + + it('should have coverage when added', () => { + expiringRangeSet.add(expiringRange); + expect(expiringRangeSet.hasCoverage(expiringRange)).toBeTruthy(); + }); + it('should not have coverage when overlapping', () => { + expiringRangeSet.add(expiringRange); + expect( + expiringRangeSet.hasCoverage({ ...expiringRange, end: add(now, { hours: 2 }) }), + ).toBeFalsy(); + }); + it('should not have coverage when non-overlapping', () => { + expiringRangeSet.add(expiringRange); + expect( + expiringRangeSet.hasCoverage({ + start: add(now, { hours: 2 }), + end: add(now, { hours: 3 }), + }), + ).toBeFalsy(); + }); + it('should not have coverage when expired', () => { + expiringRangeSet.add(expiringRange); + + vi.useFakeTimers(); + vi.setSystemTime(add(now, { hours: 2 })); + expect(expiringRangeSet.hasCoverage(expiringRange)).toBeFalsy(); + vi.useRealTimers(); + }); + + it('should be empty when cleared', () => { + expiringRangeSet.add(expiringRange); + expiringRangeSet.clear(); + expect(expiringRangeSet.hasCoverage(expiringRange)).toBeFalsy(); + }); +}); + +describe('rangesOverlap', () => { + const now = new Date(); + const a: DateRange = { + start: now, + end: add(now, { hours: 1 }), + }; + + it('should overlap when A starts within B', () => { + expect(rangesOverlap(a, { ...a, start: add(now, { minutes: 30 }) })).toBeTruthy(); + }); + it('should overlap when A ends within B', () => { + expect(rangesOverlap(a, { ...a, end: add(now, { hours: 2 }) })).toBeTruthy(); + }); + it('should overlap when A is entirely within B', () => { + expect( + rangesOverlap(a, { + start: add(now, { minutes: 1 }), + end: add(now, { minutes: 59 }), + }), + ).toBeTruthy(); + }); + + it('should not overlap when A is entirely unrelated to B', () => { + expect( + rangesOverlap(a, { start: sub(now, { hours: 2 }), end: sub(now, { hours: 1 }) }), + ).toBeFalsy(); + }); +}); + +describe('compressRanges', () => { + const now = new Date(); + const nowPlusOne = add(now, { minutes: 1 }); + const nowPlusTwo = add(now, { minutes: 2 }); + const nowPlusThree = add(now, { minutes: 3 }); + + it('should compress nearby ranges', () => { + expect( + compressRanges([ + { start: now, end: nowPlusOne }, + { start: nowPlusOne, end: nowPlusTwo }, + ]), + ).toEqual([{ start: now, end: nowPlusTwo }]); + }); + + it('should not compress unrelated ranges', () => { + const input = [ + { start: now, end: nowPlusOne }, + { start: nowPlusTwo, end: nowPlusThree }, + ]; + expect(compressRanges(input)).toEqual(input); + }); + + it('should compress unrelated ranges with large tolerance', () => { + const input = [ + { start: now, end: nowPlusOne }, + { start: nowPlusTwo, end: nowPlusThree }, + ]; + expect(compressRanges(input, 60 * 60)).toEqual([{ start: now, end: nowPlusThree }]); + }); + + it('should compress number based ranges', () => { + const input = [ + { start: 1, end: 2 }, + { start: 2, end: 3 }, + ]; + expect(compressRanges(input)).toEqual([{ start: 1, end: 3 }]); + }); +});