1/* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16import {ElapsedTimestamp, RealTimestamp, Timestamp, TimestampType} from 'trace/timestamp'; 17import {TimeUtils} from './time_utils'; 18 19describe('TimeUtils', () => { 20 const MILLISECOND = BigInt(1000000); 21 const SECOND = BigInt(1000) * MILLISECOND; 22 const MINUTE = BigInt(60) * SECOND; 23 const HOUR = BigInt(60) * MINUTE; 24 const DAY = BigInt(24) * HOUR; 25 26 describe('compareFn', () => { 27 it('throws if timestamps have different type', () => { 28 const real = new RealTimestamp(10n); 29 const elapsed = new ElapsedTimestamp(10n); 30 31 expect(() => { 32 TimeUtils.compareFn(real, elapsed); 33 }).toThrow(); 34 }); 35 36 it('allows to sort arrays', () => { 37 const array = [ 38 new RealTimestamp(100n), 39 new RealTimestamp(10n), 40 new RealTimestamp(12n), 41 new RealTimestamp(110n), 42 new RealTimestamp(11n), 43 ]; 44 array.sort(TimeUtils.compareFn); 45 46 const expected = [ 47 new RealTimestamp(10n), 48 new RealTimestamp(11n), 49 new RealTimestamp(12n), 50 new RealTimestamp(100n), 51 new RealTimestamp(110n), 52 ]; 53 expect(array).toEqual(expected); 54 }); 55 }); 56 57 it('nanosecondsToHuman', () => { 58 expect(TimeUtils.format(new ElapsedTimestamp(0n), true)).toEqual('0ms'); 59 expect(TimeUtils.format(new ElapsedTimestamp(0n), false)).toEqual('0ns'); 60 expect(TimeUtils.format(new ElapsedTimestamp(1000n), true)).toEqual('0ms'); 61 expect(TimeUtils.format(new ElapsedTimestamp(1000n), false)).toEqual('1000ns'); 62 expect(TimeUtils.format(new ElapsedTimestamp(MILLISECOND - 1n), true)).toEqual('0ms'); 63 expect(TimeUtils.format(new ElapsedTimestamp(MILLISECOND), true)).toEqual('1ms'); 64 expect(TimeUtils.format(new ElapsedTimestamp(10n * MILLISECOND), true)).toEqual('10ms'); 65 66 expect(TimeUtils.format(new ElapsedTimestamp(SECOND - 1n), true)).toEqual('999ms'); 67 expect(TimeUtils.format(new ElapsedTimestamp(SECOND), true)).toEqual('1s0ms'); 68 expect(TimeUtils.format(new ElapsedTimestamp(SECOND + MILLISECOND), true)).toEqual('1s1ms'); 69 expect(TimeUtils.format(new ElapsedTimestamp(SECOND + MILLISECOND), false)).toEqual('1s1ms0ns'); 70 71 expect(TimeUtils.format(new ElapsedTimestamp(MINUTE - 1n), true)).toEqual('59s999ms'); 72 expect(TimeUtils.format(new ElapsedTimestamp(MINUTE), true)).toEqual('1m0s0ms'); 73 expect(TimeUtils.format(new ElapsedTimestamp(MINUTE + SECOND + MILLISECOND), true)).toEqual( 74 '1m1s1ms' 75 ); 76 expect( 77 TimeUtils.format(new ElapsedTimestamp(MINUTE + SECOND + MILLISECOND + 1n), true) 78 ).toEqual('1m1s1ms'); 79 expect( 80 TimeUtils.format(new ElapsedTimestamp(MINUTE + SECOND + MILLISECOND + 1n), false) 81 ).toEqual('1m1s1ms1ns'); 82 83 expect(TimeUtils.format(new ElapsedTimestamp(HOUR - 1n), true)).toEqual('59m59s999ms'); 84 expect(TimeUtils.format(new ElapsedTimestamp(HOUR - 1n), false)).toEqual('59m59s999ms999999ns'); 85 expect(TimeUtils.format(new ElapsedTimestamp(HOUR), true)).toEqual('1h0m0s0ms'); 86 expect( 87 TimeUtils.format(new ElapsedTimestamp(HOUR + MINUTE + SECOND + MILLISECOND), true) 88 ).toEqual('1h1m1s1ms'); 89 90 expect(TimeUtils.format(new ElapsedTimestamp(DAY - 1n), true)).toEqual('23h59m59s999ms'); 91 expect(TimeUtils.format(new ElapsedTimestamp(DAY), true)).toEqual('1d0h0m0s0ms'); 92 expect( 93 TimeUtils.format(new ElapsedTimestamp(DAY + HOUR + MINUTE + SECOND + MILLISECOND), true) 94 ).toEqual('1d1h1m1s1ms'); 95 }); 96 97 it('humanElapsedToNanoseconds', () => { 98 expect(TimeUtils.parseHumanElapsed('0ns')).toEqual(new ElapsedTimestamp(0n)); 99 expect(TimeUtils.parseHumanElapsed('1000ns')).toEqual(new ElapsedTimestamp(1000n)); 100 expect(TimeUtils.parseHumanElapsed('0ms')).toEqual(new ElapsedTimestamp(0n)); 101 expect(TimeUtils.parseHumanElapsed('1ms')).toEqual(new ElapsedTimestamp(MILLISECOND)); 102 expect(TimeUtils.parseHumanElapsed('10ms')).toEqual(new ElapsedTimestamp(10n * MILLISECOND)); 103 104 expect(TimeUtils.parseHumanElapsed('999ms')).toEqual(new ElapsedTimestamp(999n * MILLISECOND)); 105 expect(TimeUtils.parseHumanElapsed('1s')).toEqual(new ElapsedTimestamp(SECOND)); 106 expect(TimeUtils.parseHumanElapsed('1s0ms')).toEqual(new ElapsedTimestamp(SECOND)); 107 expect(TimeUtils.parseHumanElapsed('1s0ms0ns')).toEqual(new ElapsedTimestamp(SECOND)); 108 expect(TimeUtils.parseHumanElapsed('1s0ms1ns')).toEqual(new ElapsedTimestamp(SECOND + 1n)); 109 expect(TimeUtils.parseHumanElapsed('0d1s1ms')).toEqual( 110 new ElapsedTimestamp(SECOND + MILLISECOND) 111 ); 112 113 expect(TimeUtils.parseHumanElapsed('1m0s0ms')).toEqual(new ElapsedTimestamp(MINUTE)); 114 expect(TimeUtils.parseHumanElapsed('1m1s1ms')).toEqual( 115 new ElapsedTimestamp(MINUTE + SECOND + MILLISECOND) 116 ); 117 118 expect(TimeUtils.parseHumanElapsed('1h0m')).toEqual(new ElapsedTimestamp(HOUR)); 119 expect(TimeUtils.parseHumanElapsed('1h1m1s1ms')).toEqual( 120 new ElapsedTimestamp(HOUR + MINUTE + SECOND + MILLISECOND) 121 ); 122 123 expect(TimeUtils.parseHumanElapsed('1d0s1ms')).toEqual(new ElapsedTimestamp(DAY + MILLISECOND)); 124 expect(TimeUtils.parseHumanElapsed('1d1h1m1s1ms')).toEqual( 125 new ElapsedTimestamp(DAY + HOUR + MINUTE + SECOND + MILLISECOND) 126 ); 127 128 expect(TimeUtils.parseHumanElapsed('1d')).toEqual(new ElapsedTimestamp(DAY)); 129 expect(TimeUtils.parseHumanElapsed('1d1ms')).toEqual(new ElapsedTimestamp(DAY + MILLISECOND)); 130 }); 131 132 it('humanToNanoseconds throws on invalid input format', () => { 133 const invalidFormatError = new Error('Invalid elapsed timestamp format'); 134 expect(() => TimeUtils.parseHumanElapsed('1d1h1m1s0ns1ms')).toThrow(invalidFormatError); 135 expect(() => TimeUtils.parseHumanElapsed('1dns')).toThrow(invalidFormatError); 136 expect(() => TimeUtils.parseHumanElapsed('100')).toThrow(invalidFormatError); 137 expect(() => TimeUtils.parseHumanElapsed('')).toThrow(invalidFormatError); 138 }); 139 140 it('nanosecondsToHumanReal', () => { 141 const NOV_10_2022 = 1668038400000n * MILLISECOND; 142 expect(TimeUtils.format(new RealTimestamp(0n), true)).toEqual('1970-01-01T00:00:00.000'); 143 expect( 144 TimeUtils.format( 145 new RealTimestamp( 146 NOV_10_2022 + 22n * HOUR + 4n * MINUTE + 54n * SECOND + 186n * MILLISECOND + 123212n 147 ), 148 true 149 ) 150 ).toEqual('2022-11-10T22:04:54.186'); 151 expect(TimeUtils.format(new RealTimestamp(NOV_10_2022), true)).toEqual( 152 '2022-11-10T00:00:00.000' 153 ); 154 expect(TimeUtils.format(new RealTimestamp(NOV_10_2022 + 1n), true)).toEqual( 155 '2022-11-10T00:00:00.000' 156 ); 157 158 expect(TimeUtils.format(new RealTimestamp(0n), false)).toEqual('1970-01-01T00:00:00.000000000'); 159 expect( 160 TimeUtils.format( 161 new RealTimestamp( 162 NOV_10_2022 + 22n * HOUR + 4n * MINUTE + 54n * SECOND + 186n * MILLISECOND + 123212n 163 ), 164 false 165 ) 166 ).toEqual('2022-11-10T22:04:54.186123212'); 167 expect(TimeUtils.format(new RealTimestamp(NOV_10_2022), false)).toEqual( 168 '2022-11-10T00:00:00.000000000' 169 ); 170 expect(TimeUtils.format(new RealTimestamp(NOV_10_2022 + 1n), false)).toEqual( 171 '2022-11-10T00:00:00.000000001' 172 ); 173 }); 174 175 it('humanRealToNanoseconds', () => { 176 const NOV_10_2022 = 1668038400000n * MILLISECOND; 177 expect(TimeUtils.parseHumanReal('2022-11-10T22:04:54.186123212')).toEqual( 178 new RealTimestamp( 179 NOV_10_2022 + 22n * HOUR + 4n * MINUTE + 54n * SECOND + 186n * MILLISECOND + 123212n 180 ) 181 ); 182 expect(TimeUtils.parseHumanReal('2022-11-10T22:04:54.186123212Z')).toEqual( 183 new RealTimestamp(1668117894186123212n) 184 ); 185 expect(TimeUtils.parseHumanReal('2022-11-10T22:04:54.186000212')).toEqual( 186 new RealTimestamp(1668117894186000212n) 187 ); 188 expect(TimeUtils.parseHumanReal('2022-11-10T22:04:54.006000002')).toEqual( 189 new RealTimestamp(1668117894006000002n) 190 ); 191 expect(TimeUtils.parseHumanReal('2022-11-10T06:04:54.006000002')).toEqual( 192 new RealTimestamp(1668060294006000002n) 193 ); 194 }); 195 196 it('canReverseDateFormatting', () => { 197 let timestamp = new RealTimestamp(1668117894186123212n); 198 expect(TimeUtils.parseHumanReal(TimeUtils.format(timestamp))).toEqual(timestamp); 199 200 timestamp = new ElapsedTimestamp(DAY + HOUR + MINUTE + SECOND + MILLISECOND + 1n); 201 expect(TimeUtils.parseHumanElapsed(TimeUtils.format(timestamp))).toEqual(timestamp); 202 }); 203 204 it('humanToNanoseconds throws on invalid input format', () => { 205 const invalidFormatError = new Error('Invalid real timestamp format'); 206 expect(() => TimeUtils.parseHumanReal('23h59m59s999ms5ns')).toThrow(invalidFormatError); 207 expect(() => TimeUtils.parseHumanReal('1d')).toThrow(invalidFormatError); 208 expect(() => TimeUtils.parseHumanReal('100')).toThrow(invalidFormatError); 209 expect(() => TimeUtils.parseHumanReal('06h4m54s, 10 Nov 2022')).toThrow(invalidFormatError); 210 expect(() => TimeUtils.parseHumanReal('')).toThrow(invalidFormatError); 211 }); 212 213 it('nano second regex accept all expected inputs', () => { 214 expect(TimeUtils.NS_TIMESTAMP_REGEX.test('123')).toBeTrue(); 215 expect(TimeUtils.NS_TIMESTAMP_REGEX.test('123ns')).toBeTrue(); 216 expect(TimeUtils.NS_TIMESTAMP_REGEX.test('123 ns')).toBeTrue(); 217 expect(TimeUtils.NS_TIMESTAMP_REGEX.test(' 123 ns ')).toBeTrue(); 218 expect(TimeUtils.NS_TIMESTAMP_REGEX.test(' 123 ')).toBeTrue(); 219 220 expect(TimeUtils.NS_TIMESTAMP_REGEX.test('1a23')).toBeFalse(); 221 expect(TimeUtils.NS_TIMESTAMP_REGEX.test('a123 ns')).toBeFalse(); 222 expect(TimeUtils.NS_TIMESTAMP_REGEX.test('')).toBeFalse(); 223 }); 224 225 it('format real', () => { 226 expect(TimeUtils.format(Timestamp.from(TimestampType.REAL, 100n, 500n))).toEqual( 227 '1970-01-01T00:00:00.000000600' 228 ); 229 expect( 230 TimeUtils.format(Timestamp.from(TimestampType.REAL, 100n * MILLISECOND, 500n), true) 231 ).toEqual('1970-01-01T00:00:00.100'); 232 }); 233 234 it('format elapsed', () => { 235 expect( 236 TimeUtils.format(Timestamp.from(TimestampType.ELAPSED, 100n * MILLISECOND, 500n), true) 237 ).toEqual('100ms'); 238 expect( 239 TimeUtils.format(Timestamp.from(TimestampType.ELAPSED, 100n * MILLISECOND), true) 240 ).toEqual('100ms'); 241 expect( 242 TimeUtils.format(Timestamp.from(TimestampType.ELAPSED, 100n * MILLISECOND, 500n)) 243 ).toEqual('100ms0ns'); 244 expect(TimeUtils.format(Timestamp.from(TimestampType.ELAPSED, 100n * MILLISECOND))).toEqual( 245 '100ms0ns' 246 ); 247 }); 248}); 249