michael@0: /* michael@0: * Copyright 2013 Mozilla Foundation and contributors michael@0: * Licensed under the New BSD license. See LICENSE.md or: michael@0: * http://opensource.org/licenses/BSD-2-Clause michael@0: */ michael@0: var prettyFast = this.prettyFast || require("./pretty-fast"); michael@0: michael@0: var testCases = [ michael@0: michael@0: { michael@0: name: "Simple function", michael@0: input: "function foo() { bar(); }", michael@0: output: "function foo() {\n" + michael@0: " bar();\n" + michael@0: "}\n", michael@0: mappings: [ michael@0: // function foo() { michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 1 michael@0: }, michael@0: // bar(); michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 2 michael@0: }, michael@0: // } michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 3 michael@0: }, michael@0: ] michael@0: }, michael@0: michael@0: { michael@0: name: "Nested function", michael@0: input: "function foo() { function bar() { debugger; } bar(); }", michael@0: output: "function foo() {\n" + michael@0: " function bar() {\n" + michael@0: " debugger;\n" + michael@0: " }\n" + michael@0: " bar();\n" + michael@0: "}\n", michael@0: mappings: [ michael@0: // function bar() { michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 2 michael@0: }, michael@0: // debugger; michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 3 michael@0: }, michael@0: // bar(); michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 5 michael@0: }, michael@0: ] michael@0: }, michael@0: michael@0: { michael@0: name: "Immediately invoked function expression", michael@0: input: "(function(){thingy()}())", michael@0: output: "(function () {\n" + michael@0: " thingy()\n" + michael@0: "}())\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Single line comment", michael@0: input: "// Comment\n" + michael@0: "function foo() { bar(); }\n", michael@0: output: "// Comment\n" + michael@0: "function foo() {\n" + michael@0: " bar();\n" + michael@0: "}\n", michael@0: mappings: [ michael@0: // // Comment michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 1 michael@0: } michael@0: ] michael@0: }, michael@0: michael@0: { michael@0: name: "Multi line comment", michael@0: input: "/* Comment\n" + michael@0: "more comment */\n" + michael@0: "function foo() { bar(); }\n", michael@0: output: "/* Comment\n" + michael@0: "more comment */\n" + michael@0: "function foo() {\n" + michael@0: " bar();\n" + michael@0: "}\n", michael@0: mappings: [ michael@0: // /* Comment michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 1 michael@0: }, michael@0: // \nmore comment */ michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 2 michael@0: } michael@0: ] michael@0: }, michael@0: michael@0: { michael@0: name: "Null assignment", michael@0: input: "var i=null;\n", michael@0: output: "var i = null;\n", michael@0: mappings: [ michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 1 michael@0: } michael@0: ] michael@0: }, michael@0: michael@0: { michael@0: name: "Undefined assignment", michael@0: input: "var i=undefined;\n", michael@0: output: "var i = undefined;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Void 0 assignment", michael@0: input: "var i=void 0;\n", michael@0: output: "var i = void 0;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "This property access", michael@0: input: "var foo=this.foo;\n", michael@0: output: "var foo = this.foo;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "True assignment", michael@0: input: "var foo=true;\n", michael@0: output: "var foo = true;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "False assignment", michael@0: input: "var foo=false;\n", michael@0: output: "var foo = false;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "For loop", michael@0: input: "for (var i = 0; i < n; i++) { console.log(i); }", michael@0: output: "for (var i = 0; i < n; i++) {\n" + michael@0: " console.log(i);\n" + michael@0: "}\n", michael@0: mappings: [ michael@0: // for (var i = 0; i < n; i++) { michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 1 michael@0: }, michael@0: // console.log(i); michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 2 michael@0: }, michael@0: ] michael@0: }, michael@0: michael@0: { michael@0: name: "String with semicolon", michael@0: input: "var foo = ';';\n", michael@0: output: "var foo = ';';\n" michael@0: }, michael@0: michael@0: { michael@0: name: "String with quote", michael@0: input: "var foo = \"'\";\n", michael@0: output: "var foo = '\\'';\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Function calls", michael@0: input: "var result=func(a,b,c,d);", michael@0: output: "var result = func(a, b, c, d);\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Regexp", michael@0: input: "var r=/foobar/g;", michael@0: output: "var r = /foobar/g;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "In operator", michael@0: input: "if(foo in bar){doThing()}", michael@0: output: "if (foo in bar) {\n" + michael@0: " doThing()\n" + michael@0: "}\n" michael@0: }, michael@0: michael@0: { michael@0: name: "With statement", michael@0: input: "with(obj){crock()}", michael@0: output: "with (obj) {\n" + michael@0: " crock()\n" + michael@0: "}\n" michael@0: }, michael@0: michael@0: { michael@0: name: "New expression", michael@0: input: "var foo=new Foo();", michael@0: output: "var foo = new Foo();\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Continue/break statements", michael@0: input: "while(1){if(x){continue}if(y){break}if(z){break foo}}", michael@0: output: "while (1) {\n" + michael@0: " if (x) {\n" + michael@0: " continue\n" + michael@0: " }\n" + michael@0: " if (y) {\n" + michael@0: " break\n" + michael@0: " }\n" + michael@0: " if (z) {\n" + michael@0: " break foo\n" + michael@0: " }\n" + michael@0: "}\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Instanceof", michael@0: input: "var a=x instanceof y;", michael@0: output: "var a = x instanceof y;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Binary operators", michael@0: input: "var a=5*30;var b=5>>3;", michael@0: output: "var a = 5 * 30;\n" + michael@0: "var b = 5 >> 3;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Delete", michael@0: input: "delete obj.prop;", michael@0: output: "delete obj.prop;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Try/catch/finally statement", michael@0: input: "try{dangerous()}catch(e){handle(e)}finally{cleanup()}", michael@0: output: "try {\n" + michael@0: " dangerous()\n" + michael@0: "} catch (e) {\n" + michael@0: " handle(e)\n" + michael@0: "} finally {\n" + michael@0: " cleanup()\n" + michael@0: "}\n" michael@0: }, michael@0: michael@0: { michael@0: name: "If/else statement", michael@0: input: "if(c){then()}else{other()}", michael@0: output: "if (c) {\n" + michael@0: " then()\n" + michael@0: "} else {\n" + michael@0: " other()\n" + michael@0: "}\n" michael@0: }, michael@0: michael@0: { michael@0: name: "If/else without curlies", michael@0: input: "if(c) a else b", michael@0: output: "if (c) a else b\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Objects", michael@0: input: "var o={a:1,\n" + michael@0: " b:2};", michael@0: output: "var o = {\n" + michael@0: " a: 1,\n" + michael@0: " b: 2\n" + michael@0: "};\n", michael@0: mappings: [ michael@0: // a: 1, michael@0: { michael@0: inputLine: 1, michael@0: outputLine: 2 michael@0: }, michael@0: // b: 2 michael@0: { michael@0: inputLine: 2, michael@0: outputLine: 3 michael@0: }, michael@0: ] michael@0: }, michael@0: michael@0: { michael@0: name: "Do/while loop", michael@0: input: "do{x}while(y)", michael@0: output: "do {\n" + michael@0: " x\n" + michael@0: "} while (y)\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Arrays", michael@0: input: "var a=[1,2,3];", michael@0: output: "var a = [\n" + michael@0: " 1,\n" + michael@0: " 2,\n" + michael@0: " 3\n" + michael@0: "];\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Code that relies on ASI", michael@0: input: "var foo = 10\n" + michael@0: "var bar = 20\n" + michael@0: "function g() {\n" + michael@0: " a()\n" + michael@0: " b()\n" + michael@0: "}", michael@0: output: "var foo = 10\n" + michael@0: "var bar = 20\n" + michael@0: "function g() {\n" + michael@0: " a()\n" + michael@0: " b()\n" + michael@0: "}\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Ternary operator", michael@0: input: "bar?baz:bang;", michael@0: output: "bar ? baz : bang;\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Switch statements", michael@0: input: "switch(x){case a:foo();break;default:bar()}", michael@0: output: "switch (x) {\n" + michael@0: "case a:\n" + michael@0: " foo();\n" + michael@0: " break;\n" + michael@0: "default:\n" + michael@0: " bar()\n" + michael@0: "}\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Multiple single line comments", michael@0: input: "function f() {\n" + michael@0: " // a\n" + michael@0: " // b\n" + michael@0: " // c\n" + michael@0: "}\n", michael@0: output: "function f() {\n" + michael@0: " // a\n" + michael@0: " // b\n" + michael@0: " // c\n" + michael@0: "}\n", michael@0: }, michael@0: michael@0: { michael@0: name: "Indented multiline comment", michael@0: input: "function foo() {\n" + michael@0: " /**\n" + michael@0: " * java doc style comment\n" + michael@0: " * more comment\n" + michael@0: " */\n" + michael@0: " bar();\n" + michael@0: "}\n", michael@0: output: "function foo() {\n" + michael@0: " /**\n" + michael@0: " * java doc style comment\n" + michael@0: " * more comment\n" + michael@0: " */\n" + michael@0: " bar();\n" + michael@0: "}\n", michael@0: }, michael@0: michael@0: { michael@0: name: "ASI return", michael@0: input: "function f() {\n" + michael@0: " return\n" + michael@0: " {}\n" + michael@0: "}\n", michael@0: output: "function f() {\n" + michael@0: " return\n" + michael@0: " {\n" + michael@0: " }\n" + michael@0: "}\n", michael@0: }, michael@0: michael@0: { michael@0: name: "Non-ASI property access", michael@0: input: "[1,2,3]\n" + michael@0: "[0]", michael@0: output: "[\n" + michael@0: " 1,\n" + michael@0: " 2,\n" + michael@0: " 3\n" + michael@0: "]\n" + michael@0: "[0]\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Non-ASI in", michael@0: input: "'x'\n" + michael@0: "in foo", michael@0: output: "'x' in foo\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Non-ASI function call", michael@0: input: "f\n" + michael@0: "()", michael@0: output: "f()\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Non-ASI new", michael@0: input: "new\n" + michael@0: "F()", michael@0: output: "new F()\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Getter and setter literals", michael@0: input: "var obj={get foo(){return this._foo},set foo(v){this._foo=v}}", michael@0: output: "var obj = {\n" + michael@0: " get foo() {\n" + michael@0: " return this._foo\n" + michael@0: " },\n" + michael@0: " set foo(v) {\n" + michael@0: " this._foo = v\n" + michael@0: " }\n" + michael@0: "}\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Escaping backslashes in strings", michael@0: input: "'\\\\'\n", michael@0: output: "'\\\\'\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Escaping carriage return in strings", michael@0: input: "'\\r'\n", michael@0: output: "'\\r'\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Escaping tab in strings", michael@0: input: "'\\t'\n", michael@0: output: "'\\t'\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Escaping vertical tab in strings", michael@0: input: "'\\v'\n", michael@0: output: "'\\v'\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Escaping form feed in strings", michael@0: input: "'\\f'\n", michael@0: output: "'\\f'\n" michael@0: }, michael@0: michael@0: { michael@0: name: "Escaping null character in strings", michael@0: input: "'\\0'\n", michael@0: output: "'\\0'\n" michael@0: }, michael@0: michael@0: ]; michael@0: michael@0: var sourceMap = this.sourceMap || require("source-map"); michael@0: michael@0: function run_test() { michael@0: testCases.forEach(function (test) { michael@0: console.log(test.name); michael@0: michael@0: var actual = prettyFast(test.input, { michael@0: indent: " ", michael@0: url: "test.js" michael@0: }); michael@0: michael@0: if (actual.code !== test.output) { michael@0: throw new Error("Expected:\n" + test.output michael@0: + "\nGot:\n" + actual.code); michael@0: } michael@0: michael@0: if (test.mappings) { michael@0: var smc = new sourceMap.SourceMapConsumer(actual.map.toJSON()); michael@0: test.mappings.forEach(function (m) { michael@0: var query = { line: m.outputLine, column: 0 }; michael@0: var original = smc.originalPositionFor(query); michael@0: if (original.line != m.inputLine) { michael@0: throw new Error("Querying:\n" + JSON.stringify(query, null, 2) + "\n" michael@0: + "Expected line:\n" + m.inputLine + "\n" michael@0: + "Got:\n" + JSON.stringify(original, null, 2)); michael@0: } michael@0: }); michael@0: } michael@0: }); michael@0: console.log("✓ All tests pass!"); michael@0: } michael@0: michael@0: // Only run the tests if this is node and we are running this file michael@0: // directly. (Firefox's test runner will import this test file, and then call michael@0: // run_test itself.) michael@0: if (typeof require == "function" && typeof module == "object" michael@0: && require.main === module) { michael@0: run_test(); michael@0: }