summaryrefslogtreecommitdiffstats
path: root/devtools/shared/pretty-fast/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/pretty-fast/tests/unit')
-rw-r--r--devtools/shared/pretty-fast/tests/unit/head_pretty-fast.js49
-rw-r--r--devtools/shared/pretty-fast/tests/unit/test.js572
-rw-r--r--devtools/shared/pretty-fast/tests/unit/xpcshell.ini8
3 files changed, 629 insertions, 0 deletions
diff --git a/devtools/shared/pretty-fast/tests/unit/head_pretty-fast.js b/devtools/shared/pretty-fast/tests/unit/head_pretty-fast.js
new file mode 100644
index 000000000..abde4b197
--- /dev/null
+++ b/devtools/shared/pretty-fast/tests/unit/head_pretty-fast.js
@@ -0,0 +1,49 @@
+"use strict";
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cu = Components.utils;
+var Cr = Components.results;
+
+const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {});
+
+this.sourceMap = require("source-map");
+this.acorn = require("acorn/acorn");
+this.prettyFast = require("devtools/shared/pretty-fast/pretty-fast");
+const { console } = Cu.import("resource://gre/modules/Console.jsm", {});
+
+// Register a console listener, so console messages don't just disappear
+// into the ether.
+var errorCount = 0;
+var listener = {
+ observe: function (aMessage) {
+ errorCount++;
+ try {
+ // If we've been given an nsIScriptError, then we can print out
+ // something nicely formatted, for tools like Emacs to pick up.
+ var scriptError = aMessage.QueryInterface(Ci.nsIScriptError);
+ dump(aMessage.sourceName + ":" + aMessage.lineNumber + ": " +
+ scriptErrorFlagsToKind(aMessage.flags) + ": " +
+ aMessage.errorMessage + "\n");
+ var string = aMessage.errorMessage;
+ } catch (x) {
+ // Be a little paranoid with message, as the whole goal here is to lose
+ // no information.
+ try {
+ var string = "" + aMessage.message;
+ } catch (x) {
+ var string = "<error converting error message to string>";
+ }
+ }
+
+ // Ignored until they are fixed in bug 1242968.
+ if (string.includes("JavaScript Warning")) {
+ return;
+ }
+
+ do_throw("head_pretty-fast.js got console message: " + string + "\n");
+ }
+};
+
+var consoleService = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
+consoleService.registerListener(listener);
+
diff --git a/devtools/shared/pretty-fast/tests/unit/test.js b/devtools/shared/pretty-fast/tests/unit/test.js
new file mode 100644
index 000000000..b462726a2
--- /dev/null
+++ b/devtools/shared/pretty-fast/tests/unit/test.js
@@ -0,0 +1,572 @@
+/* -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2; fill-column: 80 -*- */
+
+"use strict";
+
+/*
+ * Copyright 2013 Mozilla Foundation and contributors
+ * Licensed under the New BSD license. See LICENSE.md or:
+ * http://opensource.org/licenses/BSD-2-Clause
+ */
+var prettyFast = this.prettyFast || require("./pretty-fast");
+
+var testCases = [
+
+ {
+ name: "Simple function",
+ input: "function foo() { bar(); }",
+ output: "function foo() {\n" +
+ " bar();\n" +
+ "}\n",
+ mappings: [
+ // function foo() {
+ {
+ inputLine: 1,
+ outputLine: 1
+ },
+ // bar();
+ {
+ inputLine: 1,
+ outputLine: 2
+ },
+ // }
+ {
+ inputLine: 1,
+ outputLine: 3
+ },
+ ]
+ },
+
+ {
+ name: "Nested function",
+ input: "function foo() { function bar() { debugger; } bar(); }",
+ output: "function foo() {\n" +
+ " function bar() {\n" +
+ " debugger;\n" +
+ " }\n" +
+ " bar();\n" +
+ "}\n",
+ mappings: [
+ // function bar() {
+ {
+ inputLine: 1,
+ outputLine: 2
+ },
+ // debugger;
+ {
+ inputLine: 1,
+ outputLine: 3
+ },
+ // bar();
+ {
+ inputLine: 1,
+ outputLine: 5
+ },
+ ]
+ },
+
+ {
+ name: "Immediately invoked function expression",
+ input: "(function(){thingy()}())",
+ output: "(function () {\n" +
+ " thingy()\n" +
+ "}())\n"
+ },
+
+ {
+ name: "Single line comment",
+ input: "// Comment\n" +
+ "function foo() { bar(); }\n",
+ output: "// Comment\n" +
+ "function foo() {\n" +
+ " bar();\n" +
+ "}\n",
+ mappings: [
+ // // Comment
+ {
+ inputLine: 1,
+ outputLine: 1
+ }
+ ]
+ },
+
+ {
+ name: "Multi line comment",
+ input: "/* Comment\n" +
+ "more comment */\n" +
+ "function foo() { bar(); }\n",
+ output: "/* Comment\n" +
+ "more comment */\n" +
+ "function foo() {\n" +
+ " bar();\n" +
+ "}\n",
+ mappings: [
+ // /* Comment
+ {
+ inputLine: 1,
+ outputLine: 1
+ },
+ // \nmore comment */
+ {
+ inputLine: 1,
+ outputLine: 2
+ }
+ ]
+ },
+
+ {
+ name: "Null assignment",
+ input: "var i=null;\n",
+ output: "var i = null;\n",
+ mappings: [
+ {
+ inputLine: 1,
+ outputLine: 1
+ }
+ ]
+ },
+
+ {
+ name: "Undefined assignment",
+ input: "var i=undefined;\n",
+ output: "var i = undefined;\n"
+ },
+
+ {
+ name: "Void 0 assignment",
+ input: "var i=void 0;\n",
+ output: "var i = void 0;\n"
+ },
+
+ {
+ name: "This property access",
+ input: "var foo=this.foo;\n",
+ output: "var foo = this.foo;\n"
+ },
+
+ {
+ name: "True assignment",
+ input: "var foo=true;\n",
+ output: "var foo = true;\n"
+ },
+
+ {
+ name: "False assignment",
+ input: "var foo=false;\n",
+ output: "var foo = false;\n"
+ },
+
+ {
+ name: "For loop",
+ input: "for (var i = 0; i < n; i++) { console.log(i); }",
+ output: "for (var i = 0; i < n; i++) {\n" +
+ " console.log(i);\n" +
+ "}\n",
+ mappings: [
+ // for (var i = 0; i < n; i++) {
+ {
+ inputLine: 1,
+ outputLine: 1
+ },
+ // console.log(i);
+ {
+ inputLine: 1,
+ outputLine: 2
+ },
+ ]
+ },
+
+ {
+ name: "String with semicolon",
+ input: "var foo = ';';\n",
+ output: "var foo = ';';\n"
+ },
+
+ {
+ name: "String with quote",
+ input: "var foo = \"'\";\n",
+ output: "var foo = '\\'';\n"
+ },
+
+ {
+ name: "Function calls",
+ input: "var result=func(a,b,c,d);",
+ output: "var result = func(a, b, c, d);\n"
+ },
+
+ {
+ name: "Regexp",
+ input: "var r=/foobar/g;",
+ output: "var r = /foobar/g;\n"
+ },
+
+ {
+ name: "In operator",
+ input: "if(foo in bar){doThing()}",
+ output: "if (foo in bar) {\n" +
+ " doThing()\n" +
+ "}\n"
+ },
+
+ {
+ name: "With statement",
+ input: "with(obj){crock()}",
+ output: "with (obj) {\n" +
+ " crock()\n" +
+ "}\n"
+ },
+
+ {
+ name: "New expression",
+ input: "var foo=new Foo();",
+ output: "var foo = new Foo();\n"
+ },
+
+ {
+ name: "Continue/break statements",
+ input: "while(1){if(x){continue}if(y){break}if(z){break foo}}",
+ output: "while (1) {\n" +
+ " if (x) {\n" +
+ " continue\n" +
+ " }\n" +
+ " if (y) {\n" +
+ " break\n" +
+ " }\n" +
+ " if (z) {\n" +
+ " break foo\n" +
+ " }\n" +
+ "}\n"
+ },
+
+ {
+ name: "Instanceof",
+ input: "var a=x instanceof y;",
+ output: "var a = x instanceof y;\n"
+ },
+
+ {
+ name: "Binary operators",
+ input: "var a=5*30;var b=5>>3;",
+ output: "var a = 5 * 30;\n" +
+ "var b = 5 >> 3;\n"
+ },
+
+ {
+ name: "Delete",
+ input: "delete obj.prop;",
+ output: "delete obj.prop;\n"
+ },
+
+ {
+ name: "Try/catch/finally statement",
+ input: "try{dangerous()}catch(e){handle(e)}finally{cleanup()}",
+ output: "try {\n" +
+ " dangerous()\n" +
+ "} catch (e) {\n" +
+ " handle(e)\n" +
+ "} finally {\n" +
+ " cleanup()\n" +
+ "}\n"
+ },
+
+ {
+ name: "If/else statement",
+ input: "if(c){then()}else{other()}",
+ output: "if (c) {\n" +
+ " then()\n" +
+ "} else {\n" +
+ " other()\n" +
+ "}\n"
+ },
+
+ {
+ name: "If/else without curlies",
+ input: "if(c) a else b",
+ output: "if (c) a else b\n"
+ },
+
+ {
+ name: "Objects",
+ input: "var o={a:1,\n" +
+ " b:2};",
+ output: "var o = {\n" +
+ " a: 1,\n" +
+ " b: 2\n" +
+ "};\n",
+ mappings: [
+ // a: 1,
+ {
+ inputLine: 1,
+ outputLine: 2
+ },
+ // b: 2
+ {
+ inputLine: 2,
+ outputLine: 3
+ },
+ ]
+ },
+
+ {
+ name: "Do/while loop",
+ input: "do{x}while(y)",
+ output: "do {\n" +
+ " x\n" +
+ "} while (y)\n"
+ },
+
+ {
+ name: "Arrays",
+ input: "var a=[1,2,3];",
+ output: "var a = [\n" +
+ " 1,\n" +
+ " 2,\n" +
+ " 3\n" +
+ "];\n"
+ },
+
+ {
+ name: "Code that relies on ASI",
+ input: "var foo = 10\n" +
+ "var bar = 20\n" +
+ "function g() {\n" +
+ " a()\n" +
+ " b()\n" +
+ "}",
+ output: "var foo = 10\n" +
+ "var bar = 20\n" +
+ "function g() {\n" +
+ " a()\n" +
+ " b()\n" +
+ "}\n"
+ },
+
+ {
+ name: "Ternary operator",
+ input: "bar?baz:bang;",
+ output: "bar ? baz : bang;\n"
+ },
+
+ {
+ name: "Switch statements",
+ input: "switch(x){case a:foo();break;default:bar()}",
+ output: "switch (x) {\n" +
+ " case a:\n" +
+ " foo();\n" +
+ " break;\n" +
+ " default:\n" +
+ " bar()\n" +
+ "}\n"
+ },
+
+ {
+ name: "Multiple single line comments",
+ input: "function f() {\n" +
+ " // a\n" +
+ " // b\n" +
+ " // c\n" +
+ "}\n",
+ output: "function f() {\n" +
+ " // a\n" +
+ " // b\n" +
+ " // c\n" +
+ "}\n",
+ },
+
+ {
+ name: "Indented multiline comment",
+ input: "function foo() {\n" +
+ " /**\n" +
+ " * java doc style comment\n" +
+ " * more comment\n" +
+ " */\n" +
+ " bar();\n" +
+ "}\n",
+ output: "function foo() {\n" +
+ " /**\n" +
+ " * java doc style comment\n" +
+ " * more comment\n" +
+ " */\n" +
+ " bar();\n" +
+ "}\n",
+ },
+
+ {
+ name: "ASI return",
+ input: "function f() {\n" +
+ " return\n" +
+ " {}\n" +
+ "}\n",
+ output: "function f() {\n" +
+ " return\n" +
+ " {\n" +
+ " }\n" +
+ "}\n",
+ },
+
+ {
+ name: "Non-ASI property access",
+ input: "[1,2,3]\n" +
+ "[0]",
+ output: "[\n" +
+ " 1,\n" +
+ " 2,\n" +
+ " 3\n" +
+ "]\n" +
+ "[0]\n"
+ },
+
+ {
+ name: "Non-ASI in",
+ input: "'x'\n" +
+ "in foo",
+ output: "'x' in foo\n"
+ },
+
+ {
+ name: "Non-ASI function call",
+ input: "f\n" +
+ "()",
+ output: "f()\n"
+ },
+
+ {
+ name: "Non-ASI new",
+ input: "new\n" +
+ "F()",
+ output: "new F()\n"
+ },
+
+ {
+ name: "Getter and setter literals",
+ input: "var obj={get foo(){return this._foo},set foo(v){this._foo=v}}",
+ output: "var obj = {\n" +
+ " get foo() {\n" +
+ " return this._foo\n" +
+ " },\n" +
+ " set foo(v) {\n" +
+ " this._foo = v\n" +
+ " }\n" +
+ "}\n"
+ },
+
+ {
+ name: "Escaping backslashes in strings",
+ input: "'\\\\'\n",
+ output: "'\\\\'\n"
+ },
+
+ {
+ name: "Escaping carriage return in strings",
+ input: "'\\r'\n",
+ output: "'\\r'\n"
+ },
+
+ {
+ name: "Escaping tab in strings",
+ input: "'\\t'\n",
+ output: "'\\t'\n"
+ },
+
+ {
+ name: "Escaping vertical tab in strings",
+ input: "'\\v'\n",
+ output: "'\\v'\n"
+ },
+
+ {
+ name: "Escaping form feed in strings",
+ input: "'\\f'\n",
+ output: "'\\f'\n"
+ },
+
+ {
+ name: "Escaping null character in strings",
+ input: "'\\0'\n",
+ output: "'\\0'\n"
+ },
+
+ {
+ name: "Bug 977082 - space between grouping operator and dot notation",
+ input: "JSON.stringify(3).length;\n" +
+ "([1,2,3]).length;\n" +
+ "(new Date()).toLocaleString();\n",
+ output: "JSON.stringify(3).length;\n" +
+ "([1,\n" +
+ "2,\n" +
+ "3]).length;\n" +
+ "(new Date()).toLocaleString();\n"
+ },
+
+ {
+ name: "Bug 975477 don't move end of line comments to next line",
+ input: "switch (request.action) {\n" +
+ " case 'show': //$NON-NLS-0$\n" +
+ " if (localStorage.hideicon !== 'true') { //$NON-NLS-0$\n" +
+ " chrome.pageAction.show(sender.tab.id);\n" +
+ " }\n" +
+ " break;\n" +
+ " case 'hide': /*Multiline\n" +
+ " Comment */" +
+ " break;\n" +
+ " default:\n" +
+ " console.warn('unknown request'); //$NON-NLS-0$\n" +
+ " // don't respond if you don't understand the message.\n" +
+ " return;\n" +
+ "}\n",
+ output: "switch (request.action) {\n" +
+ " case 'show': //$NON-NLS-0$\n" +
+ " if (localStorage.hideicon !== 'true') { //$NON-NLS-0$\n" +
+ " chrome.pageAction.show(sender.tab.id);\n" +
+ " }\n" +
+ " break;\n" +
+ " case 'hide': /*Multiline\n" +
+ " Comment */\n" +
+ " break;\n" +
+ " default:\n" +
+ " console.warn('unknown request'); //$NON-NLS-0$\n" +
+ " // don't respond if you don't understand the message.\n" +
+ " return;\n" +
+ "}\n"
+ }
+
+];
+
+var sourceMap = this.sourceMap || require("source-map");
+
+function run_test() {
+ testCases.forEach(function (test) {
+ console.log(test.name);
+
+ var actual = prettyFast(test.input, {
+ indent: " ",
+ url: "test.js"
+ });
+
+ if (actual.code !== test.output) {
+ throw new Error("Expected:\n" + test.output
+ + "\nGot:\n" + actual.code);
+ }
+
+ if (test.mappings) {
+ var smc = new sourceMap.SourceMapConsumer(actual.map.toJSON());
+ test.mappings.forEach(function (m) {
+ var query = { line: m.outputLine, column: 0 };
+ var original = smc.originalPositionFor(query);
+ if (original.line != m.inputLine) {
+ throw new Error("Querying:\n" + JSON.stringify(query, null, 2) + "\n"
+ + "Expected line:\n" + m.inputLine + "\n"
+ + "Got:\n" + JSON.stringify(original, null, 2));
+ }
+ });
+ }
+ });
+ console.log("✓ All tests pass!");
+}
+
+// Only run the tests if this is node and we are running this file
+// directly. (Firefox's test runner will import this test file, and then call
+// run_test itself.)
+if (typeof require == "function" && typeof module == "object"
+ && require.main === module) {
+ run_test();
+}
diff --git a/devtools/shared/pretty-fast/tests/unit/xpcshell.ini b/devtools/shared/pretty-fast/tests/unit/xpcshell.ini
new file mode 100644
index 000000000..cb92b1825
--- /dev/null
+++ b/devtools/shared/pretty-fast/tests/unit/xpcshell.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+tags = devtools
+head = head_pretty-fast.js
+tail =
+firefox-appdir = browser
+skip-if = toolkit == 'android'
+
+[test.js]