diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 00:47:55 +0000 |
commit | 26a029d407be480d791972afb5975cf62c9360a6 (patch) | |
tree | f435a8308119effd964b339f76abb83a57c29483 /devtools/client/shared/test/xpcshell/test_rewriteDeclarations.js | |
parent | Initial commit. (diff) | |
download | firefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz firefox-26a029d407be480d791972afb5975cf62c9360a6.zip |
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/shared/test/xpcshell/test_rewriteDeclarations.js')
-rw-r--r-- | devtools/client/shared/test/xpcshell/test_rewriteDeclarations.js | 816 |
1 files changed, 816 insertions, 0 deletions
diff --git a/devtools/client/shared/test/xpcshell/test_rewriteDeclarations.js b/devtools/client/shared/test/xpcshell/test_rewriteDeclarations.js new file mode 100644 index 0000000000..228d2dc79d --- /dev/null +++ b/devtools/client/shared/test/xpcshell/test_rewriteDeclarations.js @@ -0,0 +1,816 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const RuleRewriter = require("resource://devtools/client/fronts/inspector/rule-rewriter.js"); +const { + isCssPropertyKnown, +} = require("resource://devtools/server/actors/css-properties.js"); + +const TEST_DATA = [ + { + desc: "simple set", + input: "p:v;", + instruction: { type: "set", name: "p", value: "N", priority: "", index: 0 }, + expected: "p:N;", + }, + { + desc: "simple set clearing !important", + input: "p:v !important;", + instruction: { type: "set", name: "p", value: "N", priority: "", index: 0 }, + expected: "p:N;", + }, + { + desc: "simple set adding !important", + input: "p:v;", + instruction: { + type: "set", + name: "p", + value: "N", + priority: "important", + index: 0, + }, + expected: "p:N !important;", + }, + { + desc: "simple set between comments", + input: "/*color:red;*/ p:v; /*color:green;*/", + instruction: { type: "set", name: "p", value: "N", priority: "", index: 1 }, + expected: "/*color:red;*/ p:N; /*color:green;*/", + }, + // The rule view can generate a "set" with a previously unknown + // property index; which should work like "create". + { + desc: "set at unknown index", + input: "a:b; e: f;", + instruction: { type: "set", name: "c", value: "d", priority: "", index: 2 }, + expected: "a:b; e: f;c: d;", + }, + { + desc: "simple rename", + input: "p:v;", + instruction: { type: "rename", name: "p", newName: "q", index: 0 }, + expected: "q:v;", + }, + // "rename" is passed the name that the user entered, and must do + // any escaping necessary to ensure that this is an identifier. + { + desc: "rename requiring escape", + input: "p:v;", + instruction: { type: "rename", name: "p", newName: "a b", index: 0 }, + expected: "a\\ b:v;", + }, + { + desc: "simple create", + input: "", + instruction: { + type: "create", + name: "p", + value: "v", + priority: "important", + index: 0, + enabled: true, + }, + expected: "p: v !important;", + }, + { + desc: "create between two properties", + input: "a:b; e: f;", + instruction: { + type: "create", + name: "c", + value: "d", + priority: "", + index: 1, + enabled: true, + }, + expected: "a:b; c: d;e: f;", + }, + // "create" is passed the name that the user entered, and must do + // any escaping necessary to ensure that this is an identifier. + { + desc: "create requiring escape", + input: "", + instruction: { + type: "create", + name: "a b", + value: "d", + priority: "", + index: 1, + enabled: true, + }, + expected: "a\\ b: d;", + }, + { + desc: "simple disable", + input: "p:v;", + instruction: { type: "enable", name: "p", value: false, index: 0 }, + expected: "/*! p:v; */", + }, + { + desc: "simple enable", + input: "/* color:v; */", + instruction: { type: "enable", name: "color", value: true, index: 0 }, + expected: "color:v;", + }, + { + desc: "enable with following property in comment", + input: "/* color:red; color: blue; */", + instruction: { type: "enable", name: "color", value: true, index: 0 }, + expected: "color:red; /* color: blue; */", + }, + { + desc: "enable with preceding property in comment", + input: "/* color:red; color: blue; */", + instruction: { type: "enable", name: "color", value: true, index: 1 }, + expected: "/* color:red; */ color: blue;", + }, + { + desc: "simple remove", + input: "a:b;c:d;e:f;", + instruction: { type: "remove", name: "c", index: 1 }, + expected: "a:b;e:f;", + }, + { + desc: "disable with comment ender in string", + input: "content: '*/';", + instruction: { type: "enable", name: "content", value: false, index: 0 }, + expected: "/*! content: '*\\/'; */", + }, + { + desc: "enable with comment ender in string", + input: "/* content: '*\\/'; */", + instruction: { type: "enable", name: "content", value: true, index: 0 }, + expected: "content: '*/';", + }, + { + desc: "enable requiring semicolon insertion", + // Note the lack of a trailing semicolon in the comment. + input: "/* color:red */ color: blue;", + instruction: { type: "enable", name: "color", value: true, index: 0 }, + expected: "color:red; color: blue;", + }, + { + desc: "create requiring semicolon insertion", + // Note the lack of a trailing semicolon. + input: "color: red", + instruction: { + type: "create", + name: "a", + value: "b", + priority: "", + index: 1, + enabled: true, + }, + expected: "color: red;a: b;", + }, + + // Newline insertion. + { + desc: "simple newline insertion", + input: "\ncolor: red;\n", + instruction: { + type: "create", + name: "a", + value: "b", + priority: "", + index: 1, + enabled: true, + }, + expected: "\ncolor: red;\na: b;\n", + }, + // Newline insertion. + { + desc: "semicolon insertion before newline", + // Note the lack of a trailing semicolon. + input: "\ncolor: red\n", + instruction: { + type: "create", + name: "a", + value: "b", + priority: "", + index: 1, + enabled: true, + }, + expected: "\ncolor: red;\na: b;\n", + }, + // Newline insertion. + { + desc: "newline and semicolon insertion", + // Note the lack of a trailing semicolon and newline. + input: "\ncolor: red", + instruction: { + type: "create", + name: "a", + value: "b", + priority: "", + index: 1, + enabled: true, + }, + expected: "\ncolor: red;\na: b;\n", + }, + + // Newline insertion and indentation. + { + desc: "indentation with create", + input: "\n color: red;\n", + instruction: { + type: "create", + name: "a", + value: "b", + priority: "", + index: 1, + enabled: true, + }, + expected: "\n color: red;\n a: b;\n", + }, + // Newline insertion and indentation. + { + desc: "indentation plus semicolon insertion before newline", + // Note the lack of a trailing semicolon. + input: "\n color: red\n", + instruction: { + type: "create", + name: "a", + value: "b", + priority: "", + index: 1, + enabled: true, + }, + expected: "\n color: red;\n a: b;\n", + }, + { + desc: "indentation inserted before trailing whitespace", + // Note the trailing whitespace. This could come from a rule + // like: + // @supports (mumble) { + // body { + // color: red; + // } + // } + // Here if we create a rule we don't want it to follow + // the indentation of the "}". + input: "\n color: red;\n ", + instruction: { + type: "create", + name: "a", + value: "b", + priority: "", + index: 1, + enabled: true, + }, + expected: "\n color: red;\n a: b;\n ", + }, + // Newline insertion and indentation. + { + desc: "indentation comes from preceding comment", + // Note how the comment comes before the declaration. + input: "\n /* comment */ color: red\n", + instruction: { + type: "create", + name: "a", + value: "b", + priority: "", + index: 1, + enabled: true, + }, + expected: "\n /* comment */ color: red;\n a: b;\n", + }, + // Default indentation. + { + desc: "use of default indentation", + input: "\n", + instruction: { + type: "create", + name: "a", + value: "b", + priority: "", + index: 0, + enabled: true, + }, + expected: "\n\ta: b;\n", + }, + + // Deletion handles newlines properly. + { + desc: "deletion removes newline", + input: "a:b;\nc:d;\ne:f;", + instruction: { type: "remove", name: "c", index: 1 }, + expected: "a:b;\ne:f;", + }, + // Deletion handles newlines properly. + { + desc: "deletion remove blank line", + input: "\n a:b;\n c:d; \ne:f;", + instruction: { type: "remove", name: "c", index: 1 }, + expected: "\n a:b;\ne:f;", + }, + // Deletion handles newlines properly. + { + desc: "deletion leaves comment", + input: "\n a:b;\n /* something */ c:d; \ne:f;", + instruction: { type: "remove", name: "c", index: 1 }, + expected: "\n a:b;\n /* something */ \ne:f;", + }, + // Deletion handles newlines properly. + { + desc: "deletion leaves previous newline", + input: "\n a:b;\n c:d; \ne:f;", + instruction: { type: "remove", name: "e", index: 2 }, + expected: "\n a:b;\n c:d; \n", + }, + // Deletion handles newlines properly. + { + desc: "deletion removes trailing whitespace", + input: "\n a:b;\n c:d; \n e:f;", + instruction: { type: "remove", name: "e", index: 2 }, + expected: "\n a:b;\n c:d; \n", + }, + // Deletion handles newlines properly. + { + desc: "deletion preserves indentation", + input: " a:b;\n c:d; \n e:f;", + instruction: { type: "remove", name: "a", index: 0 }, + expected: " c:d; \n e:f;", + }, + + // Termination insertion corner case. + { + desc: "enable single quote termination", + input: "/* content: 'hi */ color: red;", + instruction: { type: "enable", name: "content", value: true, index: 0 }, + expected: "content: 'hi'; color: red;", + changed: { 0: "'hi'" }, + }, + // Termination insertion corner case. + { + desc: "create single quote termination", + input: "content: 'hi", + instruction: { + type: "create", + name: "color", + value: "red", + priority: "", + index: 1, + enabled: true, + }, + expected: "content: 'hi';color: red;", + changed: { 0: "'hi'" }, + }, + + // Termination insertion corner case. + { + desc: "enable double quote termination", + input: '/* content: "hi */ color: red;', + instruction: { type: "enable", name: "content", value: true, index: 0 }, + expected: 'content: "hi"; color: red;', + changed: { 0: '"hi"' }, + }, + // Termination insertion corner case. + { + desc: "create double quote termination", + input: 'content: "hi', + instruction: { + type: "create", + name: "color", + value: "red", + priority: "", + index: 1, + enabled: true, + }, + expected: 'content: "hi";color: red;', + changed: { 0: '"hi"' }, + }, + + // Termination insertion corner case. + { + desc: "enable url termination", + input: "/* background-image: url(something.jpg */ color: red;", + instruction: { + type: "enable", + name: "background-image", + value: true, + index: 0, + }, + expected: "background-image: url(something.jpg); color: red;", + changed: { 0: "url(something.jpg)" }, + }, + // Termination insertion corner case. + { + desc: "create url termination", + input: "background-image: url(something.jpg", + instruction: { + type: "create", + name: "color", + value: "red", + priority: "", + index: 1, + enabled: true, + }, + expected: "background-image: url(something.jpg);color: red;", + changed: { 0: "url(something.jpg)" }, + }, + + // Termination insertion corner case. + { + desc: "enable url single quote termination", + input: "/* background-image: url('something.jpg */ color: red;", + instruction: { + type: "enable", + name: "background-image", + value: true, + index: 0, + }, + expected: "background-image: url('something.jpg'); color: red;", + changed: { 0: "url('something.jpg')" }, + }, + // Termination insertion corner case. + { + desc: "create url single quote termination", + input: "background-image: url('something.jpg", + instruction: { + type: "create", + name: "color", + value: "red", + priority: "", + index: 1, + enabled: true, + }, + expected: "background-image: url('something.jpg');color: red;", + changed: { 0: "url('something.jpg')" }, + }, + + // Termination insertion corner case. + { + desc: "create url double quote termination", + input: '/* background-image: url("something.jpg */ color: red;', + instruction: { + type: "enable", + name: "background-image", + value: true, + index: 0, + }, + expected: 'background-image: url("something.jpg"); color: red;', + changed: { 0: 'url("something.jpg")' }, + }, + // Termination insertion corner case. + { + desc: "enable url double quote termination", + input: 'background-image: url("something.jpg', + instruction: { + type: "create", + name: "color", + value: "red", + priority: "", + index: 1, + enabled: true, + }, + expected: 'background-image: url("something.jpg");color: red;', + changed: { 0: 'url("something.jpg")' }, + }, + + // Termination insertion corner case. + { + desc: "create backslash termination", + input: "something: \\", + instruction: { + type: "create", + name: "color", + value: "red", + priority: "", + index: 1, + enabled: true, + }, + expected: "something: \\\\;color: red;", + // The lexer rewrites the token before we see it. However this is + // so obscure as to be inconsequential. + changed: { 0: "\uFFFD\\" }, + }, + + // Termination insertion corner case. + { + desc: "enable backslash single quote termination", + input: "something: '\\", + instruction: { + type: "create", + name: "color", + value: "red", + priority: "", + index: 1, + enabled: true, + }, + expected: "something: '\\\\';color: red;", + changed: { 0: "'\\\\'" }, + }, + { + desc: "enable backslash double quote termination", + input: 'something: "\\', + instruction: { + type: "create", + name: "color", + value: "red", + priority: "", + index: 1, + enabled: true, + }, + expected: 'something: "\\\\";color: red;', + changed: { 0: '"\\\\"' }, + }, + + // Termination insertion corner case. + { + desc: "enable comment termination", + input: "something: blah /* comment ", + instruction: { + type: "create", + name: "color", + value: "red", + priority: "", + index: 1, + enabled: true, + }, + expected: "something: blah /* comment*/; color: red;", + }, + + // Rewrite a "heuristic override" comment. + { + desc: "enable with heuristic override comment", + input: "/*! walrus: zebra; */", + instruction: { type: "enable", name: "walrus", value: true, index: 0 }, + expected: "walrus: zebra;", + }, + + // Sanitize a bad value. + { + desc: "create sanitize unpaired brace", + input: "", + instruction: { + type: "create", + name: "p", + value: "}", + priority: "", + index: 0, + enabled: true, + }, + expected: "p: \\};", + changed: { 0: "\\}" }, + }, + // Sanitize a bad value. + { + desc: "set sanitize unpaired brace", + input: "walrus: zebra;", + instruction: { + type: "set", + name: "walrus", + value: "{{}}}", + priority: "", + index: 0, + }, + expected: "walrus: {{}}\\};", + changed: { 0: "{{}}\\}" }, + }, + // Sanitize a bad value. + { + desc: "enable sanitize unpaired brace", + input: "/*! walrus: }*/", + instruction: { type: "enable", name: "walrus", value: true, index: 0 }, + expected: "walrus: \\};", + changed: { 0: "\\}" }, + }, + + // Creating a new declaration does not require an attempt to + // terminate a previous commented declaration. + { + desc: "disabled declaration does not need semicolon insertion", + input: "/*! no: semicolon */\n", + instruction: { + type: "create", + name: "walrus", + value: "zebra", + priority: "", + index: 1, + enabled: true, + }, + expected: "/*! no: semicolon */\nwalrus: zebra;\n", + changed: {}, + }, + + { + desc: "create commented-out property", + input: "p: v", + instruction: { + type: "create", + name: "shoveler", + value: "duck", + priority: "", + index: 1, + enabled: false, + }, + expected: "p: v;/*! shoveler: duck; */", + }, + { + desc: "disabled create with comment ender in string", + input: "", + instruction: { + type: "create", + name: "content", + value: "'*/'", + priority: "", + index: 0, + enabled: false, + }, + expected: "/*! content: '*\\/'; */", + }, + + { + desc: "delete disabled property", + input: "\n a:b;\n /* color:#f06; */\n e:f;", + instruction: { type: "remove", name: "color", index: 1 }, + expected: "\n a:b;\n e:f;", + }, + { + desc: "delete heuristic-disabled property", + input: "\n a:b;\n /*! c:d; */\n e:f;", + instruction: { type: "remove", name: "c", index: 1 }, + expected: "\n a:b;\n e:f;", + }, + { + desc: "delete disabled property leaving other disabled property", + input: "\n a:b;\n /* color:#f06; background-color: seagreen; */\n e:f;", + instruction: { type: "remove", name: "color", index: 1 }, + expected: "\n a:b;\n /* background-color: seagreen; */\n e:f;", + }, + + { + desc: "regression test for bug 1328016", + input: "position:absolute;top50px;height:50px;width:50px;", + instruction: { + type: "set", + name: "width", + value: "60px", + priority: "", + index: 2, + }, + expected: "position:absolute;top50px;height:50px;width:60px;", + }, + + { + desc: "url regression test for bug 1321970", + input: "", + instruction: { + type: "create", + name: "p", + value: "url(", + priority: "", + index: 0, + enabled: true, + }, + expected: "p: url();", + changed: { 0: "url()" }, + }, + + { + desc: "url semicolon regression test for bug 1321970", + input: "", + instruction: { + type: "create", + name: "p", + value: "url(;", + priority: "", + index: 0, + enabled: true, + }, + expected: "p: url();", + changed: { 0: "url()" }, + }, + + { + desc: "basic regression test for bug 1321970", + input: "", + instruction: { + type: "create", + name: "p", + value: "(", + priority: "", + index: 0, + enabled: true, + }, + expected: "p: \\(;", + changed: { 0: "\\(" }, + }, + + { + desc: "unbalanced regression test for bug 1321970", + input: "", + instruction: { + type: "create", + name: "p", + value: "({[})", + priority: "", + index: 0, + enabled: true, + }, + expected: "p: ({\\[});", + changed: { 0: "({\\[})" }, + }, + + { + desc: "function regression test for bug 1321970", + input: "", + instruction: { + type: "create", + name: "p", + value: "func(1,2)", + priority: "", + index: 0, + enabled: true, + }, + expected: "p: func(1,2);", + }, + + { + desc: "function regression test for bug 1355233", + input: "", + instruction: { + type: "create", + name: "p", + value: "func(", + priority: "", + index: 0, + enabled: true, + }, + expected: "p: func\\(;", + changed: { 0: "func\\(" }, + }, +]; + +function rewriteDeclarations(inputString, instruction, defaultIndentation) { + const rewriter = new RuleRewriter(isCssPropertyKnown, null, inputString); + rewriter.defaultIndentation = defaultIndentation; + + switch (instruction.type) { + case "rename": + rewriter.renameProperty( + instruction.index, + instruction.name, + instruction.newName + ); + break; + + case "enable": + rewriter.setPropertyEnabled( + instruction.index, + instruction.name, + instruction.value + ); + break; + + case "create": + rewriter.createProperty( + instruction.index, + instruction.name, + instruction.value, + instruction.priority, + instruction.enabled + ); + break; + + case "set": + rewriter.setProperty( + instruction.index, + instruction.name, + instruction.value, + instruction.priority + ); + break; + + case "remove": + rewriter.removeProperty(instruction.index, instruction.name); + break; + + default: + throw new Error("unrecognized instruction"); + } + + return rewriter.getResult(); +} + +function run_test() { + for (const test of TEST_DATA) { + const { changed, text } = rewriteDeclarations( + test.input, + test.instruction, + "\t" + ); + equal(text, test.expected, "output for " + test.desc); + + let expectChanged; + if ("changed" in test) { + expectChanged = test.changed; + } else { + expectChanged = {}; + } + deepEqual(changed, expectChanged, "changed result for " + test.desc); + } +} |