Use bin/jsx and browserify to build a jasmine bundle.

This commit is contained in:
Ben Newman
2013-06-03 13:20:13 -04:00
parent 83029eb756
commit f8af93237a
18 changed files with 92 additions and 36 deletions
-166
View File
@@ -1,166 +0,0 @@
exports.HtmlReporter =
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);
setExceptionHandling();
reporterView = new jasmine.HtmlReporter.ReporterView(dom);
reporterView.addSpecs(specs, self.specFilter);
};
self.reportRunnerResults = function(runner) {
reporterView && 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 = jasmine.HtmlReporter.parameters(doc);
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'},
self.createDom('span', { className: 'exceptions' },
self.createDom('label', { className: 'label', 'for': 'no_try_catch' }, 'No try/catch'),
self.createDom('input', { id: 'no_try_catch', type: 'checkbox' }))),
dom.results = self.createDom('div', {className: 'results'},
dom.summary = self.createDom('div', { className: 'summary' }),
dom.details = self.createDom('div', { id: 'details' }))
);
}
function noTryCatch() {
return window.location.search.match(/catch=false/);
}
function searchWithCatch() {
var params = jasmine.HtmlReporter.parameters(window.document);
var removed = false;
var i = 0;
while (!removed && i < params.length) {
if (params[i].match(/catch=/)) {
params.splice(i, 1);
removed = true;
}
i++;
}
if (jasmine.CATCH_EXCEPTIONS) {
params.push("catch=false");
}
return params.join("&");
}
function setExceptionHandling() {
var chxCatch = document.getElementById('no_try_catch');
if (noTryCatch()) {
chxCatch.setAttribute('checked', true);
jasmine.CATCH_EXCEPTIONS = false;
}
chxCatch.onclick = function() {
window.location.search = searchWithCatch();
};
}
};
jasmine.HtmlReporter.parameters = function(doc) {
var paramStr = doc.location.search.substring(1);
var params = [];
if (paramStr.length > 0) {
params = paramStr.split('&');
}
return params;
}
jasmine.HtmlReporter.sectionLink = function(sectionName) {
var link = '?';
var params = [];
if (sectionName) {
params.push('spec=' + encodeURIComponent(sectionName));
}
if (!jasmine.CATCH_EXCEPTIONS) {
params.push("catch=false");
}
if (params.length > 0) {
link += params.join("&");
}
return link;
};
jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);
-127
View File
@@ -1,127 +0,0 @@
var diff = require('./diff');
var red = '\u001b[1;41m';
var reset = '\u001b[0m';
function highlightDifferences(a, b) {
var changes = diff.diffChars(a, b);
var ret = {a: '', b: ''};
var change;
for (var i = 0, il = changes.length; i < il; i++) {
change = changes[i];
if (change.added) {
ret.b += red + change.value + reset;
} else if (change.removed) {
ret.a += red + change.value + reset;
} else {
ret.a += change.value;
ret.b += change.value;
}
}
return ret;
}
function PrintReporter(name, root_directory) {
this.skipCount = 0;
this.failCount = 0;
this.expectCount = 0;
this.specCount = 0;
this.name = name;
this.rootDirectory = root_directory;
}
exports.PrintReporter =
jasmine.PrintReporter = PrintReporter;
PrintReporter.prototype = new jasmine.Reporter();
// Set verbose=true on the test instance to enable additional logging
PrintReporter.prototype.verbose = false;
PrintReporter.prototype._didSpecName = false;
PrintReporter.prototype.reportSpecStarting = function(spec) {
this._didSpecName = false;
this._spec = spec;
};
PrintReporter.prototype.reportRunnerResults = function(runner) {
// Don't print out the spec name at the end
this._didSpecName = true;
this.log([
this.specCount + " spec",
this.expectCount + " expect",
this.skipCount + " skip",
this.failCount + " fail"
].join(" "));
require("test/phantom").exit(this.failCount);
};
PrintReporter.prototype.reportSuiteResults = function(suite) {
var results = suite.results();
if (this.verbose) {
this.log('Suite "' + suite.description + '": ' +
results.passedCount + '/' + results.totalCount + ' passed.');
}
// If suite is nested, only count the root suite
if (!suite.parentSuite) {
this.failCount += results.totalCount - results.passedCount;
this.expectCount += results.totalCount;
}
};
PrintReporter.prototype.reportSpecResults = function(spec) {
if (this.verbose) {
this.log('it... ' +
spec.description + ': ' + (spec.results().passed() ? 'pass' : 'fail'));
}
var self = this;
var results = spec.results();
this.specCount += 1;
if (results.skipped)
this.skipCount += 1;
results.getItems().forEach(function(result) {
if (result.type == 'log') {
self.log(result.toString());
} else if (result.type == 'expect' && result.passed && !result.passed()) {
var ppActual = jasmine.pp(result.actual);
var ppExpected = jasmine.pp(result.expected);
var colorDiff = highlightDifferences(ppActual, ppExpected);
var message = result.message;
message = message.replace(ppActual, colorDiff.a);
message = message.replace(ppExpected, colorDiff.b);
self.log(message);
if (result.trace.stack) {
self.log();
result.trace.stack.split('\n').forEach(function(stackFrame) {
if (stackFrame.indexOf('/jasmine/lib/jasmine-core') > -1) {
return;
}
if (this.rootDirectory) {
stackFrame = stackFrame.replace(this.rootDirectory + '/', '');
}
self.log(' ' + stackFrame);
}.bind(this));
}
}
});
};
PrintReporter.prototype.log = function(str) {
if (!this._didSpecName) {
console.log('');
console.log(
this._spec.suite.description + ': it ' + this._spec.description);
this._didSpecName = true;
}
console.log(str || '');
};
-164
View File
@@ -1,164 +0,0 @@
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: jasmine.HtmlReporter.sectionLink(), 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: jasmine.HtmlReporter.sectionLink(), 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: jasmine.HtmlReporter.sectionLink(), 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);
-79
View File
@@ -1,79 +0,0 @@
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: jasmine.HtmlReporter.sectionLink(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);
-22
View File
@@ -1,22 +0,0 @@
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: jasmine.HtmlReporter.sectionLink(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);
-9
View File
@@ -2,17 +2,8 @@
// modules in src/test and to specify an ordering on those modules, since
// some still have implicit dependencies on others.
require("./phantom");
require("./console");
require("ReactTestUtils");
require("reactComponentExpect");
require("./diff");
require("./PrintReporter");
require("./HtmlReporter");
require("./ReporterView");
require("./SpecView");
require("./SuiteView");
require("./jasmine-support");
require("mocks");
require("mock-modules");
require("./mock-timers");
-92
View File
@@ -1,92 +0,0 @@
/**
* Copyright 2013 Facebook, Inc.
*
* 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.
*
* This module allows interception of console.* method calls, so that
* listeners other than the native console object can consume logged
* messages.
*/
var global = Function("return this")();
var Ap = Array.prototype;
var slice = Ap.slice;
var nativeConsole;
if ("console" in global) {
var gc = global.console;
try { delete global.console } catch (ignored) {}
nativeConsole = global.console || gc;
global.console = gc;
}
// Provide a reliable console interface in all browsers.
global.console = exports;
function makeLogger(method) {
var logger = exports[method] = function() {
var args = slice.call(arguments);
listeners.forEach(function(listener) {
listener(method, args, logger);
});
};
}
makeLogger("info");
makeLogger("log");
makeLogger("debug");
makeLogger("warn");
makeLogger("error");
makeLogger("dir");
makeLogger("dirxml");
makeLogger("trace");
makeLogger("assert");
makeLogger("count");
makeLogger("markTimeline");
makeLogger("profile");
makeLogger("profileEnd");
makeLogger("time");
makeLogger("timeEnd");
makeLogger("timeStamp");
makeLogger("group");
makeLogger("groupCollapsed");
makeLogger("groupEnd");
makeLogger("clear");
var listeners = [];
function addListener(listener) {
listeners.push(listener);
}
exports.addListener = addListener
function clean(arg) {
if (typeof arg === "string") {
// Remove any xterm-color escape sequences.
// TODO Display colors in console if possible.
arg = arg.replace(/\033\[\d+m/g, "");
}
return arg;
}
if (nativeConsole) {
// If present, the native console object becomes a listener just like
// any other.
addListener(function(method, args) {
var method = nativeConsole[method];
if (method) {
method.apply(nativeConsole, args.map(clean));
} else {
// Ignore this call.
}
});
}
-349
View File
@@ -1,349 +0,0 @@
/* See LICENSE file for terms of use */
/*
* Text diff implementation.
*
* This library supports the following APIS:
* JsDiff.diffChars: Character by character diff
* JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace
* JsDiff.diffLines: Line based diff
*
* JsDiff.diffCss: Diff targeted at CSS content
*
* These methods are based on the implementation proposed in
* "An O(ND) Difference Algorithm and its Variations" (Myers, 1986).
* http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927
*/
var JsDiff = (function() {
function clonePath(path) {
return { newPos: path.newPos, components: path.components.slice(0) };
}
function removeEmpty(array) {
var ret = [];
for (var i = 0; i < array.length; i++) {
if (array[i]) {
ret.push(array[i]);
}
}
return ret;
}
function escapeHTML(s) {
var n = s;
n = n.replace(/&/g, "&amp;");
n = n.replace(/</g, "&lt;");
n = n.replace(/>/g, "&gt;");
n = n.replace(/"/g, "&quot;");
return n;
}
var fbDiff = function(ignoreWhitespace) {
this.ignoreWhitespace = ignoreWhitespace;
};
fbDiff.prototype = {
diff: function(oldString, newString) {
// Handle the identity case (this is due to unrolling editLength == 0
if (newString == oldString) {
return [{ value: newString }];
}
if (!newString) {
return [{ value: oldString, removed: true }];
}
if (!oldString) {
return [{ value: newString, added: true }];
}
newString = this.tokenize(newString);
oldString = this.tokenize(oldString);
var newLen = newString.length, oldLen = oldString.length;
var maxEditLength = newLen + oldLen;
var bestPath = [{ newPos: -1, components: [] }];
// Seed editLength = 0
var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0);
if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) {
return bestPath[0].components;
}
for (var editLength = 1; editLength <= maxEditLength; editLength++) {
for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) {
var basePath;
var addPath = bestPath[diagonalPath-1],
removePath = bestPath[diagonalPath+1];
oldPos = (removePath ? removePath.newPos : 0) - diagonalPath;
if (addPath) {
// No one else is going to attempt to use this value, clear it
bestPath[diagonalPath-1] = undefined;
}
var canAdd = addPath && addPath.newPos+1 < newLen;
var canRemove = removePath && 0 <= oldPos && oldPos < oldLen;
if (!canAdd && !canRemove) {
bestPath[diagonalPath] = undefined;
continue;
}
// Select the diagonal that we want to branch from. We select the prior
// path whose position in the new string is the farthest from the origin
// and does not pass the bounds of the diff graph
if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) {
basePath = clonePath(removePath);
this.pushComponent(basePath.components, oldString[oldPos], undefined, true);
} else {
basePath = clonePath(addPath);
basePath.newPos++;
this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined);
}
var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath);
if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) {
return basePath.components;
} else {
bestPath[diagonalPath] = basePath;
}
}
}
},
pushComponent: function(components, value, added, removed) {
var last = components[components.length-1];
if (last && last.added === added && last.removed === removed) {
// We need to clone here as the component clone operation is just
// as shallow array clone
components[components.length-1] =
{value: this.join(last.value, value), added: added, removed: removed };
} else {
components.push({value: value, added: added, removed: removed });
}
},
extractCommon: function(basePath, newString, oldString, diagonalPath) {
var newLen = newString.length,
oldLen = oldString.length,
newPos = basePath.newPos,
oldPos = newPos - diagonalPath;
while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) {
newPos++;
oldPos++;
this.pushComponent(basePath.components, newString[newPos], undefined, undefined);
}
basePath.newPos = newPos;
return oldPos;
},
equals: function(left, right) {
var reWhitespace = /\S/;
if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) {
return true;
} else {
return left == right;
}
},
join: function(left, right) {
return left + right;
},
tokenize: function(value) {
return value;
}
};
var CharDiff = new fbDiff();
var WordDiff = new fbDiff(true);
WordDiff.tokenize = function(value) {
return removeEmpty(value.split(/(\s+|\b)/));
};
var CssDiff = new fbDiff(true);
CssDiff.tokenize = function(value) {
return removeEmpty(value.split(/([{}:;,]|\s+)/));
};
var LineDiff = new fbDiff();
LineDiff.tokenize = function(value) {
return value.split(/^/m);
};
return {
diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); },
diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); },
diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); },
diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); },
createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) {
var ret = [];
ret.push("Index: " + fileName);
ret.push("===================================================================");
ret.push("--- " + fileName + (typeof oldHeader === "undefined" ? "" : "\t" + oldHeader));
ret.push("+++ " + fileName + (typeof newHeader === "undefined" ? "" : "\t" + newHeader));
var diff = LineDiff.diff(oldStr, newStr);
if (!diff[diff.length-1].value) {
diff.pop(); // Remove trailing newline add
}
diff.push({value: "", lines: []}); // Append an empty value to make cleanup easier
function contextLines(lines) {
return lines.map(function(entry) { return ' ' + entry; });
}
function eofNL(curRange, i, current) {
var last = diff[diff.length-2],
isLast = i === diff.length-2,
isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed);
// Figure out if this is the last line for the given file and missing NL
if (!/\n$/.test(current.value) && (isLast || isLastOfType)) {
curRange.push('\\ No newline at end of file');
}
}
var oldRangeStart = 0, newRangeStart = 0, curRange = [],
oldLine = 1, newLine = 1;
for (var i = 0; i < diff.length; i++) {
var current = diff[i],
lines = current.lines || current.value.replace(/\n$/, "").split("\n");
current.lines = lines;
if (current.added || current.removed) {
if (!oldRangeStart) {
var prev = diff[i-1];
oldRangeStart = oldLine;
newRangeStart = newLine;
if (prev) {
curRange = contextLines(prev.lines.slice(-4));
oldRangeStart -= curRange.length;
newRangeStart -= curRange.length;
}
}
curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?"+":"-") + entry; }));
eofNL(curRange, i, current);
if (current.added) {
newLine += lines.length;
} else {
oldLine += lines.length;
}
} else {
if (oldRangeStart) {
// Close out any changes that have been output (or join overlapping)
if (lines.length <= 8 && i < diff.length-2) {
// Overlapping
curRange.push.apply(curRange, contextLines(lines));
} else {
// end the range and output
var contextSize = Math.min(lines.length, 4);
ret.push(
"@@ -" + oldRangeStart + "," + (oldLine-oldRangeStart+contextSize)
+ " +" + newRangeStart + "," + (newLine-newRangeStart+contextSize)
+ " @@");
ret.push.apply(ret, curRange);
ret.push.apply(ret, contextLines(lines.slice(0, contextSize)));
if (lines.length <= 4) {
eofNL(ret, i, current);
}
oldRangeStart = 0; newRangeStart = 0; curRange = [];
}
}
oldLine += lines.length;
newLine += lines.length;
}
}
return ret.join('\n') + '\n';
},
applyPatch: function(oldStr, uniDiff) {
var diffstr = uniDiff.split("\n");
var diff = [];
var remEOFNL = false,
addEOFNL = false;
for (var i = (diffstr[0][0]=="I"?4:0); i < diffstr.length; i++) {
if(diffstr[i][0] == "@") {
var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/);
diff.unshift({
start:meh[3],
oldlength:meh[2],
oldlines:[],
newlength:meh[4],
newlines:[]
});
} else if(diffstr[i][0] == '+') {
diff[0].newlines.push(diffstr[i].substr(1));
} else if(diffstr[i][0] == '-') {
diff[0].oldlines.push(diffstr[i].substr(1));
} else if(diffstr[i][0] == ' ') {
diff[0].newlines.push(diffstr[i].substr(1));
diff[0].oldlines.push(diffstr[i].substr(1));
} else if(diffstr[i][0] == '\\') {
if (diffstr[i-1][0] == '+') {
remEOFNL = true;
} else if(diffstr[i-1][0] == '-') {
addEOFNL = true;
}
}
}
var str = oldStr.split("\n");
for (var i = diff.length - 1; i >= 0; i--) {
var d = diff[i];
for (var j = 0; j < d.oldlength; j++) {
if(str[d.start-1+j] != d.oldlines[j]) {
return false;
}
}
Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines));
}
if (remEOFNL) {
while (!str[str.length-1]) {
str.pop();
}
} else if (addEOFNL) {
str.push('');
}
return str.join('\n');
},
convertChangesToXML: function(changes){
var ret = [];
for ( var i = 0; i < changes.length; i++) {
var change = changes[i];
if (change.added) {
ret.push("<ins>");
} else if (change.removed) {
ret.push("<del>");
}
ret.push(escapeHTML(change.value));
if (change.added) {
ret.push("</ins>");
} else if (change.removed) {
ret.push("</del>");
}
}
return ret.join("");
},
// See: http://code.google.com/p/google-diff-match-patch/wiki/API
convertChangesToDMP: function(changes){
var ret = [], change;
for ( var i = 0; i < changes.length; i++) {
change = changes[i];
ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]);
}
return ret;
}
};
})();
if (typeof module !== "undefined") {
module.exports = JsDiff;
}
-134
View File
@@ -1,134 +0,0 @@
var global = Function("return this")();
var jasmine = global.jasmine;
var spec = false; // TODO
// Add some matcher for mock functions
jasmine.getEnv().beforeEach(function() {
this.addMatchers({
toBeCalled: function() {
if (this.actual.mock === undefined) {
throw Error('toBeCalled() should be used on a mock function');
}
return this.actual.mock.calls.length !== 0;
},
lastCalledWith: function() {
if (this.actual.mock === undefined) {
throw Error('toBeCalled() should be used on a mock function');
}
var calls = this.actual.mock.calls;
var args = Array.prototype.slice.call(arguments);
return this.env.equals_(calls[calls.length - 1], args);
},
toBeCalledWith: function() {
if (this.actual.mock === undefined) {
throw Error('toBeCalled() should be used on a mock function');
}
var args = Array.prototype.slice.call(arguments);
return this.actual.mock.calls.some(function(call) {
return this.env.equals_(call, args);
}.bind(this));
}
});
});
var _it = jasmine.Env.prototype.it;
var _xit = jasmine.Env.prototype.xit;
jasmine.Env.prototype.it = function(desc, func) {
// If spec is provided, only run matching specs
if (!spec || desc.match(new RegExp(spec, 'i'))) {
return _it.bind(this, desc, func)();
} else {
return this.xit(desc, func);
}
};
jasmine.Env.prototype.xit = function(desc, func) {
if (typeof func == 'function') {
var matches = func.toString().match(/.*\W?expect\(/g);
if (matches) {
this.reporter.subReporters_[0].skipCount += matches.length;
this.reporter.subReporters_[0].totalCount += matches.length;
}
}
return _xit.bind(this, desc, func)();
}
// Mainline Jasmine sets __Jasmine_been_here_before__ on each object to detect
// cycles, but that doesn't work on frozen objects so we use a WeakMap instead.
// We can only do this if if WeakMap is available, but if WeakMap is
// unavailable, then objects probably can't be frozen anyway.
if (typeof WeakMap !== "undefined") {
var _comparedObjects = new WeakMap;
jasmine.Env.prototype.compareObjects_ =
function(a, b, mismatchKeys, mismatchValues) {
if (_comparedObjects.get(a) === b && _comparedObjects.get(b) === a) {
return true;
}
var areArrays = jasmine.isArray_(a) && jasmine.isArray_(b);
_comparedObjects.set(a, b);
_comparedObjects.set(b, a);
var hasKey = function(obj, keyName) {
return obj != null && obj[keyName] !== jasmine.undefined;
};
for (var property in b) {
if (areArrays && typeof b[property] == 'function') {
continue;
}
if (!hasKey(a, property) && hasKey(b, property)) {
mismatchKeys.push(
"expected has key '" + property + "', but missing from actual."
);
}
}
for (property in a) {
if (areArrays && typeof a[property] == 'function') {
continue;
}
if (!hasKey(b, property) && hasKey(a, property)) {
mismatchKeys.push(
"expected missing key '" + property + "', but present in actual."
);
}
}
for (property in b) {
// The only different implementation from the original jasmine
if (areArrays &&
(typeof a[property] == 'function' ||
typeof b[property] == 'function')) {
continue;
}
if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues))
{
mismatchValues.push(
"'" + property + "' was '" + (b[property] ?
jasmine.util.htmlEscape(b[property].toString()) :
b[property]) +
"' in expected, but was '" + (a[property] ?
jasmine.util.htmlEscape(a[property].toString()) :
a[property]) + "' in actual."
);
}
}
if (areArrays &&
a.length != b.length) {
mismatchValues.push("arrays were not the same length");
}
_comparedObjects.delete(a);
_comparedObjects.delete(b);
return (mismatchKeys.length == 0 && mismatchValues.length == 0);
};
}
var HtmlReporter = require("./HtmlReporter").HtmlReporter;
var PrintReporter = require("./PrintReporter").PrintReporter;
jasmine.getEnv().addReporter(new HtmlReporter);
jasmine.getEnv().addReporter(new PrintReporter);
-64
View File
@@ -1,64 +0,0 @@
/**
* Copyright 2013 Facebook, Inc.
*
* 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.
*
* This module provides a bridge from content-land to phantom-land via the
* window.callPhantom interface.
*/
var console = require("./console");
var global = Function("return this")();
var Ap = Array.prototype;
var slice = Ap.slice;
var Fp = Function.prototype;
if (!Fp.bind) {
// PhantomJS doesn't support Function.prototype.bind natively, so
// polyfill it whenever this module is required.
Fp.bind = function(context) {
var func = this;
var args = slice.call(arguments, 1);
return args.length > 0 ? function() {
return func.apply(
context || this,
args.concat(slice.call(arguments))
);
} : function() {
return func.apply(context || this, arguments);
};
};
}
if (global.callPhantom) {
// Phantom's onConsoleMessage support is lacking (only one argument
// supported, and it must be a string), so we use callPhantom to
// forward console messages instead.
console.addListener(function(method, args) {
global.callPhantom({
type: "console",
method: method,
args: args
});
});
exports.exit = function(code) {
global.callPhantom({
type: "exit",
code: code
});
};
} else {
exports.exit = function() {};
}