Switch from Jasmine to Mocha & Chai

The switch is mostly mechanical, with assertions translated 1:1. The
biggest non-mechanical part is rewriting Jasmine custom matchers as Chai
helpers. The matchers were streamlined and simplified in the process and
their messages were made more in line with messages produced by built-in
Chai helpers.

Fixes #409.
redux
David Majda 7 years ago
parent 266f17d11c
commit 73de2c9384

@ -9,7 +9,7 @@ let del = require("del");
let eslint = require("gulp-eslint"); let eslint = require("gulp-eslint");
let gulp = require("gulp"); let gulp = require("gulp");
let header = require("gulp-header"); let header = require("gulp-header");
let jasmine = require("gulp-jasmine"); let mocha = require("gulp-mocha");
let package_ = require("./package"); let package_ = require("./package");
let peg = require("./lib/peg"); let peg = require("./lib/peg");
let rename = require("gulp-rename"); let rename = require("gulp-rename");
@ -65,8 +65,8 @@ gulp.task("lint", () =>
// Run specs. // Run specs.
gulp.task("spec", () => gulp.task("spec", () =>
gulp.src(SPEC_FILES) gulp.src(SPEC_FILES, { read: false })
.pipe(jasmine()) .pipe(mocha())
); );
// Run benchmarks. // Run benchmarks.

@ -47,6 +47,7 @@
"babel-preset-es2015": "6.14.0", "babel-preset-es2015": "6.14.0",
"babelify": "7.3.0", "babelify": "7.3.0",
"browserify": "13.1.0", "browserify": "13.1.0",
"chai": "3.5.0",
"del": "2.2.2", "del": "2.2.2",
"eslint-config-dmajda": "1.0.0", "eslint-config-dmajda": "1.0.0",
"express": "4.14.0", "express": "4.14.0",
@ -54,12 +55,13 @@
"gulp": "3.9.1", "gulp": "3.9.1",
"gulp-eslint": "3.0.1", "gulp-eslint": "3.0.1",
"gulp-header": "1.8.8", "gulp-header": "1.8.8",
"gulp-jasmine": "0.2.0", "gulp-mocha": "3.0.1",
"gulp-rename": "1.2.2", "gulp-rename": "1.2.2",
"gulp-transform": "1.0.8", "gulp-transform": "1.0.8",
"gulp-uglify": "2.0.0", "gulp-uglify": "2.0.0",
"morgan": "1.7.0", "morgan": "1.7.0",
"run-sequence": "^1.2.2", "run-sequence": "^1.2.2",
"sinon": "1.17.6",
"vinyl-buffer": "1.0.0", "vinyl-buffer": "1.0.0",
"vinyl-source-stream": "1.1.0" "vinyl-source-stream": "1.1.0"
}, },

@ -1,6 +1,6 @@
{ {
"env": { "env": {
"commonjs": true, "commonjs": true,
"jasmine": true "mocha": true
} }
} }

@ -2,20 +2,24 @@
/* global console */ /* global console */
let chai = require("chai");
let peg = require("../../lib/peg"); let peg = require("../../lib/peg");
let sinon = require("sinon");
let expect = chai.expect;
describe("generated parser API", function() { describe("generated parser API", function() {
describe("parse", function() { describe("parse", function() {
it("parses input", function() { it("parses input", function() {
let parser = peg.generate("start = 'a'"); let parser = peg.generate("start = 'a'");
expect(parser.parse("a")).toBe("a"); expect(parser.parse("a")).to.equal("a");
}); });
it("throws an exception on syntax error", function() { it("throws an exception on syntax error", function() {
let parser = peg.generate("start = 'a'"); let parser = peg.generate("start = 'a'");
expect(() => { parser.parse("b"); }).toThrow(); expect(() => { parser.parse("b"); }).to.throw();
}); });
describe("start rule", function() { describe("start rule", function() {
@ -27,20 +31,20 @@ describe("generated parser API", function() {
describe("when |startRule| is not set", function() { describe("when |startRule| is not set", function() {
it("starts parsing from the first allowed rule", function() { it("starts parsing from the first allowed rule", function() {
expect(parser.parse("x")).toBe("b"); expect(parser.parse("x")).to.equal("b");
}); });
}); });
describe("when |startRule| is set to an allowed rule", function() { describe("when |startRule| is set to an allowed rule", function() {
it("starts parsing from specified rule", function() { it("starts parsing from specified rule", function() {
expect(parser.parse("x", { startRule: "b" })).toBe("b"); expect(parser.parse("x", { startRule: "b" })).to.equal("b");
expect(parser.parse("x", { startRule: "c" })).toBe("c"); expect(parser.parse("x", { startRule: "c" })).to.equal("c");
}); });
}); });
describe("when |startRule| is set to a disallowed start rule", function() { describe("when |startRule| is set to a disallowed start rule", function() {
it("throws an exception", function() { it("throws an exception", function() {
expect(() => { parser.parse("x", { startRule: "a" }); }).toThrow(); expect(() => { parser.parse("x", { startRule: "a" }); }).to.throw();
}); });
}); });
}); });
@ -55,18 +59,24 @@ describe("generated parser API", function() {
describe("default tracer", function() { describe("default tracer", function() {
it("traces using console.log (if console is defined)", function() { it("traces using console.log (if console is defined)", function() {
if (typeof console === "object") { if (typeof console === "object") {
spyOn(console, "log"); sinon.stub(console, "log");
} }
parser.parse("b"); try {
parser.parse("b");
if (typeof console === "object") {
expect(console.log).toHaveBeenCalledWith("1:1-1:1 rule.enter start"); if (typeof console === "object") {
expect(console.log).toHaveBeenCalledWith("1:1-1:1 rule.enter a"); expect(console.log.calledWithExactly("1:1-1:1 rule.enter start")).to.equal(true);
expect(console.log).toHaveBeenCalledWith("1:1-1:1 rule.fail a"); expect(console.log.calledWithExactly("1:1-1:1 rule.enter a")).to.equal(true);
expect(console.log).toHaveBeenCalledWith("1:1-1:1 rule.enter b"); expect(console.log.calledWithExactly("1:1-1:1 rule.fail a")).to.equal(true);
expect(console.log).toHaveBeenCalledWith("1:1-1:2 rule.match b"); expect(console.log.calledWithExactly("1:1-1:1 rule.enter b")).to.equal(true);
expect(console.log).toHaveBeenCalledWith("1:1-1:2 rule.match start"); expect(console.log.calledWithExactly("1:1-1:2 rule.match b")).to.equal(true);
expect(console.log.calledWithExactly("1:1-1:2 rule.match start")).to.equal(true);
}
} finally {
if (typeof console === "object") {
console.log.restore();
}
} }
}); });
}); });
@ -74,43 +84,43 @@ describe("generated parser API", function() {
describe("custom tracers", function() { describe("custom tracers", function() {
describe("trace", function() { describe("trace", function() {
it("receives tracing events", function() { it("receives tracing events", function() {
let tracer = jasmine.createSpyObj("tracer", ["trace"]); let tracer = { trace: sinon.spy() };
parser.parse("b", { tracer: tracer }); parser.parse("b", { tracer: tracer });
expect(tracer.trace).toHaveBeenCalledWith({ expect(tracer.trace.calledWithExactly({
type: "rule.enter", type: "rule.enter",
rule: "start", rule: "start",
location: { location: {
start: { offset: 0, line: 1, column: 1 }, start: { offset: 0, line: 1, column: 1 },
end: { offset: 0, line: 1, column: 1 } end: { offset: 0, line: 1, column: 1 }
} }
}); })).to.equal(true);
expect(tracer.trace).toHaveBeenCalledWith({ expect(tracer.trace.calledWithExactly({
type: "rule.enter", type: "rule.enter",
rule: "a", rule: "a",
location: { location: {
start: { offset: 0, line: 1, column: 1 }, start: { offset: 0, line: 1, column: 1 },
end: { offset: 0, line: 1, column: 1 } end: { offset: 0, line: 1, column: 1 }
} }
}); })).to.equal(true);
expect(tracer.trace).toHaveBeenCalledWith({ expect(tracer.trace.calledWithExactly({
type: "rule.fail", type: "rule.fail",
rule: "a", rule: "a",
location: { location: {
start: { offset: 0, line: 1, column: 1 }, start: { offset: 0, line: 1, column: 1 },
end: { offset: 0, line: 1, column: 1 } end: { offset: 0, line: 1, column: 1 }
} }
}); })).to.equal(true);
expect(tracer.trace).toHaveBeenCalledWith({ expect(tracer.trace.calledWithExactly({
type: "rule.enter", type: "rule.enter",
rule: "b", rule: "b",
location: { location: {
start: { offset: 0, line: 1, column: 1 }, start: { offset: 0, line: 1, column: 1 },
end: { offset: 0, line: 1, column: 1 } end: { offset: 0, line: 1, column: 1 }
} }
}); })).to.equal(true);
expect(tracer.trace).toHaveBeenCalledWith({ expect(tracer.trace.calledWithExactly({
type: "rule.match", type: "rule.match",
rule: "b", rule: "b",
result: "b", result: "b",
@ -118,8 +128,8 @@ describe("generated parser API", function() {
start: { offset: 0, line: 1, column: 1 }, start: { offset: 0, line: 1, column: 1 },
end: { offset: 1, line: 1, column: 2 } end: { offset: 1, line: 1, column: 2 }
} }
}); })).to.equal(true);
expect(tracer.trace).toHaveBeenCalledWith({ expect(tracer.trace.calledWithExactly({
type: "rule.match", type: "rule.match",
rule: "start", rule: "start",
result: "b", result: "b",
@ -127,7 +137,7 @@ describe("generated parser API", function() {
start: { offset: 0, line: 1, column: 1 }, start: { offset: 0, line: 1, column: 1 },
end: { offset: 1, line: 1, column: 2 } end: { offset: 1, line: 1, column: 2 }
} }
}); })).to.equal(true);
}); });
}); });
}); });

@ -1,22 +1,26 @@
"use strict"; "use strict";
let chai = require("chai");
let peg = require("../../lib/peg"); let peg = require("../../lib/peg");
let sinon = require("sinon");
let expect = chai.expect;
describe("PEG.js API", function() { describe("PEG.js API", function() {
describe("generate", function() { describe("generate", function() {
it("generates a parser", function() { it("generates a parser", function() {
let parser = peg.generate("start = 'a'"); let parser = peg.generate("start = 'a'");
expect(typeof parser).toBe("object"); expect(typeof parser).to.equal("object");
expect(parser.parse("a")).toBe("a"); expect(parser.parse("a")).to.equal("a");
}); });
it("throws an exception on syntax error", function() { it("throws an exception on syntax error", function() {
expect(() => { peg.generate("start = @"); }).toThrow(); expect(() => { peg.generate("start = @"); }).to.throw();
}); });
it("throws an exception on semantic error", function() { it("throws an exception on semantic error", function() {
expect(() => { peg.generate("start = undefined"); }).toThrow(); expect(() => { peg.generate("start = undefined"); }).to.throw();
}); });
describe("allowed start rules", function() { describe("allowed start rules", function() {
@ -34,9 +38,9 @@ describe("PEG.js API", function() {
it("generated parser can start only from the first rule", function() { it("generated parser can start only from the first rule", function() {
let parser = peg.generate(grammar, { optimize: "speed" }); let parser = peg.generate(grammar, { optimize: "speed" });
expect(parser.parse("x", { startRule: "a" })).toBe("x"); expect(parser.parse("x", { startRule: "a" })).to.equal("x");
expect(() => { parser.parse("x", { startRule: "b" }); }).toThrow(); expect(() => { parser.parse("x", { startRule: "b" }); }).to.throw();
expect(() => { parser.parse("x", { startRule: "c" }); }).toThrow(); expect(() => { parser.parse("x", { startRule: "c" }); }).to.throw();
}); });
}); });
@ -47,9 +51,9 @@ describe("PEG.js API", function() {
allowedStartRules: ["b", "c"] allowedStartRules: ["b", "c"]
}); });
expect(() => { parser.parse("x", { startRule: "a" }); }).toThrow(); expect(() => { parser.parse("x", { startRule: "a" }); }).to.throw();
expect(parser.parse("x", { startRule: "b" })).toBe("x"); expect(parser.parse("x", { startRule: "b" })).to.equal("x");
expect(parser.parse("x", { startRule: "c" })).toBe("x"); expect(parser.parse("x", { startRule: "c" })).to.equal("x");
}); });
}); });
}); });
@ -59,9 +63,9 @@ describe("PEG.js API", function() {
it("generated parser can start only from the first rule", function() { it("generated parser can start only from the first rule", function() {
let parser = peg.generate(grammar, { optimize: "size" }); let parser = peg.generate(grammar, { optimize: "size" });
expect(parser.parse("x", { startRule: "a" })).toBe("x"); expect(parser.parse("x", { startRule: "a" })).to.equal("x");
expect(() => { parser.parse("x", { startRule: "b" }); }).toThrow(); expect(() => { parser.parse("x", { startRule: "b" }); }).to.throw();
expect(() => { parser.parse("x", { startRule: "c" }); }).toThrow(); expect(() => { parser.parse("x", { startRule: "c" }); }).to.throw();
}); });
}); });
@ -72,9 +76,9 @@ describe("PEG.js API", function() {
allowedStartRules: ["b", "c"] allowedStartRules: ["b", "c"]
}); });
expect(() => { parser.parse("x", { startRule: "a" }); }).toThrow(); expect(() => { parser.parse("x", { startRule: "a" }); }).to.throw();
expect(parser.parse("x", { startRule: "b" })).toBe("x"); expect(parser.parse("x", { startRule: "b" })).to.equal("x");
expect(parser.parse("x", { startRule: "c" })).toBe("x"); expect(parser.parse("x", { startRule: "c" })).to.equal("x");
}); });
}); });
}); });
@ -91,7 +95,7 @@ describe("PEG.js API", function() {
it("generated parser doesn't cache intermediate parse results", function() { it("generated parser doesn't cache intermediate parse results", function() {
let parser = peg.generate(grammar); let parser = peg.generate(grammar);
expect(parser.parse("ac")).toBe(2); expect(parser.parse("ac")).to.equal(2);
}); });
}); });
@ -99,7 +103,7 @@ describe("PEG.js API", function() {
it("generated parser doesn't cache intermediate parse results", function() { it("generated parser doesn't cache intermediate parse results", function() {
let parser = peg.generate(grammar, { cache: false }); let parser = peg.generate(grammar, { cache: false });
expect(parser.parse("ac")).toBe(2); expect(parser.parse("ac")).to.equal(2);
}); });
}); });
@ -107,7 +111,7 @@ describe("PEG.js API", function() {
it("generated parser caches intermediate parse results", function() { it("generated parser caches intermediate parse results", function() {
let parser = peg.generate(grammar, { cache: true }); let parser = peg.generate(grammar, { cache: true });
expect(parser.parse("ac")).toBe(1); expect(parser.parse("ac")).to.equal(1);
}); });
}); });
}); });
@ -118,33 +122,33 @@ describe("PEG.js API", function() {
describe("when |trace| is not set", function() { describe("when |trace| is not set", function() {
it("generated parser doesn't trace", function() { it("generated parser doesn't trace", function() {
let parser = peg.generate(grammar); let parser = peg.generate(grammar);
let tracer = jasmine.createSpyObj("tracer", ["trace"]); let tracer = { trace: sinon.spy() };
parser.parse("a", { tracer: tracer }); parser.parse("a", { tracer: tracer });
expect(tracer.trace).not.toHaveBeenCalled(); expect(tracer.trace.called).to.equal(false);
}); });
}); });
describe("when |trace| is set to |false|", function() { describe("when |trace| is set to |false|", function() {
it("generated parser doesn't trace", function() { it("generated parser doesn't trace", function() {
let parser = peg.generate(grammar, { trace: false }); let parser = peg.generate(grammar, { trace: false });
let tracer = jasmine.createSpyObj("tracer", ["trace"]); let tracer = { trace: sinon.spy() };
parser.parse("a", { tracer: tracer }); parser.parse("a", { tracer: tracer });
expect(tracer.trace).not.toHaveBeenCalled(); expect(tracer.trace.called).to.equal(false);
}); });
}); });
describe("when |trace| is set to |true|", function() { describe("when |trace| is set to |true|", function() {
it("generated parser traces", function() { it("generated parser traces", function() {
let parser = peg.generate(grammar, { trace: true }); let parser = peg.generate(grammar, { trace: true });
let tracer = jasmine.createSpyObj("tracer", ["trace"]); let tracer = { trace: sinon.spy() };
parser.parse("a", { tracer: tracer }); parser.parse("a", { tracer: tracer });
expect(tracer.trace).toHaveBeenCalled(); expect(tracer.trace.called).to.equal(true);
}); });
}); });
}); });
@ -159,8 +163,8 @@ describe("PEG.js API", function() {
it("returns generated parser object", function() { it("returns generated parser object", function() {
let parser = peg.generate(grammar); let parser = peg.generate(grammar);
expect(typeof parser).toBe("object"); expect(typeof parser).to.equal("object");
expect(parser.parse("a")).toBe("a"); expect(parser.parse("a")).to.equal("a");
}); });
}); });
@ -168,8 +172,8 @@ describe("PEG.js API", function() {
it("returns generated parser object", function() { it("returns generated parser object", function() {
let parser = peg.generate(grammar, { output: "parser" }); let parser = peg.generate(grammar, { output: "parser" });
expect(typeof parser).toBe("object"); expect(typeof parser).to.equal("object");
expect(parser.parse("a")).toBe("a"); expect(parser.parse("a")).to.equal("a");
}); });
}); });
@ -177,8 +181,8 @@ describe("PEG.js API", function() {
it("returns generated parser source code", function() { it("returns generated parser source code", function() {
let source = peg.generate(grammar, { output: "source" }); let source = peg.generate(grammar, { output: "source" });
expect(typeof source).toBe("string"); expect(typeof source).to.equal("string");
expect(eval(source).parse("a")).toBe("a"); expect(eval(source).parse("a")).to.equal("a");
}); });
}); });
}); });

