1// Copyright (C) 2024 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import {HighPrecisionTime as HPTime} from './high_precision_time'; 16import {HighPrecisionTimeSpan as HPTimeSpan} from './high_precision_time_span'; 17import {Time} from './time'; 18 19const t = Time.fromRaw; 20 21// Quick 'n' dirty function to convert a string to a HPtime 22// Used to make tests more readable 23// E.g. '1.3' -> {base: 1, offset: 0.3} 24// E.g. '-0.3' -> {base: -1, offset: 0.7} 25function hptime(time: string): HPTime { 26 const array = time.split('.'); 27 if (array.length > 2) throw new Error(`Bad time format ${time}`); 28 const [base, fractions] = array; 29 const negative = time.startsWith('-'); 30 const numBase = BigInt(base); 31 32 if (fractions) { 33 const numFractions = Number(`0.${fractions}`); 34 if (negative) { 35 return new HPTime(t(numBase - 1n), 1.0 - numFractions); 36 } else { 37 return new HPTime(t(numBase), numFractions); 38 } 39 } else { 40 return new HPTime(t(numBase)); 41 } 42} 43 44describe('HighPrecisionTimeSpan', () => { 45 it('can be constructed from integer time', () => { 46 const span = HPTimeSpan.fromTime(t(10n), t(20n)); 47 expect(span.start.integral).toEqual(10n); 48 expect(span.start.fractional).toBeCloseTo(0); 49 expect(span.duration).toBeCloseTo(10); 50 }); 51 52 it('can be constructed from hp times', () => { 53 const span = HPTimeSpan.fromHpTimes(hptime('123'), hptime('456')); 54 expect(span.start.integral).toEqual(123n); 55 expect(span.start.fractional).toBeCloseTo(0); 56 expect(span.duration).toBeCloseTo(333); 57 }); 58 59 it('can be constructed from hp times reversed', () => { 60 const span = HPTimeSpan.fromHpTimes(hptime('456'), hptime('123')); 61 expect(span.start.integral).toEqual(123n); 62 expect(span.start.fractional).toBeCloseTo(0); 63 expect(span.duration).toBeCloseTo(333); 64 }); 65 66 test('end', () => { 67 const span = HPTimeSpan.fromTime(t(10n), t(20n)); 68 expect(span.end.integral).toEqual(20n); 69 expect(span.end.fractional).toBeCloseTo(0); 70 }); 71 72 test('midpoint', () => { 73 const span = HPTimeSpan.fromTime(t(10n), t(20n)); 74 expect(span.midpoint.integral).toEqual(15n); 75 expect(span.midpoint.fractional).toBeCloseTo(0); 76 }); 77 78 test('translate', () => { 79 const span = HPTimeSpan.fromTime(t(10n), t(20n)); 80 expect(span.translate(10).start.integral).toEqual(20n); 81 expect(span.translate(10).start.fractional).toEqual(0); 82 expect(span.translate(10).duration).toBeCloseTo(10); 83 }); 84 85 test('pad', () => { 86 const span = HPTimeSpan.fromTime(t(10n), t(20n)); 87 expect(span.pad(10).start.integral).toEqual(0n); 88 expect(span.pad(10).start.fractional).toEqual(0); 89 expect(span.pad(10).duration).toBeCloseTo(30); 90 }); 91 92 test('scale', () => { 93 const span = HPTimeSpan.fromTime(t(10n), t(20n)); 94 const zoomed = span.scale(2, 0.5, 0); 95 expect(zoomed.start.integral).toEqual(5n); 96 expect(zoomed.start.fractional).toBeCloseTo(0); 97 expect(zoomed.duration).toBeCloseTo(20); 98 }); 99 100 test('intersect', () => { 101 const span = new HPTimeSpan(hptime('5'), 3); 102 103 let result = span.intersect(t(7n), t(10n)); 104 expect(result.start.integral).toBe(7n); 105 expect(result.start.fractional).toBeCloseTo(0); 106 expect(result.duration).toBeCloseTo(1); 107 108 result = span.intersect(t(1n), t(6n)); 109 expect(result.start.integral).toBe(5n); 110 expect(result.start.fractional).toBeCloseTo(0); 111 expect(result.duration).toBeCloseTo(1); 112 113 // Non overlapping time spans should return 0 114 result = span.intersect(t(100n), t(200n)); 115 expect(result.start.integral).toBe(0n); 116 expect(result.start.fractional).toBeCloseTo(0); 117 expect(result.duration).toBeCloseTo(0); 118 }); 119 120 test('fitWithin', () => { 121 const span = new HPTimeSpan(hptime('5'), 3); 122 123 let result = span.fitWithin(t(10n), t(20n)); 124 expect(result.start.integral).toBe(10n); 125 expect(result.start.fractional).toBeCloseTo(0); 126 expect(result.duration).toBeCloseTo(3); 127 128 result = span.fitWithin(t(-10n), t(-5n)); 129 expect(result.start.integral).toBe(-8n); 130 expect(result.start.fractional).toBeCloseTo(0); 131 expect(result.duration).toBeCloseTo(3); 132 133 result = span.fitWithin(t(1n), t(2n)); 134 expect(result.start.integral).toBe(1n); 135 expect(result.start.fractional).toBeCloseTo(0); 136 expect(result.duration).toBeCloseTo(1); 137 }); 138 139 test('clampDuration', () => { 140 const span = new HPTimeSpan(hptime('5'), 1); 141 const clamped = span.clampDuration(10); 142 143 expect(clamped.start.integral).toBe(5n); 144 expect(clamped.start.fractional).toBeCloseTo(0); 145 expect(clamped.duration).toBeCloseTo(10); 146 }); 147 148 test('equality', () => { 149 const span = new HPTimeSpan(hptime('10'), 10); 150 expect(span.equals(span)).toBe(true); 151 expect(span.equals(new HPTimeSpan(hptime('10'), 10.5))).toBe(false); 152 expect(span.equals(new HPTimeSpan(hptime('10.1'), 10))).toBe(false); 153 }); 154 155 test('contains', () => { 156 const span = new HPTimeSpan(hptime('10'), 10); 157 expect(span.contains(t(9n))).toBe(false); 158 expect(span.contains(t(10n))).toBe(true); 159 expect(span.contains(t(19n))).toBe(true); 160 expect(span.contains(t(20n))).toBe(false); 161 }); 162 163 test('containsSpan', () => { 164 const span = new HPTimeSpan(hptime('10'), 10); 165 expect(span.containsSpan(t(9n), t(15n))).toBe(false); 166 expect(span.containsSpan(t(10n), t(15n))).toBe(true); 167 expect(span.containsSpan(t(15n), t(20n))).toBe(true); 168 expect(span.containsSpan(t(15n), t(21n))).toBe(false); 169 expect(span.containsSpan(t(30n), t(40n))).toBe(false); 170 }); 171 172 test('overlapsSpan', () => { 173 const span = new HPTimeSpan(hptime('10'), 10); 174 expect(span.overlaps(t(9n), t(10n))).toBe(false); 175 expect(span.overlaps(t(9n), t(11n))).toBe(true); 176 expect(span.overlaps(t(19n), t(21n))).toBe(true); 177 expect(span.overlaps(t(20n), t(21n))).toBe(false); 178 }); 179}); 180