• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1<!DOCTYPE HTML>
2<html>
3<!--
4Copyright (c) 2012 The Chromium Authors. All rights reserved.
5Use of this source code is governed by a BSD-style license that can be
6found in the LICENSE file.
7-->
8<head i18n-values="dir:textdirection;">
9<title>TimelineTrack tests</title>
10<script
11   src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js">
12</script>
13<script>
14  goog.require('goog.testing.jsunit');
15</script>
16<style>
17* {
18  box-sizing: border-box;
19  -webkit-user-select: none;
20}
21
22.timeline-container {
23  border: 1px solid red;
24}
25
26</style>
27<link rel="stylesheet" href="timeline.css">
28<script src="../shared/js/cr.js"></script>
29<script src="../shared/js/cr/event_target.js"></script>
30<script src="../shared/js/cr/ui.js"></script>
31<script src="../shared/js/util.js"></script>
32<script src="timeline_model.js"></script>
33<script src="sorted_array_utils.js"></script>
34<script src="measuring_stick.js"></script>
35<script src="timeline.js"></script>
36<script src="timeline_track.js"></script>
37<script src="fast_rect_renderer.js"></script>
38</head>
39<body>
40<script>
41</script>
42<script>
43  'use strict';
44
45  var TimelineAsyncSlice = tracing.TimelineAsyncSlice;
46  var TimelineAsyncSliceGroup = tracing.TimelineAsyncSliceGroup;
47  var TimelineCounter = tracing.TimelineCounter;
48  var TimelineCounterTrack = tracing.TimelineCounterTrack;
49  var TimelineCpu = tracing.TimelineCpu;
50  var TimelineCpuTrack = tracing.TimelineCpuTrack;
51  var TimelineProcess = tracing.TimelineProcess;
52  var TimelineSelection = tracing.TimelineSelection;
53  var TimelineSliceTrack = tracing.TimelineSliceTrack;
54  var TimelineSlice = tracing.TimelineSlice;
55  var TimelineThread = tracing.TimelineThread;
56  var TimelineThreadSlice = tracing.TimelineThreadSlice;
57  var TimelineThreadTrack = tracing.TimelineThreadTrack;
58  var TimelineViewport = tracing.TimelineViewport;
59  var testDivs = {};
60
61  // Helper function to create a slice.
62  function newAsyncSlice(start, duration, startThread, endThread) {
63    var s = new TimelineAsyncSlice('a', 0, start);
64    s.duration = duration;
65    s.startThread = startThread;
66    s.endThread = endThread;
67    return s;
68  }
69
70  function getTestDiv(name) {
71    if (!testDivs[name]) {
72      testDivs[name] = document.createElement('div');
73      document.body.appendChild(testDivs[name]);
74    }
75    testDivs[name].textContent = '';
76    return testDivs[name];
77  }
78
79  function testBasicSlices() {
80    var testEl = getTestDiv('testBasicSlices');
81    var track = TimelineSliceTrack();
82    testEl.appendChild(track);
83    track.heading = 'testBasicSlices';
84    track.slices = [
85      new TimelineSlice('a', 0, 1, {}, 1),
86      new TimelineSlice('b', 1, 2.1, {}, 4.8),
87      new TimelineSlice('b', 1, 7, {}, 0.5),
88      new TimelineSlice('c', 2, 7.6, {}, 0.4)
89    ];
90    track.viewport = new TimelineViewport(testEl);
91    track.viewport.xSetWorldRange(0, 8.8, track.clientWidth);
92  }
93
94  function testFindAllObjectsMatchingInSliceTrack() {
95    var track = TimelineSliceTrack();
96    track.slices = [
97      new TimelineSlice('a', 0, 1, {}, 1),
98      new TimelineSlice('b', 1, 2.1, {}, 4.8),
99      new TimelineSlice('b', 1, 7, {}, 0.5),
100      new TimelineSlice('c', 2, 7.6, {}, 0.4)
101    ];
102    var selection = new TimelineSelection();
103    track.addAllObjectsMatchingFilterToSelection(
104        new tracing.TimelineFilter("b"), selection);
105
106    assertEquals(2, selection.length);
107    assertEquals(track.slices[1], selection[0].slice);
108    assertEquals(track.slices[2], selection[1].slice);
109  }
110
111  function testShrinkingSliceSizes() {
112    var testEl = getTestDiv('testShrinkingSliceSizes');
113    var track = TimelineSliceTrack();
114    testEl.appendChild(track);
115    track.heading = 'testShrinkingSliceSizes';
116    var x = 0;
117    var widths = [10, 5, 4, 3, 2, 1, 0.5, 0.4, 0.3, 0.2, 0.1, 0.05];
118    var slices = [];
119    for (var i = 0; i < widths.length; i++) {
120      var s = new TimelineSlice('a', 1, x, {}, widths[i]);
121      x += s.duration + 0.5;
122      slices.push(s);
123    }
124    track.slices = slices;
125    track.viewport = new TimelineViewport(testEl);
126    track.viewport.xSetWorldRange(0, 1.1 * x, track.clientWidth);
127  }
128
129  function testSelectionHitTesting() {
130    var testEl = getTestDiv('testSelectionHitTesting');
131    var track = new TimelineSliceTrack();
132    testEl.appendChild(track);
133    track.heading = 'testSelectionHitTesting';
134    track.headingWidth = '100px';
135    track.slices = [
136      new TimelineSlice('a', 0, 1, {}, 1),
137      new TimelineSlice('b', 1, 2.1, {}, 4.8)
138    ];
139    track.style.width = '500px';
140    track.viewport = new TimelineViewport(testEl);
141    track.viewport.xSetWorldRange(0, 7.6, track.clientWidth);
142    var clientRect = track.getBoundingClientRect();
143
144    var selection = new TimelineSelection();
145    track.addIntersectingItemsToSelection(1.5, clientRect.top + 5, selection);
146    assertEquals(track.slices[0], selection[0].slice);
147
148    var selection = new TimelineSelection();
149    track.addIntersectingItemsToSelection(2, clientRect.top + 5, selection);
150    assertEquals(0, selection.length);
151
152    var selection = new TimelineSelection();
153    track.addIntersectingItemsToSelection(6.8, clientRect.top + 5, selection);
154    assertEquals(track.slices[1], selection[0].slice);
155
156    var selection = new TimelineSelection();
157    track.addIntersectingItemsToSelection(6.9, clientRect.top + 5, selection);
158    assertEquals(0, selection.length);
159  }
160
161  function testSelectionHitTestingWithTimelineThreadTrack() {
162    var model = new tracing.TimelineModel();
163    var p1 = model.getOrCreateProcess(1);
164    var t1 = p1.getOrCreateThread(1);
165    t1.subRows[0].push(new tracing.TimelineThreadSlice('a', 0, 1, {}, 5));
166    t1.subRows[0].push(new tracing.TimelineThreadSlice('b', 0, 5.1, {}, 4));
167
168    var testEl = getTestDiv('testSelectionHitTestingWithTimelineThreadTrack');
169    var track = new tracing.TimelineThreadTrack();
170    testEl.appendChild(track);
171    track.heading = 'testSelectionHitTestingWithTimelineThreadTrack';
172    track.headingWidth = '100px';
173    track.thread = t1;
174
175    track.style.width = '500px';
176    track.viewport = new TimelineViewport(testEl);
177    track.viewport.xSetWorldRange(0, 10, track.clientWidth);
178    var clientRect = track.getBoundingClientRect();
179
180    var selection = new TimelineSelection();
181    track.addIntersectingItemsToSelection(1.5, clientRect.top + 5, selection);
182    assertEquals(t1.subRows[0][0], selection[0].slice);
183
184    var selection = new TimelineSelection();
185    track.addIntersectingItemsInRangeToSelection(1.5, 1.8, clientRect.top + 5, clientRect.top + 7, selection);
186    assertEquals(t1.subRows[0][0], selection[0].slice);
187  }
188
189  function testBasicCpu() {
190    var testEl = getTestDiv('testBasicCpu');
191
192    var cpu = new TimelineCpu(7);
193    cpu.slices = [
194      new TimelineSlice('a', 0, 1, {}, 1),
195      new TimelineSlice('b', 1, 2.1, {}, 4.8)
196    ];
197    cpu.updateBounds();
198
199    var track = TimelineCpuTrack();
200    testEl.appendChild(track);
201    track.heading = 'CPU ' + cpu.cpuNumber;
202    track.cpu = cpu;
203    track.viewport = new TimelineViewport(testEl);
204    track.viewport.xSetWorldRange(0, 11.1, track.clientWidth);
205  }
206
207  function testViewport() {
208    var testEl = getTestDiv('testViewport');
209
210    var track = tracing.TimelineViewportTrack();
211    testEl.appendChild(track);
212    track.viewport = new TimelineViewport(testEl);
213    track.viewport.setPanAndScale(0,
214        track.clientWidth / 1000);
215  }
216
217  function testBasicCounter() {
218    var testEl = getTestDiv('testBasicCounter');
219
220    var ctr = new TimelineCounter(undefined,
221                                  'testBasicCounter', 'testBasicCounter');
222    ctr.seriesNames = ['value1', 'value2'];
223    ctr.seriesColors = [tracing.getStringColorId('testBasicCounter.value1'),
224                        tracing.getStringColorId('testBasicCounter.value2')];
225    ctr.timestamps = [0, 1, 2, 3, 4, 5, 6, 7];
226    ctr.samples = [0, 5,
227                   3, 3,
228                   1, 1,
229                   2, 1.1,
230                   3, 0,
231                   1, 7,
232                   3, 0,
233                   3.1, 0.5];
234    ctr.updateBounds();
235
236    var track = new TimelineCounterTrack();
237    testEl.appendChild(track);
238    track.heading = ctr.name;
239    track.counter = ctr;
240    track.viewport = new TimelineViewport(testEl);
241    track.viewport.xSetWorldRange(0, 7.7, track.clientWidth);
242  }
243
244  function runOffscreenCounterTest(timestamps, samples, testFn) {
245    var testEl = document.createElement('div');
246    var ctr = new TimelineCounter(undefined,
247                                  'foo', 'foo');
248    var n = samples.length / timestamps.length;
249    ctr.timestamps = timestamps;
250    ctr.samples = samples;
251    ctr.seriesNames = []
252    ctr.seriesColors = []
253    for (var i = 0; i < n; ++i) {
254      ctr.seriesNames.push('value' + i);
255      ctr.seriesColors.push(tracing.getStringColorId(ctr.seriesNames[i]));
256    }
257    ctr.updateBounds();
258
259    var track = new TimelineCounterTrack();
260    testEl.appendChild(track);
261    document.body.appendChild(testEl);
262
263    track.heading = ctr.name;
264    track.counter = ctr;
265    track.viewport = new TimelineViewport(testEl);
266    track.viewport.xSetWorldRange(0, 10, track.clientWidth);
267
268    try {
269      testFn(ctr, track);
270    } finally {
271      document.body.removeChild(testEl);
272    }
273  }
274
275  function testBasicCounterXPointPicking() {
276    var timestamps = [0, 1, 2, 3, 4, 5, 6, 7];
277    var samples = [0, 5,
278                   3, 3,
279                   1, 1,
280                   2, 1.1,
281                   3, 0,
282                   1, 7,
283                   3, 0,
284                   3.1, 0.5];
285    runOffscreenCounterTest(timestamps, samples, function(ctr, track) {
286      var clientRect = track.getBoundingClientRect();
287      var y75 = clientRect.top + 0.75 * clientRect.height;
288      var sel;
289
290      // In bounds.
291      sel = new tracing.TimelineSelection();
292      track.addIntersectingItemsToSelection(1.5, y75, sel);
293      assertEquals(1, sel.length);
294      assertEquals(track, sel[0].track);
295      assertEquals(ctr, sel[0].counter);
296      assertEquals(1, sel[0].sampleIndex);
297
298      // Outside bouds.
299      sel = new tracing.TimelineSelection();
300      track.addIntersectingItemsToSelection(-1, y75, sel);
301      assertEquals(0, sel.length);
302
303      sel = new tracing.TimelineSelection();
304      track.addIntersectingItemsToSelection(8, y75, sel);
305      assertEquals(0, sel.length);
306    });
307  }
308
309  /* You'll need visual inspection to test eliding with this one. */
310  function testElideVisualInspection() {
311    var optDicts = [{ trackName: 'elideOff', elide: false },
312                    { trackName: 'elideOn', elide: true }];
313    for (var dictIndex in optDicts) {
314      var dict = optDicts[dictIndex];
315      var testEl = getTestDiv(dict.trackName);
316      var track = new TimelineSliceTrack();
317      if (dict.elide) {
318        track.SHOULD_ELIDE_TEXT = true;
319      } else {
320        track.SHOULD_ELIDE_TEXT = false;
321      }
322      var tooLongTitle = 'Unless eliding this SHOULD NOT BE DISPLAYED.  ';
323      var bigTitle = 'Very big title name that goes on longer ' +
324                     'than you may expect';
325      testEl.appendChild(track);
326      track.heading = 'Visual: ' + dict.trackName;
327      track.slices = [
328          // title, colorId, start, args, opt_duration
329          new TimelineSlice('a ' + tooLongTitle + bigTitle, 0, 1, {}, 1),
330          new TimelineSlice(bigTitle, 1, 2.1, {}, 4.8),
331          new TimelineSlice('cccc cccc cccc', 1, 7, {}, 0.5),
332          new TimelineSlice('d', 2, 7.6, {}, 1.0)
333      ];
334      track.viewport = new TimelineViewport(testEl);
335      track.viewport.xSetWorldRange(0, 9.5, track.clientWidth);
336    }
337  }
338
339  function testElide() {
340    var testEl = getTestDiv('testElide');
341    var track = new TimelineSliceTrack();
342    testEl.appendChild(track);
343    var bigtitle = 'Super duper long long title ' +
344      'holy moly when did you get so verbose?';
345    var smalltitle = 'small';
346    track.viewport = new TimelineViewport(testEl);
347    track.heading = 'testElide';
348    track.slices = [
349        // title, colorId, start, args, opt_duration
350        new TimelineSlice(bigtitle, 0, 1, {}, 1),
351        new TimelineSlice(smalltitle, 1, 2, {}, 1)
352    ];
353    track.viewport = new TimelineViewport(testEl);
354    track.viewport.xSetWorldRange(0, 3.3, track.clientWidth);
355    var stringWidthPair = undefined;
356    var pixWidth = track.viewport_.xViewVectorToWorld(1);
357
358    // Small titles on big slices are not elided.
359    stringWidthPair = track.elidedTitleCache.get(track, pixWidth, smalltitle,
360      track.labelWidth(smalltitle), 1);
361    assertEquals(smalltitle, stringWidthPair.string);
362    // Keep shrinking the slice until eliding starts.
363    var elidedWhenSmallEnough = false;
364    for (var sliceLength = 1; sliceLength >= 0.00001; sliceLength /= 2.0) {
365      stringWidthPair = track.elidedTitleCache.get(track, pixWidth, smalltitle,
366        track.labelWidth(smalltitle), sliceLength);
367      if (stringWidthPair.string.length < smalltitle.length) {
368        elidedWhenSmallEnough = true;
369        break;
370      }
371    }
372    assertTrue(elidedWhenSmallEnough);
373
374    // Big titles are elided immediately.
375    var superBigTitle = '';
376    for (var x = 0; x < 10; x++) {
377      superBigTitle += bigtitle;
378    }
379    stringWidthPair = track.elidedTitleCache.get(track, pixWidth,
380      superBigTitle, track.labelWidth(superBigTitle), 1);
381    assertTrue(stringWidthPair.string.length < superBigTitle.length);
382    // And elided text ends with ...
383    var len = stringWidthPair.string.length;
384    assertEquals('...', stringWidthPair.string.substring(len - 3, len));
385  }
386
387  function testTimelineThreadTrackWithRegularSlices() {
388    var testEl = getTestDiv('testTimelineThreadTrackWithRegularSlices');
389    var track = TimelineThreadTrack();
390    testEl.appendChild(track);
391    track.heading = 'testTimelineThreadTrackWithRegularSlices';
392    var thread = new TimelineThread(new TimelineProcess(7), 1);
393    thread.subRows = [
394      [
395        new TimelineThreadSlice('a', 0, 1, {}, 1),
396        new TimelineThreadSlice('b', 1, 2.1, {}, 4.8),
397        new TimelineThreadSlice('b', 1, 7, {}, 0.5),
398        new TimelineThreadSlice('c', 2, 7.6, {}, 0.4)
399      ],
400      [
401        new TimelineThreadSlice('d', 3, 1.1, {}, 0.8),
402        new TimelineThreadSlice('e', 4, 7.1, {}, 0.3)
403      ]
404    ];
405    thread.updateBounds();
406    track.heading = 'thread regular';
407    track.headingWidth = '150px';
408    track.toolTip = thread.userFriendlyDetails + ':';
409    track.thread = thread;
410    track.viewport = new TimelineViewport(testEl);
411    track.viewport.xSetWorldRange(0, 8.2, track.clientWidth);
412  }
413
414  function testTimelineThreadTrackWithTallSlices() {
415    var testEl = getTestDiv('testTimelineThreadTrackWithTallSlices');
416    var track = TimelineThreadTrack();
417    testEl.appendChild(track);
418    track.heading = 'testTimelineThreadTrackWithTallSlices';
419    var thread = new TimelineThread(new TimelineProcess(7), 1);
420    thread.subRows = [
421      [new TimelineThreadSlice('a', 1, 0, {}, 1)],
422      [new TimelineThreadSlice('b', 2, 0.1, {}, 0.8)],
423      [new TimelineThreadSlice('c', 3, 0.15, {}, 0.70)],
424      [new TimelineThreadSlice('d', 4, 0.20, {}, 0.50)],
425      [new TimelineThreadSlice('e', 5, 0.30, {}, 0.28)],
426      [new TimelineThreadSlice('e', 6, 0.35, {}, 0.20)],
427      [new TimelineThreadSlice('f', 7, 0.40, {}, 0.10)]
428    ];
429    thread.updateBounds();
430    track.heading = 'thread tall';
431    track.headingWidth = '150px';
432    track.toolTip = thread.userFriendlyDetails + ':';
433    track.thread = thread;
434    track.viewport = new TimelineViewport(testEl);
435    track.viewport.xSetWorldRange(0, 1.1, track.clientWidth);
436  }
437
438  function testTimelineThreadTrackWithRegularAndAsyncSlices() {
439    var testEl = getTestDiv('testTimelineThreadTrackWithAsyncSlices');
440    var track = TimelineThreadTrack();
441    testEl.appendChild(track);
442    var thread = new TimelineThread(new TimelineProcess(7), 1);
443    thread.subRows = [
444      [
445        new TimelineThreadSlice('a', 0, 1, {}, 1),
446        new TimelineThreadSlice('b', 1, 2.1, {}, 4.8),
447        new TimelineThreadSlice('b', 1, 7, {}, 0.5),
448        new TimelineThreadSlice('c', 2, 7.6, {}, 0.4)
449      ],
450      [
451        new TimelineThreadSlice('d', 3, 1.1, {}, 0.8),
452        new TimelineThreadSlice('e', 4, 7.1, {}, 0.3)
453      ]
454    ];
455    thread.asyncSlices.push(newAsyncSlice(1.2, 7.2 - 1.2, thread, thread));
456    thread.asyncSlices.push(newAsyncSlice(1.3, 7.3 - 1.3, thread, thread));
457    thread.updateBounds();
458    track.heading = 'thread regular + async';
459    track.headingWidth = '150px';
460    track.toolTip = thread.userFriendlyDetails + ':';
461    track.thread = thread;
462    track.viewport = new TimelineViewport(testEl);
463    track.viewport.xSetWorldRange(0, 8.15, track.clientWidth);
464  }
465
466  function testTimelineSliceTrackAddItemNearToProvidedHit() {
467    var track = new TimelineSliceTrack();
468    track.slices = [
469      new TimelineSlice('a', 0, 1, {}, 1),
470      new TimelineSlice('b', 1, 2.1, {}, 4.8),
471      new TimelineSlice('b', 1, 7, {}, 0.5),
472      new TimelineSlice('c', 2, 7.6, {}, 0.4)
473    ];
474    var sel = new tracing.TimelineSelection();
475    track.addAllObjectsMatchingFilterToSelection(new tracing.TimelineFilter("b"), sel);
476    var ret;
477
478    // Select to the right of B.
479    var selRight = new tracing.TimelineSelection();
480    ret = track.addItemNearToProvidedHitToSelection(sel[0], 1, selRight);
481    assertTrue(ret);
482    assertEquals(track.slices[2], selRight[0].slice);
483
484    // Select to the right of the 2nd b.
485    var selRight2 = new tracing.TimelineSelection();
486    ret = track.addItemNearToProvidedHitToSelection(sel[0], 2, selRight2);
487    assertTrue(ret);
488    assertEquals(track.slices[3], selRight2[0].slice);
489
490    // Select to 2 to the right of the 2nd b.
491    var selRightOfRight = new tracing.TimelineSelection();
492    ret = track.addItemNearToProvidedHitToSelection(selRight[0], 1, selRightOfRight);
493    assertTrue(ret);
494    assertEquals(track.slices[3], selRightOfRight[0].slice);
495
496    // Select to the right of the rightmost slice.
497    var selNone = new tracing.TimelineSelection();
498    ret = track.addItemNearToProvidedHitToSelection(selRightOfRight[0], 1, selNone);
499    assertFalse(ret);
500    assertEquals(0, selNone.length);
501
502    // Select A and then select left.
503    var sel = new tracing.TimelineSelection();
504    track.addAllObjectsMatchingFilterToSelection(new tracing.TimelineFilter("a"), sel);
505    var ret;
506
507    selNone = new tracing.TimelineSelection();
508    ret = track.addItemNearToProvidedHitToSelection(sel[0], -1, selNone);
509    assertFalse(ret);
510    assertEquals(0, selNone.length);
511
512  }
513</script>
514</body>
515</html>
516