@ -1,39 +1,11 @@
"use strict"; "use strict";
let chai = require("chai");
let peg = require("../../lib/peg"); let peg = require("../../lib/peg");
describe("plugin API", function() { let expect = chai.expect;
beforeEach(function() {
this.addMatchers({
toBeObject() {
this.message = () =>
"Expected " + jasmine.pp(this.actual) + " "
+ (this.isNot ? "not " : "")
+ "to be an object.";
return this.actual !== null && typeof this.actual === "object";
},
toBeArray() {
this.message = () =>
"Expected " + jasmine.pp(this.actual) + " "
+ (this.isNot ? "not " : "")
+ "to be an array.";
return Object.prototype.toString.apply(this.actual) === "[object Array]";
},
toBeFunction() {
this.message = () =>
"Expected " + jasmine.pp(this.actual) + " "
+ (this.isNot ? "not " : "")
+ "to be a function.";
return typeof this.actual === "function";
}
});
});
describe("plugin API", function() {
describe("use", function() { describe("use", function() {
let grammar = "start = 'a'"; let grammar = "start = 'a'";
@ -47,32 +19,32 @@ describe("plugin API", function() {
peg.generate(grammar, { plugins: plugins }); peg.generate(grammar, { plugins: plugins });
expect(pluginsUsed).toEqual([true, true, true]); expect(pluginsUsed).to.deep.equal([true, true, true]);
}); });
it("receives configuration", function() { it("receives configuration", function() {
let plugin = { let plugin = {
use(config) { use(config) {
expect(config).toBeObject(); expect(config).to.be.an("object");
expect(config.parser).toBeObject(); expect(config.parser).to.be.an("object");
expect(config.parser.parse("start = 'a'")).toBeObject(); expect(config.parser.parse("start = 'a'")).to.be.an("object");
expect(config.passes).toBeObject(); expect(config.passes).to.be.an("object");
expect(config.passes.check).toBeArray(); expect(config.passes.check).to.be.an("array");
config.passes.check.forEach(pass => { config.passes.check.forEach(pass => {
expect(pass).toBeFunction(); expect(pass).to.be.a("function");
}); });
expect(config.passes.transform).toBeArray(); expect(config.passes.transform).to.be.an("array");
config.passes.transform.forEach(pass => { config.passes.transform.forEach(pass => {
expect(pass).toBeFunction(); expect(pass).to.be.a("function");
}); });
expect(config.passes.generate).toBeArray(); expect(config.passes.generate).to.be.an("array");
config.passes.generate.forEach(pass => { config.passes.generate.forEach(pass => {
expect(pass).toBeFunction(); expect(pass).to.be.a("function");
}); });
} }
}; };
@ -83,7 +55,7 @@ describe("plugin API", function() {
it("receives options", function() { it("receives options", function() {
let plugin = { let plugin = {
use(config, options) { use(config, options) {
expect(options).toEqual(generateOptions); expect(options).to.equal(generateOptions);
} }
}; };
let generateOptions = { plugins: [plugin], foo: 42 }; let generateOptions = { plugins: [plugin], foo: 42 };
@ -114,7 +86,7 @@ describe("plugin API", function() {
}; };
let parser = peg.generate("a", { plugins: [plugin] }); let parser = peg.generate("a", { plugins: [plugin] });
expect(parser.parse("a")).toBe("a"); expect(parser.parse("a")).to.equal("a");
}); });
it("can change compiler passes", function() { it("can change compiler passes", function() {
@ -129,7 +101,7 @@ describe("plugin API", function() {
}; };
let parser = peg.generate(grammar, { plugins: [plugin] }); let parser = peg.generate(grammar, { plugins: [plugin] });
expect(parser.parse("a")).toBe(42); expect(parser.parse("a")).to.equal(42);
}); });
it("can change options", function() { it("can change options", function() {
@ -148,9 +120,9 @@ describe("plugin API", function() {
plugins: [plugin] plugins: [plugin]
}); });
expect(() => { parser.parse("x", { startRule: "a" }); }).toThrow(); expect(() => { parser.parse("x", { startRule: "a" }); }).to.throw();
expect(parser.parse("x", { startRule: "b" })).toBe("x"); expect(parser.parse("x", { startRule: "b" })).to.equal("x");
expect(parser.parse("x", { startRule: "c" })).toBe("x"); expect(parser.parse("x", { startRule: "c" })).to.equal("x");
}); });
}); });
}); });

File diff suppressed because it is too large Load Diff

@ -3,22 +3,17 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>PEG.js Spec Suite</title> <title>PEG.js Spec Suite</title>
<link rel="stylesheet" href="vendor/jasmine/jasmine.css"> <link rel="stylesheet" href="vendor/mocha/mocha.css">
<script src="vendor/jasmine/jasmine.js"></script> </head>
<script src="vendor/jasmine/jasmine-html.js"></script> <body>
<div id="mocha"></div>
<script src="vendor/mocha/mocha.js"></script>
<script>
mocha.setup('bdd');
</script>
<script src="bundle.js"></script> <script src="bundle.js"></script>
<script> <script>
(function() { mocha.run();
var env = jasmine.getEnv(),
reporter = new jasmine.HtmlReporter();
env.addReporter(reporter);
env.specFilter = reporter.specFilter;
window.onload = function() { env.execute(); };
})();
</script> </script>
</head>
<body>
</body> </body>
</html> </html>

@ -1,7 +1,13 @@
"use strict"; "use strict";
let chai = require("chai");
let helpers = require("./helpers");
let peg = require("../../../../lib/peg"); let peg = require("../../../../lib/peg");
chai.use(helpers);
let expect = chai.expect;
describe("compiler pass |generateBytecode|", function() { describe("compiler pass |generateBytecode|", function() {
let pass = peg.compiler.passes.generate.generateBytecode; let pass = peg.compiler.passes.generate.generateBytecode;
@ -15,7 +21,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for grammar", function() { describe("for grammar", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST([ expect(pass).to.changeAST([
"a = 'a'", "a = 'a'",
"b = 'b'", "b = 'b'",
"c = 'c'" "c = 'c'"
@ -29,7 +35,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST([ expect(pass).to.changeAST([
"a = 'a'", "a = 'a'",
"b = 'b'", "b = 'b'",
"c = 'c'" "c = 'c'"
@ -46,7 +52,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for rule", function() { describe("for rule", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST("start = 'a'", bytecodeDetails([ expect(pass).to.changeAST("start = 'a'", bytecodeDetails([
18, 0, 2, 2, 22, 0, 23, 1 // <expression> 18, 0, 2, 2, 22, 0, 23, 1 // <expression>
])); ]));
}); });
@ -56,7 +62,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start 'start' = 'a'"; let grammar = "start 'start' = 'a'";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
28, // SILENT_FAILS_ON 28, // SILENT_FAILS_ON
18, 1, 2, 2, 22, 1, 23, 2, // <expression> 18, 1, 2, 2, 22, 1, 23, 2, // <expression>
29, // SILENT_FAILS_OFF 29, // SILENT_FAILS_OFF
@ -66,7 +72,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"peg$otherExpectation(\"start\")", "peg$otherExpectation(\"start\")",
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)" "peg$literalExpectation(\"a\", false)"
@ -76,7 +82,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for choice", function() { describe("for choice", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST("start = 'a' / 'b' / 'c'", bytecodeDetails([ expect(pass).to.changeAST("start = 'a' / 'b' / 'c'", bytecodeDetails([
18, 0, 2, 2, 22, 0, 23, 1, // <alternatives[0]> 18, 0, 2, 2, 22, 0, 23, 1, // <alternatives[0]>
14, 21, 0, // IF_ERROR 14, 21, 0, // IF_ERROR
6, // * POP 6, // * POP
@ -93,7 +99,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = 'a' { code }"; let grammar = "start = 'a' { code }";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
5, // PUSH_CURR_POS 5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <expression> 18, 0, 2, 2, 22, 0, 23, 1, // <expression>
15, 6, 0, // IF_NOT_ERROR 15, 6, 0, // IF_NOT_ERROR
@ -104,7 +110,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)", "peg$literalExpectation(\"a\", false)",
"function() { code }" "function() { code }"
@ -116,7 +122,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = a:'a' { code }"; let grammar = "start = a:'a' { code }";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
5, // PUSH_CURR_POS 5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <expression> 18, 0, 2, 2, 22, 0, 23, 1, // <expression>
15, 7, 0, // IF_NOT_ERROR 15, 7, 0, // IF_NOT_ERROR
@ -127,7 +133,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)", "peg$literalExpectation(\"a\", false)",
"function(a) { code }" "function(a) { code }"
@ -139,7 +145,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = a:'a' b:'b' c:'c' { code }"; let grammar = "start = a:'a' b:'b' c:'c' { code }";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
5, // PUSH_CURR_POS 5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]> 18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]>
15, 40, 3, // IF_NOT_ERROR 15, 40, 3, // IF_NOT_ERROR
@ -163,7 +169,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)", "peg$literalExpectation(\"a\", false)",
"\"b\"", "\"b\"",
@ -180,7 +186,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = 'a' 'b' 'c'"; let grammar = "start = 'a' 'b' 'c'";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
5, // PUSH_CURR_POS 5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]> 18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]>
15, 33, 3, // IF_NOT_ERROR 15, 33, 3, // IF_NOT_ERROR
@ -203,7 +209,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)", "peg$literalExpectation(\"a\", false)",
"\"b\"", "\"b\"",
@ -216,7 +222,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for labeled", function() { describe("for labeled", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST("start = a:'a'", bytecodeDetails([ expect(pass).to.changeAST("start = a:'a'", bytecodeDetails([
18, 0, 2, 2, 22, 0, 23, 1 // <expression> 18, 0, 2, 2, 22, 0, 23, 1 // <expression>
])); ]));
}); });
@ -224,7 +230,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for text", function() { describe("for text", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST("start = $'a'", bytecodeDetails([ expect(pass).to.changeAST("start = $'a'", bytecodeDetails([
5, // PUSH_CURR_POS 5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <expression> 18, 0, 2, 2, 22, 0, 23, 1, // <expression>
15, 2, 1, // IF_NOT_ERROR 15, 2, 1, // IF_NOT_ERROR
@ -239,7 +245,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = &'a'"; let grammar = "start = &'a'";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
5, // PUSH_CURR_POS 5, // PUSH_CURR_POS
28, // SILENT_FAILS_ON 28, // SILENT_FAILS_ON
18, 0, 2, 2, 22, 0, 23, 1, // <expression> 18, 0, 2, 2, 22, 0, 23, 1, // <expression>
@ -255,7 +261,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)" "peg$literalExpectation(\"a\", false)"
])); ]));
@ -266,7 +272,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = !'a'"; let grammar = "start = !'a'";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
5, // PUSH_CURR_POS 5, // PUSH_CURR_POS
28, // SILENT_FAILS_ON 28, // SILENT_FAILS_ON
18, 0, 2, 2, 22, 0, 23, 1, // <expression> 18, 0, 2, 2, 22, 0, 23, 1, // <expression>
@ -282,7 +288,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)" "peg$literalExpectation(\"a\", false)"
])); ]));
@ -293,7 +299,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = 'a'?"; let grammar = "start = 'a'?";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
18, 0, 2, 2, 22, 0, 23, 1, // <expression> 18, 0, 2, 2, 22, 0, 23, 1, // <expression>
14, 2, 0, // IF_ERROR 14, 2, 0, // IF_ERROR
6, // * POP 6, // * POP
@ -302,7 +308,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)" "peg$literalExpectation(\"a\", false)"
])); ]));
@ -313,7 +319,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = 'a'*"; let grammar = "start = 'a'*";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
4, // PUSH_EMPTY_ARRAY 4, // PUSH_EMPTY_ARRAY
18, 0, 2, 2, 22, 0, 23, 1, // <expression> 18, 0, 2, 2, 22, 0, 23, 1, // <expression>
16, 9, // WHILE_NOT_ERROR 16, 9, // WHILE_NOT_ERROR
@ -324,7 +330,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)" "peg$literalExpectation(\"a\", false)"
])); ]));
@ -335,7 +341,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = 'a'+"; let grammar = "start = 'a'+";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
4, // PUSH_EMPTY_ARRAY 4, // PUSH_EMPTY_ARRAY
18, 0, 2, 2, 22, 0, 23, 1, // <expression> 18, 0, 2, 2, 22, 0, 23, 1, // <expression>
15, 12, 3, // IF_NOT_ERROR 15, 12, 3, // IF_NOT_ERROR
@ -350,7 +356,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)" "peg$literalExpectation(\"a\", false)"
])); ]));
@ -359,7 +365,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for group", function() { describe("for group", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST("start = ('a')", bytecodeDetails([ expect(pass).to.changeAST("start = ('a')", bytecodeDetails([
18, 0, 2, 2, 22, 0, 23, 1 // <expression> 18, 0, 2, 2, 22, 0, 23, 1 // <expression>
])); ]));
}); });
@ -370,7 +376,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = &{ code }"; let grammar = "start = &{ code }";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
25, // UPDATE_SAVED_POS 25, // UPDATE_SAVED_POS
26, 0, 0, 0, // CALL 26, 0, 0, 0, // CALL
13, 2, 2, // IF 13, 2, 2, // IF
@ -382,7 +388,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST( expect(pass).to.changeAST(
grammar, grammar,
constsDetails(["function() { code }"]) constsDetails(["function() { code }"])
); );
@ -393,7 +399,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = a:'a' b:'b' c:'c' &{ code }"; let grammar = "start = a:'a' b:'b' c:'c' &{ code }";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
5, // PUSH_CURR_POS 5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]> 18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]>
15, 55, 3, // IF_NOT_ERROR 15, 55, 3, // IF_NOT_ERROR
@ -427,7 +433,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)", "peg$literalExpectation(\"a\", false)",
"\"b\"", "\"b\"",
@ -445,7 +451,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = !{ code }"; let grammar = "start = !{ code }";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
25, // UPDATE_SAVED_POS 25, // UPDATE_SAVED_POS
26, 0, 0, 0, // CALL 26, 0, 0, 0, // CALL
13, 2, 2, // IF 13, 2, 2, // IF
@ -457,7 +463,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST( expect(pass).to.changeAST(
grammar, grammar,
constsDetails(["function() { code }"]) constsDetails(["function() { code }"])
); );
@ -468,7 +474,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = a:'a' b:'b' c:'c' !{ code }"; let grammar = "start = a:'a' b:'b' c:'c' !{ code }";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
5, // PUSH_CURR_POS 5, // PUSH_CURR_POS
18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]> 18, 0, 2, 2, 22, 0, 23, 1, // <elements[0]>
15, 55, 3, // IF_NOT_ERROR 15, 55, 3, // IF_NOT_ERROR
@ -502,7 +508,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)", "peg$literalExpectation(\"a\", false)",
"\"b\"", "\"b\"",
@ -517,7 +523,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for rule_ref", function() { describe("for rule_ref", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST([ expect(pass).to.changeAST([
"start = other", "start = other",
"other = 'other'" "other = 'other'"
].join("\n"), { ].join("\n"), {
@ -536,13 +542,13 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = ''"; let grammar = "start = ''";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
0, 0 // PUSH 0, 0 // PUSH
])); ]));
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails(["\"\""])); expect(pass).to.changeAST(grammar, constsDetails(["\"\""]));
}); });
}); });
@ -550,7 +556,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = 'a'"; let grammar = "start = 'a'";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
18, 0, 2, 2, // MATCH_STRING 18, 0, 2, 2, // MATCH_STRING
22, 0, // * ACCEPT_STRING 22, 0, // * ACCEPT_STRING
23, 1 // * FAIL 23, 1 // * FAIL
@ -558,7 +564,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"a\", false)" "peg$literalExpectation(\"a\", false)"
])); ]));
@ -569,7 +575,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = 'A'i"; let grammar = "start = 'A'i";
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
19, 0, 2, 2, // MATCH_STRING_IC 19, 0, 2, 2, // MATCH_STRING_IC
21, 1, // * ACCEPT_N 21, 1, // * ACCEPT_N
23, 1 // * FAIL 23, 1 // * FAIL
@ -577,7 +583,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST(grammar, constsDetails([ expect(pass).to.changeAST(grammar, constsDetails([
"\"a\"", "\"a\"",
"peg$literalExpectation(\"A\", true)" "peg$literalExpectation(\"A\", true)"
])); ]));
@ -587,7 +593,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("for class", function() { describe("for class", function() {
it("generates correct bytecode", function() { it("generates correct bytecode", function() {
expect(pass).toChangeAST("start = [a]", bytecodeDetails([ expect(pass).to.changeAST("start = [a]", bytecodeDetails([
20, 0, 2, 2, // MATCH_REGEXP 20, 0, 2, 2, // MATCH_REGEXP
21, 1, // * ACCEPT_N 21, 1, // * ACCEPT_N
23, 1 // * FAIL 23, 1 // * FAIL
@ -596,7 +602,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("non-inverted case-sensitive", function() { describe("non-inverted case-sensitive", function() {
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST("start = [a]", constsDetails([ expect(pass).to.changeAST("start = [a]", constsDetails([
"/^[a]/", "/^[a]/",
"peg$classExpectation([\"a\"], false, false)" "peg$classExpectation([\"a\"], false, false)"
])); ]));
@ -605,7 +611,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("inverted case-sensitive", function() { describe("inverted case-sensitive", function() {
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST("start = [^a]", constsDetails([ expect(pass).to.changeAST("start = [^a]", constsDetails([
"/^[^a]/", "/^[^a]/",
"peg$classExpectation([\"a\"], true, false)" "peg$classExpectation([\"a\"], true, false)"
])); ]));
@ -614,7 +620,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("non-inverted case-insensitive", function() { describe("non-inverted case-insensitive", function() {
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST("start = [a]i", constsDetails([ expect(pass).to.changeAST("start = [a]i", constsDetails([
"/^[a]/i", "/^[a]/i",
"peg$classExpectation([\"a\"], false, true)" "peg$classExpectation([\"a\"], false, true)"
])); ]));
@ -623,7 +629,7 @@ describe("compiler pass |generateBytecode|", function() {
describe("complex", function() { describe("complex", function() {
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST("start = [ab-def-hij-l]", constsDetails([ expect(pass).to.changeAST("start = [ab-def-hij-l]", constsDetails([
"/^[ab-def-hij-l]/", "/^[ab-def-hij-l]/",
"peg$classExpectation([\"a\", [\"b\", \"d\"], \"e\", [\"f\", \"h\"], \"i\", [\"j\", \"l\"]], false, false)" "peg$classExpectation([\"a\", [\"b\", \"d\"], \"e\", [\"f\", \"h\"], \"i\", [\"j\", \"l\"]], false, false)"
])); ]));
@ -635,7 +641,7 @@ describe("compiler pass |generateBytecode|", function() {
let grammar = "start = ."; let grammar = "start = .";
it("generates bytecode", function() { it("generates bytecode", function() {
expect(pass).toChangeAST(grammar, bytecodeDetails([ expect(pass).to.changeAST(grammar, bytecodeDetails([
17, 2, 2, // MATCH_ANY 17, 2, 2, // MATCH_ANY
21, 1, // * ACCEPT_N 21, 1, // * ACCEPT_N
23, 0 // * FAIL 23, 0 // * FAIL
@ -643,7 +649,7 @@ describe("compiler pass |generateBytecode|", function() {
}); });
it("defines correct constants", function() { it("defines correct constants", function() {
expect(pass).toChangeAST( expect(pass).to.changeAST(
grammar, grammar,
constsDetails(["peg$anyExpectation()"]) constsDetails(["peg$anyExpectation()"])
); );

@ -2,103 +2,87 @@
let peg = require("../../../../lib/peg"); let peg = require("../../../../lib/peg");
beforeEach(function() { module.exports = function(chai, utils) {
this.addMatchers({ let Assertion = chai.Assertion;
toChangeAST(grammar, details, options) {
options = options !== undefined ? options : {};
function matchDetails(value, details) {
function isArray(value) {
return Object.prototype.toString.apply(value) === "[object Array]";
}
function isObject(value) { Assertion.addMethod("changeAST", function(grammar, props, options) {
return value !== null && typeof value === "object"; options = options !== undefined ? options : {};
}
if (isArray(details)) { function matchProps(value, props) {
if (!isArray(value)) { return false; } function isArray(value) {
return Object.prototype.toString.apply(value) === "[object Array]";
}
if (value.length !== details.length) { return false; } function isObject(value) {
for (let i = 0; i < details.length; i++) { return value !== null && typeof value === "object";
if (!matchDetails(value[i], details[i])) { return false; } }
}
return true; if (isArray(props)) {
} else if (isObject(details)) { if (!isArray(value)) { return false; }
if (!isObject(value)) { return false; }
let keys = Object.keys(details); if (value.length !== props.length) { return false; }
for (let i = 0; i < keys.length; i++) { for (let i = 0; i < props.length; i++) {
let key = keys[i]; if (!matchProps(value[i], props[i])) { return false; }
}
if (!(key in value)) { return false; } return true;
} else if (isObject(props)) {
if (!isObject(value)) { return false; }
if (!matchDetails(value[key], details[key])) { return false; } let keys = Object.keys(props);
} for (let i = 0; i < keys.length; i++) {
let key = keys[i];
return true; if (!(key in value)) { return false; }
} else {
return value === details;
}
}
let ast = peg.parser.parse(grammar); if (!matchProps(value[key], props[key])) { return false; }
this.actual(ast, options);
this.message = () =>
"Expected the pass "
+ "with options " + jasmine.pp(options) + " "
+ (this.isNot ? "not " : "")
+ "to change the AST " + jasmine.pp(ast) + " "
+ "to match " + jasmine.pp(details) + ", "
+ "but it " + (this.isNot ? "did" : "didn't") + ".";
return matchDetails(ast, details);
},
toReportError(grammar, details) {
let ast = peg.parser.parse(grammar);
try {
this.actual(ast);
} catch (e) {
if (this.isNot) {
this.message = () =>
"Expected the pass not to report an error "
+ "for grammar " + jasmine.pp(grammar) + ", "
+ "but it did.";
} else {
if (details) {
let keys = Object.keys(details);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
if (!this.env.equals_(e[key], details[key])) {
this.message = () =>
"Expected the pass to report an error "
+ "with details " + jasmine.pp(details) + " "
+ "for grammar " + jasmine.pp(grammar) + ", "
+ "but " + jasmine.pp(key) + " "
+ "is " + jasmine.pp(e[key]) + ".";
return false;
}
}
}
} }
return true; return true;
} else {
return value === props;
} }
}
let ast = peg.parser.parse(grammar);
utils.flag(this, "object")(ast, options);
this.assert(
matchProps(ast, props),
"expected #{this} to change the AST to match #{exp}",
"expected #{this} to not change the AST to match #{exp}",
props,
ast
);
});
Assertion.addMethod("reportError", function(grammar, props) {
let ast = peg.parser.parse(grammar);
this.message = () => let passed, result;
"Expected the pass to report an error "
+ (details ? "with details " + jasmine.pp(details) + " " : "") try {
+ "for grammar " + jasmine.pp(grammar) + ", " utils.flag(this, "object")(ast);
+ "but it didn't."; passed = true;
} catch (e) {
result = e;
passed = false;
}
return false; this.assert(
!passed,
"expected #{this} to report an error but it didn't",
"expected #{this} to not report an error but #{act} was reported",
null,
result
);
if (!passed && props !== undefined) {
Object.keys(props).forEach(key => {
new Assertion(result).to.have.property(key)
.that.is.deep.equal(props[key]);
});
} }
}); });
}); };

@ -1,13 +1,19 @@
"use strict"; "use strict";
let chai = require("chai");
let helpers = require("./helpers");
let peg = require("../../../../lib/peg"); let peg = require("../../../../lib/peg");
chai.use(helpers);
let expect = chai.expect;
describe("compiler pass |removeProxyRules|", function() { describe("compiler pass |removeProxyRules|", function() {
let pass = peg.compiler.passes.transform.removeProxyRules; let pass = peg.compiler.passes.transform.removeProxyRules;
describe("when a proxy rule isn't listed in |allowedStartRules|", function() { describe("when a proxy rule isn't listed in |allowedStartRules|", function() {
it("updates references and removes it", function() { it("updates references and removes it", function() {
expect(pass).toChangeAST( expect(pass).to.changeAST(
[ [
"start = proxy", "start = proxy",
"proxy = proxied", "proxy = proxied",
@ -29,7 +35,7 @@ describe("compiler pass |removeProxyRules|", function() {
describe("when a proxy rule is listed in |allowedStartRules|", function() { describe("when a proxy rule is listed in |allowedStartRules|", function() {
it("updates references but doesn't remove it", function() { it("updates references but doesn't remove it", function() {
expect(pass).toChangeAST( expect(pass).to.changeAST(
[ [
"start = proxy", "start = proxy",
"proxy = proxied", "proxy = proxied",

@ -1,13 +1,19 @@
"use strict"; "use strict";
let chai = require("chai");
let helpers = require("./helpers");
let peg = require("../../../../lib/peg"); let peg = require("../../../../lib/peg");
chai.use(helpers);
let expect = chai.expect;
describe("compiler pass |reportDuplicateLabels|", function() { describe("compiler pass |reportDuplicateLabels|", function() {
let pass = peg.compiler.passes.check.reportDuplicateLabels; let pass = peg.compiler.passes.check.reportDuplicateLabels;
describe("in a sequence", function() { describe("in a sequence", function() {
it("reports labels duplicate with labels of preceding elements", function() { it("reports labels duplicate with labels of preceding elements", function() {
expect(pass).toReportError("start = a:'a' a:'a'", { expect(pass).to.reportError("start = a:'a' a:'a'", {
message: "Label \"a\" is already defined at line 1, column 9.", message: "Label \"a\" is already defined at line 1, column 9.",
location: { location: {
start: { offset: 14, line: 1, column: 15 }, start: { offset: 14, line: 1, column: 15 },
@ -17,29 +23,29 @@ describe("compiler pass |reportDuplicateLabels|", function() {
}); });
it("doesn't report labels duplicate with labels in subexpressions", function() { it("doesn't report labels duplicate with labels in subexpressions", function() {
expect(pass).not.toReportError("start = ('a' / a:'a' / 'a') a:'a'"); expect(pass).to.not.reportError("start = ('a' / a:'a' / 'a') a:'a'");
expect(pass).not.toReportError("start = (a:'a' { }) a:'a'"); expect(pass).to.not.reportError("start = (a:'a' { }) a:'a'");
expect(pass).not.toReportError("start = ('a' a:'a' 'a') a:'a'"); expect(pass).to.not.reportError("start = ('a' a:'a' 'a') a:'a'");
expect(pass).not.toReportError("start = b:(a:'a') a:'a'"); expect(pass).to.not.reportError("start = b:(a:'a') a:'a'");
expect(pass).not.toReportError("start = $(a:'a') a:'a'"); expect(pass).to.not.reportError("start = $(a:'a') a:'a'");
expect(pass).not.toReportError("start = &(a:'a') a:'a'"); expect(pass).to.not.reportError("start = &(a:'a') a:'a'");
expect(pass).not.toReportError("start = !(a:'a') a:'a'"); expect(pass).to.not.reportError("start = !(a:'a') a:'a'");
expect(pass).not.toReportError("start = (a:'a')? a:'a'"); expect(pass).to.not.reportError("start = (a:'a')? a:'a'");
expect(pass).not.toReportError("start = (a:'a')* a:'a'"); expect(pass).to.not.reportError("start = (a:'a')* a:'a'");
expect(pass).not.toReportError("start = (a:'a')+ a:'a'"); expect(pass).to.not.reportError("start = (a:'a')+ a:'a'");
expect(pass).not.toReportError("start = (a:'a') a:'a'"); expect(pass).to.not.reportError("start = (a:'a') a:'a'");
}); });
}); });
describe("in a choice", function() { describe("in a choice", function() {
it("doesn't report labels duplicate with labels of preceding alternatives", function() { it("doesn't report labels duplicate with labels of preceding alternatives", function() {
expect(pass).not.toReportError("start = a:'a' / a:'a'"); expect(pass).to.not.reportError("start = a:'a' / a:'a'");
}); });
}); });
describe("in outer sequence", function() { describe("in outer sequence", function() {
it("reports labels duplicate with labels of preceding elements", function() { it("reports labels duplicate with labels of preceding elements", function() {
expect(pass).toReportError("start = a:'a' (a:'a')", { expect(pass).to.reportError("start = a:'a' (a:'a')", {
message: "Label \"a\" is already defined at line 1, column 9.", message: "Label \"a\" is already defined at line 1, column 9.",
location: { location: {
start: { offset: 15, line: 1, column: 16 }, start: { offset: 15, line: 1, column: 16 },
@ -49,11 +55,11 @@ describe("compiler pass |reportDuplicateLabels|", function() {
}); });
it("doesn't report labels duplicate with the label of the current element", function() { it("doesn't report labels duplicate with the label of the current element", function() {
expect(pass).not.toReportError("start = a:(a:'a')"); expect(pass).to.not.reportError("start = a:(a:'a')");
}); });
it("doesn't report labels duplicate with labels of following elements", function() { it("doesn't report labels duplicate with labels of following elements", function() {
expect(pass).not.toReportError("start = (a:'a') a:'a'"); expect(pass).to.not.reportError("start = (a:'a') a:'a'");
}); });
}); });
}); });

@ -1,12 +1,18 @@
"use strict"; "use strict";
let chai = require("chai");
let helpers = require("./helpers");
let peg = require("../../../../lib/peg"); let peg = require("../../../../lib/peg");
chai.use(helpers);
let expect = chai.expect;
describe("compiler pass |reportDuplicateRules|", function() { describe("compiler pass |reportDuplicateRules|", function() {
let pass = peg.compiler.passes.check.reportDuplicateRules; let pass = peg.compiler.passes.check.reportDuplicateRules;
it("reports duplicate rules", function() { it("reports duplicate rules", function() {
expect(pass).toReportError([ expect(pass).to.reportError([
"start = 'a'", "start = 'a'",
"start = 'b'" "start = 'b'"
].join("\n"), { ].join("\n"), {

@ -1,12 +1,18 @@
"use strict"; "use strict";
let chai = require("chai");
let helpers = require("./helpers");
let peg = require("../../../../lib/peg"); let peg = require("../../../../lib/peg");
chai.use(helpers);
let expect = chai.expect;
describe("compiler pass |reportInfiniteRecursion|", function() { describe("compiler pass |reportInfiniteRecursion|", function() {
let pass = peg.compiler.passes.check.reportInfiniteRecursion; let pass = peg.compiler.passes.check.reportInfiniteRecursion;
it("reports direct left recursion", function() { it("reports direct left recursion", function() {
expect(pass).toReportError("start = start", { expect(pass).to.reportError("start = start", {
message: "Possible infinite loop when parsing (left recursion: start -> start).", message: "Possible infinite loop when parsing (left recursion: start -> start).",
location: { location: {
start: { offset: 8, line: 1, column: 9 }, start: { offset: 8, line: 1, column: 9 },
@ -16,7 +22,7 @@ describe("compiler pass |reportInfiniteRecursion|", function() {
}); });
it("reports indirect left recursion", function() { it("reports indirect left recursion", function() {
expect(pass).toReportError([ expect(pass).to.reportError([
"start = stop", "start = stop",
"stop = start" "stop = start"
].join("\n"), { ].join("\n"), {
@ -30,86 +36,86 @@ describe("compiler pass |reportInfiniteRecursion|", function() {
describe("in sequences", function() { describe("in sequences", function() {
it("reports left recursion if all preceding elements match empty string", function() { it("reports left recursion if all preceding elements match empty string", function() {
expect(pass).toReportError("start = '' '' '' start"); expect(pass).to.reportError("start = '' '' '' start");
}); });
it("doesn't report left recursion if some preceding element doesn't match empty string", function() { it("doesn't report left recursion if some preceding element doesn't match empty string", function() {
expect(pass).not.toReportError("start = 'a' '' '' start"); expect(pass).to.not.reportError("start = 'a' '' '' start");
expect(pass).not.toReportError("start = '' 'a' '' start"); expect(pass).to.not.reportError("start = '' 'a' '' start");
expect(pass).not.toReportError("start = '' '' 'a' start"); expect(pass).to.not.reportError("start = '' '' 'a' start");
}); });
// Regression test for #359. // Regression test for #359.
it("reports left recursion when rule reference is wrapped in an expression", function() { it("reports left recursion when rule reference is wrapped in an expression", function() {
expect(pass).toReportError("start = '' start?"); expect(pass).to.reportError("start = '' start?");
}); });
it("computes expressions that always consume input on success correctly", function() { it("computes expressions that always consume input on success correctly", function() {
expect(pass).toReportError([ expect(pass).to.reportError([
"start = a start", "start = a start",
"a 'a' = ''" "a 'a' = ''"
].join("\n")); ].join("\n"));
expect(pass).not.toReportError([ expect(pass).to.not.reportError([
"start = a start", "start = a start",
"a 'a' = 'a'" "a 'a' = 'a'"
].join("\n")); ].join("\n"));
expect(pass).toReportError("start = ('' / 'a' / 'b') start"); expect(pass).to.reportError("start = ('' / 'a' / 'b') start");
expect(pass).toReportError("start = ('a' / '' / 'b') start"); expect(pass).to.reportError("start = ('a' / '' / 'b') start");
expect(pass).toReportError("start = ('a' / 'b' / '') start"); expect(pass).to.reportError("start = ('a' / 'b' / '') start");
expect(pass).not.toReportError("start = ('a' / 'b' / 'c') start"); expect(pass).to.not.reportError("start = ('a' / 'b' / 'c') start");
expect(pass).toReportError("start = ('' { }) start"); expect(pass).to.reportError("start = ('' { }) start");
expect(pass).not.toReportError("start = ('a' { }) start"); expect(pass).to.not.reportError("start = ('a' { }) start");
expect(pass).toReportError("start = ('' '' '') start"); expect(pass).to.reportError("start = ('' '' '') start");
expect(pass).not.toReportError("start = ('a' '' '') start"); expect(pass).to.not.reportError("start = ('a' '' '') start");
expect(pass).not.toReportError("start = ('' 'a' '') start"); expect(pass).to.not.reportError("start = ('' 'a' '') start");
expect(pass).not.toReportError("start = ('' '' 'a') start"); expect(pass).to.not.reportError("start = ('' '' 'a') start");
expect(pass).toReportError("start = a:'' start"); expect(pass).to.reportError("start = a:'' start");
expect(pass).not.toReportError("start = a:'a' start"); expect(pass).to.not.reportError("start = a:'a' start");
expect(pass).toReportError("start = $'' start"); expect(pass).to.reportError("start = $'' start");
expect(pass).not.toReportError("start = $'a' start"); expect(pass).to.not.reportError("start = $'a' start");
expect(pass).toReportError("start = &'' start"); expect(pass).to.reportError("start = &'' start");
expect(pass).toReportError("start = &'a' start"); expect(pass).to.reportError("start = &'a' start");
expect(pass).toReportError("start = !'' start"); expect(pass).to.reportError("start = !'' start");
expect(pass).toReportError("start = !'a' start"); expect(pass).to.reportError("start = !'a' start");
expect(pass).toReportError("start = ''? start"); expect(pass).to.reportError("start = ''? start");
expect(pass).toReportError("start = 'a'? start"); expect(pass).to.reportError("start = 'a'? start");
expect(pass).toReportError("start = ''* start"); expect(pass).to.reportError("start = ''* start");
expect(pass).toReportError("start = 'a'* start"); expect(pass).to.reportError("start = 'a'* start");
expect(pass).toReportError("start = ''+ start"); expect(pass).to.reportError("start = ''+ start");
expect(pass).not.toReportError("start = 'a'+ start"); expect(pass).to.not.reportError("start = 'a'+ start");
expect(pass).toReportError("start = ('') start"); expect(pass).to.reportError("start = ('') start");
expect(pass).not.toReportError("start = ('a') start"); expect(pass).to.not.reportError("start = ('a') start");
expect(pass).toReportError("start = &{ } start"); expect(pass).to.reportError("start = &{ } start");
expect(pass).toReportError("start = !{ } start"); expect(pass).to.reportError("start = !{ } start");
expect(pass).toReportError([ expect(pass).to.reportError([
"start = a start", "start = a start",
"a = ''" "a = ''"
].join("\n")); ].join("\n"));
expect(pass).not.toReportError([ expect(pass).to.not.reportError([
"start = a start", "start = a start",
"a = 'a'" "a = 'a'"
].join("\n")); ].join("\n"));
expect(pass).toReportError("start = '' start"); expect(pass).to.reportError("start = '' start");
expect(pass).not.toReportError("start = 'a' start"); expect(pass).to.not.reportError("start = 'a' start");
expect(pass).not.toReportError("start = [a-d] start"); expect(pass).to.not.reportError("start = [a-d] start");
expect(pass).not.toReportError("start = . start"); expect(pass).to.not.reportError("start = . start");
}); });
}); });
}); });

@ -1,12 +1,18 @@
"use strict"; "use strict";
let chai = require("chai");
let helpers = require("./helpers");
let peg = require("../../../../lib/peg"); let peg = require("../../../../lib/peg");
chai.use(helpers);
let expect = chai.expect;
describe("compiler pass |reportInfiniteRepetition|", function() { describe("compiler pass |reportInfiniteRepetition|", function() {
let pass = peg.compiler.passes.check.reportInfiniteRepetition; let pass = peg.compiler.passes.check.reportInfiniteRepetition;
it("reports infinite loops for zero_or_more", function() { it("reports infinite loops for zero_or_more", function() {
expect(pass).toReportError("start = ('')*", { expect(pass).to.reportError("start = ('')*", {
message: "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).", message: "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).",
location: { location: {
start: { offset: 8, line: 1, column: 9 }, start: { offset: 8, line: 1, column: 9 },
@ -16,7 +22,7 @@ describe("compiler pass |reportInfiniteRepetition|", function() {
}); });
it("reports infinite loops for one_or_more", function() { it("reports infinite loops for one_or_more", function() {
expect(pass).toReportError("start = ('')+", { expect(pass).to.reportError("start = ('')+", {
message: "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).", message: "Possible infinite loop when parsing (repetition used with an expression that may not consume any input).",
location: { location: {
start: { offset: 8, line: 1, column: 9 }, start: { offset: 8, line: 1, column: 9 },
@ -26,70 +32,70 @@ describe("compiler pass |reportInfiniteRepetition|", function() {
}); });
it("computes expressions that always consume input on success correctly", function() { it("computes expressions that always consume input on success correctly", function() {
expect(pass).toReportError([ expect(pass).to.reportError([
"start = a*", "start = a*",
"a 'a' = ''" "a 'a' = ''"
].join("\n")); ].join("\n"));
expect(pass).not.toReportError([ expect(pass).to.not.reportError([
"start = a*", "start = a*",
"a 'a' = 'a'" "a 'a' = 'a'"
].join("\n")); ].join("\n"));
expect(pass).toReportError("start = ('' / 'a' / 'b')*"); expect(pass).to.reportError("start = ('' / 'a' / 'b')*");
expect(pass).toReportError("start = ('a' / '' / 'b')*"); expect(pass).to.reportError("start = ('a' / '' / 'b')*");
expect(pass).toReportError("start = ('a' / 'b' / '')*"); expect(pass).to.reportError("start = ('a' / 'b' / '')*");
expect(pass).not.toReportError("start = ('a' / 'b' / 'c')*"); expect(pass).to.not.reportError("start = ('a' / 'b' / 'c')*");
expect(pass).toReportError("start = ('' { })*"); expect(pass).to.reportError("start = ('' { })*");
expect(pass).not.toReportError("start = ('a' { })*"); expect(pass).to.not.reportError("start = ('a' { })*");
expect(pass).toReportError("start = ('' '' '')*"); expect(pass).to.reportError("start = ('' '' '')*");
expect(pass).not.toReportError("start = ('a' '' '')*"); expect(pass).to.not.reportError("start = ('a' '' '')*");
expect(pass).not.toReportError("start = ('' 'a' '')*"); expect(pass).to.not.reportError("start = ('' 'a' '')*");
expect(pass).not.toReportError("start = ('' '' 'a')*"); expect(pass).to.not.reportError("start = ('' '' 'a')*");
expect(pass).toReportError("start = (a:'')*"); expect(pass).to.reportError("start = (a:'')*");
expect(pass).not.toReportError("start = (a:'a')*"); expect(pass).to.not.reportError("start = (a:'a')*");
expect(pass).toReportError("start = ($'')*"); expect(pass).to.reportError("start = ($'')*");
expect(pass).not.toReportError("start = ($'a')*"); expect(pass).to.not.reportError("start = ($'a')*");
expect(pass).toReportError("start = (&'')*"); expect(pass).to.reportError("start = (&'')*");
expect(pass).toReportError("start = (&'a')*"); expect(pass).to.reportError("start = (&'a')*");
expect(pass).toReportError("start = (!'')*"); expect(pass).to.reportError("start = (!'')*");
expect(pass).toReportError("start = (!'a')*"); expect(pass).to.reportError("start = (!'a')*");
expect(pass).toReportError("start = (''?)*"); expect(pass).to.reportError("start = (''?)*");
expect(pass).toReportError("start = ('a'?)*"); expect(pass).to.reportError("start = ('a'?)*");
expect(pass).toReportError("start = (''*)*"); expect(pass).to.reportError("start = (''*)*");
expect(pass).toReportError("start = ('a'*)*"); expect(pass).to.reportError("start = ('a'*)*");
expect(pass).toReportError("start = (''+)*"); expect(pass).to.reportError("start = (''+)*");
expect(pass).not.toReportError("start = ('a'+)*"); expect(pass).to.not.reportError("start = ('a'+)*");
expect(pass).toReportError("start = ('')*"); expect(pass).to.reportError("start = ('')*");
expect(pass).not.toReportError("start = ('a')*"); expect(pass).to.not.reportError("start = ('a')*");
expect(pass).toReportError("start = (&{ })*"); expect(pass).to.reportError("start = (&{ })*");
expect(pass).toReportError("start = (!{ })*"); expect(pass).to.reportError("start = (!{ })*");
expect(pass).toReportError([ expect(pass).to.reportError([
"start = a*", "start = a*",
"a = ''" "a = ''"
].join("\n")); ].join("\n"));
expect(pass).not.toReportError([ expect(pass).to.not.reportError([
"start = a*", "start = a*",
"a = 'a'" "a = 'a'"
].join("\n")); ].join("\n"));
expect(pass).toReportError("start = ''*"); expect(pass).to.reportError("start = ''*");
expect(pass).not.toReportError("start = 'a'*"); expect(pass).to.not.reportError("start = 'a'*");
expect(pass).not.toReportError("start = [a-d]*"); expect(pass).to.not.reportError("start = [a-d]*");
expect(pass).not.toReportError("start = .*"); expect(pass).to.not.reportError("start = .*");
}); });
}); });

@ -1,12 +1,18 @@
"use strict"; "use strict";
let chai = require("chai");
let helpers = require("./helpers");
let peg = require("../../../../lib/peg"); let peg = require("../../../../lib/peg");
chai.use(helpers);
let expect = chai.expect;
describe("compiler pass |reportUndefinedRules|", function() { describe("compiler pass |reportUndefinedRules|", function() {
let pass = peg.compiler.passes.check.reportUndefinedRules; let pass = peg.compiler.passes.check.reportUndefinedRules;
it("reports undefined rules", function() { it("reports undefined rules", function() {
expect(pass).toReportError("start = undefined", { expect(pass).to.reportError("start = undefined", {
message: "Rule \"undefined\" is not defined.", message: "Rule \"undefined\" is not defined.",
location: { location: {
start: { offset: 8, line: 1, column: 9 }, start: { offset: 8, line: 1, column: 9 },

@ -1,7 +1,10 @@
"use strict"; "use strict";
let chai = require("chai");
let peg = require("../../lib/peg"); let peg = require("../../lib/peg");
let expect = chai.expect;
describe("PEG.js grammar parser", function() { describe("PEG.js grammar parser", function() {
let literalAbcd = { type: "literal", value: "abcd", ignoreCase: false }; let literalAbcd = { type: "literal", value: "abcd", ignoreCase: false };
let literalEfgh = { type: "literal", value: "efgh", ignoreCase: false }; let literalEfgh = { type: "literal", value: "efgh", ignoreCase: false };
@ -163,441 +166,425 @@ describe("PEG.js grammar parser", function() {
return strip; return strip;
})(); })();
beforeEach(function() { function helpers(chai, utils) {
this.addMatchers({ let Assertion = chai.Assertion;
toParseAs(expected) {
let result;
try {
result = peg.parser.parse(this.actual);
} catch (e) {
this.message = () =>
"Expected " + jasmine.pp(this.actual) + " "
+ "to parse as " + jasmine.pp(expected) + ", "
+ "but it failed to parse with message "
+ jasmine.pp(e.message) + ".";
return false;
}
stripLocation(result); Assertion.addMethod("parseAs", function(expected) {
let result = peg.parser.parse(utils.flag(this, "object"));
this.message = () => stripLocation(result);
"Expected " + jasmine.pp(this.actual) + " "
+ (this.isNot ? "not " : "")
+ "to parse as " + jasmine.pp(expected) + ", "
+ "but it parsed as " + jasmine.pp(result) + ".";
return this.env.equals_(result, expected); this.assert(
}, utils.eql(result, expected),
"expected #{this} to parse as #{exp} but got #{act}",
"expected #{this} to not parse as #{exp}",
expected,
result,
!utils.flag(this, "negate")
);
});
toFailToParse(details) { Assertion.addMethod("failToParse", function(props) {
let result; let passed, result;
try {
result = peg.parser.parse(this.actual);
} catch (e) {
if (this.isNot) {
this.message = () =>
"Expected " + jasmine.pp(this.actual) + " to parse, "
+ "but it failed with message "
+ jasmine.pp(e.message) + ".";
} else {
if (details) {
let keys = Object.keys(details);
for (let i = 0; i < keys.length; i++) {
let key = keys[i];
if (!this.env.equals_(e[key], details[key])) {
this.message = () =>
"Expected " + jasmine.pp(this.actual) + " to fail to parse"
+ (details ? " with details " + jasmine.pp(details) : "") + ", "
+ "but " + jasmine.pp(key) + " "
+ "is " + jasmine.pp(e[key]) + ".";
return false;
}
}
}
}
return true;
}
stripLocation(result); try {
result = peg.parser.parse(utils.flag(this, "object"));
passed = true;
} catch (e) {
result = e;
passed = false;
}
this.message = () => if (passed) {
"Expected " + jasmine.pp(this.actual) + " to fail to parse" stripLocation(result);
+ (details ? " with details " + jasmine.pp(details) : "") + ", " }
+ "but it parsed as " + jasmine.pp(result) + ".";
return false; this.assert(
!passed,
"expected #{this} to fail to parse but got #{act}",
"expected #{this} to not fail to parse but it failed with #{act}",
null,
result
);
if (!passed && props !== undefined) {
Object.keys(props).forEach(key => {
new Assertion(result).to.have.property(key)
.that.is.deep.equal(props[key]);
});
} }
}); });
}
// Helper activation needs to put inside a |beforeEach| block because the
// helpers conflict with the ones in
// spec/behavior/generated-parser-behavior.spec.js.
beforeEach(function() {
chai.use(helpers);
}); });
// Canonical Grammar is "a = 'abcd'; b = 'efgh'; c = 'ijkl';". // Canonical Grammar is "a = 'abcd'; b = 'efgh'; c = 'ijkl';".
it("parses Grammar", function() { it("parses Grammar", function() {
expect("\na = 'abcd';\n").toParseAs( expect("\na = 'abcd';\n").to.parseAs(
{ type: "grammar", initializer: null, rules: [ruleA] } { type: "grammar", initializer: null, rules: [ruleA] }
); );
expect("\na = 'abcd';\nb = 'efgh';\nc = 'ijkl';\n").toParseAs( expect("\na = 'abcd';\nb = 'efgh';\nc = 'ijkl';\n").to.parseAs(
{ type: "grammar", initializer: null, rules: [ruleA, ruleB, ruleC] } { type: "grammar", initializer: null, rules: [ruleA, ruleB, ruleC] }
); );
expect("\n{ code };\na = 'abcd';\n").toParseAs( expect("\n{ code };\na = 'abcd';\n").to.parseAs(
{ type: "grammar", initializer: initializer, rules: [ruleA] } { type: "grammar", initializer: initializer, rules: [ruleA] }
); );
}); });
// Canonical Initializer is "{ code }". // Canonical Initializer is "{ code }".
it("parses Initializer", function() { it("parses Initializer", function() {
expect("{ code };start = 'abcd'").toParseAs( expect("{ code };start = 'abcd'").to.parseAs(
{ type: "grammar", initializer: initializer, rules: [ruleStart] } { type: "grammar", initializer: initializer, rules: [ruleStart] }
); );
}); });
// Canonical Rule is "a = 'abcd';". // Canonical Rule is "a = 'abcd';".
it("parses Rule", function() { it("parses Rule", function() {
expect("start\n=\n'abcd';").toParseAs( expect("start\n=\n'abcd';").to.parseAs(
oneRuleGrammar(literalAbcd) oneRuleGrammar(literalAbcd)
); );
expect("start\n'start rule'\n=\n'abcd';").toParseAs( expect("start\n'start rule'\n=\n'abcd';").to.parseAs(
oneRuleGrammar(named) oneRuleGrammar(named)
); );
}); });
// Canonical Expression is "'abcd'". // Canonical Expression is "'abcd'".
it("parses Expression", function() { it("parses Expression", function() {
expect("start = 'abcd' / 'efgh' / 'ijkl'").toParseAs( expect("start = 'abcd' / 'efgh' / 'ijkl'").to.parseAs(
oneRuleGrammar(choice) oneRuleGrammar(choice)
); );
}); });
// Canonical ChoiceExpression is "'abcd' / 'efgh' / 'ijkl'". // Canonical ChoiceExpression is "'abcd' / 'efgh' / 'ijkl'".
it("parses ChoiceExpression", function() { it("parses ChoiceExpression", function() {
expect("start = 'abcd' { code }").toParseAs( expect("start = 'abcd' { code }").to.parseAs(
oneRuleGrammar(actionAbcd) oneRuleGrammar(actionAbcd)
); );
expect("start = 'abcd' { code }\n/\n'efgh' { code }").toParseAs( expect("start = 'abcd' { code }\n/\n'efgh' { code }").to.parseAs(
oneRuleGrammar(choice2) oneRuleGrammar(choice2)
); );
expect( expect(
"start = 'abcd' { code }\n/\n'efgh' { code }\n/\n'ijkl' { code }\n/\n'mnop' { code }" "start = 'abcd' { code }\n/\n'efgh' { code }\n/\n'ijkl' { code }\n/\n'mnop' { code }"
).toParseAs( ).to.parseAs(
oneRuleGrammar(choice4) oneRuleGrammar(choice4)
); );
}); });
// Canonical ActionExpression is "'abcd' { code }". // Canonical ActionExpression is "'abcd' { code }".
it("parses ActionExpression", function() { it("parses ActionExpression", function() {
expect("start = 'abcd' 'efgh' 'ijkl'").toParseAs( expect("start = 'abcd' 'efgh' 'ijkl'").to.parseAs(
oneRuleGrammar(sequence) oneRuleGrammar(sequence)
); );
expect("start = 'abcd' 'efgh' 'ijkl'\n{ code }").toParseAs( expect("start = 'abcd' 'efgh' 'ijkl'\n{ code }").to.parseAs(
oneRuleGrammar(actionSequence) oneRuleGrammar(actionSequence)
); );
}); });
// Canonical SequenceExpression is "'abcd' 'efgh' 'ijkl'". // Canonical SequenceExpression is "'abcd' 'efgh' 'ijkl'".
it("parses SequenceExpression", function() { it("parses SequenceExpression", function() {
expect("start = a:'abcd'").toParseAs( expect("start = a:'abcd'").to.parseAs(
oneRuleGrammar(labeledAbcd) oneRuleGrammar(labeledAbcd)
); );
expect("start = a:'abcd'\nb:'efgh'").toParseAs( expect("start = a:'abcd'\nb:'efgh'").to.parseAs(
oneRuleGrammar(sequence2) oneRuleGrammar(sequence2)
); );
expect("start = a:'abcd'\nb:'efgh'\nc:'ijkl'\nd:'mnop'").toParseAs( expect("start = a:'abcd'\nb:'efgh'\nc:'ijkl'\nd:'mnop'").to.parseAs(
oneRuleGrammar(sequence4) oneRuleGrammar(sequence4)
); );
}); });
// Canonical LabeledExpression is "a:'abcd'". // Canonical LabeledExpression is "a:'abcd'".
it("parses LabeledExpression", function() { it("parses LabeledExpression", function() {
expect("start = a\n:\n!'abcd'").toParseAs(oneRuleGrammar(labeledSimpleNot)); expect("start = a\n:\n!'abcd'").to.parseAs(oneRuleGrammar(labeledSimpleNot));
expect("start = !'abcd'").toParseAs(oneRuleGrammar(simpleNotAbcd)); expect("start = !'abcd'").to.parseAs(oneRuleGrammar(simpleNotAbcd));
}); });
// Canonical PrefixedExpression is "!'abcd'". // Canonical PrefixedExpression is "!'abcd'".
it("parses PrefixedExpression", function() { it("parses PrefixedExpression", function() {
expect("start = !\n'abcd'?").toParseAs(oneRuleGrammar(simpleNotOptional)); expect("start = !\n'abcd'?").to.parseAs(oneRuleGrammar(simpleNotOptional));
expect("start = 'abcd'?").toParseAs(oneRuleGrammar(optional)); expect("start = 'abcd'?").to.parseAs(oneRuleGrammar(optional));
}); });
// Canonical PrefixedOperator is "!". // Canonical PrefixedOperator is "!".
it("parses PrefixedOperator", function() { it("parses PrefixedOperator", function() {
expect("start = $'abcd'?").toParseAs(oneRuleGrammar(textOptional)); expect("start = $'abcd'?").to.parseAs(oneRuleGrammar(textOptional));
expect("start = &'abcd'?").toParseAs(oneRuleGrammar(simpleAndOptional)); expect("start = &'abcd'?").to.parseAs(oneRuleGrammar(simpleAndOptional));
expect("start = !'abcd'?").toParseAs(oneRuleGrammar(simpleNotOptional)); expect("start = !'abcd'?").to.parseAs(oneRuleGrammar(simpleNotOptional));
}); });
// Canonical SuffixedExpression is "'abcd'?". // Canonical SuffixedExpression is "'abcd'?".
it("parses SuffixedExpression", function() { it("parses SuffixedExpression", function() {
expect("start = 'abcd'\n?").toParseAs(oneRuleGrammar(optional)); expect("start = 'abcd'\n?").to.parseAs(oneRuleGrammar(optional));
expect("start = 'abcd'").toParseAs(oneRuleGrammar(literalAbcd)); expect("start = 'abcd'").to.parseAs(oneRuleGrammar(literalAbcd));
}); });
// Canonical SuffixedOperator is "?". // Canonical SuffixedOperator is "?".
it("parses SuffixedOperator", function() { it("parses SuffixedOperator", function() {
expect("start = 'abcd'?").toParseAs(oneRuleGrammar(optional)); expect("start = 'abcd'?").to.parseAs(oneRuleGrammar(optional));
expect("start = 'abcd'*").toParseAs(oneRuleGrammar(zeroOrMore)); expect("start = 'abcd'*").to.parseAs(oneRuleGrammar(zeroOrMore));
expect("start = 'abcd'+").toParseAs(oneRuleGrammar(oneOrMore)); expect("start = 'abcd'+").to.parseAs(oneRuleGrammar(oneOrMore));
}); });
// Canonical PrimaryExpression is "'abcd'". // Canonical PrimaryExpression is "'abcd'".
it("parses PrimaryExpression", function() { it("parses PrimaryExpression", function() {
expect("start = 'abcd'").toParseAs(trivialGrammar); expect("start = 'abcd'").to.parseAs(trivialGrammar);
expect("start = [a-d]").toParseAs(classGrammar([["a", "d"]], false, false)); expect("start = [a-d]").to.parseAs(classGrammar([["a", "d"]], false, false));
expect("start = .").toParseAs(anyGrammar()); expect("start = .").to.parseAs(anyGrammar());
expect("start = a").toParseAs(ruleRefGrammar("a")); expect("start = a").to.parseAs(ruleRefGrammar("a"));
expect("start = &{ code }").toParseAs(oneRuleGrammar(semanticAnd)); expect("start = &{ code }").to.parseAs(oneRuleGrammar(semanticAnd));
expect("start = (\na:'abcd'\n)").toParseAs(oneRuleGrammar(groupLabeled)); expect("start = (\na:'abcd'\n)").to.parseAs(oneRuleGrammar(groupLabeled));
expect("start = (\n'abcd' 'efgh' 'ijkl'\n)").toParseAs(oneRuleGrammar(groupSequence)); expect("start = (\n'abcd' 'efgh' 'ijkl'\n)").to.parseAs(oneRuleGrammar(groupSequence));
expect("start = (\n'abcd'\n)").toParseAs(trivialGrammar); expect("start = (\n'abcd'\n)").to.parseAs(trivialGrammar);
}); });
// Canonical RuleReferenceExpression is "a". // Canonical RuleReferenceExpression is "a".
it("parses RuleReferenceExpression", function() { it("parses RuleReferenceExpression", function() {
expect("start = a").toParseAs(ruleRefGrammar("a")); expect("start = a").to.parseAs(ruleRefGrammar("a"));
expect("start = a\n=").toFailToParse(); expect("start = a\n=").to.failToParse();
expect("start = a\n'abcd'\n=").toFailToParse(); expect("start = a\n'abcd'\n=").to.failToParse();
}); });
// Canonical SemanticPredicateExpression is "!{ code }". // Canonical SemanticPredicateExpression is "!{ code }".
it("parses SemanticPredicateExpression", function() { it("parses SemanticPredicateExpression", function() {
expect("start = !\n{ code }").toParseAs(oneRuleGrammar(semanticNot)); expect("start = !\n{ code }").to.parseAs(oneRuleGrammar(semanticNot));
}); });
// Canonical SemanticPredicateOperator is "!". // Canonical SemanticPredicateOperator is "!".
it("parses SemanticPredicateOperator", function() { it("parses SemanticPredicateOperator", function() {
expect("start = &{ code }").toParseAs(oneRuleGrammar(semanticAnd)); expect("start = &{ code }").to.parseAs(oneRuleGrammar(semanticAnd));
expect("start = !{ code }").toParseAs(oneRuleGrammar(semanticNot)); expect("start = !{ code }").to.parseAs(oneRuleGrammar(semanticNot));
}); });
// The SourceCharacter rule is not tested. // The SourceCharacter rule is not tested.
// Canonical WhiteSpace is " ". // Canonical WhiteSpace is " ".
it("parses WhiteSpace", function() { it("parses WhiteSpace", function() {
expect("start =\t'abcd'").toParseAs(trivialGrammar); expect("start =\t'abcd'").to.parseAs(trivialGrammar);
expect("start =\v'abcd'").toParseAs(trivialGrammar); expect("start =\v'abcd'").to.parseAs(trivialGrammar);
expect("start =\f'abcd'").toParseAs(trivialGrammar); expect("start =\f'abcd'").to.parseAs(trivialGrammar);
expect("start = 'abcd'").toParseAs(trivialGrammar); expect("start = 'abcd'").to.parseAs(trivialGrammar);
expect("start =\u00A0'abcd'").toParseAs(trivialGrammar); expect("start =\u00A0'abcd'").to.parseAs(trivialGrammar);
expect("start =\uFEFF'abcd'").toParseAs(trivialGrammar); expect("start =\uFEFF'abcd'").to.parseAs(trivialGrammar);
expect("start =\u1680'abcd'").toParseAs(trivialGrammar); expect("start =\u1680'abcd'").to.parseAs(trivialGrammar);
}); });
// Canonical LineTerminator is "\n". // Canonical LineTerminator is "\n".
it("parses LineTerminator", function() { it("parses LineTerminator", function() {
expect("start = '\n'").toFailToParse(); expect("start = '\n'").to.failToParse();
expect("start = '\r'").toFailToParse(); expect("start = '\r'").to.failToParse();
expect("start = '\u2028'").toFailToParse(); expect("start = '\u2028'").to.failToParse();
expect("start = '\u2029'").toFailToParse(); expect("start = '\u2029'").to.failToParse();
}); });
// Canonical LineTerminatorSequence is "\r\n". // Canonical LineTerminatorSequence is "\r\n".
it("parses LineTerminatorSequence", function() { it("parses LineTerminatorSequence", function() {
expect("start =\n'abcd'").toParseAs(trivialGrammar); expect("start =\n'abcd'").to.parseAs(trivialGrammar);
expect("start =\r\n'abcd'").toParseAs(trivialGrammar); expect("start =\r\n'abcd'").to.parseAs(trivialGrammar);
expect("start =\r'abcd'").toParseAs(trivialGrammar); expect("start =\r'abcd'").to.parseAs(trivialGrammar);
expect("start =\u2028'abcd'").toParseAs(trivialGrammar); expect("start =\u2028'abcd'").to.parseAs(trivialGrammar);
expect("start =\u2029'abcd'").toParseAs(trivialGrammar); expect("start =\u2029'abcd'").to.parseAs(trivialGrammar);
}); });
// Canonical Comment is "/* comment */". // Canonical Comment is "/* comment */".
it("parses Comment", function() { it("parses Comment", function() {
expect("start =// comment\n'abcd'").toParseAs(trivialGrammar); expect("start =// comment\n'abcd'").to.parseAs(trivialGrammar);
expect("start =/* comment */'abcd'").toParseAs(trivialGrammar); expect("start =/* comment */'abcd'").to.parseAs(trivialGrammar);
}); });
// Canonical MultiLineComment is "/* comment */". // Canonical MultiLineComment is "/* comment */".
it("parses MultiLineComment", function() { it("parses MultiLineComment", function() {
expect("start =/**/'abcd'").toParseAs(trivialGrammar); expect("start =/**/'abcd'").to.parseAs(trivialGrammar);
expect("start =/*a*/'abcd'").toParseAs(trivialGrammar); expect("start =/*a*/'abcd'").to.parseAs(trivialGrammar);
expect("start =/*abc*/'abcd'").toParseAs(trivialGrammar); expect("start =/*abc*/'abcd'").to.parseAs(trivialGrammar);
expect("start =/**/*/'abcd'").toFailToParse(); expect("start =/**/*/'abcd'").to.failToParse();
}); });
// Canonical MultiLineCommentNoLineTerminator is "/* comment */". // Canonical MultiLineCommentNoLineTerminator is "/* comment */".
it("parses MultiLineCommentNoLineTerminator", function() { it("parses MultiLineCommentNoLineTerminator", function() {
expect("a = 'abcd'/**/\r\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd'/**/\r\nb = 'efgh'").to.parseAs(twoRuleGrammar);
expect("a = 'abcd'/*a*/\r\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd'/*a*/\r\nb = 'efgh'").to.parseAs(twoRuleGrammar);
expect("a = 'abcd'/*abc*/\r\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd'/*abc*/\r\nb = 'efgh'").to.parseAs(twoRuleGrammar);
expect("a = 'abcd'/**/*/\r\nb = 'efgh'").toFailToParse(); expect("a = 'abcd'/**/*/\r\nb = 'efgh'").to.failToParse();
expect("a = 'abcd'/*\n*/\r\nb = 'efgh'").toFailToParse(); expect("a = 'abcd'/*\n*/\r\nb = 'efgh'").to.failToParse();
}); });
// Canonical SingleLineComment is "// comment". // Canonical SingleLineComment is "// comment".
it("parses SingleLineComment", function() { it("parses SingleLineComment", function() {
expect("start =//\n'abcd'").toParseAs(trivialGrammar); expect("start =//\n'abcd'").to.parseAs(trivialGrammar);
expect("start =//a\n'abcd'").toParseAs(trivialGrammar); expect("start =//a\n'abcd'").to.parseAs(trivialGrammar);
expect("start =//abc\n'abcd'").toParseAs(trivialGrammar); expect("start =//abc\n'abcd'").to.parseAs(trivialGrammar);
expect("start =//\n@\n'abcd'").toFailToParse(); expect("start =//\n@\n'abcd'").to.failToParse();
}); });
// Canonical Identifier is "a". // Canonical Identifier is "a".
it("parses Identifier", function() { it("parses Identifier", function() {
expect("start = a:'abcd'").toParseAs(oneRuleGrammar(labeledAbcd)); expect("start = a:'abcd'").to.parseAs(oneRuleGrammar(labeledAbcd));
}); });
// Canonical IdentifierName is "a". // Canonical IdentifierName is "a".
it("parses IdentifierName", function() { it("parses IdentifierName", function() {
expect("start = a").toParseAs(ruleRefGrammar("a")); expect("start = a").to.parseAs(ruleRefGrammar("a"));
expect("start = ab").toParseAs(ruleRefGrammar("ab")); expect("start = ab").to.parseAs(ruleRefGrammar("ab"));
expect("start = abcd").toParseAs(ruleRefGrammar("abcd")); expect("start = abcd").to.parseAs(ruleRefGrammar("abcd"));
}); });
// Canonical IdentifierStart is "a". // Canonical IdentifierStart is "a".
it("parses IdentifierStart", function() { it("parses IdentifierStart", function() {
expect("start = a").toParseAs(ruleRefGrammar("a")); expect("start = a").to.parseAs(ruleRefGrammar("a"));
expect("start = $").toParseAs(ruleRefGrammar("$")); expect("start = $").to.parseAs(ruleRefGrammar("$"));
expect("start = _").toParseAs(ruleRefGrammar("_")); expect("start = _").to.parseAs(ruleRefGrammar("_"));
expect("start = \\u0061").toParseAs(ruleRefGrammar("a")); expect("start = \\u0061").to.parseAs(ruleRefGrammar("a"));
}); });
// Canonical IdentifierPart is "a". // Canonical IdentifierPart is "a".
it("parses IdentifierPart", function() { it("parses IdentifierPart", function() {
expect("start = aa").toParseAs(ruleRefGrammar("aa")); expect("start = aa").to.parseAs(ruleRefGrammar("aa"));
expect("start = a\u0300").toParseAs(ruleRefGrammar("a\u0300")); expect("start = a\u0300").to.parseAs(ruleRefGrammar("a\u0300"));
expect("start = a0").toParseAs(ruleRefGrammar("a0")); expect("start = a0").to.parseAs(ruleRefGrammar("a0"));
expect("start = a\u203F").toParseAs(ruleRefGrammar("a\u203F")); expect("start = a\u203F").to.parseAs(ruleRefGrammar("a\u203F"));
expect("start = a\u200C").toParseAs(ruleRefGrammar("a\u200C")); expect("start = a\u200C").to.parseAs(ruleRefGrammar("a\u200C"));
expect("start = a\u200D").toParseAs(ruleRefGrammar("a\u200D")); expect("start = a\u200D").to.parseAs(ruleRefGrammar("a\u200D"));
}); });
// Unicode rules and reserved word rules are not tested. // Unicode rules and reserved word rules are not tested.
// Canonical LiteralMatcher is "'abcd'". // Canonical LiteralMatcher is "'abcd'".
it("parses LiteralMatcher", function() { it("parses LiteralMatcher", function() {
expect("start = 'abcd'").toParseAs(literalGrammar("abcd", false)); expect("start = 'abcd'").to.parseAs(literalGrammar("abcd", false));
expect("start = 'abcd'i").toParseAs(literalGrammar("abcd", true)); expect("start = 'abcd'i").to.parseAs(literalGrammar("abcd", true));
}); });
// Canonical StringLiteral is "'abcd'". // Canonical StringLiteral is "'abcd'".
it("parses StringLiteral", function() { it("parses StringLiteral", function() {
expect("start = \"\"").toParseAs(literalGrammar("", false)); expect("start = \"\"").to.parseAs(literalGrammar("", false));
expect("start = \"a\"").toParseAs(literalGrammar("a", false)); expect("start = \"a\"").to.parseAs(literalGrammar("a", false));
expect("start = \"abc\"").toParseAs(literalGrammar("abc", false)); expect("start = \"abc\"").to.parseAs(literalGrammar("abc", false));
expect("start = ''").toParseAs(literalGrammar("", false)); expect("start = ''").to.parseAs(literalGrammar("", false));
expect("start = 'a'").toParseAs(literalGrammar("a", false)); expect("start = 'a'").to.parseAs(literalGrammar("a", false));
expect("start = 'abc'").toParseAs(literalGrammar("abc", false)); expect("start = 'abc'").to.parseAs(literalGrammar("abc", false));
}); });
// Canonical DoubleStringCharacter is "a". // Canonical DoubleStringCharacter is "a".
it("parses DoubleStringCharacter", function() { it("parses DoubleStringCharacter", function() {
expect("start = \"a\"").toParseAs(literalGrammar("a", false)); expect("start = \"a\"").to.parseAs(literalGrammar("a", false));
expect("start = \"\\n\"").toParseAs(literalGrammar("\n", false)); expect("start = \"\\n\"").to.parseAs(literalGrammar("\n", false));
expect("start = \"\\\n\"").toParseAs(literalGrammar("", false)); expect("start = \"\\\n\"").to.parseAs(literalGrammar("", false));
expect("start = \"\"\"").toFailToParse(); expect("start = \"\"\"").to.failToParse();
expect("start = \"\\\"").toFailToParse(); expect("start = \"\\\"").to.failToParse();
expect("start = \"\n\"").toFailToParse(); expect("start = \"\n\"").to.failToParse();
}); });
// Canonical SingleStringCharacter is "a". // Canonical SingleStringCharacter is "a".
it("parses SingleStringCharacter", function() { it("parses SingleStringCharacter", function() {
expect("start = 'a'").toParseAs(literalGrammar("a", false)); expect("start = 'a'").to.parseAs(literalGrammar("a", false));
expect("start = '\\n'").toParseAs(literalGrammar("\n", false)); expect("start = '\\n'").to.parseAs(literalGrammar("\n", false));
expect("start = '\\\n'").toParseAs(literalGrammar("", false)); expect("start = '\\\n'").to.parseAs(literalGrammar("", false));
expect("start = '''").toFailToParse(); expect("start = '''").to.failToParse();
expect("start = '\\'").toFailToParse(); expect("start = '\\'").to.failToParse();
expect("start = '\n'").toFailToParse(); expect("start = '\n'").to.failToParse();
}); });
// Canonical CharacterClassMatcher is "[a-d]". // Canonical CharacterClassMatcher is "[a-d]".
it("parses CharacterClassMatcher", function() { it("parses CharacterClassMatcher", function() {
expect("start = []").toParseAs( expect("start = []").to.parseAs(
classGrammar([], false, false) classGrammar([], false, false)
); );
expect("start = [a-d]").toParseAs( expect("start = [a-d]").to.parseAs(
classGrammar([["a", "d"]], false, false) classGrammar([["a", "d"]], false, false)
); );
expect("start = [a]").toParseAs( expect("start = [a]").to.parseAs(
classGrammar(["a"], false, false) classGrammar(["a"], false, false)
); );
expect("start = [a-de-hi-l]").toParseAs( expect("start = [a-de-hi-l]").to.parseAs(
classGrammar( classGrammar(
[["a", "d"], ["e", "h"], ["i", "l"]], [["a", "d"], ["e", "h"], ["i", "l"]],
false, false,
false false
) )
); );
expect("start = [^a-d]").toParseAs( expect("start = [^a-d]").to.parseAs(
classGrammar([["a", "d"]], true, false) classGrammar([["a", "d"]], true, false)
); );
expect("start = [a-d]i").toParseAs( expect("start = [a-d]i").to.parseAs(
classGrammar([["a", "d"]], false, true) classGrammar([["a", "d"]], false, true)
); );
expect("start = [\\\n]").toParseAs( expect("start = [\\\n]").to.parseAs(
classGrammar([], false, false) classGrammar([], false, false)
); );
}); });
// Canonical ClassCharacterRange is "a-d". // Canonical ClassCharacterRange is "a-d".
it("parses ClassCharacterRange", function() { it("parses ClassCharacterRange", function() {
expect("start = [a-d]").toParseAs(classGrammar([["a", "d"]], false, false)); expect("start = [a-d]").to.parseAs(classGrammar([["a", "d"]], false, false));
expect("start = [a-a]").toParseAs(classGrammar([["a", "a"]], false, false)); expect("start = [a-a]").to.parseAs(classGrammar([["a", "a"]], false, false));
expect("start = [b-a]").toFailToParse({ expect("start = [b-a]").to.failToParse({
message: "Invalid character range: b-a." message: "Invalid character range: b-a."
}); });
}); });
// Canonical ClassCharacter is "a". // Canonical ClassCharacter is "a".
it("parses ClassCharacter", function() { it("parses ClassCharacter", function() {
expect("start = [a]").toParseAs(classGrammar(["a"], false, false)); expect("start = [a]").to.parseAs(classGrammar(["a"], false, false));
expect("start = [\\n]").toParseAs(classGrammar(["\n"], false, false)); expect("start = [\\n]").to.parseAs(classGrammar(["\n"], false, false));
expect("start = [\\\n]").toParseAs(classGrammar([], false, false)); expect("start = [\\\n]").to.parseAs(classGrammar([], false, false));
expect("start = []]").toFailToParse(); expect("start = []]").to.failToParse();
expect("start = [\\]").toFailToParse(); expect("start = [\\]").to.failToParse();
expect("start = [\n]").toFailToParse(); expect("start = [\n]").to.failToParse();
}); });
// Canonical LineContinuation is "\\\n". // Canonical LineContinuation is "\\\n".
it("parses LineContinuation", function() { it("parses LineContinuation", function() {
expect("start = '\\\r\n'").toParseAs(literalGrammar("", false)); expect("start = '\\\r\n'").to.parseAs(literalGrammar("", false));
}); });
// Canonical EscapeSequence is "n". // Canonical EscapeSequence is "n".
it("parses EscapeSequence", function() { it("parses EscapeSequence", function() {
expect("start = '\\n'").toParseAs(literalGrammar("\n", false)); expect("start = '\\n'").to.parseAs(literalGrammar("\n", false));
expect("start = '\\0'").toParseAs(literalGrammar("\x00", false)); expect("start = '\\0'").to.parseAs(literalGrammar("\x00", false));
expect("start = '\\xFF'").toParseAs(literalGrammar("\xFF", false)); expect("start = '\\xFF'").to.parseAs(literalGrammar("\xFF", false));
expect("start = '\\uFFFF'").toParseAs(literalGrammar("\uFFFF", false)); expect("start = '\\uFFFF'").to.parseAs(literalGrammar("\uFFFF", false));
expect("start = '\\09'").toFailToParse(); expect("start = '\\09'").to.failToParse();
}); });
// Canonical CharacterEscapeSequence is "n". // Canonical CharacterEscapeSequence is "n".
it("parses CharacterEscapeSequence", function() { it("parses CharacterEscapeSequence", function() {
expect("start = '\\n'").toParseAs(literalGrammar("\n", false)); expect("start = '\\n'").to.parseAs(literalGrammar("\n", false));
expect("start = '\\a'").toParseAs(literalGrammar("a", false)); expect("start = '\\a'").to.parseAs(literalGrammar("a", false));
}); });
// Canonical SingleEscapeCharacter is "n". // Canonical SingleEscapeCharacter is "n".
it("parses SingleEscapeCharacter", function() { it("parses SingleEscapeCharacter", function() {
expect("start = '\\''").toParseAs(literalGrammar("'", false)); expect("start = '\\''").to.parseAs(literalGrammar("'", false));
expect("start = '\\\"'").toParseAs(literalGrammar("\"", false)); expect("start = '\\\"'").to.parseAs(literalGrammar("\"", false));
expect("start = '\\\\'").toParseAs(literalGrammar("\\", false)); expect("start = '\\\\'").to.parseAs(literalGrammar("\\", false));
expect("start = '\\b'").toParseAs(literalGrammar("\b", false)); expect("start = '\\b'").to.parseAs(literalGrammar("\b", false));
expect("start = '\\f'").toParseAs(literalGrammar("\f", false)); expect("start = '\\f'").to.parseAs(literalGrammar("\f", false));
expect("start = '\\n'").toParseAs(literalGrammar("\n", false)); expect("start = '\\n'").to.parseAs(literalGrammar("\n", false));
expect("start = '\\r'").toParseAs(literalGrammar("\r", false)); expect("start = '\\r'").to.parseAs(literalGrammar("\r", false));
expect("start = '\\t'").toParseAs(literalGrammar("\t", false)); expect("start = '\\t'").to.parseAs(literalGrammar("\t", false));
expect("start = '\\v'").toParseAs(literalGrammar("\v", false)); expect("start = '\\v'").to.parseAs(literalGrammar("\v", false));
}); });
// Canonical NonEscapeCharacter is "a". // Canonical NonEscapeCharacter is "a".
it("parses NonEscapeCharacter", function() { it("parses NonEscapeCharacter", function() {
expect("start = '\\a'").toParseAs(literalGrammar("a", false)); expect("start = '\\a'").to.parseAs(literalGrammar("a", false));
// The negative predicate is impossible to test with PEG.js grammar // The negative predicate is impossible to test with PEG.js grammar
// structure. // structure.
@ -608,66 +595,66 @@ describe("PEG.js grammar parser", function() {
// Canonical HexEscapeSequence is "xFF". // Canonical HexEscapeSequence is "xFF".
it("parses HexEscapeSequence", function() { it("parses HexEscapeSequence", function() {
expect("start = '\\xFF'").toParseAs(literalGrammar("\xFF", false)); expect("start = '\\xFF'").to.parseAs(literalGrammar("\xFF", false));
}); });
// Canonical UnicodeEscapeSequence is "uFFFF". // Canonical UnicodeEscapeSequence is "uFFFF".
it("parses UnicodeEscapeSequence", function() { it("parses UnicodeEscapeSequence", function() {
expect("start = '\\uFFFF'").toParseAs(literalGrammar("\uFFFF", false)); expect("start = '\\uFFFF'").to.parseAs(literalGrammar("\uFFFF", false));
}); });
// Digit rules are not tested. // Digit rules are not tested.
// Canonical AnyMatcher is ".". // Canonical AnyMatcher is ".".
it("parses AnyMatcher", function() { it("parses AnyMatcher", function() {
expect("start = .").toParseAs(anyGrammar()); expect("start = .").to.parseAs(anyGrammar());
}); });
// Canonical CodeBlock is "{ code }". // Canonical CodeBlock is "{ code }".
it("parses CodeBlock", function() { it("parses CodeBlock", function() {
expect("start = 'abcd' { code }").toParseAs(actionGrammar(" code ")); expect("start = 'abcd' { code }").to.parseAs(actionGrammar(" code "));
}); });
// Canonical Code is " code ". // Canonical Code is " code ".
it("parses Code", function() { it("parses Code", function() {
expect("start = 'abcd' {a}").toParseAs(actionGrammar("a")); expect("start = 'abcd' {a}").to.parseAs(actionGrammar("a"));
expect("start = 'abcd' {abc}").toParseAs(actionGrammar("abc")); expect("start = 'abcd' {abc}").to.parseAs(actionGrammar("abc"));
expect("start = 'abcd' {{a}}").toParseAs(actionGrammar("{a}")); expect("start = 'abcd' {{a}}").to.parseAs(actionGrammar("{a}"));
expect("start = 'abcd' {{a}{b}{c}}").toParseAs(actionGrammar("{a}{b}{c}")); expect("start = 'abcd' {{a}{b}{c}}").to.parseAs(actionGrammar("{a}{b}{c}"));
expect("start = 'abcd' {{}").toFailToParse(); expect("start = 'abcd' {{}").to.failToParse();
expect("start = 'abcd' {}}").toFailToParse(); expect("start = 'abcd' {}}").to.failToParse();
}); });
// Unicode character category rules and token rules are not tested. // Unicode character category rules and token rules are not tested.
// Canonical __ is "\n". // Canonical __ is "\n".
it("parses __", function() { it("parses __", function() {
expect("start ='abcd'").toParseAs(trivialGrammar); expect("start ='abcd'").to.parseAs(trivialGrammar);
expect("start = 'abcd'").toParseAs(trivialGrammar); expect("start = 'abcd'").to.parseAs(trivialGrammar);
expect("start =\r\n'abcd'").toParseAs(trivialGrammar); expect("start =\r\n'abcd'").to.parseAs(trivialGrammar);
expect("start =/* comment */'abcd'").toParseAs(trivialGrammar); expect("start =/* comment */'abcd'").to.parseAs(trivialGrammar);
expect("start = 'abcd'").toParseAs(trivialGrammar); expect("start = 'abcd'").to.parseAs(trivialGrammar);
}); });
// Canonical _ is " ". // Canonical _ is " ".
it("parses _", function() { it("parses _", function() {
expect("a = 'abcd'\r\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd'\r\nb = 'efgh'").to.parseAs(twoRuleGrammar);
expect("a = 'abcd' \r\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd' \r\nb = 'efgh'").to.parseAs(twoRuleGrammar);
expect("a = 'abcd'/* comment */\r\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd'/* comment */\r\nb = 'efgh'").to.parseAs(twoRuleGrammar);
expect("a = 'abcd' \r\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd' \r\nb = 'efgh'").to.parseAs(twoRuleGrammar);
}); });
// Canonical EOS is ";". // Canonical EOS is ";".
it("parses EOS", function() { it("parses EOS", function() {
expect("a = 'abcd'\n;b = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd'\n;b = 'efgh'").to.parseAs(twoRuleGrammar);
expect("a = 'abcd' \r\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd' \r\nb = 'efgh'").to.parseAs(twoRuleGrammar);
expect("a = 'abcd' // comment\r\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd' // comment\r\nb = 'efgh'").to.parseAs(twoRuleGrammar);
expect("a = 'abcd'\nb = 'efgh'").toParseAs(twoRuleGrammar); expect("a = 'abcd'\nb = 'efgh'").to.parseAs(twoRuleGrammar);
}); });
// Canonical EOF is the end of input. // Canonical EOF is the end of input.
it("parses EOF", function() { it("parses EOF", function() {
expect("start = 'abcd'\n").toParseAs(trivialGrammar); expect("start = 'abcd'\n").to.parseAs(trivialGrammar);
}); });
}); });

@ -1,681 +0,0 @@
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);
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);
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);
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);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);
/* @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;
};

@ -1,82 +0,0 @@
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 .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; }
#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; }

File diff suppressed because it is too large Load Diff

@ -1,8 +1,10 @@
Copyright (c) 2008-2011 Pivotal Labs (The MIT License)
Copyright (c) 2016 JS Foundation and contributors, https://js.foundation
Permission is hereby granted, free of charge, to any person obtaining Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including 'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to permit persons to whom the Software is furnished to do so, subject to
@ -11,10 +13,10 @@ the following conditions:
The above copyright notice and this permission notice shall be The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software. included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -0,0 +1,326 @@
@charset "utf-8";
body {
margin:0;
}
#mocha {
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 60px 50px;
}
#mocha ul,
#mocha li {
margin: 0;
padding: 0;
}
#mocha ul {
list-style: none;
}
#mocha h1,
#mocha h2 {
margin: 0;
}
#mocha h1 {
margin-top: 15px;
font-size: 1em;
font-weight: 200;
}
#mocha h1 a {
text-decoration: none;
color: inherit;
}
#mocha h1 a:hover {
text-decoration: underline;
}
#mocha .suite .suite h1 {
margin-top: 0;
font-size: .8em;
}
#mocha .hidden {
display: none;
}
#mocha h2 {
font-size: 12px;
font-weight: normal;
cursor: pointer;
}
#mocha .suite {
margin-left: 15px;
}
#mocha .test {
margin-left: 15px;
overflow: hidden;
}
#mocha .test.pending:hover h2::after {
content: '(pending)';
font-family: arial, sans-serif;
}
#mocha .test.pass.medium .duration {
background: #c09853;
}
#mocha .test.pass.slow .duration {
background: #b94a48;
}
#mocha .test.pass::before {
content: '✓';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #00d6b2;
}
#mocha .test.pass .duration {
font-size: 9px;
margin-left: 5px;
padding: 2px 5px;
color: #fff;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
}
#mocha .test.pass.fast .duration {
display: none;
}
#mocha .test.pending {
color: #0b97c4;
}
#mocha .test.pending::before {
content: '◦';
color: #0b97c4;
}
#mocha .test.fail {
color: #c00;
}
#mocha .test.fail pre {
color: black;
}
#mocha .test.fail::before {
content: '✖';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #c00;
}
#mocha .test pre.error {
color: #c00;
max-height: 300px;
overflow: auto;
}
#mocha .test .html-error {
overflow: auto;
color: black;
line-height: 1.5;
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: -webkit-calc(100% - 42px);
max-width: -moz-calc(100% - 42px);
max-width: calc(100% - 42px); /*(2)*/
max-height: 300px;
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-box-shadow: 0 1px 3px #eee;
box-shadow: 0 1px 3px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
#mocha .test .html-error pre.error {
border: none;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: 0;
-moz-box-shadow: 0;
box-shadow: 0;
padding: 0;
margin: 0;
margin-top: 18px;
max-height: none;
}
/**
* (1): approximate for browsers not supporting calc
* (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
* ^^ seriously
*/
#mocha .test pre {
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: -webkit-calc(100% - 42px);
max-width: -moz-calc(100% - 42px);
max-width: calc(100% - 42px); /*(2)*/
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-box-shadow: 0 1px 3px #eee;
box-shadow: 0 1px 3px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
}
#mocha .test h2 {
position: relative;
}
#mocha .test a.replay {
position: absolute;
top: 3px;
right: 0;
text-decoration: none;
vertical-align: middle;
display: block;
width: 15px;
height: 15px;
line-height: 15px;
text-align: center;
background: #eee;
font-size: 15px;
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
-webkit-transition:opacity 200ms;
-moz-transition:opacity 200ms;
-o-transition:opacity 200ms;
transition: opacity 200ms;
opacity: 0.3;
color: #888;
}
#mocha .test:hover a.replay {
opacity: 1;
}
#mocha-report.pass .test.fail {
display: none;
}
#mocha-report.fail .test.pass {
display: none;
}
#mocha-report.pending .test.pass,
#mocha-report.pending .test.fail {
display: none;
}
#mocha-report.pending .test.pass.pending {
display: block;
}
#mocha-error {
color: #c00;
font-size: 1.5em;
font-weight: 100;
letter-spacing: 1px;
}
#mocha-stats {
position: fixed;
top: 15px;
right: 10px;
font-size: 12px;
margin: 0;
color: #888;
z-index: 1;
}
#mocha-stats .progress {
float: right;
padding-top: 0;
/**
* Set safe initial values, so mochas .progress does not inherit these
* properties from Bootstrap .progress (which causes .progress height to
* equal line height set in Bootstrap).
*/
height: auto;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
background-color: initial;
}
#mocha-stats em {
color: black;
}
#mocha-stats a {
text-decoration: none;
color: inherit;
}
#mocha-stats a:hover {
border-bottom: 1px solid #eee;
}
#mocha-stats li {
display: inline-block;
margin: 0 5px;
list-style: none;
padding-top: 11px;
}
#mocha-stats canvas {
width: 40px;
height: 40px;
}
#mocha code .comment { color: #ddd; }
#mocha code .init { color: #2f6fad; }
#mocha code .string { color: #5890ad; }
#mocha code .keyword { color: #8a6343; }
#mocha code .number { color: #2f6fad; }
@media screen and (max-device-width: 480px) {
#mocha {
margin: 60px 0px;
}
#mocha #stats {
position: absolute;
}
}

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save