# make unit-test
#
-# This target runs in-browser unit tests with js-test-driver and jasmine unit
-# test framework.
+# This target runs in-browser unit tests with our test framework and the
+# jasmine unit test framework.
unit-test:
- @cd test/unit/ ; make ;
+ cd test; \
+ $(DEFAULT_PYTHON) test.py --unitTest \
+ --browserManifestFile=$(PDF_BROWSERS)
# make browser-test
#
--- /dev/null
+jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+ var results = child.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+
+ return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+ var parentDiv = this.dom.summary;
+ var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+ var parent = child[parentSuite];
+
+ if (parent) {
+ if (typeof this.views.suites[parent.id] == 'undefined') {
+ this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+ }
+ parentDiv = this.views.suites[parent.id].element;
+ }
+
+ parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+ for(var fn in jasmine.HtmlReporterHelpers) {
+ ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+ }
+};
+
+jasmine.HtmlReporter = function(_doc) {
+ var self = this;
+ var doc = _doc || window.document;
+
+ var reporterView;
+
+ var dom = {};
+
+ // Jasmine Reporter Public Interface
+ self.logRunningSpecs = false;
+
+ self.reportRunnerStarting = function(runner) {
+ var specs = runner.specs() || [];
+
+ if (specs.length == 0) {
+ return;
+ }
+
+ createReporterDom(runner.env.versionString());
+ doc.body.appendChild(dom.reporter);
+
+ reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+ reporterView.addSpecs(specs, self.specFilter);
+ };
+
+ self.reportRunnerResults = function(runner) {
+ reporterView.complete();
+ };
+
+ self.reportSuiteResults = function(suite) {
+ reporterView.suiteComplete(suite);
+ };
+
+ self.reportSpecStarting = function(spec) {
+ if (self.logRunningSpecs) {
+ self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+ };
+
+ self.reportSpecResults = function(spec) {
+ reporterView.specComplete(spec);
+ };
+
+ self.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+ };
+
+ self.specFilter = function(spec) {
+ if (!focusedSpecName()) {
+ return true;
+ }
+
+ return spec.getFullName().indexOf(focusedSpecName()) === 0;
+ };
+
+ return self;
+
+ function focusedSpecName() {
+ var specName;
+
+ (function memoizeFocusedSpec() {
+ if (specName) {
+ return;
+ }
+
+ var paramMap = [];
+ var params = doc.location.search.substring(1).split('&');
+
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ specName = paramMap.spec;
+ })();
+
+ return specName;
+ }
+
+ function createReporterDom(version) {
+ dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+ dom.banner = self.createDom('div', { className: 'banner' },
+ self.createDom('span', { className: 'title' }, "Jasmine "),
+ self.createDom('span', { className: 'version' }, version)),
+
+ dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+ dom.alert = self.createDom('div', {className: 'alert'}),
+ dom.results = self.createDom('div', {className: 'results'},
+ dom.summary = self.createDom('div', { className: 'summary' }),
+ dom.details = self.createDom('div', { id: 'details' }))
+ );
+ }
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+ var results = child.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+
+ return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+ var parentDiv = this.dom.summary;
+ var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+ var parent = child[parentSuite];
+
+ if (parent) {
+ if (typeof this.views.suites[parent.id] == 'undefined') {
+ this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+ }
+ parentDiv = this.views.suites[parent.id].element;
+ }
+
+ parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+ for(var fn in jasmine.HtmlReporterHelpers) {
+ ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+ }
+};
+
+jasmine.HtmlReporter.ReporterView = function(dom) {
+ this.startedAt = new Date();
+ this.runningSpecCount = 0;
+ this.completeSpecCount = 0;
+ this.passedCount = 0;
+ this.failedCount = 0;
+ this.skippedCount = 0;
+
+ this.createResultsMenu = function() {
+ this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+ this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+ ' | ',
+ this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+ this.summaryMenuItem.onclick = function() {
+ dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+ };
+
+ this.detailsMenuItem.onclick = function() {
+ showDetails();
+ };
+ };
+
+ this.addSpecs = function(specs, specFilter) {
+ this.totalSpecCount = specs.length;
+
+ this.views = {
+ specs: {},
+ suites: {}
+ };
+
+ for (var i = 0; i < specs.length; i++) {
+ var spec = specs[i];
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+ if (specFilter(spec)) {
+ this.runningSpecCount++;
+ }
+ }
+ };
+
+ this.specComplete = function(spec) {
+ this.completeSpecCount++;
+
+ if (isUndefined(this.views.specs[spec.id])) {
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+ }
+
+ var specView = this.views.specs[spec.id];
+
+ switch (specView.status()) {
+ case 'passed':
+ this.passedCount++;
+ break;
+
+ case 'failed':
+ this.failedCount++;
+ break;
+
+ case 'skipped':
+ this.skippedCount++;
+ break;
+ }
+
+ specView.refresh();
+ this.refresh();
+ };
+
+ this.suiteComplete = function(suite) {
+ var suiteView = this.views.suites[suite.id];
+ if (isUndefined(suiteView)) {
+ return;
+ }
+ suiteView.refresh();
+ };
+
+ this.refresh = function() {
+
+ if (isUndefined(this.resultsMenu)) {
+ this.createResultsMenu();
+ }
+
+ // currently running UI
+ if (isUndefined(this.runningAlert)) {
+ this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
+ dom.alert.appendChild(this.runningAlert);
+ }
+ this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+ // skipped specs UI
+ if (isUndefined(this.skippedAlert)) {
+ this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
+ }
+
+ this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.skippedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.skippedAlert);
+ }
+
+ // passing specs UI
+ if (isUndefined(this.passedAlert)) {
+ this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
+ }
+ this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+ // failing specs UI
+ if (isUndefined(this.failedAlert)) {
+ this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+ }
+ this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+ if (this.failedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.failedAlert);
+ dom.alert.appendChild(this.resultsMenu);
+ }
+
+ // summary info
+ this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+ this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+ };
+
+ this.complete = function() {
+ dom.alert.removeChild(this.runningAlert);
+
+ this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.failedCount === 0) {
+ dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+ } else {
+ showDetails();
+ }
+
+ dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+ };
+
+ return this;
+
+ function showDetails() {
+ if (dom.reporter.className.search(/showDetails/) === -1) {
+ dom.reporter.className += " showDetails";
+ }
+ }
+
+ function isUndefined(obj) {
+ return typeof obj === 'undefined';
+ }
+
+ function isDefined(obj) {
+ return !isUndefined(obj);
+ }
+
+ function specPluralizedFor(count) {
+ var str = count + " spec";
+ if (count > 1) {
+ str += "s"
+ }
+ return str;
+ }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
+jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
+ this.spec = spec;
+ this.dom = dom;
+ this.views = views;
+
+ this.symbol = this.createDom('li', { className: 'pending' });
+ this.dom.symbolSummary.appendChild(this.symbol);
+
+ this.summary = this.createDom('div', { className: 'specSummary' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.description)
+ );
+
+ this.detail = this.createDom('div', { className: 'specDetail' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.getFullName())
+ );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function() {
+ return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
+ this.symbol.className = this.status();
+
+ switch (this.status()) {
+ case 'skipped':
+ break;
+
+ case 'passed':
+ this.appendSummaryToSuiteDiv();
+ break;
+
+ case 'failed':
+ this.appendSummaryToSuiteDiv();
+ this.appendFailureDetail();
+ break;
+ }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
+ this.summary.className += ' ' + this.status();
+ this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
+ this.detail.className += ' ' + this.status();
+
+ var resultItems = this.spec.results().getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ this.detail.appendChild(messagesDiv);
+ this.dom.details.appendChild(this.detail);
+ }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
+ this.suite = suite;
+ this.dom = dom;
+ this.views = views;
+
+ this.element = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
+ );
+
+ this.appendToSummary(this.suite, this.element);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.status = function() {
+ return this.getSpecStatus(this.suite);
+};
+
+jasmine.HtmlReporter.SuiteView.prototype.refresh = function() {
+ this.element.className += " " + this.status();
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SuiteView);
+
+/* @deprecated Use jasmine.HtmlReporter instead
+ */
+jasmine.TrivialReporter = function(doc) {
+ this.document = doc || document;
+ this.suiteDivs = {};
+ this.logRunningSpecs = false;
+};
+
+jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) { el.appendChild(child); }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
+ var showPassed, showSkipped;
+
+ this.outerDiv = this.createDom('div', { id: 'TrivialReporter', className: 'jasmine_reporter' },
+ this.createDom('div', { className: 'banner' },
+ this.createDom('div', { className: 'logo' },
+ this.createDom('span', { className: 'title' }, "Jasmine"),
+ this.createDom('span', { className: 'version' }, runner.env.versionString())),
+ this.createDom('div', { className: 'options' },
+ "Show ",
+ showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
+ showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
+ this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
+ )
+ ),
+
+ this.runnerDiv = this.createDom('div', { className: 'runner running' },
+ this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
+ this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
+ this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
+ );
+
+ this.document.body.appendChild(this.outerDiv);
+
+ var suites = runner.suites();
+ for (var i = 0; i < suites.length; i++) {
+ var suite = suites[i];
+ var suiteDiv = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
+ this.suiteDivs[suite.id] = suiteDiv;
+ var parentDiv = this.outerDiv;
+ if (suite.parentSuite) {
+ parentDiv = this.suiteDivs[suite.parentSuite.id];
+ }
+ parentDiv.appendChild(suiteDiv);
+ }
+
+ this.startedAt = new Date();
+
+ var self = this;
+ showPassed.onclick = function(evt) {
+ if (showPassed.checked) {
+ self.outerDiv.className += ' show-passed';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
+ }
+ };
+
+ showSkipped.onclick = function(evt) {
+ if (showSkipped.checked) {
+ self.outerDiv.className += ' show-skipped';
+ } else {
+ self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
+ }
+ };
+};
+
+jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
+ var results = runner.results();
+ var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
+ this.runnerDiv.setAttribute("class", className);
+ //do it twice for IE
+ this.runnerDiv.setAttribute("className", className);
+ var specs = runner.specs();
+ var specCount = 0;
+ for (var i = 0; i < specs.length; i++) {
+ if (this.specFilter(specs[i])) {
+ specCount++;
+ }
+ }
+ var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
+ message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
+ this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
+
+ this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
+};
+
+jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
+ var results = suite.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.totalCount === 0) { // todo: change this to check results.skipped
+ status = 'skipped';
+ }
+ this.suiteDivs[suite.id].className += " " + status;
+};
+
+jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
+ if (this.logRunningSpecs) {
+ this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+};
+
+jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
+ var results = spec.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+ var specDiv = this.createDom('div', { className: 'spec ' + status },
+ this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(spec.getFullName()),
+ title: spec.getFullName()
+ }, spec.description));
+
+
+ var resultItems = results.getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ specDiv.appendChild(messagesDiv);
+ }
+
+ this.suiteDivs[spec.suite.id].appendChild(specDiv);
+};
+
+jasmine.TrivialReporter.prototype.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+};
+
+jasmine.TrivialReporter.prototype.getLocation = function() {
+ return this.document.location;
+};
+
+jasmine.TrivialReporter.prototype.specFilter = function(spec) {
+ var paramMap = {};
+ var params = this.getLocation().search.substring(1).split('&');
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ if (!paramMap.spec) {
+ return true;
+ }
+ return spec.getFullName().indexOf(paramMap.spec) === 0;
+};
--- /dev/null
+body { background-color: #eeeeee; padding: 0; margin: 5px; overflow-y: scroll; }
+
+#HTMLReporter { font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; }
+#HTMLReporter a { text-decoration: none; }
+#HTMLReporter a:hover { text-decoration: underline; }
+#HTMLReporter p, #HTMLReporter h1, #HTMLReporter h2, #HTMLReporter h3, #HTMLReporter h4, #HTMLReporter h5, #HTMLReporter h6 { margin: 0; line-height: 14px; }
+#HTMLReporter .banner, #HTMLReporter .symbolSummary, #HTMLReporter .summary, #HTMLReporter .resultMessage, #HTMLReporter .specDetail .description, #HTMLReporter .alert .bar, #HTMLReporter .stackTrace { padding-left: 9px; padding-right: 9px; }
+#HTMLReporter #jasmine_content { position: fixed; right: 100%; }
+#HTMLReporter .version { color: #aaaaaa; }
+#HTMLReporter .banner { margin-top: 14px; }
+#HTMLReporter .duration { color: #aaaaaa; float: right; }
+#HTMLReporter .symbolSummary { overflow: hidden; *zoom: 1; margin: 14px 0; }
+#HTMLReporter .symbolSummary li { display: block; float: left; height: 7px; width: 14px; margin-bottom: 7px; font-size: 16px; }
+#HTMLReporter .symbolSummary li.passed { font-size: 14px; }
+#HTMLReporter .symbolSummary li.passed:before { color: #5e7d00; content: "\02022"; }
+#HTMLReporter .symbolSummary li.failed { line-height: 9px; }
+#HTMLReporter .symbolSummary li.failed:before { color: #b03911; content: "x"; font-weight: bold; margin-left: -1px; }
+#HTMLReporter .symbolSummary li.skipped { font-size: 14px; }
+#HTMLReporter .symbolSummary li.skipped:before { color: #bababa; content: "\02022"; }
+#HTMLReporter .symbolSummary li.pending { line-height: 11px; }
+#HTMLReporter .symbolSummary li.pending:before { color: #aaaaaa; content: "-"; }
+#HTMLReporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; }
+#HTMLReporter .runningAlert { background-color: #666666; }
+#HTMLReporter .skippedAlert { background-color: #aaaaaa; }
+#HTMLReporter .skippedAlert:first-child { background-color: #333333; }
+#HTMLReporter .skippedAlert:hover { text-decoration: none; color: white; text-decoration: underline; }
+#HTMLReporter .passingAlert { background-color: #a6b779; }
+#HTMLReporter .passingAlert:first-child { background-color: #5e7d00; }
+#HTMLReporter .failingAlert { background-color: #cf867e; }
+#HTMLReporter .failingAlert:first-child { background-color: #b03911; }
+#HTMLReporter .results { margin-top: 14px; }
+#HTMLReporter #details { display: none; }
+#HTMLReporter .resultsMenu, #HTMLReporter .resultsMenu a { background-color: #fff; color: #333333; }
+#HTMLReporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; }
+#HTMLReporter.showDetails .summaryMenuItem:hover { text-decoration: underline; }
+#HTMLReporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter.showDetails .summary { display: none; }
+#HTMLReporter.showDetails #details { display: block; }
+#HTMLReporter .summaryMenuItem { font-weight: bold; text-decoration: underline; }
+#HTMLReporter .summary { margin-top: 14px; }
+#HTMLReporter .summary .suite .suite, #HTMLReporter .summary .specSummary { margin-left: 14px; }
+#HTMLReporter .summary .specSummary.passed a { color: #5e7d00; }
+#HTMLReporter .summary .specSummary.failed a { color: #b03911; }
+#HTMLReporter .description + .suite { margin-top: 0; }
+#HTMLReporter .suite { margin-top: 14px; }
+#HTMLReporter .suite a { color: #333333; }
+#HTMLReporter #details .specDetail { margin-bottom: 28px; }
+#HTMLReporter #details .specDetail .description { display: block; color: white; background-color: #b03911; }
+#HTMLReporter .resultMessage { padding-top: 14px; color: #333333; }
+#HTMLReporter .resultMessage span.result { display: block; }
+#HTMLReporter .stackTrace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; }
+
+#TrivialReporter { padding: 8px 13px; position: absolute; top: 0; bottom: 0; left: 0; right: 0; overflow-y: scroll; background-color: white; font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif; /*.resultMessage {*/ /*white-space: pre;*/ /*}*/ }
+#TrivialReporter a:visited, #TrivialReporter a { color: #303; }
+#TrivialReporter a:hover, #TrivialReporter a:active { color: blue; }
+#TrivialReporter .run_spec { float: right; padding-right: 5px; font-size: .8em; text-decoration: none; }
+#TrivialReporter .banner { color: #303; background-color: #fef; padding: 5px; }
+#TrivialReporter .logo { float: left; font-size: 1.1em; padding-left: 5px; }
+#TrivialReporter .logo .version { font-size: .6em; padding-left: 1em; }
+#TrivialReporter .runner.running { background-color: yellow; }
+#TrivialReporter .options { text-align: right; font-size: .8em; }
+#TrivialReporter .suite { border: 1px outset gray; margin: 5px 0; padding-left: 1em; }
+#TrivialReporter .suite .suite { margin: 5px; }
+#TrivialReporter .suite.passed { background-color: #dfd; }
+#TrivialReporter .suite.failed { background-color: #fdd; }
+#TrivialReporter .spec { margin: 5px; padding-left: 1em; clear: both; }
+#TrivialReporter .spec.failed, #TrivialReporter .spec.passed, #TrivialReporter .spec.skipped { padding-bottom: 5px; border: 1px solid gray; }
+#TrivialReporter .spec.failed { background-color: #fbb; border-color: red; }
+#TrivialReporter .spec.passed { background-color: #bfb; border-color: green; }
+#TrivialReporter .spec.skipped { background-color: #bbb; }
+#TrivialReporter .messages { border-left: 1px dashed gray; padding-left: 1em; padding-right: 1em; }
+#TrivialReporter .passed { background-color: #cfc; display: none; }
+#TrivialReporter .failed { background-color: #fbb; }
+#TrivialReporter .skipped { color: #777; background-color: #eee; display: none; }
+#TrivialReporter .resultMessage span.result { display: block; line-height: 2em; color: black; }
+#TrivialReporter .resultMessage .mismatch { color: black; }
+#TrivialReporter .stackTrace { white-space: pre; font-size: .8em; margin-left: 10px; max-height: 5em; overflow: auto; border: 1px inset red; padding: 1em; background: #eef; }
+#TrivialReporter .finished-at { padding-left: 1em; font-size: .6em; }
+#TrivialReporter.show-passed .passed, #TrivialReporter.show-skipped .skipped { display: block; }
+#TrivialReporter #jasmine_content { position: fixed; right: 100%; }
+#TrivialReporter .runner { border: 1px solid gray; display: block; margin: 5px 0; padding: 2px 0 2px 10px; }
+++ /dev/null
-/**
- * @fileoverview Jasmine JsTestDriver Adapter.
- * @author misko@hevery.com (Misko Hevery)
- */
-(function(window) {
- var rootDescribes = new Describes(window);
- var describePath = [];
- rootDescribes.collectMode();
-
- var JASMINE_TYPE = 'jasmine test case';
- TestCase('Jasmine Adapter Tests', null, JASMINE_TYPE);
-
- var jasminePlugin = {
- name:'jasmine',
-
- getTestRunsConfigurationFor: function(testCaseInfos, expressions, testRunsConfiguration) {
- for (var i = 0; i < testCaseInfos.length; i++) {
- if (testCaseInfos[i].getType() == JASMINE_TYPE) {
- testRunsConfiguration.push(new jstestdriver.TestRunConfiguration(testCaseInfos[i], []));
- }
- }
- return false;
- },
-
- runTestConfiguration: function(testRunConfiguration, onTestDone, onTestRunConfigurationComplete){
- if (testRunConfiguration.getTestCaseInfo().getType() != JASMINE_TYPE) return false;
-
- var jasmineEnv = jasmine.currentEnv_ = new jasmine.Env();
- rootDescribes.playback();
- var specLog = jstestdriver.console.log_ = [];
- var start;
- jasmineEnv.specFilter = function(spec) {
- return rootDescribes.isExclusive(spec);
- };
- jasmineEnv.reporter = {
- log: function(str){
- specLog.push(str);
- },
-
- reportRunnerStarting: function(runner) { },
-
- reportSpecStarting: function(spec) {
- specLog = jstestdriver.console.log_ = [];
- start = new Date().getTime();
- },
-
- reportSpecResults: function(spec) {
- var suite = spec.suite;
- var results = spec.results();
- if (results.skipped) return;
- var end = new Date().getTime();
- var messages = [];
- var resultItems = results.getItems();
- var state = 'passed';
- for ( var i = 0; i < resultItems.length; i++) {
- if (!resultItems[i].passed()) {
- state = resultItems[i].message.match(/AssertionError:/) ? 'error' : 'failed';
- messages.push({
- message: resultItems[i].toString(),
- name: resultItems[i].trace.name,
- stack: formatStack(resultItems[i].trace.stack)
- });
- }
- }
- onTestDone(
- new jstestdriver.TestResult(
- suite.getFullName(),
- spec.description,
- state,
- jstestdriver.angular.toJson(messages),
- specLog.join('\n'),
- end - start));
- },
-
- reportSuiteResults: function(suite) {},
-
- reportRunnerResults: function(runner) {
- onTestRunConfigurationComplete();
- }
- };
- jasmineEnv.execute();
- return true;
- },
-
- onTestsFinish: function(){
- jasmine.currentEnv_ = null;
- rootDescribes.collectMode();
- }
- };
- jstestdriver.pluginRegistrar.register(jasminePlugin);
-
- function formatStack(stack) {
- var lines = (stack||'').split(/\r?\n/);
- var frames = [];
- for (i = 0; i < lines.length; i++) {
- if (!lines[i].match(/\/jasmine[\.-]/)) {
- frames.push(lines[i].replace(/https?:\/\/\w+(:\d+)?\/test\//, '').replace(/^\s*/, ' '));
- }
- }
- return frames.join('\n');
- }
-
- function noop(){}
- function Describes(window){
- var describes = {};
- var beforeEachs = {};
- var afterEachs = {};
- // Here we store:
- // 0: everyone runs
- // 1: run everything under ddescribe
- // 2: run only iits (ignore ddescribe)
- var exclusive = 0;
- var collectMode = true;
- intercept('describe', describes);
- intercept('xdescribe', describes);
- intercept('beforeEach', beforeEachs);
- intercept('afterEach', afterEachs);
-
- function intercept(functionName, collection){
- window[functionName] = function(desc, fn){
- if (collectMode) {
- collection[desc] = function(){
- jasmine.getEnv()[functionName](desc, fn);
- };
- } else {
- jasmine.getEnv()[functionName](desc, fn);
- }
- };
- }
- window.ddescribe = function(name, fn){
- if (exclusive < 1) {
- exclusive = 1; // run ddescribe only
- }
- window.describe(name, function(){
- var oldIt = window.it;
- window.it = function(name, fn){
- fn.exclusive = 1; // run anything under ddescribe
- jasmine.getEnv().it(name, fn);
- };
- try {
- fn.call(this);
- } finally {
- window.it = oldIt;
- };
- });
- };
- window.iit = function(name, fn){
- exclusive = fn.exclusive = 2; // run only iits
- jasmine.getEnv().it(name, fn);
- };
-
-
- this.collectMode = function() {
- collectMode = true;
- exclusive = 0; // run everything
- };
- this.playback = function(){
- collectMode = false;
- playback(beforeEachs);
- playback(afterEachs);
- playback(describes);
-
- function playback(set) {
- for ( var name in set) {
- set[name]();
- }
- }
- };
-
- this.isExclusive = function(spec) {
- if (exclusive) {
- var blocks = spec.queue.blocks;
- for ( var i = 0; i < blocks.length; i++) {
- if (blocks[i].func.exclusive >= exclusive) {
- return true;
- }
- }
- return false;
- }
- return true;
- };
- }
-
-})(window);
-
-// Patch Jasmine for proper stack traces
-jasmine.Spec.prototype.fail = function (e) {
- var expectationResult = new jasmine.ExpectationResult({
- passed: false,
- message: e ? jasmine.util.formatException(e) : 'Exception'
- });
- // PATCH
- if (e) {
- expectationResult.trace = e;
- }
- this.results_.addResult(expectationResult);
-};
-
+++ /dev/null
-Copyright (c) 2010
- Misko Hevery <misko@hevery.com>
- Olmo Maldonado <me@ibolmo.com>
- Christoph Pojer <christoph.pojer@gmail.com>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
+++ /dev/null
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
// make test
//
target.test = function() {
- target.browsertest();
- target.unittest();
+ target.unittest({}, function() {
+ target.browsertest();
+ });
};
//
// (Special tests for the Github bot)
//
target.bottest = function() {
- target.browsertest({noreftest: true});
- // target.unittest();
+ target.unittest();
+ target.browsertest({noreftest: true}, function() {
+ target.browsertest();
+ });
};
//
//
// make unittest
//
-target.unittest = function() {
+target.unittest = function(options, callback) {
cd(ROOT_DIR);
echo();
echo('### Running unit tests');
- if (!which('make')) {
- echo('make not found. Skipping unit tests...');
- return;
- }
+ var PDF_BROWSERS = env['PDF_BROWSERS'] || 'resources/browser_manifests/browser_manifest.json';
- cd('test/unit');
- exec('make', {async: true});
+ if (!test('-f', 'test/' + PDF_BROWSERS)) {
+ echo('Browser manifest file test/' + PDF_BROWSERS + ' does not exist.');
+ echo('Try copying one of the examples in test/resources/browser_manifests/');
+ exit(1);
+ }
+ callback = callback || function() {};
+ cd('test');
+ exec(PYTHON_BIN + ' -u test.py --unitTest --browserManifestFile=' + PDF_BROWSERS,
+ {async: true}, callback);
};
//
default=False)
self.add_option("--port", action="store", dest="port", type="int",
help="The port the HTTP server should listen on.", default=8080)
+ self.add_option("--unitTest", action="store_true", dest="unitTest",
+ help="Run the unit tests.", default=False)
self.set_usage(USAGE_EXAMPLE)
def verifyOptions(self, options):
+ if options.reftest and options.unitTest:
+ self.error("--reftest and --unitTest must not be specified at the same time.")
if options.masterMode and options.manifestFile:
self.error("--masterMode and --manifestFile must not be specified at the same time.")
if not options.manifestFile:
print "Warning: ignoring browser argument since manifest file was also supplied"
if not options.browser and not options.browserManifestFile:
print "Starting server on port %s." % options.port
+
return options
def prompt(question):
eqLog = None
lastPost = { }
+class UnitTestState:
+ browsers = [ ]
+ browsersRunning = 0
+ lastPost = { }
+ numErrors = 0
+ numRun = 0
+
class Result:
def __init__(self, snapshot, failure, page):
self.snapshot = snapshot
class TestServer(SocketServer.TCPServer):
allow_reuse_address = True
-class PDFTestHandler(BaseHTTPRequestHandler):
-
+class TestHandlerBase(BaseHTTPRequestHandler):
# Disable annoying noise by default
def log_request(code=0, size=0):
if VERBOSE:
with open(path, "rb") as f:
self.wfile.write(f.read())
- def sendIndex(self, path, query):
- if not path.endswith("/"):
- # we need trailing slash
- self.send_response(301)
- redirectLocation = path + "/"
- if query:
- redirectLocation += "?" + query
- self.send_header("Location", redirectLocation)
- self.end_headers()
- return
-
- self.send_response(200)
- self.send_header("Content-Type", "text/html")
- self.end_headers()
- if query == "frame":
- self.wfile.write("<html><frameset cols=*,200><frame name=pdf>" +
- "<frame src='" + path + "'></frameset></html>")
- return
-
- location = os.path.abspath(os.path.realpath(DOC_ROOT + os.sep + path))
- self.wfile.write("<html><body><h1>PDFs of " + path + "</h1>\n")
- for filename in os.listdir(location):
- if filename.lower().endswith('.pdf'):
- self.wfile.write("<a href='/web/viewer.html?file=" +
- urllib.quote_plus(path + filename, '/') + "' target=pdf>" +
- filename + "</a><br>\n")
- self.wfile.write("</body></html>")
-
def do_GET(self):
url = urlparse(self.path)
# Ignore query string
self.sendFile(path, ext)
+class UnitTestHandler(TestHandlerBase):
+ def sendIndex(self, path, query):
+ print "send index"
+ def do_POST(self):
+ numBytes = int(self.headers['Content-Length'])
+
+ self.send_response(200)
+ self.send_header('Content-Type', 'text/plain')
+ self.end_headers()
+
+ url = urlparse(self.path)
+ result = json.loads(self.rfile.read(numBytes))
+ browser = result['browser']
+ UnitTestState.lastPost[browser] = int(time.time())
+ if url.path == "/tellMeToQuit":
+ tellAppToQuit(url.path, url.query)
+ UnitTestState.browsersRunning -= 1
+ UnitTestState.lastPost[browser] = None
+ return
+ elif url.path == '/info':
+ print result['message']
+ elif url.path == '/submit_task_results':
+ status, description = result['status'], result['description']
+ UnitTestState.numRun += 1
+ if status == 'TEST-UNEXPECTED-FAIL':
+ UnitTestState.numErrors += 1
+ message = status + ' | ' + description + ' | in ' + browser
+ if 'error' in result:
+ message += ' | ' + result['error']
+ print message
+ else:
+ print 'Error: uknown action' + url.path
+
+class PDFTestHandler(TestHandlerBase):
+
+ def sendIndex(self, path, query):
+ if not path.endswith("/"):
+ # we need trailing slash
+ self.send_response(301)
+ redirectLocation = path + "/"
+ if query:
+ redirectLocation += "?" + query
+ self.send_header("Location", redirectLocation)
+ self.end_headers()
+ return
+
+ self.send_response(200)
+ self.send_header("Content-Type", "text/html")
+ self.end_headers()
+ if query == "frame":
+ self.wfile.write("<html><frameset cols=*,200><frame name=pdf>" +
+ "<frame src='" + path + "'></frameset></html>")
+ return
+
+ location = os.path.abspath(os.path.realpath(DOC_ROOT + os.sep + path))
+ self.wfile.write("<html><body><h1>PDFs of " + path + "</h1>\n")
+ for filename in os.listdir(location):
+ if filename.lower().endswith('.pdf'):
+ self.wfile.write("<a href='/web/viewer.html?file=" +
+ urllib.quote_plus(path + filename, '/') + "' target=pdf>" +
+ filename + "</a><br>\n")
+ self.wfile.write("</body></html>")
+
+
def do_POST(self):
numBytes = int(self.headers['Content-Length'])
error = True
return not error
+def getTestBrowsers(options):
+ testBrowsers = []
+ if options.browserManifestFile:
+ testBrowsers = makeBrowserCommands(options.browserManifestFile)
+ elif options.browser:
+ testBrowsers = [makeBrowserCommand({"path":options.browser, "name":None})]
+
+ if options.browserManifestFile or options.browser:
+ assert len(testBrowsers) > 0
+ return testBrowsers
+
def setUp(options):
# Only serve files from a pdf.js clone
assert not GIT_CLONE_CHECK or os.path.isfile('../src/pdf.js') and os.path.isdir('../.git')
assert not os.path.isdir(TMPDIR)
- testBrowsers = []
- if options.browserManifestFile:
- testBrowsers = makeBrowserCommands(options.browserManifestFile)
- elif options.browser:
- testBrowsers = [makeBrowserCommand({"path":options.browser, "name":None})]
-
- if options.browserManifestFile or options.browser:
- assert len(testBrowsers) > 0
+ testBrowsers = getTestBrowsers(options)
with open(options.manifestFile) as mf:
manifestList = json.load(mf)
return testBrowsers
-def startBrowsers(browsers, options):
+def setUpUnitTests(options):
+ # Only serve files from a pdf.js clone
+ assert not GIT_CLONE_CHECK or os.path.isfile('../src/pdf.js') and os.path.isdir('../.git')
+
+ testBrowsers = getTestBrowsers(options)
+
+ UnitTestState.browsersRunning = len(testBrowsers)
+ for b in testBrowsers:
+ UnitTestState.lastPost[b.name] = int(time.time())
+ return testBrowsers
+
+def startBrowsers(browsers, options, path):
for b in browsers:
b.setup()
print 'Launching', b.name
host = 'http://%s:%s' % (SERVER_HOST, options.port)
- path = '/test/test_slave.html?'
- qs = 'browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile)
+ qs = '?browser='+ urllib.quote(b.name) +'&manifestFile='+ urllib.quote(options.manifestFile)
qs += '&path=' + b.path
b.start(host + path + qs)
def runTests(options, browsers):
t1 = time.time()
try:
- startBrowsers(browsers, options)
+ startBrowsers(browsers, options, '/test/test_slave.html')
while not State.done:
for b in State.lastPost:
if State.remaining[b] > 0 and int(time.time()) - State.lastPost[b] > BROWSER_TIMEOUT:
print "\nStarting reftest harness to examine %d eq test failures." % State.numEqFailures
startReftest(browsers[0], options)
+def runUnitTests(options, browsers):
+ t1 = time.time()
+ try:
+ startBrowsers(browsers, options, '/test/unit/unit_test.html')
+ while UnitTestState.browsersRunning > 0:
+ for b in UnitTestState.lastPost:
+ if UnitTestState.lastPost[b] != None and int(time.time()) - UnitTestState.lastPost[b] > BROWSER_TIMEOUT:
+ print 'TEST-UNEXPECTED-FAIL | test failed', b, "has not responded in", BROWSER_TIMEOUT, "s"
+ UnitTestState.lastPost[b] = None
+ UnitTestState.browsersRunning -= 1
+ UnitTestState.numErrors += 1
+ time.sleep(1)
+ print ''
+ print 'Ran', UnitTestState.numRun, 'tests'
+ if UnitTestState.numErrors > 0:
+ print 'OHNOES! Some tests failed!'
+ print ' ', UnitTestState.numErrors, 'of', UnitTestState.numRun, 'failed'
+ else:
+ print 'All unit tests passed.'
+ finally:
+ teardownBrowsers(browsers)
+ t2 = time.time()
+ print "Unit test Runtime was", int(t2 - t1), "seconds"
+
def main():
optionParser = TestOptions()
options, args = optionParser.parse_args()
if options == None:
sys.exit(1)
- httpd = TestServer((SERVER_HOST, options.port), PDFTestHandler)
- httpd.masterMode = options.masterMode
- httpd_thread = threading.Thread(target=httpd.serve_forever)
- httpd_thread.setDaemon(True)
- httpd_thread.start()
+ if options.unitTest:
+ httpd = TestServer((SERVER_HOST, options.port), UnitTestHandler)
+ httpd_thread = threading.Thread(target=httpd.serve_forever)
+ httpd_thread.setDaemon(True)
+ httpd_thread.start()
- browsers = setUp(options)
- if len(browsers) > 0:
- runTests(options, browsers)
+ browsers = setUpUnitTests(options)
+ if len(browsers) > 0:
+ runUnitTests(options, browsers)
else:
- # just run the server
- print "Running HTTP server. Press Ctrl-C to quit."
- try:
- while True:
- time.sleep(1)
- except (KeyboardInterrupt):
- print "\nExiting."
+ httpd = TestServer((SERVER_HOST, options.port), PDFTestHandler)
+ httpd.masterMode = options.masterMode
+ httpd_thread = threading.Thread(target=httpd.serve_forever)
+ httpd_thread.setDaemon(True)
+ httpd_thread.start()
+
+ browsers = setUp(options)
+ if len(browsers) > 0:
+ runTests(options, browsers)
+ else:
+ # just run the server
+ print "Running HTTP server. Press Ctrl-C to quit."
+ try:
+ while True:
+ time.sleep(1)
+ except (KeyboardInterrupt):
+ print "\nExiting."
if __name__ == '__main__':
main()
+++ /dev/null
-# Create temporary profile directory name.
-TEMP_PROFILE:=$(shell echo `pwd`)/test_reports/temp_profile
-
-# These are the Firefox command line arguments.
-FIREFOX_ARGS:=-no-remote -profile $(TEMP_PROFILE)
-
-# These are the Chrome command line arguments.
-CHROME_ARGS:=--user-data-dir=$(TEMP_PROFILE) --no-first-run --disable-sync
-
-# Unit test uses the manifest from ref test to determine which browsers will
-# be used for running the unit tests.
-MANIFEST:=../resources/browser_manifests/browser_manifest.json
-
-# This is a helper command to separate multiple browsers to their own lines
-# for an easier sed operation.
-SPLIT_LINES:=sed 's|,|,@|g' | tr '@' '\n'
-
-# This is a helper command to join multiple lines together.
-JOIN_LINES:=tr -d '\n'
-
-# Fetch the paths to browsers that are going to be used in testing.
-# For OS X the path to the binary needs to be added.
-# Add the browser arguments for each browser.
-# Create random profile directory for each browser.
-BROWSERS_PATHS:=$(shell echo `\
- sed -n 's|.*"path":\(.*\)|\1,|p' $(MANIFEST) | \
- $(JOIN_LINES) \
-`)
-
-# The browser_manifest.json file has only the app directory for mac browsers.
-# The absolute path to the browser binary needs to be used.
-BROWSERS_PATHS_WITH_MAC_CORRECTION:=$(shell echo '$(BROWSERS_PATHS)' | \
- $(SPLIT_LINES) | \
- sed 's|\(Aurora\.app\)|\1/Contents/MacOS/firefox-bin|' | \
- sed 's|\(Firefox.*\.app\)|\1/Contents/MacOS/firefox-bin|' | \
- sed 's|\(Google Chrome\.app\)|\1/Contents/MacOS/Google Chrome|' | \
- $(JOIN_LINES) \
-)
-
-# Replace " with @@@@ so that echoing do not destroy the quotation marks.
-QUOTATION_MARK:=\"
-SUBSTITUTE_FOR_QUOTATION_MARK:=@@@@
-
-# Each of the browser can have their own separate arguments.
-BROWSERS_WITH_ARGUMENTS:=$(shell echo '$(BROWSERS_PATHS_WITH_MAC_CORRECTION)' | \
- $(SPLIT_LINES) | \
- sed "s|\(irefox.*\)\($(QUOTATION_MARK)\),|\1;$(FIREFOX_ARGS)\2,|" | \
- sed "s|\(hrome.*\)\($(QUOTATION_MARK)\),|\1;$(CHROME_ARGS)\2,|" | \
- $(JOIN_LINES) \
-)
-
-# A temporary profile directory is needed for each of the browser. In this way
-# a unit test run will not disturb the main browsing session of the user. The
-# $RANDOM shell variable is used to generate non-conflicting temporary
-# directories.
-BROWSERS_WITH_UKNOWN_RANDOM_PROFILE_PATHS:=$(shell echo '$(BROWSERS_WITH_ARGUMENTS)' | \
- $(SPLIT_LINES) | \
- sed 's|\(temp_profile\)|\1_$$RANDOM$$RANDOM|' | \
- sed "s|$(QUOTATION_MARK)|$(SUBSTITUTE_FOR_QUOTATION_MARK)|g" | \
- $(JOIN_LINES) \
-)
-
-# Echo the variable so that the unknown random directories become known.
-# Replace @@@@ with " so that jsTestDriver will work properly.
-BROWSERS:=$(shell echo "$(BROWSERS_WITH_UKNOWN_RANDOM_PROFILE_PATHS)" | \
- sed "s|$(SUBSTITUTE_FOR_QUOTATION_MARK)|$(QUOTATION_MARK)|g" \
-)
-
-# Get the known random directories for browsers. This information will be used
-# to create the profile directories beforehand. Create also the dummy temp
-# profile directory so that the mkdir command would not fail for browsers that
-# do not need it.
-PROFILES:=$(TEMP_PROFILE) $(shell echo '$(BROWSERS)' | \
- $(SPLIT_LINES) | \
- sed -n "s|.*\( $(TEMP_PROFILE)_[0-9]\+\).*|\1|p" | \
- $(JOIN_LINES) \
-)
-
-# This is the command to invoke the unit test.
-PROG:=java \
--Xms512m \
--Xmx1024m \
--jar ../../external/jsTestDriver/JsTestDriver-1.3.3d.jar \
---config ./jsTestDriver.conf \
---reset \
---port 4224 \
---browser $(BROWSERS) \
---tests all \
---testOutput ./test_reports/
-
-# This default rule runs the unit tests with the constructed command.
-test:
- @mkdir -p $(PROFILES)
- $(PROG)
- @rm -rf $(PROFILES)
-
-# In case this Makefile needs to be debugged then this rule will provide all
-# the information from intermediate steps.
-debug:
- @echo 'Debug browsers paths: $(BROWSERS_PATHS)'
- @echo
- @echo 'Debug browsers paths with mac correction: $(BROWSERS_PATHS_WITH_MAC_CORRECTION)'
- @echo
- @echo 'Debug browsers with arguments: $(BROWSERS_WITH_ARGUMENTS)'
- @echo
- @echo 'Debug browsers random profile paths: $(BROWSERS_WITH_UKNOWN_RANDOM_PROFILE_PATHS)'
- @echo
- @echo 'Debug browsers: $(BROWSERS)'
- @echo
- @echo 'Debug profiles: $(PROFILES)'
- @echo
- @echo 'Command to be run: $(PROG)'
- @echo
-
-.phony:: test
-
describe('api', function() {
// TODO run with worker enabled
PDFJS.disableWorker = true;
- var basicApiUrl = '/basicapi.pdf';
+ var basicApiUrl = '../pdfs/basicapi.pdf';
function waitsForPromise(promise) {
waitsFor(function() {
return promise.isResolved || promise.isRejected;
- }, 250);
+ }, 1000);
}
function expectAfterPromise(promise, successCallback) {
waitsForPromise(promise);
describe('PDFJS', function() {
describe('getDocument', function() {
it('creates pdf doc from URL', function() {
- console.log('what is');
- debugger;
var promise = PDFJS.getDocument(basicApiUrl);
expectAfterPromise(promise, function(data) {
expect(true).toEqual(true);
+++ /dev/null
-server: http://localhost:4224
-
-basepath: ..
-
-load:
- - ../external/jasmine/jasmine.js
- - ../external/jasmineAdapter/JasmineAdapter.js
- - ../src/obj.js
- - ../src/core.js
- - ../src/util.js
- - ../src/api.js
- - ../src/canvas.js
- - ../src/obj.js
- - ../src/function.js
- - ../src/charsets.js
- - ../src/cidmaps.js
- - ../src/colorspace.js
- - ../src/crypto.js
- - ../src/evaluator.js
- - ../src/fonts.js
- - ../src/glyphlist.js
- - ../src/image.js
- - ../src/metrics.js
- - ../src/parser.js
- - ../src/pattern.js
- - ../src/stream.js
- - ../src/worker.js
- - ../src/bidi.js
- - ../src/metadata.js
- - ../external/jpgjs/jpg.js
- - unit/obj_spec.js
- - unit/font_spec.js
- - unit/function_spec.js
- - unit/crypto_spec.js
- - unit/stream_spec.js
- - unit/api_spec.js
-
-gateway:
- - {matcher: "*.pdf", server: "http://localhost:8888/test/pdfs/"}
'use strict';
describe('stream', function() {
-
+ beforeEach(function() {
+ this.addMatchers({
+ toMatchTypedArray: function(expected) {
+ var actual = this.actual;
+ if (actual.length != expected.length)
+ return false;
+ for (var i = 0, ii = expected.length; i < ii; i++) {
+ var a = actual[i], b = expected[i];
+ if (a !== b)
+ return false;
+ }
+ return true;
+ }
+ });
+ });
describe('PredictorStream', function() {
it('should decode simple predictor data', function() {
var dict = new Dict();
var predictor = new PredictorStream(input, dict);
var result = predictor.getBytes(6);
- expect(result).toEqual(new Uint8Array([100, 3, 101, 2, 102, 1]));
+ expect(result).toMatchTypedArray(new Uint8Array([100, 3, 101, 2, 102, 1]));
});
});
});
+++ /dev/null
-TEST*
-temp*
-
--- /dev/null
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+
+var TestReporter = function(browser, appPath) {
+ function send(action, json) {
+ var r = new XMLHttpRequest();
+ // (The POST URI is ignored atm.)
+ r.open('POST', action, true);
+ r.setRequestHeader('Content-Type', 'application/json');
+ r.onreadystatechange = function sendTaskResultOnreadystatechange(e) {
+ if (r.readyState == 4) {
+ // Retry until successful
+ if (r.status !== 200)
+ send(action, json);
+ }
+ };
+ json['browser'] = browser;
+ r.send(JSON.stringify(json));
+ }
+
+ function sendInfo(message) {
+ send('/info', {message: message});
+ }
+
+ function sendResult(status, description, error) {
+ var message = {
+ status: status,
+ description: description
+ };
+ if (typeof error !== 'undefined')
+ message['error'] = error;
+ send('/submit_task_results', message);
+ }
+
+ function sendQuitRequest() {
+ send('/tellMeToQuit?path=' + escape(appPath), {});
+ }
+
+ this.now = function() {
+ return new Date().getTime();
+ };
+
+ this.reportRunnerStarting = function() {
+ this.runnerStartTime = this.now();
+ sendInfo('Started unit tests for ' + browser + '.');
+ };
+
+ this.reportSpecStarting = function() { };
+
+ this.reportSpecResults = function(spec) {
+ var results = spec.results();
+ if (results.skipped) {
+ sendResult('TEST-SKIPPED', results.description);
+ } else if (results.passed()) {
+ sendResult('TEST-PASSED', results.description);
+ } else {
+ var failedMessages = '';
+ var items = results.getItems();
+ for (var i = 0, ii = items.length; i < ii; i++)
+ if (!items[i].passed())
+ failedMessages += items[i].message + ' ';
+ sendResult('TEST-UNEXPECTED-FAIL', results.description, failedMessages);
+ }
+ };
+
+ this.reportSuiteResults = function(suite) { };
+
+ this.reportRunnerResults = function(runner) {
+ sendQuitRequest();
+ };
+};
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+ <title>pdf.js unit test</title>
+
+ <link rel="shortcut icon" type="image/png" href="../../external/jasmine/jasmine_favicon.png">
+ <link rel="stylesheet" type="text/css" href="../../external/jasmine/jasmine.css">
+
+ <script type="text/javascript" src="../../external/jasmine/jasmine.js"></script>
+ <script type="text/javascript" src="../../external/jasmine/jasmine-html.js"></script>
+ <script type="text/javascript" src="testreporter.js"></script>
+
+ <!-- include source files here... -->
+ <script type="text/javascript" src="../../src/core.js"></script>
+ <script type="text/javascript" src="../../src/api.js"></script>
+ <script type="text/javascript" src="../../src/util.js"></script>
+ <script type="text/javascript" src="../../src/canvas.js"></script>
+ <script type="text/javascript" src="../../src/obj.js"></script>
+ <script type="text/javascript" src="../../src/function.js"></script>
+ <script type="text/javascript" src="../../src/charsets.js"></script>
+ <script type="text/javascript" src="../../src/cidmaps.js"></script>
+ <script type="text/javascript" src="../../src/colorspace.js"></script>
+ <script type="text/javascript" src="../../src/crypto.js"></script>
+ <script type="text/javascript" src="../../src/evaluator.js"></script>
+ <script type="text/javascript" src="../../src/fonts.js"></script>
+ <script type="text/javascript" src="../../src/glyphlist.js"></script>
+ <script type="text/javascript" src="../../src/image.js"></script>
+ <script type="text/javascript" src="../../src/metrics.js"></script>
+ <script type="text/javascript" src="../../src/parser.js"></script>
+ <script type="text/javascript" src="../../src/pattern.js"></script>
+ <script type="text/javascript" src="../../src/stream.js"></script>
+ <script type="text/javascript" src="../../src/worker.js"></script>
+ <script type="text/javascript" src="../../src/metadata.js"></script>
+ <script type="text/javascript" src="../../external/jpgjs/jpg.js"></script>
+ <script type="text/javascript">PDFJS.workerSrc = '../../src/worker_loader.js';</script>
+
+ <!-- include spec files here... -->
+ <script type="text/javascript" src="obj_spec.js"></script>
+ <script type="text/javascript" src="font_spec.js"></script>
+ <script type="text/javascript" src="function_spec.js"></script>
+ <script type="text/javascript" src="crypto_spec.js"></script>
+ <script type="text/javascript" src="stream_spec.js"></script>
+ <script type="text/javascript" src="api_spec.js"></script>
+ <script type="text/javascript">
+ 'use strict';
+
+ (function pdfJsUnitTest() {
+ function queryParams() {
+ var qs = window.location.search.substring(1);
+ var kvs = qs.split('&');
+ var params = { };
+ for (var i = 0; i < kvs.length; ++i) {
+ var kv = kvs[i].split('=');
+ params[unescape(kv[0])] = unescape(kv[1]);
+ }
+ return params;
+ }
+
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.updateInterval = 1000;
+
+ var trivialReporter = new jasmine.TrivialReporter();
+
+ jasmineEnv.addReporter(trivialReporter);
+
+ var params = queryParams();
+ if (params['browser']) {
+ var testReporter = new TestReporter(params['browser'], params['path']);
+ jasmineEnv.addReporter(testReporter);
+ }
+
+ jasmineEnv.specFilter = function pdfJsUnitTestSpecFilter(spec) {
+ return trivialReporter.specFilter(spec);
+ };
+
+ var currentWindowOnload = window.onload;
+
+ window.onload = function pdfJsUnitTestOnload() {
+ if (currentWindowOnload) {
+ currentWindowOnload();
+ }
+ execJasmine();
+ };
+
+ function execJasmine() {
+ jasmineEnv.execute();
+ }
+ })();
+ </script>
+</head>
+<body>
+</body>
+</html>
+