// Copyright (C) 2024 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import {Time, time} from './time'; import {HighPrecisionTime as HPTime} from './high_precision_time'; const t = Time.fromRaw; // Quick 'n' dirty function to convert a string to a HPtime // Used to make tests more readable // E.g. '1.3' -> {base: 1, offset: 0.3} // E.g. '-0.3' -> {base: -1, offset: 0.7} function mkTime(time: string): HPTime { const array = time.split('.'); if (array.length > 2) throw new Error(`Bad time format ${time}`); const [base, fractions] = array; const negative = time.startsWith('-'); const numBase = BigInt(base); if (fractions) { const numFractions = Number(`0.${fractions}`); if (negative) { return new HPTime(t(numBase - 1n), 1.0 - numFractions); } else { return new HPTime(t(numBase), numFractions); } } else { return new HPTime(t(numBase)); } } describe('Time', () => { it('should create a new Time object with the given base and offset', () => { const time = new HPTime(t(136n), 0.3); expect(time.integral).toBe(136n); expect(time.fractional).toBeCloseTo(0.3); }); it('should normalize when offset is >= 1', () => { let time = new HPTime(t(1n), 2.3); expect(time.integral).toBe(3n); expect(time.fractional).toBeCloseTo(0.3); time = new HPTime(t(1n), 1); expect(time.integral).toBe(2n); expect(time.fractional).toBeCloseTo(0); }); it('should normalize when offset is < 0', () => { const time = new HPTime(t(1n), -0.4); expect(time.integral).toBe(0n); expect(time.fractional).toBeCloseTo(0.6); }); it('should store timestamps without losing precision', () => { const time = new HPTime(t(1152921504606846976n)); expect(time.toTime()).toBe(1152921504606846976n as time); }); it('should store and manipulate timestamps without losing precision', () => { let time = new HPTime(t(2315700508990407843n)); time = time.addTime(2315718101717517451n as time); expect(time.toTime()).toBe(4631418610707925294n); }); test('add', () => { const result = mkTime('1.3').add(mkTime('3.1')); expect(result.integral).toEqual(4n); expect(result.fractional).toBeCloseTo(0.4); }); test('addTime', () => { const result = mkTime('200.334').addTime(t(150n)); expect(result.integral).toBe(350n); expect(result.fractional).toBeCloseTo(0.334); }); test('addNumber', () => { const result = mkTime('200.334').addNumber(150.5); expect(result.integral).toBe(350n); expect(result.fractional).toBeCloseTo(0.834); }); test('sub', () => { const result = mkTime('1.3').sub(mkTime('3.1')); expect(result.integral).toEqual(-2n); expect(result.fractional).toBeCloseTo(0.2); }); test('addTime', () => { const result = mkTime('200.334').subTime(t(150n)); expect(result.integral).toBe(50n); expect(result.fractional).toBeCloseTo(0.334); }); test('subNumber', () => { const result = mkTime('200.334').subNumber(150.5); expect(result.integral).toBe(49n); expect(result.fractional).toBeCloseTo(0.834); }); test('gte', () => { expect(mkTime('1.0').gte(t(1n))).toBe(true); expect(mkTime('1.0').gte(t(2n))).toBe(false); expect(mkTime('1.2').gte(t(1n))).toBe(true); expect(mkTime('1.2').gte(t(2n))).toBe(false); }); test('gt', () => { expect(mkTime('1.0').gt(t(1n))).toBe(false); expect(mkTime('1.0').gt(t(2n))).toBe(false); expect(mkTime('1.2').gt(t(1n))).toBe(true); expect(mkTime('1.2').gt(t(2n))).toBe(false); }); test('lte', () => { expect(mkTime('1.0').lte(t(0n))).toBe(false); expect(mkTime('1.0').lte(t(1n))).toBe(true); expect(mkTime('1.0').lte(t(2n))).toBe(true); expect(mkTime('1.2').lte(t(1n))).toBe(false); expect(mkTime('1.2').lte(t(2n))).toBe(true); }); test('lt', () => { expect(mkTime('1.0').lt(t(0n))).toBe(false); expect(mkTime('1.0').lt(t(1n))).toBe(false); expect(mkTime('1.0').lt(t(2n))).toBe(true); expect(mkTime('1.2').lt(t(1n))).toBe(false); expect(mkTime('1.2').lt(t(2n))).toBe(true); }); test('equals', () => { const time = new HPTime(t(1n), 0.2); expect(time.equals(new HPTime(t(1n), 0.2))).toBeTruthy(); expect(time.equals(new HPTime(t(0n), 1.2))).toBeTruthy(); expect(time.equals(new HPTime(t(-100n), 101.2))).toBeTruthy(); expect(time.equals(new HPTime(t(1n), 0.3))).toBeFalsy(); expect(time.equals(new HPTime(t(2n), 0.2))).toBeFalsy(); }); test('containedWithin', () => { expect(mkTime('0.9').containedWithin(t(1n), t(2n))).toBe(false); expect(mkTime('1.0').containedWithin(t(1n), t(2n))).toBe(true); expect(mkTime('1.2').containedWithin(t(1n), t(2n))).toBe(true); expect(mkTime('2.0').containedWithin(t(1n), t(2n))).toBe(false); expect(mkTime('2.1').containedWithin(t(1n), t(2n))).toBe(false); }); test('clamp', () => { let result = mkTime('1.2').clamp(t(1n), t(2n)); expect(result.integral).toBe(1n); expect(result.fractional).toBeCloseTo(0.2); result = mkTime('2.2').clamp(t(1n), t(2n)); expect(result.integral).toBe(2n); expect(result.fractional).toBeCloseTo(0); result = mkTime('0.2').clamp(t(1n), t(2n)); expect(result.integral).toBe(1n); expect(result.fractional).toBeCloseTo(0); }); test('toNumber', () => { expect(new HPTime(t(1n), 0.2).toNumber()).toBeCloseTo(1.2); expect(new HPTime(t(1000000000n), 0.0).toNumber()).toBeCloseTo(1e9); }); test('toTime', () => { expect(new HPTime(t(1n), 0.2).toTime('round')).toBe(1n); expect(new HPTime(t(1n), 0.5).toTime('round')).toBe(2n); expect(new HPTime(t(1n), 0.2).toTime('floor')).toBe(1n); expect(new HPTime(t(1n), 0.5).toTime('floor')).toBe(1n); expect(new HPTime(t(1n), 0.2).toTime('ceil')).toBe(2n); expect(new HPTime(t(1n), 0.5).toTime('ceil')).toBe(2n); }); test('toString', () => { expect(mkTime('1.3').toString()).toBe('1.3'); expect(mkTime('12983423847.332533').toString()).toBe('12983423847.332533'); expect(new HPTime(t(234n)).toString()).toBe('234'); }); test('abs', () => { let result = mkTime('-0.7').abs(); expect(result.integral).toEqual(0n); expect(result.fractional).toBeCloseTo(0.7); result = mkTime('-1.3').abs(); expect(result.integral).toEqual(1n); expect(result.fractional).toBeCloseTo(0.3); result = mkTime('-100').abs(); expect(result.integral).toEqual(100n); expect(result.fractional).toBeCloseTo(0); result = mkTime('34.5345').abs(); expect(result.integral).toEqual(34n); expect(result.fractional).toBeCloseTo(0.5345); }); });