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