From 2ac840d84572b344c75a138fae4e2c86b3d097fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jovan=20Kruni=C4=87?= Date: Mon, 4 Nov 2024 18:01:03 +0100 Subject: [PATCH] fix: observable immediately returns false if scheduled beyond max delay Closes #229 --- frontend/app/src/app/util/in-range.pipe.ts | 6 ++++-- frontend/app/src/app/util/in-range.spec.ts | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/frontend/app/src/app/util/in-range.pipe.ts b/frontend/app/src/app/util/in-range.pipe.ts index 093a1660..5a6ce53d 100644 --- a/frontend/app/src/app/util/in-range.pipe.ts +++ b/frontend/app/src/app/util/in-range.pipe.ts @@ -1,6 +1,6 @@ import {Pipe, PipeTransform} from '@angular/core'; import {SCRange, isInRange, SCISO8601DateRange} from '@openstapps/core'; -import {NormalizedInterval, differenceInMilliseconds, interval, isEqual} from 'date-fns'; +import {NormalizedInterval, differenceInMilliseconds, interval} from 'date-fns'; import {EMPTY, Observable, SchedulerLike, asyncScheduler, concat, defer, map, of, timer} from 'rxjs'; @Pipe({ @@ -16,6 +16,8 @@ export class InRangePipe implements PipeTransform { export const MIN_DATE = new Date(0); export const MAX_DATE = new Date(1e15); +// Maximum safe delay for JavaScript timers (~24.8 days) +export const MAX_DELAY = 2 ** 31 - 1; @Pipe({ name: 'rangeToDateInterval', @@ -43,7 +45,7 @@ export function isWithinIntervalObservable( return concat( of(activate <= 0 && deactivate > 0), activate <= 0 ? EMPTY : timer(value.start, scheduler).pipe(map(() => true)), - isEqual(value.end, MAX_DATE) || deactivate <= 0 + differenceInMilliseconds(value.end, now) >= MAX_DELAY || deactivate <= 0 ? EMPTY : timer(value.end, scheduler).pipe(map(() => false)), ); diff --git a/frontend/app/src/app/util/in-range.spec.ts b/frontend/app/src/app/util/in-range.spec.ts index 836717b7..dc31df58 100644 --- a/frontend/app/src/app/util/in-range.spec.ts +++ b/frontend/app/src/app/util/in-range.spec.ts @@ -1,6 +1,7 @@ import {TestScheduler} from 'rxjs/testing'; import {MAX_DATE, MIN_DATE, isWithinIntervalObservable} from './in-range.pipe'; import {interval} from 'date-fns'; +import {MAX_DELAY} from './in-range.pipe'; /** * Test macro @@ -39,4 +40,7 @@ describe('isWithinIntervalObservable', () => { test([500, 1000], '499ms ^', '499ms f t 499ms (f|)'); test([500, 1000], '^ 750ms !', 'f 499ms t'); + + // Long interval test case: emit `true` and then complete (EMPTY) because `end` is beyond the delay limit + test([500, 500 + MAX_DELAY + 2000], '1s ^', '1s (t|)'); });