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 {Time, time} from './time'; 16import {HighPrecisionTime as HPTime} from './high_precision_time'; 17 18const t = Time.fromRaw; 19 20// Quick 'n' dirty function to convert a string to a HPtime 21// Used to make tests more readable 22// E.g. '1.3' -> {base: 1, offset: 0.3} 23// E.g. '-0.3' -> {base: -1, offset: 0.7} 24function mkTime(time: string): HPTime { 25 const array = time.split('.'); 26 if (array.length > 2) throw new Error(`Bad time format ${time}`); 27 const [base, fractions] = array; 28 const negative = time.startsWith('-'); 29 const numBase = BigInt(base); 30 31 if (fractions) { 32 const numFractions = Number(`0.${fractions}`); 33 if (negative) { 34 return new HPTime(t(numBase - 1n), 1.0 - numFractions); 35 } else { 36 return new HPTime(t(numBase), numFractions); 37 } 38 } else { 39 return new HPTime(t(numBase)); 40 } 41} 42 43describe('Time', () => { 44 it('should create a new Time object with the given base and offset', () => { 45 const time = new HPTime(t(136n), 0.3); 46 expect(time.integral).toBe(136n); 47 expect(time.fractional).toBeCloseTo(0.3); 48 }); 49 50 it('should normalize when offset is >= 1', () => { 51 let time = new HPTime(t(1n), 2.3); 52 expect(time.integral).toBe(3n); 53 expect(time.fractional).toBeCloseTo(0.3); 54 55 time = new HPTime(t(1n), 1); 56 expect(time.integral).toBe(2n); 57 expect(time.fractional).toBeCloseTo(0); 58 }); 59 60 it('should normalize when offset is < 0', () => { 61 const time = new HPTime(t(1n), -0.4); 62 expect(time.integral).toBe(0n); 63 expect(time.fractional).toBeCloseTo(0.6); 64 }); 65 66 it('should store timestamps without losing precision', () => { 67 const time = new HPTime(t(1152921504606846976n)); 68 expect(time.toTime()).toBe(1152921504606846976n as time); 69 }); 70 71 it('should store and manipulate timestamps without losing precision', () => { 72 let time = new HPTime(t(2315700508990407843n)); 73 time = time.addTime(2315718101717517451n as time); 74 expect(time.toTime()).toBe(4631418610707925294n); 75 }); 76 77 test('add', () => { 78 const result = mkTime('1.3').add(mkTime('3.1')); 79 expect(result.integral).toEqual(4n); 80 expect(result.fractional).toBeCloseTo(0.4); 81 }); 82 83 test('addTime', () => { 84 const result = mkTime('200.334').addTime(t(150n)); 85 expect(result.integral).toBe(350n); 86 expect(result.fractional).toBeCloseTo(0.334); 87 }); 88 89 test('addNumber', () => { 90 const result = mkTime('200.334').addNumber(150.5); 91 expect(result.integral).toBe(350n); 92 expect(result.fractional).toBeCloseTo(0.834); 93 }); 94 95 test('sub', () => { 96 const result = mkTime('1.3').sub(mkTime('3.1')); 97 expect(result.integral).toEqual(-2n); 98 expect(result.fractional).toBeCloseTo(0.2); 99 }); 100 101 test('addTime', () => { 102 const result = mkTime('200.334').subTime(t(150n)); 103 expect(result.integral).toBe(50n); 104 expect(result.fractional).toBeCloseTo(0.334); 105 }); 106 107 test('subNumber', () => { 108 const result = mkTime('200.334').subNumber(150.5); 109 expect(result.integral).toBe(49n); 110 expect(result.fractional).toBeCloseTo(0.834); 111 }); 112 113 test('gte', () => { 114 expect(mkTime('1.0').gte(t(1n))).toBe(true); 115 expect(mkTime('1.0').gte(t(2n))).toBe(false); 116 expect(mkTime('1.2').gte(t(1n))).toBe(true); 117 expect(mkTime('1.2').gte(t(2n))).toBe(false); 118 }); 119 120 test('gt', () => { 121 expect(mkTime('1.0').gt(t(1n))).toBe(false); 122 expect(mkTime('1.0').gt(t(2n))).toBe(false); 123 expect(mkTime('1.2').gt(t(1n))).toBe(true); 124 expect(mkTime('1.2').gt(t(2n))).toBe(false); 125 }); 126 127 test('lte', () => { 128 expect(mkTime('1.0').lte(t(0n))).toBe(false); 129 expect(mkTime('1.0').lte(t(1n))).toBe(true); 130 expect(mkTime('1.0').lte(t(2n))).toBe(true); 131 expect(mkTime('1.2').lte(t(1n))).toBe(false); 132 expect(mkTime('1.2').lte(t(2n))).toBe(true); 133 }); 134 135 test('lt', () => { 136 expect(mkTime('1.0').lt(t(0n))).toBe(false); 137 expect(mkTime('1.0').lt(t(1n))).toBe(false); 138 expect(mkTime('1.0').lt(t(2n))).toBe(true); 139 expect(mkTime('1.2').lt(t(1n))).toBe(false); 140 expect(mkTime('1.2').lt(t(2n))).toBe(true); 141 }); 142 143 test('equals', () => { 144 const time = new HPTime(t(1n), 0.2); 145 expect(time.equals(new HPTime(t(1n), 0.2))).toBeTruthy(); 146 expect(time.equals(new HPTime(t(0n), 1.2))).toBeTruthy(); 147 expect(time.equals(new HPTime(t(-100n), 101.2))).toBeTruthy(); 148 expect(time.equals(new HPTime(t(1n), 0.3))).toBeFalsy(); 149 expect(time.equals(new HPTime(t(2n), 0.2))).toBeFalsy(); 150 }); 151 152 test('containedWithin', () => { 153 expect(mkTime('0.9').containedWithin(t(1n), t(2n))).toBe(false); 154 expect(mkTime('1.0').containedWithin(t(1n), t(2n))).toBe(true); 155 expect(mkTime('1.2').containedWithin(t(1n), t(2n))).toBe(true); 156 expect(mkTime('2.0').containedWithin(t(1n), t(2n))).toBe(false); 157 expect(mkTime('2.1').containedWithin(t(1n), t(2n))).toBe(false); 158 }); 159 160 test('clamp', () => { 161 let result = mkTime('1.2').clamp(t(1n), t(2n)); 162 expect(result.integral).toBe(1n); 163 expect(result.fractional).toBeCloseTo(0.2); 164 165 result = mkTime('2.2').clamp(t(1n), t(2n)); 166 expect(result.integral).toBe(2n); 167 expect(result.fractional).toBeCloseTo(0); 168 169 result = mkTime('0.2').clamp(t(1n), t(2n)); 170 expect(result.integral).toBe(1n); 171 expect(result.fractional).toBeCloseTo(0); 172 }); 173 174 test('toNumber', () => { 175 expect(new HPTime(t(1n), 0.2).toNumber()).toBeCloseTo(1.2); 176 expect(new HPTime(t(1000000000n), 0.0).toNumber()).toBeCloseTo(1e9); 177 }); 178 179 test('toTime', () => { 180 expect(new HPTime(t(1n), 0.2).toTime('round')).toBe(1n); 181 expect(new HPTime(t(1n), 0.5).toTime('round')).toBe(2n); 182 expect(new HPTime(t(1n), 0.2).toTime('floor')).toBe(1n); 183 expect(new HPTime(t(1n), 0.5).toTime('floor')).toBe(1n); 184 expect(new HPTime(t(1n), 0.2).toTime('ceil')).toBe(2n); 185 expect(new HPTime(t(1n), 0.5).toTime('ceil')).toBe(2n); 186 }); 187 188 test('toString', () => { 189 expect(mkTime('1.3').toString()).toBe('1.3'); 190 expect(mkTime('12983423847.332533').toString()).toBe('12983423847.332533'); 191 expect(new HPTime(t(234n)).toString()).toBe('234'); 192 }); 193 194 test('abs', () => { 195 let result = mkTime('-0.7').abs(); 196 expect(result.integral).toEqual(0n); 197 expect(result.fractional).toBeCloseTo(0.7); 198 199 result = mkTime('-1.3').abs(); 200 expect(result.integral).toEqual(1n); 201 expect(result.fractional).toBeCloseTo(0.3); 202 203 result = mkTime('-100').abs(); 204 expect(result.integral).toEqual(100n); 205 expect(result.fractional).toBeCloseTo(0); 206 207 result = mkTime('34.5345').abs(); 208 expect(result.integral).toEqual(34n); 209 expect(result.fractional).toBeCloseTo(0.5345); 210 }); 211}); 212