xref: /aosp_15_r20/development/tools/winscope/src/trace/trace_test.ts (revision 90c8c64db3049935a07c6143d7fd006e26f8ecca)
1/*
2 * Copyright (C) 2023 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 */
16
17import {TIME_UNIT_TO_NANO} from 'common/time_units';
18import {ParserBuilder} from 'test/unit/parser_builder';
19import {TimestampConverterUtils} from 'test/unit/timestamp_converter_utils';
20import {TraceBuilder} from 'test/unit/trace_builder';
21import {TraceUtils} from 'test/unit/trace_utils';
22import {UnitTestUtils} from 'test/unit/utils';
23import {FrameMapBuilder} from './frame_map_builder';
24import {AbsoluteFrameIndex} from './index_types';
25import {Trace} from './trace';
26import {TraceType} from './trace_type';
27
28describe('Trace', () => {
29  let trace: Trace<string>;
30
31  const time9 = TimestampConverterUtils.makeRealTimestamp(9n);
32  const time10 = TimestampConverterUtils.makeRealTimestamp(10n);
33  const time11 = TimestampConverterUtils.makeRealTimestamp(11n);
34  const time12 = TimestampConverterUtils.makeRealTimestamp(12n);
35  const time13 = TimestampConverterUtils.makeRealTimestamp(13n);
36  const time14 = TimestampConverterUtils.makeRealTimestamp(14n);
37  const time15 = TimestampConverterUtils.makeRealTimestamp(15n);
38
39  beforeAll(() => {
40    // Time:       10    11                 12    13
41    // Entry:      0    1-2                 3     4
42    //             |     |                  |     |
43    // Frame:      0     1     2     3     4-5    6
44    trace = new TraceBuilder<string>()
45      .setEntries(['entry-0', 'entry-1', 'entry-2', 'entry-3', 'entry-4'])
46      .setTimestamps([time10, time11, time11, time12, time13])
47      .setFrame(0, 0)
48      .setFrame(1, 1)
49      .setFrame(2, 1)
50      .setFrame(3, 4)
51      .setFrame(3, 5)
52      .setFrame(4, 6)
53      .build();
54  });
55
56  it('getEntry()', async () => {
57    expect(await trace.getEntry(0).getValue()).toEqual('entry-0');
58    expect(await trace.getEntry(4).getValue()).toEqual('entry-4');
59    expect(() => {
60      trace.getEntry(5);
61    }).toThrow();
62
63    expect(await trace.getEntry(-1).getValue()).toEqual('entry-4');
64    expect(await trace.getEntry(-5).getValue()).toEqual('entry-0');
65    expect(() => {
66      trace.getEntry(-6);
67    }).toThrow();
68  });
69
70  it('getFrame()', async () => {
71    expect(await TraceUtils.extractFrames(trace.getFrame(0))).toEqual(
72      new Map<AbsoluteFrameIndex, string[]>([[0, ['entry-0']]]),
73    );
74    expect(await TraceUtils.extractFrames(trace.getFrame(1))).toEqual(
75      new Map<AbsoluteFrameIndex, string[]>([[1, ['entry-1', 'entry-2']]]),
76    );
77    expect(await TraceUtils.extractFrames(trace.getFrame(2))).toEqual(
78      new Map<AbsoluteFrameIndex, string[]>([[2, []]]),
79    );
80    expect(await TraceUtils.extractFrames(trace.getFrame(3))).toEqual(
81      new Map<AbsoluteFrameIndex, string[]>([[3, []]]),
82    );
83    expect(await TraceUtils.extractFrames(trace.getFrame(4))).toEqual(
84      new Map<AbsoluteFrameIndex, string[]>([[4, ['entry-3']]]),
85    );
86    expect(await TraceUtils.extractFrames(trace.getFrame(5))).toEqual(
87      new Map<AbsoluteFrameIndex, string[]>([[5, ['entry-3']]]),
88    );
89    expect(await TraceUtils.extractFrames(trace.getFrame(6))).toEqual(
90      new Map<AbsoluteFrameIndex, string[]>([[6, ['entry-4']]]),
91    );
92  });
93
94  it('findClosestEntry()', async () => {
95    // empty
96    expect(trace.sliceEntries(0, 0).findClosestEntry(time10)).toBeUndefined();
97
98    // slice
99    const slice = trace.sliceEntries(1, -1);
100    expect(await slice.findClosestEntry(time9)?.getValue()).toEqual('entry-1');
101    expect(await slice.findClosestEntry(time10)?.getValue()).toEqual('entry-1');
102    expect(await slice.findClosestEntry(time11)?.getValue()).toEqual('entry-1');
103    expect(await slice.findClosestEntry(time12)?.getValue()).toEqual('entry-3');
104    expect(await slice.findClosestEntry(time13)?.getValue()).toEqual('entry-3');
105    expect(await slice.findClosestEntry(time14)?.getValue()).toEqual('entry-3');
106
107    // full trace
108    expect(await trace.findClosestEntry(time9)?.getValue()).toEqual('entry-0');
109    expect(await trace.findClosestEntry(time10)?.getValue()).toEqual('entry-0');
110    expect(await trace.findClosestEntry(time11)?.getValue()).toEqual('entry-1');
111    expect(await trace.findClosestEntry(time12)?.getValue()).toEqual('entry-3');
112    expect(await trace.findClosestEntry(time13)?.getValue()).toEqual('entry-4');
113    expect(await trace.findClosestEntry(time14)?.getValue()).toEqual('entry-4');
114  });
115
116  it('findFirstGreaterOrEqualEntry()', async () => {
117    // empty
118    expect(
119      trace.sliceEntries(0, 0).findFirstGreaterOrEqualEntry(time10),
120    ).toBeUndefined();
121
122    // slice
123    const slice = trace.sliceEntries(1, -1);
124    expect(await slice.findFirstGreaterOrEqualEntry(time9)?.getValue()).toEqual(
125      'entry-1',
126    );
127    expect(
128      await slice.findFirstGreaterOrEqualEntry(time10)?.getValue(),
129    ).toEqual('entry-1');
130    expect(
131      await slice.findFirstGreaterOrEqualEntry(time11)?.getValue(),
132    ).toEqual('entry-1');
133    expect(
134      await slice.findFirstGreaterOrEqualEntry(time12)?.getValue(),
135    ).toEqual('entry-3');
136    expect(await slice.findFirstGreaterOrEqualEntry(time13)).toBeUndefined();
137
138    // full trace
139    expect(await trace.findFirstGreaterOrEqualEntry(time9)?.getValue()).toEqual(
140      'entry-0',
141    );
142    expect(
143      await trace.findFirstGreaterOrEqualEntry(time10)?.getValue(),
144    ).toEqual('entry-0');
145    expect(
146      await trace.findFirstGreaterOrEqualEntry(time11)?.getValue(),
147    ).toEqual('entry-1');
148    expect(
149      await trace.findFirstGreaterOrEqualEntry(time12)?.getValue(),
150    ).toEqual('entry-3');
151    expect(
152      await trace.findFirstGreaterOrEqualEntry(time13)?.getValue(),
153    ).toEqual('entry-4');
154    expect(await trace.findFirstGreaterOrEqualEntry(time14)).toBeUndefined();
155  });
156
157  it('findFirstGreaterEntry()', async () => {
158    // empty
159    expect(
160      trace.sliceEntries(0, 0).findFirstGreaterEntry(time10),
161    ).toBeUndefined();
162
163    // slice
164    const slice = trace.sliceEntries(1, -1);
165    expect(await slice.findFirstGreaterEntry(time9)?.getValue()).toEqual(
166      'entry-1',
167    );
168    expect(await slice.findFirstGreaterEntry(time10)?.getValue()).toEqual(
169      'entry-1',
170    );
171    expect(await slice.findFirstGreaterEntry(time11)?.getValue()).toEqual(
172      'entry-3',
173    );
174    expect(slice.findFirstGreaterEntry(time12)).toBeUndefined();
175
176    // full trace
177    expect(await trace.findFirstGreaterEntry(time9)?.getValue()).toEqual(
178      'entry-0',
179    );
180    expect(await trace.findFirstGreaterEntry(time10)?.getValue()).toEqual(
181      'entry-1',
182    );
183    expect(await trace.findFirstGreaterEntry(time11)?.getValue()).toEqual(
184      'entry-3',
185    );
186    expect(await trace.findFirstGreaterEntry(time12)?.getValue()).toEqual(
187      'entry-4',
188    );
189    expect(trace.findFirstGreaterEntry(time13)).toBeUndefined();
190  });
191
192  it('findLastLowerOrEqualEntry()', async () => {
193    // empty
194    expect(
195      trace.sliceEntries(0, 0).findLastLowerOrEqualEntry(time10),
196    ).toBeUndefined();
197
198    // slice
199    const slice = trace.sliceEntries(1, -1);
200    expect(slice.findLastLowerOrEqualEntry(time9)).toBeUndefined();
201    expect(slice.findLastLowerOrEqualEntry(time10)).toBeUndefined();
202    expect(await slice.findLastLowerOrEqualEntry(time11)?.getValue()).toEqual(
203      'entry-2',
204    );
205    expect(await slice.findLastLowerOrEqualEntry(time12)?.getValue()).toEqual(
206      'entry-3',
207    );
208    expect(await slice.findLastLowerOrEqualEntry(time13)?.getValue()).toEqual(
209      'entry-3',
210    );
211
212    // full trace
213    expect(trace.findLastLowerOrEqualEntry(time9)).toBeUndefined();
214    expect(await trace.findLastLowerOrEqualEntry(time10)?.getValue()).toEqual(
215      'entry-0',
216    );
217    expect(await trace.findLastLowerOrEqualEntry(time11)?.getValue()).toEqual(
218      'entry-2',
219    );
220    expect(await trace.findLastLowerOrEqualEntry(time12)?.getValue()).toEqual(
221      'entry-3',
222    );
223    expect(await trace.findLastLowerOrEqualEntry(time13)?.getValue()).toEqual(
224      'entry-4',
225    );
226    expect(await trace.findLastLowerOrEqualEntry(time14)?.getValue()).toEqual(
227      'entry-4',
228    );
229  });
230
231  it('findLastLowerEntry()', async () => {
232    // empty
233    expect(trace.sliceEntries(0, 0).findLastLowerEntry(time10)).toBeUndefined();
234
235    // slice
236    const slice = trace.sliceEntries(1, -1);
237    expect(slice.findLastLowerEntry(time9)).toBeUndefined();
238    expect(slice.findLastLowerEntry(time10)).toBeUndefined();
239    expect(slice.findLastLowerEntry(time11)).toBeUndefined();
240    expect(await slice.findLastLowerEntry(time12)?.getValue()).toEqual(
241      'entry-2',
242    );
243    expect(await slice.findLastLowerEntry(time13)?.getValue()).toEqual(
244      'entry-3',
245    );
246    expect(await slice.findLastLowerEntry(time14)?.getValue()).toEqual(
247      'entry-3',
248    );
249    expect(await slice.findLastLowerEntry(time15)?.getValue()).toEqual(
250      'entry-3',
251    );
252
253    // full trace
254    expect(trace.findLastLowerEntry(time9)).toBeUndefined();
255    expect(trace.findLastLowerEntry(time10)).toBeUndefined();
256    expect(await trace.findLastLowerEntry(time11)?.getValue()).toEqual(
257      'entry-0',
258    );
259    expect(await trace.findLastLowerEntry(time12)?.getValue()).toEqual(
260      'entry-2',
261    );
262    expect(await trace.findLastLowerEntry(time13)?.getValue()).toEqual(
263      'entry-3',
264    );
265    expect(await trace.findLastLowerEntry(time14)?.getValue()).toEqual(
266      'entry-4',
267    );
268    expect(await trace.findLastLowerEntry(time15)?.getValue()).toEqual(
269      'entry-4',
270    );
271  });
272
273  // Hint: look at frame mapping specified in test's set up to fully understand the assertions
274  it('sliceEntries()', async () => {
275    const slice = trace.sliceEntries(1, 4);
276
277    const expectedEntriesFull = ['entry-1', 'entry-2', 'entry-3'];
278    const expectedFramesEmpty = new Map<AbsoluteFrameIndex, string[]>();
279    const expectedFramesFull = new Map<AbsoluteFrameIndex, string[]>([
280      [1, ['entry-1', 'entry-2']],
281      [2, []],
282      [3, []],
283      [4, ['entry-3']],
284      [5, ['entry-3']],
285    ]);
286
287    // empty
288    {
289      expect(await TraceUtils.extractFrames(slice.sliceEntries(1, 1))).toEqual(
290        expectedFramesEmpty,
291      );
292      expect(await TraceUtils.extractEntries(slice.sliceEntries(1, 1))).toEqual(
293        [],
294      );
295
296      expect(
297        await TraceUtils.extractFrames(slice.sliceEntries(-1, -1)),
298      ).toEqual(expectedFramesEmpty);
299      expect(
300        await TraceUtils.extractEntries(slice.sliceEntries(-1, -1)),
301      ).toEqual([]);
302
303      expect(await TraceUtils.extractFrames(slice.sliceEntries(2, 1))).toEqual(
304        expectedFramesEmpty,
305      );
306      expect(await TraceUtils.extractEntries(slice.sliceEntries(2, 1))).toEqual(
307        [],
308      );
309
310      expect(
311        await TraceUtils.extractFrames(slice.sliceEntries(-1, -2)),
312      ).toEqual(expectedFramesEmpty);
313      expect(
314        await TraceUtils.extractEntries(slice.sliceEntries(-1, -2)),
315      ).toEqual([]);
316    }
317
318    // full
319    {
320      expect(await TraceUtils.extractEntries(slice.sliceEntries())).toEqual(
321        expectedEntriesFull,
322      );
323      expect(await TraceUtils.extractFrames(slice.sliceEntries())).toEqual(
324        expectedFramesFull,
325      );
326
327      expect(await TraceUtils.extractEntries(slice.sliceEntries(0))).toEqual(
328        expectedEntriesFull,
329      );
330      expect(await TraceUtils.extractFrames(slice.sliceEntries(0))).toEqual(
331        expectedFramesFull,
332      );
333
334      expect(await TraceUtils.extractEntries(slice.sliceEntries(0, 3))).toEqual(
335        expectedEntriesFull,
336      );
337      expect(await TraceUtils.extractFrames(slice.sliceEntries(0, 3))).toEqual(
338        expectedFramesFull,
339      );
340
341      expect(await TraceUtils.extractEntries(slice.sliceEntries(-3))).toEqual(
342        expectedEntriesFull,
343      );
344      expect(await TraceUtils.extractFrames(slice.sliceEntries(-3))).toEqual(
345        expectedFramesFull,
346      );
347
348      expect(
349        await TraceUtils.extractEntries(slice.sliceEntries(-3, 3)),
350      ).toEqual(expectedEntriesFull);
351      expect(await TraceUtils.extractFrames(slice.sliceEntries(-3, 3))).toEqual(
352        expectedFramesFull,
353      );
354    }
355
356    // slice away front (positive index)
357    {
358      expect(await TraceUtils.extractEntries(slice.sliceEntries(1))).toEqual([
359        'entry-2',
360        'entry-3',
361      ]);
362      expect(await TraceUtils.extractFrames(slice.sliceEntries(1))).toEqual(
363        new Map<AbsoluteFrameIndex, string[]>([
364          [1, ['entry-2']],
365          [2, []],
366          [3, []],
367          [4, ['entry-3']],
368          [5, ['entry-3']],
369        ]),
370      );
371
372      expect(await TraceUtils.extractEntries(slice.sliceEntries(2))).toEqual([
373        'entry-3',
374      ]);
375      expect(await TraceUtils.extractFrames(slice.sliceEntries(2))).toEqual(
376        new Map<AbsoluteFrameIndex, string[]>([
377          [4, ['entry-3']],
378          [5, ['entry-3']],
379        ]),
380      );
381
382      expect(await TraceUtils.extractEntries(slice.sliceEntries(3))).toEqual(
383        [],
384      );
385      expect(await TraceUtils.extractFrames(slice.sliceEntries(3))).toEqual(
386        expectedFramesEmpty,
387      );
388
389      expect(await TraceUtils.extractEntries(slice.sliceEntries(4))).toEqual(
390        [],
391      );
392      expect(await TraceUtils.extractFrames(slice.sliceEntries(4))).toEqual(
393        expectedFramesEmpty,
394      );
395
396      expect(
397        await TraceUtils.extractEntries(slice.sliceEntries(1000000)),
398      ).toEqual([]);
399      expect(
400        await TraceUtils.extractFrames(slice.sliceEntries(1000000)),
401      ).toEqual(expectedFramesEmpty);
402    }
403
404    // slice away front (negative index)
405    {
406      expect(await TraceUtils.extractEntries(slice.sliceEntries(-3))).toEqual(
407        expectedEntriesFull,
408      );
409      expect(await TraceUtils.extractFrames(slice.sliceEntries(-3))).toEqual(
410        expectedFramesFull,
411      );
412
413      expect(await TraceUtils.extractEntries(slice.sliceEntries(-2))).toEqual([
414        'entry-2',
415        'entry-3',
416      ]);
417      expect(await TraceUtils.extractFrames(slice.sliceEntries(-2))).toEqual(
418        new Map<AbsoluteFrameIndex, string[]>([
419          [1, ['entry-2']],
420          [2, []],
421          [3, []],
422          [4, ['entry-3']],
423          [5, ['entry-3']],
424        ]),
425      );
426
427      expect(await TraceUtils.extractEntries(slice.sliceEntries(-1))).toEqual([
428        'entry-3',
429      ]);
430      expect(await TraceUtils.extractFrames(slice.sliceEntries(-1))).toEqual(
431        new Map<AbsoluteFrameIndex, string[]>([
432          [4, ['entry-3']],
433          [5, ['entry-3']],
434        ]),
435      );
436    }
437
438    // slice away back (positive index)
439    {
440      expect(
441        await TraceUtils.extractEntries(slice.sliceEntries(undefined, 2)),
442      ).toEqual(['entry-1', 'entry-2']);
443      expect(
444        await TraceUtils.extractFrames(slice.sliceEntries(undefined, 2)),
445      ).toEqual(
446        new Map<AbsoluteFrameIndex, string[]>([[1, ['entry-1', 'entry-2']]]),
447      );
448
449      expect(
450        await TraceUtils.extractEntries(slice.sliceEntries(undefined, 1)),
451      ).toEqual(['entry-1']);
452      expect(
453        await TraceUtils.extractFrames(slice.sliceEntries(undefined, 1)),
454      ).toEqual(new Map<AbsoluteFrameIndex, string[]>([[1, ['entry-1']]]));
455
456      expect(
457        await TraceUtils.extractEntries(slice.sliceEntries(undefined, 0)),
458      ).toEqual([]);
459      expect(
460        await TraceUtils.extractFrames(slice.sliceEntries(undefined, 0)),
461      ).toEqual(expectedFramesEmpty);
462    }
463
464    // slice away back (negative index)
465    {
466      expect(
467        await TraceUtils.extractEntries(slice.sliceEntries(undefined, -1)),
468      ).toEqual(['entry-1', 'entry-2']);
469      expect(
470        await TraceUtils.extractFrames(slice.sliceEntries(undefined, -1)),
471      ).toEqual(
472        new Map<AbsoluteFrameIndex, string[]>([[1, ['entry-1', 'entry-2']]]),
473      );
474
475      expect(
476        await TraceUtils.extractEntries(slice.sliceEntries(undefined, -2)),
477      ).toEqual(['entry-1']);
478      expect(
479        await TraceUtils.extractFrames(slice.sliceEntries(undefined, -2)),
480      ).toEqual(new Map<AbsoluteFrameIndex, string[]>([[1, ['entry-1']]]));
481
482      expect(
483        await TraceUtils.extractEntries(slice.sliceEntries(undefined, -3)),
484      ).toEqual([]);
485      expect(
486        await TraceUtils.extractFrames(slice.sliceEntries(undefined, -3)),
487      ).toEqual(expectedFramesEmpty);
488
489      expect(
490        await TraceUtils.extractEntries(slice.sliceEntries(undefined, -4)),
491      ).toEqual([]);
492      expect(
493        await TraceUtils.extractFrames(slice.sliceEntries(undefined, -4)),
494      ).toEqual(expectedFramesEmpty);
495
496      expect(
497        await TraceUtils.extractEntries(
498          slice.sliceEntries(undefined, -1000000),
499        ),
500      ).toEqual([]);
501      expect(
502        await TraceUtils.extractFrames(slice.sliceEntries(undefined, -1000000)),
503      ).toEqual(expectedFramesEmpty);
504    }
505  });
506
507  // Hint: look at frame mapping specified in test's set up to fully understand the assertions
508  it('sliceTime()', async () => {
509    const slice = trace.sliceTime(time11, time13); // drop first + last entries
510
511    const expectedEntriesFull = ['entry-1', 'entry-2', 'entry-3'];
512    const expectedFramesEmpty = new Map<AbsoluteFrameIndex, string[]>();
513    const expectedFramesFull = new Map<AbsoluteFrameIndex, string[]>([
514      [1, ['entry-1', 'entry-2']],
515      [2, []],
516      [3, []],
517      [4, ['entry-3']],
518      [5, ['entry-3']],
519    ]);
520
521    // empty
522    {
523      expect(
524        await TraceUtils.extractEntries(slice.sliceTime(time11, time11)),
525      ).toEqual([]);
526      expect(
527        await TraceUtils.extractFrames(slice.sliceTime(time11, time11)),
528      ).toEqual(expectedFramesEmpty);
529
530      expect(
531        await TraceUtils.extractEntries(slice.sliceTime(time11, time10)),
532      ).toEqual([]);
533      expect(
534        await TraceUtils.extractFrames(slice.sliceTime(time11, time10)),
535      ).toEqual(expectedFramesEmpty);
536
537      expect(
538        await TraceUtils.extractEntries(slice.sliceTime(time9, time10)),
539      ).toEqual([]);
540      expect(
541        await TraceUtils.extractFrames(slice.sliceTime(time9, time10)),
542      ).toEqual(expectedFramesEmpty);
543
544      expect(
545        await TraceUtils.extractEntries(slice.sliceTime(time10, time9)),
546      ).toEqual([]);
547      expect(
548        await TraceUtils.extractFrames(slice.sliceTime(time10, time9)),
549      ).toEqual(expectedFramesEmpty);
550
551      expect(
552        await TraceUtils.extractEntries(slice.sliceTime(time14, time15)),
553      ).toEqual([]);
554      expect(
555        await TraceUtils.extractFrames(slice.sliceTime(time14, time15)),
556      ).toEqual(expectedFramesEmpty);
557
558      expect(
559        await TraceUtils.extractEntries(slice.sliceTime(time15, time14)),
560      ).toEqual([]);
561      expect(
562        await TraceUtils.extractFrames(slice.sliceTime(time15, time14)),
563      ).toEqual(expectedFramesEmpty);
564    }
565
566    // full
567    {
568      expect(await TraceUtils.extractEntries(slice.sliceTime())).toEqual(
569        expectedEntriesFull,
570      );
571      expect(await TraceUtils.extractFrames(slice.sliceTime())).toEqual(
572        expectedFramesFull,
573      );
574
575      expect(await TraceUtils.extractEntries(slice.sliceTime(time9))).toEqual(
576        expectedEntriesFull,
577      );
578      expect(await TraceUtils.extractFrames(slice.sliceTime(time9))).toEqual(
579        expectedFramesFull,
580      );
581
582      expect(await TraceUtils.extractEntries(slice.sliceTime(time10))).toEqual(
583        expectedEntriesFull,
584      );
585      expect(await TraceUtils.extractFrames(slice.sliceTime(time10))).toEqual(
586        expectedFramesFull,
587      );
588
589      expect(
590        await TraceUtils.extractEntries(slice.sliceTime(undefined, time14)),
591      ).toEqual(expectedEntriesFull);
592      expect(
593        await TraceUtils.extractFrames(slice.sliceTime(undefined, time14)),
594      ).toEqual(expectedFramesFull);
595
596      expect(
597        await TraceUtils.extractEntries(slice.sliceTime(undefined, time15)),
598      ).toEqual(expectedEntriesFull);
599      expect(
600        await TraceUtils.extractFrames(slice.sliceTime(undefined, time15)),
601      ).toEqual(expectedFramesFull);
602
603      expect(
604        await TraceUtils.extractEntries(slice.sliceTime(time10, time14)),
605      ).toEqual(expectedEntriesFull);
606      expect(
607        await TraceUtils.extractFrames(slice.sliceTime(time10, time14)),
608      ).toEqual(expectedFramesFull);
609    }
610
611    // middle
612    {
613      expect(
614        await TraceUtils.extractEntries(slice.sliceTime(time12, time13)),
615      ).toEqual(['entry-3']);
616      expect(
617        await TraceUtils.extractFrames(slice.sliceTime(time12, time13)),
618      ).toEqual(
619        new Map<AbsoluteFrameIndex, string[]>([
620          [4, ['entry-3']],
621          [5, ['entry-3']],
622        ]),
623      );
624    }
625
626    // slice away front
627    {
628      expect(await TraceUtils.extractEntries(slice.sliceTime(time12))).toEqual([
629        'entry-3',
630      ]);
631      expect(await TraceUtils.extractFrames(slice.sliceTime(time12))).toEqual(
632        new Map<AbsoluteFrameIndex, string[]>([
633          [4, ['entry-3']],
634          [5, ['entry-3']],
635        ]),
636      );
637
638      expect(await TraceUtils.extractEntries(slice.sliceTime(time13))).toEqual(
639        [],
640      );
641      expect(await TraceUtils.extractFrames(slice.sliceTime(time13))).toEqual(
642        expectedFramesEmpty,
643      );
644
645      expect(await TraceUtils.extractEntries(slice.sliceTime(time14))).toEqual(
646        [],
647      );
648      expect(await TraceUtils.extractFrames(slice.sliceTime(time14))).toEqual(
649        expectedFramesEmpty,
650      );
651
652      expect(await TraceUtils.extractEntries(slice.sliceTime(time15))).toEqual(
653        [],
654      );
655      expect(await TraceUtils.extractFrames(slice.sliceTime(time15))).toEqual(
656        expectedFramesEmpty,
657      );
658    }
659
660    // slice away back
661    {
662      expect(
663        await TraceUtils.extractEntries(slice.sliceTime(undefined, time12)),
664      ).toEqual(['entry-1', 'entry-2']);
665      expect(
666        await TraceUtils.extractFrames(slice.sliceTime(undefined, time12)),
667      ).toEqual(
668        new Map<AbsoluteFrameIndex, string[]>([[1, ['entry-1', 'entry-2']]]),
669      );
670
671      expect(
672        await TraceUtils.extractEntries(slice.sliceTime(undefined, time11)),
673      ).toEqual([]);
674      expect(
675        await TraceUtils.extractFrames(slice.sliceTime(undefined, time11)),
676      ).toEqual(expectedFramesEmpty);
677
678      expect(
679        await TraceUtils.extractEntries(slice.sliceTime(undefined, time10)),
680      ).toEqual([]);
681      expect(
682        await TraceUtils.extractFrames(slice.sliceTime(undefined, time10)),
683      ).toEqual(expectedFramesEmpty);
684
685      expect(
686        await TraceUtils.extractEntries(slice.sliceTime(undefined, time9)),
687      ).toEqual([]);
688      expect(
689        await TraceUtils.extractFrames(slice.sliceTime(undefined, time9)),
690      ).toEqual(expectedFramesEmpty);
691    }
692  });
693
694  // Hint: look at frame mapping specified in test's set up to fully understand the assertions
695  it('sliceFrames()', async () => {
696    const slice = trace.sliceEntries(1, -1);
697
698    // empty
699    {
700      const expectedEntries = new Array<string>();
701      const expectedFrames = new Map<AbsoluteFrameIndex, string[]>([]);
702      expect(await TraceUtils.extractEntries(slice.sliceFrames(1, 1))).toEqual(
703        expectedEntries,
704      );
705      expect(await TraceUtils.extractFrames(slice.sliceFrames(1, 1))).toEqual(
706        expectedFrames,
707      );
708      expect(await TraceUtils.extractEntries(slice.sliceFrames(5, 1))).toEqual(
709        expectedEntries,
710      );
711      expect(await TraceUtils.extractFrames(slice.sliceFrames(5, 1))).toEqual(
712        expectedFrames,
713      );
714      expect(await TraceUtils.extractEntries(slice.sliceFrames(3, 2))).toEqual(
715        expectedEntries,
716      );
717      expect(await TraceUtils.extractFrames(slice.sliceFrames(3, 2))).toEqual(
718        expectedFrames,
719      );
720    }
721
722    // middle
723    {
724      expect(await TraceUtils.extractEntries(slice.sliceFrames(2, 3))).toEqual(
725        [],
726      );
727      expect(await TraceUtils.extractFrames(slice.sliceFrames(2, 3))).toEqual(
728        new Map<AbsoluteFrameIndex, string[]>([[2, []]]),
729      );
730      expect(await TraceUtils.extractEntries(slice.sliceFrames(2, 4))).toEqual(
731        [],
732      );
733      expect(await TraceUtils.extractFrames(slice.sliceFrames(2, 4))).toEqual(
734        new Map<AbsoluteFrameIndex, string[]>([
735          [2, []],
736          [3, []],
737        ]),
738      );
739      expect(await TraceUtils.extractEntries(slice.sliceFrames(2, 5))).toEqual([
740        'entry-3',
741      ]);
742      expect(await TraceUtils.extractFrames(slice.sliceFrames(2, 5))).toEqual(
743        new Map<AbsoluteFrameIndex, string[]>([
744          [2, []],
745          [3, []],
746          [4, ['entry-3']],
747        ]),
748      );
749    }
750
751    // full
752    {
753      const expectedEntries = ['entry-1', 'entry-2', 'entry-3'];
754      const expectedFrames = new Map<AbsoluteFrameIndex, string[]>([
755        [1, ['entry-1', 'entry-2']],
756        [2, []],
757        [3, []],
758        [4, ['entry-3']],
759        [5, ['entry-3']],
760      ]);
761      expect(await TraceUtils.extractEntries(slice.sliceFrames())).toEqual(
762        expectedEntries,
763      );
764      expect(await TraceUtils.extractFrames(slice.sliceFrames())).toEqual(
765        expectedFrames,
766      );
767      expect(await TraceUtils.extractEntries(slice.sliceFrames(0))).toEqual(
768        expectedEntries,
769      );
770      expect(await TraceUtils.extractFrames(slice.sliceFrames(0))).toEqual(
771        expectedFrames,
772      );
773      expect(
774        await TraceUtils.extractEntries(slice.sliceFrames(undefined, 6)),
775      ).toEqual(expectedEntries);
776      expect(
777        await TraceUtils.extractFrames(slice.sliceFrames(undefined, 6)),
778      ).toEqual(expectedFrames);
779      expect(await TraceUtils.extractEntries(slice.sliceFrames(1, 6))).toEqual(
780        expectedEntries,
781      );
782      expect(await TraceUtils.extractFrames(slice.sliceFrames(1, 6))).toEqual(
783        expectedFrames,
784      );
785      expect(await TraceUtils.extractEntries(slice.sliceFrames(0, 7))).toEqual(
786        expectedEntries,
787      );
788      expect(await TraceUtils.extractFrames(slice.sliceFrames(0, 7))).toEqual(
789        expectedFrames,
790      );
791    }
792
793    // slice away front
794    {
795      expect(await TraceUtils.extractEntries(slice.sliceFrames(2))).toEqual([
796        'entry-3',
797      ]);
798      expect(await TraceUtils.extractFrames(slice.sliceFrames(2))).toEqual(
799        new Map<AbsoluteFrameIndex, string[]>([
800          [2, []],
801          [3, []],
802          [4, ['entry-3']],
803          [5, ['entry-3']],
804        ]),
805      );
806      expect(await TraceUtils.extractEntries(slice.sliceFrames(4))).toEqual([
807        'entry-3',
808      ]);
809      expect(await TraceUtils.extractFrames(slice.sliceFrames(4))).toEqual(
810        new Map<AbsoluteFrameIndex, string[]>([
811          [4, ['entry-3']],
812          [5, ['entry-3']],
813        ]),
814      );
815      expect(await TraceUtils.extractEntries(slice.sliceFrames(5))).toEqual([
816        'entry-3',
817      ]);
818      expect(await TraceUtils.extractFrames(slice.sliceFrames(5))).toEqual(
819        new Map<AbsoluteFrameIndex, string[]>([[5, ['entry-3']]]),
820      );
821      expect(await TraceUtils.extractEntries(slice.sliceFrames(6))).toEqual([]);
822      expect(await TraceUtils.extractFrames(slice.sliceFrames(6))).toEqual(
823        new Map<AbsoluteFrameIndex, string[]>([]),
824      );
825      expect(await TraceUtils.extractEntries(slice.sliceFrames(1000))).toEqual(
826        [],
827      );
828      expect(await TraceUtils.extractFrames(slice.sliceFrames(1000))).toEqual(
829        new Map<AbsoluteFrameIndex, string[]>([]),
830      );
831    }
832
833    // slice away back
834    {
835      expect(
836        await TraceUtils.extractEntries(slice.sliceFrames(undefined, 6)),
837      ).toEqual(['entry-1', 'entry-2', 'entry-3']);
838      expect(
839        await TraceUtils.extractFrames(slice.sliceFrames(undefined, 6)),
840      ).toEqual(
841        new Map<AbsoluteFrameIndex, string[]>([
842          [1, ['entry-1', 'entry-2']],
843          [2, []],
844          [3, []],
845          [4, ['entry-3']],
846          [5, ['entry-3']],
847        ]),
848      );
849      expect(
850        await TraceUtils.extractEntries(slice.sliceFrames(undefined, 5)),
851      ).toEqual(['entry-1', 'entry-2', 'entry-3']);
852      expect(
853        await TraceUtils.extractFrames(slice.sliceFrames(undefined, 5)),
854      ).toEqual(
855        new Map<AbsoluteFrameIndex, string[]>([
856          [1, ['entry-1', 'entry-2']],
857          [2, []],
858          [3, []],
859          [4, ['entry-3']],
860        ]),
861      );
862      expect(
863        await TraceUtils.extractEntries(slice.sliceFrames(undefined, 4)),
864      ).toEqual(['entry-1', 'entry-2']);
865      expect(
866        await TraceUtils.extractFrames(slice.sliceFrames(undefined, 4)),
867      ).toEqual(
868        new Map<AbsoluteFrameIndex, string[]>([
869          [1, ['entry-1', 'entry-2']],
870          [2, []],
871          [3, []],
872        ]),
873      );
874      expect(
875        await TraceUtils.extractEntries(slice.sliceFrames(undefined, 3)),
876      ).toEqual(['entry-1', 'entry-2']);
877      expect(
878        await TraceUtils.extractFrames(slice.sliceFrames(undefined, 3)),
879      ).toEqual(
880        new Map<AbsoluteFrameIndex, string[]>([
881          [1, ['entry-1', 'entry-2']],
882          [2, []],
883        ]),
884      );
885      expect(
886        await TraceUtils.extractEntries(slice.sliceFrames(undefined, 2)),
887      ).toEqual(['entry-1', 'entry-2']);
888      expect(
889        await TraceUtils.extractFrames(slice.sliceFrames(undefined, 2)),
890      ).toEqual(
891        new Map<AbsoluteFrameIndex, string[]>([[1, ['entry-1', 'entry-2']]]),
892      );
893      expect(
894        await TraceUtils.extractEntries(slice.sliceFrames(undefined, 1)),
895      ).toEqual([]);
896      expect(
897        await TraceUtils.extractFrames(slice.sliceFrames(undefined, 1)),
898      ).toEqual(new Map<AbsoluteFrameIndex, string[]>());
899      expect(
900        await TraceUtils.extractEntries(slice.sliceFrames(undefined, 0)),
901      ).toEqual([]);
902      expect(
903        await TraceUtils.extractFrames(slice.sliceFrames(undefined, 0)),
904      ).toEqual(new Map<AbsoluteFrameIndex, string[]>());
905    }
906  });
907
908  it('can slice full trace', async () => {
909    // entries
910    expect(await TraceUtils.extractEntries(trace.sliceEntries(1, 1))).toEqual(
911      [],
912    );
913    expect(await TraceUtils.extractEntries(trace.sliceEntries())).toEqual([
914      'entry-0',
915      'entry-1',
916      'entry-2',
917      'entry-3',
918      'entry-4',
919    ]);
920    expect(await TraceUtils.extractEntries(trace.sliceEntries(2))).toEqual([
921      'entry-2',
922      'entry-3',
923      'entry-4',
924    ]);
925    expect(await TraceUtils.extractEntries(trace.sliceEntries(-3))).toEqual([
926      'entry-2',
927      'entry-3',
928      'entry-4',
929    ]);
930    expect(
931      await TraceUtils.extractEntries(trace.sliceEntries(undefined, 3)),
932    ).toEqual(['entry-0', 'entry-1', 'entry-2']);
933    expect(
934      await TraceUtils.extractEntries(trace.sliceEntries(undefined, -2)),
935    ).toEqual(['entry-0', 'entry-1', 'entry-2']);
936    expect(await TraceUtils.extractEntries(trace.sliceEntries(1, 4))).toEqual([
937      'entry-1',
938      'entry-2',
939      'entry-3',
940    ]);
941
942    // time
943    const time12 = TimestampConverterUtils.makeRealTimestamp(12n);
944    const time13 = TimestampConverterUtils.makeRealTimestamp(13n);
945    expect(
946      await TraceUtils.extractEntries(trace.sliceTime(time12, time12)),
947    ).toEqual([]);
948    expect(await TraceUtils.extractEntries(trace.sliceTime())).toEqual([
949      'entry-0',
950      'entry-1',
951      'entry-2',
952      'entry-3',
953      'entry-4',
954    ]);
955    expect(
956      await TraceUtils.extractEntries(trace.sliceTime(time12, time13)),
957    ).toEqual(['entry-3']);
958    expect(await TraceUtils.extractEntries(trace.sliceTime(time12))).toEqual([
959      'entry-3',
960      'entry-4',
961    ]);
962    expect(
963      await TraceUtils.extractEntries(trace.sliceTime(undefined, time12)),
964    ).toEqual(['entry-0', 'entry-1', 'entry-2']);
965
966    // frames
967    expect(await TraceUtils.extractEntries(trace.sliceFrames(1, 1))).toEqual(
968      [],
969    );
970    expect(await TraceUtils.extractEntries(trace.sliceFrames())).toEqual([
971      'entry-0',
972      'entry-1',
973      'entry-2',
974      'entry-3',
975      'entry-4',
976    ]);
977    expect(await TraceUtils.extractEntries(trace.sliceFrames(2))).toEqual([
978      'entry-3',
979      'entry-4',
980    ]);
981    expect(
982      await TraceUtils.extractEntries(trace.sliceFrames(undefined, 5)),
983    ).toEqual(['entry-0', 'entry-1', 'entry-2', 'entry-3']);
984    expect(await TraceUtils.extractEntries(trace.sliceFrames(2, 5))).toEqual([
985      'entry-3',
986    ]);
987  });
988
989  it('can slice empty trace', async () => {
990    const empty = trace.sliceEntries(0, 0);
991
992    // entries
993    expect(await TraceUtils.extractEntries(empty.sliceEntries())).toEqual([]);
994    expect(await TraceUtils.extractEntries(empty.sliceEntries(1))).toEqual([]);
995    expect(await TraceUtils.extractEntries(empty.sliceEntries(1, 2))).toEqual(
996      [],
997    );
998
999    // time
1000    const time12 = TimestampConverterUtils.makeRealTimestamp(12n);
1001    const time13 = TimestampConverterUtils.makeRealTimestamp(13n);
1002    expect(await TraceUtils.extractEntries(empty.sliceTime())).toEqual([]);
1003    expect(await TraceUtils.extractEntries(empty.sliceTime(time12))).toEqual(
1004      [],
1005    );
1006    expect(
1007      await TraceUtils.extractEntries(empty.sliceTime(time12, time13)),
1008    ).toEqual([]);
1009
1010    // frames
1011    expect(await TraceUtils.extractEntries(empty.sliceFrames())).toEqual([]);
1012    expect(await TraceUtils.extractEntries(empty.sliceFrames(1))).toEqual([]);
1013    expect(await TraceUtils.extractEntries(empty.sliceFrames(1, 2))).toEqual(
1014      [],
1015    );
1016  });
1017
1018  it('forEachEntry()', async () => {
1019    expect(await TraceUtils.extractEntries(trace)).toEqual([
1020      'entry-0',
1021      'entry-1',
1022      'entry-2',
1023      'entry-3',
1024      'entry-4',
1025    ]);
1026  });
1027
1028  it('forEachTimestamp()', () => {
1029    expect(TraceUtils.extractTimestamps(trace)).toEqual([
1030      time10,
1031      time11,
1032      time11,
1033      time12,
1034      time13,
1035    ]);
1036    expect(TraceUtils.extractTimestamps(trace.sliceEntries(1, -1))).toEqual([
1037      time11,
1038      time11,
1039      time12,
1040    ]);
1041  });
1042
1043  // Hint: look at frame mapping specified in test's set up to fully understand the assertions
1044  it('forEachFrame()', async () => {
1045    // full trace
1046    {
1047      const expected = new Map<AbsoluteFrameIndex, string[]>([
1048        [0, ['entry-0']],
1049        [1, ['entry-1', 'entry-2']],
1050        [2, []],
1051        [3, []],
1052        [4, ['entry-3']],
1053        [5, ['entry-3']],
1054        [6, ['entry-4']],
1055      ]);
1056      expect(await TraceUtils.extractFrames(trace)).toEqual(expected);
1057    }
1058    // slice
1059    {
1060      const slice = trace.sliceFrames(1, 5);
1061      const expected = new Map<AbsoluteFrameIndex, string[]>([
1062        [1, ['entry-1', 'entry-2']],
1063        [2, []],
1064        [3, []],
1065        [4, ['entry-3']],
1066      ]);
1067      expect(await TraceUtils.extractFrames(slice)).toEqual(expected);
1068    }
1069  });
1070
1071  it('updates frames range when slicing', () => {
1072    expect(trace.sliceEntries(0).getFramesRange()).toEqual({start: 0, end: 7});
1073    expect(trace.sliceEntries(1).getFramesRange()).toEqual({start: 1, end: 7});
1074    expect(trace.sliceEntries(2).getFramesRange()).toEqual({start: 1, end: 7});
1075    expect(trace.sliceEntries(3).getFramesRange()).toEqual({start: 4, end: 7});
1076    expect(trace.sliceEntries(4).getFramesRange()).toEqual({start: 6, end: 7});
1077    expect(trace.sliceEntries(5).getFramesRange()).toEqual(undefined);
1078
1079    expect(trace.sliceEntries(undefined, 5).getFramesRange()).toEqual({
1080      start: 0,
1081      end: 7,
1082    });
1083    expect(trace.sliceEntries(undefined, 4).getFramesRange()).toEqual({
1084      start: 0,
1085      end: 6,
1086    });
1087    expect(trace.sliceEntries(undefined, 3).getFramesRange()).toEqual({
1088      start: 0,
1089      end: 2,
1090    });
1091    expect(trace.sliceEntries(undefined, 2).getFramesRange()).toEqual({
1092      start: 0,
1093      end: 2,
1094    });
1095    expect(trace.sliceEntries(undefined, 1).getFramesRange()).toEqual({
1096      start: 0,
1097      end: 1,
1098    });
1099    expect(trace.sliceEntries(undefined, 0).getFramesRange()).toEqual(
1100      undefined,
1101    );
1102  });
1103
1104  it('can handle some trace entries with unavailable frame info', async () => {
1105    // Entry:      0     1     2     3     4
1106    //                   |           |
1107    // Frame:            0           2
1108    // Time:       10    11    12    13    14
1109    const trace = new TraceBuilder<string>()
1110      .setEntries(['entry-0', 'entry-1', 'entry-2', 'entry-3', 'entry-4'])
1111      .setTimestamps([time10, time11, time12, time13, time14])
1112      .setFrame(1, 0)
1113      .setFrame(3, 2)
1114      .build();
1115
1116    // Slice entries
1117    expect(await TraceUtils.extractEntries(trace.sliceEntries())).toEqual([
1118      'entry-0',
1119      'entry-1',
1120      'entry-2',
1121      'entry-3',
1122      'entry-4',
1123    ]);
1124    expect(await TraceUtils.extractFrames(trace.sliceEntries())).toEqual(
1125      new Map<AbsoluteFrameIndex, string[]>([
1126        [0, ['entry-1']],
1127        [1, []],
1128        [2, ['entry-3']],
1129      ]),
1130    );
1131
1132    expect(await TraceUtils.extractEntries(trace.sliceEntries(1))).toEqual([
1133      'entry-1',
1134      'entry-2',
1135      'entry-3',
1136      'entry-4',
1137    ]);
1138    expect(await TraceUtils.extractFrames(trace.sliceEntries(1))).toEqual(
1139      new Map<AbsoluteFrameIndex, string[]>([
1140        [0, ['entry-1']],
1141        [1, []],
1142        [2, ['entry-3']],
1143      ]),
1144    );
1145
1146    expect(await TraceUtils.extractEntries(trace.sliceEntries(2))).toEqual([
1147      'entry-2',
1148      'entry-3',
1149      'entry-4',
1150    ]);
1151    expect(await TraceUtils.extractFrames(trace.sliceEntries(2))).toEqual(
1152      new Map<AbsoluteFrameIndex, string[]>([[2, ['entry-3']]]),
1153    );
1154
1155    expect(await TraceUtils.extractEntries(trace.sliceEntries(3))).toEqual([
1156      'entry-3',
1157      'entry-4',
1158    ]);
1159    expect(await TraceUtils.extractFrames(trace.sliceEntries(3))).toEqual(
1160      new Map<AbsoluteFrameIndex, string[]>([[2, ['entry-3']]]),
1161    );
1162
1163    expect(await TraceUtils.extractEntries(trace.sliceEntries(4))).toEqual([
1164      'entry-4',
1165    ]);
1166    expect(await TraceUtils.extractFrames(trace.sliceEntries(4))).toEqual(
1167      new Map<AbsoluteFrameIndex, string[]>(),
1168    );
1169
1170    // Slice time
1171    expect(await TraceUtils.extractEntries(trace.sliceTime())).toEqual([
1172      'entry-0',
1173      'entry-1',
1174      'entry-2',
1175      'entry-3',
1176      'entry-4',
1177    ]);
1178    expect(await TraceUtils.extractFrames(trace.sliceTime())).toEqual(
1179      new Map<AbsoluteFrameIndex, string[]>([
1180        [0, ['entry-1']],
1181        [1, []],
1182        [2, ['entry-3']],
1183      ]),
1184    );
1185
1186    expect(await TraceUtils.extractEntries(trace.sliceTime(time11))).toEqual([
1187      'entry-1',
1188      'entry-2',
1189      'entry-3',
1190      'entry-4',
1191    ]);
1192    expect(await TraceUtils.extractFrames(trace.sliceTime(time11))).toEqual(
1193      new Map<AbsoluteFrameIndex, string[]>([
1194        [0, ['entry-1']],
1195        [1, []],
1196        [2, ['entry-3']],
1197      ]),
1198    );
1199
1200    expect(await TraceUtils.extractEntries(trace.sliceTime(time12))).toEqual([
1201      'entry-2',
1202      'entry-3',
1203      'entry-4',
1204    ]);
1205    expect(await TraceUtils.extractFrames(trace.sliceTime(time12))).toEqual(
1206      new Map<AbsoluteFrameIndex, string[]>([[2, ['entry-3']]]),
1207    );
1208
1209    expect(await TraceUtils.extractEntries(trace.sliceTime(time13))).toEqual([
1210      'entry-3',
1211      'entry-4',
1212    ]);
1213    expect(await TraceUtils.extractFrames(trace.sliceTime(time13))).toEqual(
1214      new Map<AbsoluteFrameIndex, string[]>([[2, ['entry-3']]]),
1215    );
1216
1217    expect(await TraceUtils.extractEntries(trace.sliceTime(time14))).toEqual([
1218      'entry-4',
1219    ]);
1220    expect(await TraceUtils.extractFrames(trace.sliceTime(time14))).toEqual(
1221      new Map<AbsoluteFrameIndex, string[]>(),
1222    );
1223
1224    // Slice frames
1225    expect(await TraceUtils.extractEntries(trace.sliceFrames())).toEqual([
1226      'entry-1',
1227      'entry-2',
1228      'entry-3',
1229    ]);
1230    expect(await TraceUtils.extractFrames(trace.sliceFrames())).toEqual(
1231      new Map<AbsoluteFrameIndex, string[]>([
1232        [0, ['entry-1']],
1233        [1, []],
1234        [2, ['entry-3']],
1235      ]),
1236    );
1237
1238    expect(await TraceUtils.extractEntries(trace.sliceFrames(1))).toEqual([
1239      'entry-3',
1240    ]);
1241    expect(await TraceUtils.extractFrames(trace.sliceFrames(1))).toEqual(
1242      new Map<AbsoluteFrameIndex, string[]>([
1243        [1, []],
1244        [2, ['entry-3']],
1245      ]),
1246    );
1247
1248    expect(
1249      await TraceUtils.extractEntries(trace.sliceFrames(undefined, 2)),
1250    ).toEqual(['entry-1']);
1251    expect(
1252      await TraceUtils.extractFrames(trace.sliceFrames(undefined, 2)),
1253    ).toEqual(
1254      new Map<AbsoluteFrameIndex, string[]>([
1255        [0, ['entry-1']],
1256        [1, []],
1257      ]),
1258    );
1259  });
1260
1261  it('can handle unavailable frame info', async () => {
1262    const trace = new TraceBuilder<string>()
1263      .setTimestamps([time10, time11, time12])
1264      .setEntries(['entry-0', 'entry-1', 'entry-2'])
1265      .setFrameMap(undefined)
1266      .build();
1267
1268    expect(await trace.getEntry(0).getValue()).toEqual('entry-0');
1269    expect(await TraceUtils.extractEntries(trace)).toEqual([
1270      'entry-0',
1271      'entry-1',
1272      'entry-2',
1273    ]);
1274    expect(await TraceUtils.extractEntries(trace.sliceEntries(1, 2))).toEqual([
1275      'entry-1',
1276    ]);
1277    expect(
1278      await TraceUtils.extractEntries(trace.sliceTime(time11, time12)),
1279    ).toEqual(['entry-1']);
1280
1281    expect(() => {
1282      trace.getFrame(0);
1283    }).toThrow();
1284    expect(() => {
1285      trace.sliceFrames(0, 1000);
1286    }).toThrow();
1287  });
1288
1289  it('can handle empty frame info', async () => {
1290    // empty trace
1291    {
1292      const trace = new TraceBuilder<string>()
1293        .setEntries([])
1294        .setTimestamps([])
1295        .setFrameMap(new FrameMapBuilder(0, 0).build())
1296        .build();
1297
1298      expect(await TraceUtils.extractEntries(trace)).toEqual([]);
1299      expect(await TraceUtils.extractFrames(trace)).toEqual(
1300        new Map<AbsoluteFrameIndex, string[]>(),
1301      );
1302
1303      expect(await TraceUtils.extractEntries(trace.sliceEntries(1))).toEqual(
1304        [],
1305      );
1306      expect(await TraceUtils.extractFrames(trace.sliceEntries(1))).toEqual(
1307        new Map<AbsoluteFrameIndex, string[]>(),
1308      );
1309
1310      expect(await TraceUtils.extractEntries(trace.sliceTime(time11))).toEqual(
1311        [],
1312      );
1313      expect(await TraceUtils.extractFrames(trace.sliceTime(time11))).toEqual(
1314        new Map<AbsoluteFrameIndex, string[]>(),
1315      );
1316
1317      expect(await TraceUtils.extractEntries(trace.sliceFrames())).toEqual([]);
1318      expect(await TraceUtils.extractFrames(trace.sliceFrames())).toEqual(
1319        new Map<AbsoluteFrameIndex, string[]>(),
1320      );
1321    }
1322    // non-empty trace
1323    {
1324      const trace = new TraceBuilder<string>()
1325        .setEntries(['entry-0', 'entry-1', 'entry-2'])
1326        .setTimestamps([time10, time11, time12])
1327        .setFrameMap(new FrameMapBuilder(3, 0).build())
1328        .build();
1329
1330      expect(await TraceUtils.extractEntries(trace)).toEqual([
1331        'entry-0',
1332        'entry-1',
1333        'entry-2',
1334      ]);
1335      expect(await TraceUtils.extractFrames(trace)).toEqual(
1336        new Map<AbsoluteFrameIndex, string[]>(),
1337      );
1338
1339      expect(await TraceUtils.extractEntries(trace.sliceEntries(1))).toEqual([
1340        'entry-1',
1341        'entry-2',
1342      ]);
1343      expect(await TraceUtils.extractFrames(trace.sliceEntries(1))).toEqual(
1344        new Map<AbsoluteFrameIndex, string[]>(),
1345      );
1346
1347      expect(await TraceUtils.extractEntries(trace.sliceTime(time11))).toEqual([
1348        'entry-1',
1349        'entry-2',
1350      ]);
1351      expect(await TraceUtils.extractFrames(trace.sliceTime(time11))).toEqual(
1352        new Map<AbsoluteFrameIndex, string[]>(),
1353      );
1354
1355      expect(await TraceUtils.extractEntries(trace.sliceFrames())).toEqual([]);
1356      expect(await TraceUtils.extractFrames(trace.sliceFrames())).toEqual(
1357        new Map<AbsoluteFrameIndex, string[]>(),
1358      );
1359    }
1360  });
1361
1362  it('isDump()', () => {
1363    const trace = new TraceBuilder<string>()
1364      .setEntries(['entry-0'])
1365      .setTimestamps([time10])
1366      .build();
1367    expect(trace.isDump()).toBeTrue();
1368    expect(trace.isDumpWithoutTimestamp()).toBeFalse();
1369  });
1370
1371  it('isDumpWithoutTimestamp()', () => {
1372    const trace = new TraceBuilder<string>()
1373      .setEntries(['entry-0'])
1374      .setTimestamps([TimestampConverterUtils.makeZeroTimestamp()])
1375      .build();
1376    expect(trace.isDumpWithoutTimestamp()).toBeTrue();
1377  });
1378
1379  it('updates corruptedState on failure to parse entry', async () => {
1380    const trace = new TraceBuilder<string>()
1381      .setParser(
1382        new ParserBuilder<string>()
1383          .setIsCorrupted(true)
1384          .setEntries(['entry-0'])
1385          .setTimestamps([TimestampConverterUtils.makeZeroTimestamp()])
1386          .build(),
1387      )
1388      .build();
1389    expect(trace.isCorrupted()).toBeFalse();
1390    expect(trace.getCorruptedReason()).toBeUndefined();
1391
1392    expectAsync(trace.getEntry(0).getValue()).toBeRejected();
1393    try {
1394      await trace.getEntry(0).getValue();
1395    } catch (e) {
1396      expect(trace.isCorrupted()).toBeTrue();
1397      expect(trace.getCorruptedReason()).toEqual(
1398        'Cannot parse entry at index 0',
1399      );
1400    }
1401  });
1402
1403  it('spansMultipleDates()', () => {
1404    const emptyTrace = UnitTestUtils.makeEmptyTrace(
1405      TraceType.TEST_TRACE_STRING,
1406    );
1407    expect(emptyTrace.spansMultipleDates()).toBeFalse();
1408
1409    const traceWithElapsedTimestamps = new TraceBuilder<string>()
1410      .setEntries(['entry-0', 'entry-1'])
1411      .setTimestamps([
1412        TimestampConverterUtils.makeElapsedTimestamp(0n),
1413        TimestampConverterUtils.makeElapsedTimestamp(
1414          BigInt(TIME_UNIT_TO_NANO.d),
1415        ),
1416      ])
1417      .build();
1418    expect(traceWithElapsedTimestamps.spansMultipleDates()).toBeFalse();
1419
1420    const traceWithRealTimestampsOneDate = new TraceBuilder<string>()
1421      .setEntries(['entry-0', 'entry-1'])
1422      .setTimestamps([time10, time15])
1423      .build();
1424    expect(traceWithRealTimestampsOneDate.spansMultipleDates()).toBeFalse();
1425
1426    const traceWitMultipleDates = new TraceBuilder<string>()
1427      .setEntries(['entry-0', 'entry-1'])
1428      .setTimestamps([
1429        TimestampConverterUtils.makeRealTimestamp(
1430          BigInt(TIME_UNIT_TO_NANO.h * 23),
1431        ),
1432        TimestampConverterUtils.makeRealTimestamp(
1433          BigInt(TIME_UNIT_TO_NANO.h * 25),
1434        ),
1435      ])
1436      .build();
1437    expect(traceWitMultipleDates.spansMultipleDates()).toBeTrue();
1438  });
1439});
1440