blob: f0b8d84cfafd90235aeb3f4148d711be7d6a3b64 [file] [log] [blame]
<!DOCTYPE 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.
-->
<link rel="import" href="/tracing/base/iteration_helpers.html">
<link rel="import" href="/tracing/importer/import.html">
<link rel="import" href="/tracing/model/counter.html">
<link rel="import" href="/tracing/model/model.html">
<link rel="import" href="/tracing/model/slice.html">
<link rel="import" href="/tracing/model/slice_group.html">
<link rel="import" href="/tracing/model/stack_frame.html">
<link rel="import" href="/tracing/model/thread_time_slice.html">
<link rel="import" href="/tracing/model/user_model/stub_expectation.html">
<script>
'use strict';
/**
* @fileoverview Helper functions for use in tracing tests.
*/
tr.exportTo('tr.c', function() {
var ColorScheme = tr.b.ColorScheme;
function _getStartAndCpuDurationFromDict(
options, required, startFieldName, durationFieldName, endFieldName) {
if (options[startFieldName] === undefined) {
if (required)
throw new Error('Too little information.');
else
return {start: undefined, duration: undefined};
}
if (options[durationFieldName] !== undefined &&
options[endFieldName] !== undefined) {
throw new Error('Too much information.');
}
if (options[durationFieldName] === undefined &&
options[endFieldName] === undefined) {
if (required)
throw new Error('Too little information.');
else
return {start: undefined, duration: undefined};
}
var duration;
if (options[durationFieldName] !== undefined) {
duration = options[durationFieldName];
} else {
duration = options[endFieldName] - options[startFieldName];
}
return {
start: options[startFieldName],
duration: duration
};
}
function _maybeGetCpuStartAndCpuDurationFromDict(options) {
return _getStartAndCpuDurationFromDict(
options, false, 'cpuStart', 'cpuDuration', 'cpuEnd');
}
function TestUtils() {
}
TestUtils.getStartAndDurationFromDict = function(options) {
return _getStartAndCpuDurationFromDict(
options, true, 'start', 'duration', 'end');
};
TestUtils.newAsyncSlice = function(start, duration, startThread, endThread) {
return TestUtils.newAsyncSliceNamed(
'a', start, duration, startThread, endThread);
};
TestUtils.newAsyncSliceNamed = function(
name, start, duration, startThread, endThread) {
var asyncSliceConstructor =
tr.model.AsyncSlice.getConstructor('', name);
var s = new asyncSliceConstructor('', name, 0, start);
s.duration = duration;
s.startThread = startThread;
s.endThread = endThread;
return s;
};
function getColorId(colorId) {
if (colorId) {
if (colorId === 'random') {
colorId = Math.floor(
Math.random() *
ColorScheme.proprties.numGeneralPurposeColorIds);
}
} else {
colorId = 0;
}
return colorId;
}
TestUtils.newAsyncSliceEx = function(options) {
var sd = TestUtils.getStartAndDurationFromDict(options);
var cat = options.cat ? options.cat : 'cat';
var title = options.title ? options.title : 'a';
var colorId = getColorId(options.colorId);
var isTopLevel;
if (options.isTopLevel !== undefined)
isTopLevel = options.isTopLevel;
else
isTopLevel = false;
var asyncSliceConstructor =
tr.model.AsyncSlice.getConstructor(cat, title);
var slice = new asyncSliceConstructor(
cat,
title,
colorId,
sd.start,
options.args ? options.args : {},
sd.duration, isTopLevel);
if (options.id)
slice.id = options.id;
else
slice.id = tr.b.GUID.allocate();
if (options.startStackFrame)
slice.startStackFrame = options.startStackFrame;
if (options.endStackFrame)
slice.endStackFrame = options.endStackFrame;
if (options.important)
slice.important = options.important;
if (options.startThread)
slice.startThread = options.startThread;
if (options.endThread)
slice.endThread = options.endThread;
return slice;
};
TestUtils.newCounter = function(parent) {
return TestUtils.newCounterNamed(parent, 'a');
};
TestUtils.newCounterNamed = function(parent, name) {
var s = new tr.model.Counter(parent, name, null, name);
return s;
};
TestUtils.newCounterCategory = function(parent, category, name) {
var s = new tr.model.Counter(parent, name, category, name);
return s;
};
TestUtils.newCounterSeries = function() {
var s = new tr.model.CounterSeries('a', 0);
return s;
};
TestUtils.newFlowEventEx = function(options) {
if (options.start === undefined)
throw new Error('Too little info');
var title = options.title ? options.title : 'a';
var colorId = options.colorId ? options.colorId : 0;
var sd = TestUtils.getStartAndDurationFromDict(options);
var id;
if (options.id !== undefined)
id = options.id;
else
id = tr.b.GUID.allocate();
var event = new tr.model.FlowEvent(
options.cat ? options.cat : 'cat',
id,
title,
colorId,
sd.start,
options.args ? options.args : {},
sd.duration);
if (options.startStackFrame)
event.startStackFrame = options.startStackFrame;
if (options.endStackFrame)
event.endStackFrame = options.endStackFrame;
if (options.important)
event.important = options.important;
if (options.startSlice) {
event.startSlice = options.startSlice;
event.startSlice.outFlowEvents.push(event);
}
if (options.endSlice) {
event.endSlice = options.endSlice;
event.endSlice.inFlowEvents.push(event);
}
return event;
};
TestUtils.newThreadSlice = function(thread, state, start, duration, opt_cpu) {
var s = new tr.model.ThreadTimeSlice(
thread, state, 'cat', start, {}, duration);
if (opt_cpu)
s.cpuOnWhichThreadWasRunning = opt_cpu;
return s;
};
TestUtils.newSampleNamed = function(
thread, sampleName, category, frameNames, start) {
var model;
if (thread.parent)
model = thread.parent.model;
else
model = undefined;
var sf = TestUtils.newStackTrace(model, frameNames);
var s = new tr.model.Sample(undefined, thread,
sampleName, start,
sf,
1);
return s;
};
TestUtils.newSliceEx = function(options) {
var sd = TestUtils.getStartAndDurationFromDict(options);
var title = options.title ? options.title : 'a';
var colorId = options.colorId ? options.colorId : 0;
var cpuSD = _maybeGetCpuStartAndCpuDurationFromDict(options);
var type;
if (options.type)
type = options.type;
else
type = tr.model.Slice;
var slice = new type(
options.cat ? options.cat : 'cat',
title,
colorId,
sd.start,
options.args ? options.args : {},
sd.duration,
cpuSD.start, cpuSD.duration);
return slice;
};
TestUtils.newStackTrace = function(model, titles) {
var frame = undefined;
titles.forEach(function(title) {
frame = new tr.model.StackFrame(frame, tr.b.GUID.allocate(), title, 7);
if (model)
model.addStackFrame(frame);
});
return frame;
};
TestUtils.findSliceNamed = function(slices, name) {
if (slices instanceof tr.model.SliceGroup)
slices = slices.slices;
for (var i = 0; i < slices.length; i++)
if (slices[i].title == name)
return slices[i];
return undefined;
};
TestUtils.newInteractionRecord = function(parentModel, start, duration) {
return new tr.model.um.StubExpectation({
parentModel: parentModel, start: start, duration: duration});
};
TestUtils.newModel = function(customizeModelCallback) {
return TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneEmptyContainers: false,
customizeModelCallback: customizeModelCallback
});
};
TestUtils.newModelWithEvents = function(events, opts) {
if (!(events instanceof Array))
events = [events];
opts = opts || {};
var io = new tr.importer.ImportOptions();
io.showImportWarnings = false;
io.customizeModelCallback = opts.customizeModelCallback;
io.trackDetailedModelStats = opts.trackDetailedModelStats === undefined ?
false : opts.trackDetailedModelStats;
io.shiftWorldToZero = opts.shiftWorldToZero === undefined ?
true : opts.shiftWorldToZero;
io.pruneEmptyContainers = opts.pruneEmptyContainers === undefined ?
true : opts.pruneEmptyContainers;
io.auditorConstructors = opts.auditorConstructors === undefined ?
[] : opts.auditorConstructors;
var m = new tr.Model();
var i = new tr.importer.Import(m, io);
i.importTraces(events);
return m;
};
TestUtils.newModelWithAuditor = function(customizeModelCallback, auditor) {
return TestUtils.newModelWithEvents([], {
shiftWorldToZero: false,
pruneEmptyContainers: false,
customizeModelCallback: customizeModelCallback,
auditorConstructors: [auditor]
});
};
TestUtils.newFakeThread = function() {
var process = {model: {}};
return new tr.model.Thread(process);
};
/** @constructor */
TestUtils.SourceGenerator = function() {
this.sourceList_ = [];
this.currentLineCommentList_ = [];
this.currentIndent_ = 0;
this.currentLineEmpty_ = true;
};
TestUtils.SourceGenerator.prototype = {
push: function(/* arguments */) {
if (this.currentLineEmpty_) {
this.sourceList_.push(' '.repeat(this.currentIndent_));
this.currentLineEmpty_ = false;
}
this.sourceList_.push.apply(
this.sourceList_, Array.prototype.slice.call(arguments));
},
pushComment: function(/* arguments */) {
this.currentLineCommentList_.push.apply(
this.currentLineCommentList_, Array.prototype.slice.call(arguments));
},
build: function() {
this.finishLine_();
return this.sourceList_.join('');
},
breakLine: function() {
this.finishLine_();
this.push('\n');
this.currentLineEmpty_ = true;
},
finishLine_: function() {
if (this.currentLineCommentList_.length === 0)
return;
this.push(' // ');
this.push.apply(this, this.currentLineCommentList_);
this.push('.');
this.currentLineCommentList_ = [];
},
indentBlock: function(spaces, breakLine, blockCallback, opt_this) {
opt_this = opt_this || this;
this.currentIndent_ += spaces;
if (breakLine)
this.breakLine();
blockCallback.call(opt_this);
this.currentIndent_ -= spaces;
},
formatSingleLineList: function(list, itemCallback, opt_this) {
opt_this = opt_this || this;
this.push('[');
tr.b.asArray(list).forEach(function(item, index) {
if (index > 0)
this.push(', ');
itemCallback.call(opt_this, item, index);
}, this);
this.push(']');
},
formatMultiLineList: function(list, itemCallback, opt_this) {
opt_this = opt_this || this;
this.push('[');
this.indentBlock(2, false /* don't break line */, function() {
tr.b.asArray(list).forEach(function(item, index) {
if (index > 0)
this.push(',');
this.breakLine();
itemCallback.call(opt_this, item, index);
}, this);
}, this);
if (list.length > 0)
this.breakLine();
this.push(']');
},
formatString: function(string) {
if (string === undefined)
this.push('undefined');
else
this.push('\'', string, '\'');
}
};
TestUtils.addSourceListing = function(test, source) {
var testSourceEl = document.createElement('pre');
testSourceEl.style.fontFamily = 'monospace';
testSourceEl.textContent = source;
var copyButtonEl = document.createElement('button');
copyButtonEl.textContent = 'Copy into to clipboard';
copyButtonEl.addEventListener('click', function() {
var selection = window.getSelection();
// Store the original selection.
var originalRanges = new Array(selection.rangeCount);
for (var i = 0; i < originalRanges.length; i++)
originalRanges[i] = selection.getRangeAt(i);
// Copy the generated test source code into clipboard.
selection.removeAllRanges();
var range = document.createRange();
range.selectNode(testSourceEl);
selection.addRange(range);
document.execCommand('copy');
// Restore the original selection.
selection.removeAllRanges();
for (var i = 0; i < originalRanges.length; i++)
selection.addRange(originalRanges[i]);
});
var outputEl = document.createElement('div');
outputEl.appendChild(copyButtonEl);
outputEl.appendChild(testSourceEl);
test.addHTMLOutput(outputEl);
};
TestUtils.newInstantEvent = function(options) {
var title = options.title;
var start = options.start;
if ((title === undefined) ||
(title === '') ||
(start === undefined))
throw new Error('too little information');
var category = options.category || 'category';
var colorId = getColorId(options.colorId);
var args = options.args || {};
return new tr.model.InstantEvent(
category, title, colorId, start, args);
};
return {
TestUtils: TestUtils
};
});
</script>