Html程序  |  516行  |  18.1 KB

<!DOCTYPE HTML>
<html>
<!--
Copyright (c) 2012 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<head i18n-values="dir:textdirection;">
<title>TimelineTrack tests</title>
<script
   src="http://closure-library.googlecode.com/svn/trunk/closure/goog/base.js">
</script>
<script>
  goog.require('goog.testing.jsunit');
</script>
<style>
* {
  box-sizing: border-box;
  -webkit-user-select: none;
}

.timeline-container {
  border: 1px solid red;
}

</style>
<link rel="stylesheet" href="timeline.css">
<script src="../shared/js/cr.js"></script>
<script src="../shared/js/cr/event_target.js"></script>
<script src="../shared/js/cr/ui.js"></script>
<script src="../shared/js/util.js"></script>
<script src="timeline_model.js"></script>
<script src="sorted_array_utils.js"></script>
<script src="measuring_stick.js"></script>
<script src="timeline.js"></script>
<script src="timeline_track.js"></script>
<script src="fast_rect_renderer.js"></script>
</head>
<body>
<script>
</script>
<script>
  'use strict';

  var TimelineAsyncSlice = tracing.TimelineAsyncSlice;
  var TimelineAsyncSliceGroup = tracing.TimelineAsyncSliceGroup;
  var TimelineCounter = tracing.TimelineCounter;
  var TimelineCounterTrack = tracing.TimelineCounterTrack;
  var TimelineCpu = tracing.TimelineCpu;
  var TimelineCpuTrack = tracing.TimelineCpuTrack;
  var TimelineProcess = tracing.TimelineProcess;
  var TimelineSelection = tracing.TimelineSelection;
  var TimelineSliceTrack = tracing.TimelineSliceTrack;
  var TimelineSlice = tracing.TimelineSlice;
  var TimelineThread = tracing.TimelineThread;
  var TimelineThreadSlice = tracing.TimelineThreadSlice;
  var TimelineThreadTrack = tracing.TimelineThreadTrack;
  var TimelineViewport = tracing.TimelineViewport;
  var testDivs = {};

  // Helper function to create a slice.
  function newAsyncSlice(start, duration, startThread, endThread) {
    var s = new TimelineAsyncSlice('a', 0, start);
    s.duration = duration;
    s.startThread = startThread;
    s.endThread = endThread;
    return s;
  }

  function getTestDiv(name) {
    if (!testDivs[name]) {
      testDivs[name] = document.createElement('div');
      document.body.appendChild(testDivs[name]);
    }
    testDivs[name].textContent = '';
    return testDivs[name];
  }

  function testBasicSlices() {
    var testEl = getTestDiv('testBasicSlices');
    var track = TimelineSliceTrack();
    testEl.appendChild(track);
    track.heading = 'testBasicSlices';
    track.slices = [
      new TimelineSlice('a', 0, 1, {}, 1),
      new TimelineSlice('b', 1, 2.1, {}, 4.8),
      new TimelineSlice('b', 1, 7, {}, 0.5),
      new TimelineSlice('c', 2, 7.6, {}, 0.4)
    ];
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 8.8, track.clientWidth);
  }

  function testFindAllObjectsMatchingInSliceTrack() {
    var track = TimelineSliceTrack();
    track.slices = [
      new TimelineSlice('a', 0, 1, {}, 1),
      new TimelineSlice('b', 1, 2.1, {}, 4.8),
      new TimelineSlice('b', 1, 7, {}, 0.5),
      new TimelineSlice('c', 2, 7.6, {}, 0.4)
    ];
    var selection = new TimelineSelection();
    track.addAllObjectsMatchingFilterToSelection(
        new tracing.TimelineFilter("b"), selection);

    assertEquals(2, selection.length);
    assertEquals(track.slices[1], selection[0].slice);
    assertEquals(track.slices[2], selection[1].slice);
  }

  function testShrinkingSliceSizes() {
    var testEl = getTestDiv('testShrinkingSliceSizes');
    var track = TimelineSliceTrack();
    testEl.appendChild(track);
    track.heading = 'testShrinkingSliceSizes';
    var x = 0;
    var widths = [10, 5, 4, 3, 2, 1, 0.5, 0.4, 0.3, 0.2, 0.1, 0.05];
    var slices = [];
    for (var i = 0; i < widths.length; i++) {
      var s = new TimelineSlice('a', 1, x, {}, widths[i]);
      x += s.duration + 0.5;
      slices.push(s);
    }
    track.slices = slices;
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 1.1 * x, track.clientWidth);
  }

  function testSelectionHitTesting() {
    var testEl = getTestDiv('testSelectionHitTesting');
    var track = new TimelineSliceTrack();
    testEl.appendChild(track);
    track.heading = 'testSelectionHitTesting';
    track.headingWidth = '100px';
    track.slices = [
      new TimelineSlice('a', 0, 1, {}, 1),
      new TimelineSlice('b', 1, 2.1, {}, 4.8)
    ];
    track.style.width = '500px';
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 7.6, track.clientWidth);
    var clientRect = track.getBoundingClientRect();

    var selection = new TimelineSelection();
    track.addIntersectingItemsToSelection(1.5, clientRect.top + 5, selection);
    assertEquals(track.slices[0], selection[0].slice);

    var selection = new TimelineSelection();
    track.addIntersectingItemsToSelection(2, clientRect.top + 5, selection);
    assertEquals(0, selection.length);

    var selection = new TimelineSelection();
    track.addIntersectingItemsToSelection(6.8, clientRect.top + 5, selection);
    assertEquals(track.slices[1], selection[0].slice);

    var selection = new TimelineSelection();
    track.addIntersectingItemsToSelection(6.9, clientRect.top + 5, selection);
    assertEquals(0, selection.length);
  }

  function testSelectionHitTestingWithTimelineThreadTrack() {
    var model = new tracing.TimelineModel();
    var p1 = model.getOrCreateProcess(1);
    var t1 = p1.getOrCreateThread(1);
    t1.subRows[0].push(new tracing.TimelineThreadSlice('a', 0, 1, {}, 5));
    t1.subRows[0].push(new tracing.TimelineThreadSlice('b', 0, 5.1, {}, 4));

    var testEl = getTestDiv('testSelectionHitTestingWithTimelineThreadTrack');
    var track = new tracing.TimelineThreadTrack();
    testEl.appendChild(track);
    track.heading = 'testSelectionHitTestingWithTimelineThreadTrack';
    track.headingWidth = '100px';
    track.thread = t1;

    track.style.width = '500px';
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 10, track.clientWidth);
    var clientRect = track.getBoundingClientRect();

    var selection = new TimelineSelection();
    track.addIntersectingItemsToSelection(1.5, clientRect.top + 5, selection);
    assertEquals(t1.subRows[0][0], selection[0].slice);

    var selection = new TimelineSelection();
    track.addIntersectingItemsInRangeToSelection(1.5, 1.8, clientRect.top + 5, clientRect.top + 7, selection);
    assertEquals(t1.subRows[0][0], selection[0].slice);
  }

  function testBasicCpu() {
    var testEl = getTestDiv('testBasicCpu');

    var cpu = new TimelineCpu(7);
    cpu.slices = [
      new TimelineSlice('a', 0, 1, {}, 1),
      new TimelineSlice('b', 1, 2.1, {}, 4.8)
    ];
    cpu.updateBounds();

    var track = TimelineCpuTrack();
    testEl.appendChild(track);
    track.heading = 'CPU ' + cpu.cpuNumber;
    track.cpu = cpu;
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 11.1, track.clientWidth);
  }

  function testViewport() {
    var testEl = getTestDiv('testViewport');

    var track = tracing.TimelineViewportTrack();
    testEl.appendChild(track);
    track.viewport = new TimelineViewport(testEl);
    track.viewport.setPanAndScale(0,
        track.clientWidth / 1000);
  }

  function testBasicCounter() {
    var testEl = getTestDiv('testBasicCounter');

    var ctr = new TimelineCounter(undefined,
                                  'testBasicCounter', 'testBasicCounter');
    ctr.seriesNames = ['value1', 'value2'];
    ctr.seriesColors = [tracing.getStringColorId('testBasicCounter.value1'),
                        tracing.getStringColorId('testBasicCounter.value2')];
    ctr.timestamps = [0, 1, 2, 3, 4, 5, 6, 7];
    ctr.samples = [0, 5,
                   3, 3,
                   1, 1,
                   2, 1.1,
                   3, 0,
                   1, 7,
                   3, 0,
                   3.1, 0.5];
    ctr.updateBounds();

    var track = new TimelineCounterTrack();
    testEl.appendChild(track);
    track.heading = ctr.name;
    track.counter = ctr;
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 7.7, track.clientWidth);
  }

  function runOffscreenCounterTest(timestamps, samples, testFn) {
    var testEl = document.createElement('div');
    var ctr = new TimelineCounter(undefined,
                                  'foo', 'foo');
    var n = samples.length / timestamps.length;
    ctr.timestamps = timestamps;
    ctr.samples = samples;
    ctr.seriesNames = []
    ctr.seriesColors = []
    for (var i = 0; i < n; ++i) {
      ctr.seriesNames.push('value' + i);
      ctr.seriesColors.push(tracing.getStringColorId(ctr.seriesNames[i]));
    }
    ctr.updateBounds();

    var track = new TimelineCounterTrack();
    testEl.appendChild(track);
    document.body.appendChild(testEl);

    track.heading = ctr.name;
    track.counter = ctr;
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 10, track.clientWidth);

    try {
      testFn(ctr, track);
    } finally {
      document.body.removeChild(testEl);
    }
  }

  function testBasicCounterXPointPicking() {
    var timestamps = [0, 1, 2, 3, 4, 5, 6, 7];
    var samples = [0, 5,
                   3, 3,
                   1, 1,
                   2, 1.1,
                   3, 0,
                   1, 7,
                   3, 0,
                   3.1, 0.5];
    runOffscreenCounterTest(timestamps, samples, function(ctr, track) {
      var clientRect = track.getBoundingClientRect();
      var y75 = clientRect.top + 0.75 * clientRect.height;
      var sel;

      // In bounds.
      sel = new tracing.TimelineSelection();
      track.addIntersectingItemsToSelection(1.5, y75, sel);
      assertEquals(1, sel.length);
      assertEquals(track, sel[0].track);
      assertEquals(ctr, sel[0].counter);
      assertEquals(1, sel[0].sampleIndex);

      // Outside bouds.
      sel = new tracing.TimelineSelection();
      track.addIntersectingItemsToSelection(-1, y75, sel);
      assertEquals(0, sel.length);

      sel = new tracing.TimelineSelection();
      track.addIntersectingItemsToSelection(8, y75, sel);
      assertEquals(0, sel.length);
    });
  }

  /* You'll need visual inspection to test eliding with this one. */
  function testElideVisualInspection() {
    var optDicts = [{ trackName: 'elideOff', elide: false },
                    { trackName: 'elideOn', elide: true }];
    for (var dictIndex in optDicts) {
      var dict = optDicts[dictIndex];
      var testEl = getTestDiv(dict.trackName);
      var track = new TimelineSliceTrack();
      if (dict.elide) {
        track.SHOULD_ELIDE_TEXT = true;
      } else {
        track.SHOULD_ELIDE_TEXT = false;
      }
      var tooLongTitle = 'Unless eliding this SHOULD NOT BE DISPLAYED.  ';
      var bigTitle = 'Very big title name that goes on longer ' +
                     'than you may expect';
      testEl.appendChild(track);
      track.heading = 'Visual: ' + dict.trackName;
      track.slices = [
          // title, colorId, start, args, opt_duration
          new TimelineSlice('a ' + tooLongTitle + bigTitle, 0, 1, {}, 1),
          new TimelineSlice(bigTitle, 1, 2.1, {}, 4.8),
          new TimelineSlice('cccc cccc cccc', 1, 7, {}, 0.5),
          new TimelineSlice('d', 2, 7.6, {}, 1.0)
      ];
      track.viewport = new TimelineViewport(testEl);
      track.viewport.xSetWorldRange(0, 9.5, track.clientWidth);
    }
  }

  function testElide() {
    var testEl = getTestDiv('testElide');
    var track = new TimelineSliceTrack();
    testEl.appendChild(track);
    var bigtitle = 'Super duper long long title ' +
      'holy moly when did you get so verbose?';
    var smalltitle = 'small';
    track.viewport = new TimelineViewport(testEl);
    track.heading = 'testElide';
    track.slices = [
        // title, colorId, start, args, opt_duration
        new TimelineSlice(bigtitle, 0, 1, {}, 1),
        new TimelineSlice(smalltitle, 1, 2, {}, 1)
    ];
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 3.3, track.clientWidth);
    var stringWidthPair = undefined;
    var pixWidth = track.viewport_.xViewVectorToWorld(1);

    // Small titles on big slices are not elided.
    stringWidthPair = track.elidedTitleCache.get(track, pixWidth, smalltitle,
      track.labelWidth(smalltitle), 1);
    assertEquals(smalltitle, stringWidthPair.string);
    // Keep shrinking the slice until eliding starts.
    var elidedWhenSmallEnough = false;
    for (var sliceLength = 1; sliceLength >= 0.00001; sliceLength /= 2.0) {
      stringWidthPair = track.elidedTitleCache.get(track, pixWidth, smalltitle,
        track.labelWidth(smalltitle), sliceLength);
      if (stringWidthPair.string.length < smalltitle.length) {
        elidedWhenSmallEnough = true;
        break;
      }
    }
    assertTrue(elidedWhenSmallEnough);

    // Big titles are elided immediately.
    var superBigTitle = '';
    for (var x = 0; x < 10; x++) {
      superBigTitle += bigtitle;
    }
    stringWidthPair = track.elidedTitleCache.get(track, pixWidth,
      superBigTitle, track.labelWidth(superBigTitle), 1);
    assertTrue(stringWidthPair.string.length < superBigTitle.length);
    // And elided text ends with ...
    var len = stringWidthPair.string.length;
    assertEquals('...', stringWidthPair.string.substring(len - 3, len));
  }

  function testTimelineThreadTrackWithRegularSlices() {
    var testEl = getTestDiv('testTimelineThreadTrackWithRegularSlices');
    var track = TimelineThreadTrack();
    testEl.appendChild(track);
    track.heading = 'testTimelineThreadTrackWithRegularSlices';
    var thread = new TimelineThread(new TimelineProcess(7), 1);
    thread.subRows = [
      [
        new TimelineThreadSlice('a', 0, 1, {}, 1),
        new TimelineThreadSlice('b', 1, 2.1, {}, 4.8),
        new TimelineThreadSlice('b', 1, 7, {}, 0.5),
        new TimelineThreadSlice('c', 2, 7.6, {}, 0.4)
      ],
      [
        new TimelineThreadSlice('d', 3, 1.1, {}, 0.8),
        new TimelineThreadSlice('e', 4, 7.1, {}, 0.3)
      ]
    ];
    thread.updateBounds();
    track.heading = 'thread regular';
    track.headingWidth = '150px';
    track.toolTip = thread.userFriendlyDetails + ':';
    track.thread = thread;
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 8.2, track.clientWidth);
  }

  function testTimelineThreadTrackWithTallSlices() {
    var testEl = getTestDiv('testTimelineThreadTrackWithTallSlices');
    var track = TimelineThreadTrack();
    testEl.appendChild(track);
    track.heading = 'testTimelineThreadTrackWithTallSlices';
    var thread = new TimelineThread(new TimelineProcess(7), 1);
    thread.subRows = [
      [new TimelineThreadSlice('a', 1, 0, {}, 1)],
      [new TimelineThreadSlice('b', 2, 0.1, {}, 0.8)],
      [new TimelineThreadSlice('c', 3, 0.15, {}, 0.70)],
      [new TimelineThreadSlice('d', 4, 0.20, {}, 0.50)],
      [new TimelineThreadSlice('e', 5, 0.30, {}, 0.28)],
      [new TimelineThreadSlice('e', 6, 0.35, {}, 0.20)],
      [new TimelineThreadSlice('f', 7, 0.40, {}, 0.10)]
    ];
    thread.updateBounds();
    track.heading = 'thread tall';
    track.headingWidth = '150px';
    track.toolTip = thread.userFriendlyDetails + ':';
    track.thread = thread;
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 1.1, track.clientWidth);
  }

  function testTimelineThreadTrackWithRegularAndAsyncSlices() {
    var testEl = getTestDiv('testTimelineThreadTrackWithAsyncSlices');
    var track = TimelineThreadTrack();
    testEl.appendChild(track);
    var thread = new TimelineThread(new TimelineProcess(7), 1);
    thread.subRows = [
      [
        new TimelineThreadSlice('a', 0, 1, {}, 1),
        new TimelineThreadSlice('b', 1, 2.1, {}, 4.8),
        new TimelineThreadSlice('b', 1, 7, {}, 0.5),
        new TimelineThreadSlice('c', 2, 7.6, {}, 0.4)
      ],
      [
        new TimelineThreadSlice('d', 3, 1.1, {}, 0.8),
        new TimelineThreadSlice('e', 4, 7.1, {}, 0.3)
      ]
    ];
    thread.asyncSlices.push(newAsyncSlice(1.2, 7.2 - 1.2, thread, thread));
    thread.asyncSlices.push(newAsyncSlice(1.3, 7.3 - 1.3, thread, thread));
    thread.updateBounds();
    track.heading = 'thread regular + async';
    track.headingWidth = '150px';
    track.toolTip = thread.userFriendlyDetails + ':';
    track.thread = thread;
    track.viewport = new TimelineViewport(testEl);
    track.viewport.xSetWorldRange(0, 8.15, track.clientWidth);
  }

  function testTimelineSliceTrackAddItemNearToProvidedHit() {
    var track = new TimelineSliceTrack();
    track.slices = [
      new TimelineSlice('a', 0, 1, {}, 1),
      new TimelineSlice('b', 1, 2.1, {}, 4.8),
      new TimelineSlice('b', 1, 7, {}, 0.5),
      new TimelineSlice('c', 2, 7.6, {}, 0.4)
    ];
    var sel = new tracing.TimelineSelection();
    track.addAllObjectsMatchingFilterToSelection(new tracing.TimelineFilter("b"), sel);
    var ret;

    // Select to the right of B.
    var selRight = new tracing.TimelineSelection();
    ret = track.addItemNearToProvidedHitToSelection(sel[0], 1, selRight);
    assertTrue(ret);
    assertEquals(track.slices[2], selRight[0].slice);

    // Select to the right of the 2nd b.
    var selRight2 = new tracing.TimelineSelection();
    ret = track.addItemNearToProvidedHitToSelection(sel[0], 2, selRight2);
    assertTrue(ret);
    assertEquals(track.slices[3], selRight2[0].slice);

    // Select to 2 to the right of the 2nd b.
    var selRightOfRight = new tracing.TimelineSelection();
    ret = track.addItemNearToProvidedHitToSelection(selRight[0], 1, selRightOfRight);
    assertTrue(ret);
    assertEquals(track.slices[3], selRightOfRight[0].slice);

    // Select to the right of the rightmost slice.
    var selNone = new tracing.TimelineSelection();
    ret = track.addItemNearToProvidedHitToSelection(selRightOfRight[0], 1, selNone);
    assertFalse(ret);
    assertEquals(0, selNone.length);

    // Select A and then select left.
    var sel = new tracing.TimelineSelection();
    track.addAllObjectsMatchingFilterToSelection(new tracing.TimelineFilter("a"), sel);
    var ret;

    selNone = new tracing.TimelineSelection();
    ret = track.addItemNearToProvidedHitToSelection(sel[0], -1, selNone);
    assertFalse(ret);
    assertEquals(0, selNone.length);

  }
</script>
</body>
</html>