mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-05 15:28:39 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
6
devtools/client/shared/test/unit/.eslintrc.js
Normal file
6
devtools/client/shared/test/unit/.eslintrc.js
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
// Extend from the common devtools xpcshell eslintrc config.
|
||||
"extends": "../../../../.eslintrc.xpcshell.js"
|
||||
};
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that VariablesView._doSearch() works even without an attached
|
||||
// VariablesViewController (bug 1196341).
|
||||
|
||||
var Cu = Components.utils;
|
||||
var Cc = Components.classes;
|
||||
var Ci = Components.interfaces;
|
||||
const DOMParser = Cc["@mozilla.org/xmlextras/domparser;1"]
|
||||
.createInstance(Ci.nsIDOMParser);
|
||||
const { VariablesView } =
|
||||
Cu.import("resource://devtools/client/shared/widgets/VariablesView.jsm", {});
|
||||
|
||||
function run_test() {
|
||||
let doc = DOMParser.parseFromString("<div>", "text/html");
|
||||
let container = doc.body.firstChild;
|
||||
ok(container, "Got a container.");
|
||||
|
||||
let vv = new VariablesView(container, { searchEnabled: true });
|
||||
let scope = vv.addScope("Test scope");
|
||||
let item1 = scope.addItem("a", { value: "1" });
|
||||
let item2 = scope.addItem("b", { value: "2" });
|
||||
|
||||
do_print("Performing a search without a controller.");
|
||||
vv._doSearch("a");
|
||||
|
||||
equal(item1.target.hasAttribute("unmatched"), false,
|
||||
"First item that matched the filter is visible.");
|
||||
equal(item2.target.hasAttribute("unmatched"), true,
|
||||
"The second item that did not match the filter is hidden.");
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { VariablesView } = Components.utils.import("resource://devtools/client/shared/widgets/VariablesView.jsm", {});
|
||||
|
||||
const PENDING = {
|
||||
"type": "object",
|
||||
"class": "Promise",
|
||||
"actor": "conn0.pausedobj35",
|
||||
"extensible": true,
|
||||
"frozen": false,
|
||||
"sealed": false,
|
||||
"promiseState": {
|
||||
"state": "pending"
|
||||
},
|
||||
"preview": {
|
||||
"kind": "Object",
|
||||
"ownProperties": {},
|
||||
"ownPropertiesLength": 0,
|
||||
"safeGetterValues": {}
|
||||
}
|
||||
};
|
||||
|
||||
const FULFILLED = {
|
||||
"type": "object",
|
||||
"class": "Promise",
|
||||
"actor": "conn0.pausedobj35",
|
||||
"extensible": true,
|
||||
"frozen": false,
|
||||
"sealed": false,
|
||||
"promiseState": {
|
||||
"state": "fulfilled",
|
||||
"value": 10
|
||||
},
|
||||
"preview": {
|
||||
"kind": "Object",
|
||||
"ownProperties": {},
|
||||
"ownPropertiesLength": 0,
|
||||
"safeGetterValues": {}
|
||||
}
|
||||
};
|
||||
|
||||
const REJECTED = {
|
||||
"type": "object",
|
||||
"class": "Promise",
|
||||
"actor": "conn0.pausedobj35",
|
||||
"extensible": true,
|
||||
"frozen": false,
|
||||
"sealed": false,
|
||||
"promiseState": {
|
||||
"state": "rejected",
|
||||
"reason": 10
|
||||
},
|
||||
"preview": {
|
||||
"kind": "Object",
|
||||
"ownProperties": {},
|
||||
"ownPropertiesLength": 0,
|
||||
"safeGetterValues": {}
|
||||
}
|
||||
};
|
||||
|
||||
function run_test() {
|
||||
equal(VariablesView.getString(PENDING, { concise: true }), "Promise");
|
||||
equal(VariablesView.getString(PENDING), 'Promise {<state>: "pending"}');
|
||||
|
||||
equal(VariablesView.getString(FULFILLED, { concise: true }), "Promise");
|
||||
equal(VariablesView.getString(FULFILLED),
|
||||
'Promise {<state>: "fulfilled", <value>: 10}');
|
||||
|
||||
equal(VariablesView.getString(REJECTED, { concise: true }), "Promise");
|
||||
equal(VariablesView.getString(REJECTED), 'Promise {<state>: "rejected", <reason>: 10}');
|
||||
}
|
||||
31
devtools/client/shared/test/unit/test_advanceValidate.js
Normal file
31
devtools/client/shared/test/unit/test_advanceValidate.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests the advanceValidate function from rule-view.js.
|
||||
|
||||
const {utils: Cu, interfaces: Ci} = Components;
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {advanceValidate} = require("devtools/client/inspector/shared/utils");
|
||||
|
||||
// 1 2 3
|
||||
// 0123456789012345678901234567890
|
||||
const sampleInput = '\\symbol "string" url(somewhere)';
|
||||
|
||||
function testInsertion(where, result, testName) {
|
||||
do_print(testName);
|
||||
equal(advanceValidate(Ci.nsIDOMKeyEvent.DOM_VK_SEMICOLON, sampleInput, where),
|
||||
result, "testing advanceValidate at " + where);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
testInsertion(4, true, "inside a symbol");
|
||||
testInsertion(1, false, "after a backslash");
|
||||
testInsertion(8, true, "after whitespace");
|
||||
testInsertion(11, false, "inside a string");
|
||||
testInsertion(24, false, "inside a URL");
|
||||
testInsertion(31, true, "at the end");
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test splitBy from node-attribute-parser.js
|
||||
|
||||
const {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {splitBy} = require("devtools/client/shared/node-attribute-parser");
|
||||
|
||||
const TEST_DATA = [{
|
||||
value: "this is a test",
|
||||
splitChar: " ",
|
||||
expected: [
|
||||
{value: "this"},
|
||||
{value: " ", type: "string"},
|
||||
{value: "is"},
|
||||
{value: " ", type: "string"},
|
||||
{value: "a"},
|
||||
{value: " ", type: "string"},
|
||||
{value: "test"}
|
||||
]
|
||||
}, {
|
||||
value: "/path/to/handler",
|
||||
splitChar: " ",
|
||||
expected: [
|
||||
{value: "/path/to/handler"}
|
||||
]
|
||||
}, {
|
||||
value: "test",
|
||||
splitChar: " ",
|
||||
expected: [
|
||||
{value: "test"}
|
||||
]
|
||||
}, {
|
||||
value: " test ",
|
||||
splitChar: " ",
|
||||
expected: [
|
||||
{value: " ", type: "string"},
|
||||
{value: "test"},
|
||||
{value: " ", type: "string"}
|
||||
]
|
||||
}, {
|
||||
value: "",
|
||||
splitChar: " ",
|
||||
expected: []
|
||||
}, {
|
||||
value: " ",
|
||||
splitChar: " ",
|
||||
expected: [
|
||||
{value: " ", type: "string"},
|
||||
{value: " ", type: "string"},
|
||||
{value: " ", type: "string"}
|
||||
]
|
||||
}];
|
||||
|
||||
function run_test() {
|
||||
for (let {value, splitChar, expected} of TEST_DATA) {
|
||||
do_print("Splitting string: " + value);
|
||||
let tokens = splitBy(value, splitChar);
|
||||
|
||||
do_print("Checking that the number of parsed tokens is correct");
|
||||
do_check_eq(tokens.length, expected.length);
|
||||
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
do_print("Checking the data in token " + i);
|
||||
do_check_eq(tokens[i].value, expected[i].value);
|
||||
if (expected[i].type) {
|
||||
do_check_eq(tokens[i].type, expected[i].type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
134
devtools/client/shared/test/unit/test_attribute-parsing-02.js
Normal file
134
devtools/client/shared/test/unit/test_attribute-parsing-02.js
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test parseAttribute from node-attribute-parser.js
|
||||
|
||||
const {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {parseAttribute} = require("devtools/client/shared/node-attribute-parser");
|
||||
|
||||
const TEST_DATA = [{
|
||||
tagName: "body",
|
||||
namespaceURI: "http://www.w3.org/1999/xhtml",
|
||||
attributeName: "class",
|
||||
attributeValue: "some css class names",
|
||||
expected: [
|
||||
{value: "some css class names", type: "string"}
|
||||
]
|
||||
}, {
|
||||
tagName: "box",
|
||||
namespaceURI: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
||||
attributeName: "datasources",
|
||||
attributeValue: "/url/1?test=1#test http://mozilla.org/wow",
|
||||
expected: [
|
||||
{value: "/url/1?test=1#test", type: "uri"},
|
||||
{value: " ", type: "string"},
|
||||
{value: "http://mozilla.org/wow", type: "uri"}
|
||||
]
|
||||
}, {
|
||||
tagName: "form",
|
||||
namespaceURI: "http://www.w3.org/1999/xhtml",
|
||||
attributeName: "action",
|
||||
attributeValue: "/path/to/handler",
|
||||
expected: [
|
||||
{value: "/path/to/handler", type: "uri"}
|
||||
]
|
||||
}, {
|
||||
tagName: "a",
|
||||
namespaceURI: "http://www.w3.org/1999/xhtml",
|
||||
attributeName: "ping",
|
||||
attributeValue: "http://analytics.com/track?id=54 http://analytics.com/track?id=55",
|
||||
expected: [
|
||||
{value: "http://analytics.com/track?id=54", type: "uri"},
|
||||
{value: " ", type: "string"},
|
||||
{value: "http://analytics.com/track?id=55", type: "uri"}
|
||||
]
|
||||
}, {
|
||||
tagName: "link",
|
||||
namespaceURI: "http://www.w3.org/1999/xhtml",
|
||||
attributeName: "href",
|
||||
attributeValue: "styles.css",
|
||||
otherAttributes: [{name: "rel", value: "stylesheet"}],
|
||||
expected: [
|
||||
{value: "styles.css", type: "cssresource"}
|
||||
]
|
||||
}, {
|
||||
tagName: "link",
|
||||
namespaceURI: "http://www.w3.org/1999/xhtml",
|
||||
attributeName: "href",
|
||||
attributeValue: "styles.css",
|
||||
expected: [
|
||||
{value: "styles.css", type: "uri"}
|
||||
]
|
||||
}, {
|
||||
tagName: "output",
|
||||
namespaceURI: "http://www.w3.org/1999/xhtml",
|
||||
attributeName: "for",
|
||||
attributeValue: "element-id something id",
|
||||
expected: [
|
||||
{value: "element-id", type: "idref"},
|
||||
{value: " ", type: "string"},
|
||||
{value: "something", type: "idref"},
|
||||
{value: " ", type: "string"},
|
||||
{value: "id", type: "idref"}
|
||||
]
|
||||
}, {
|
||||
tagName: "img",
|
||||
namespaceURI: "http://www.w3.org/1999/xhtml",
|
||||
attributeName: "contextmenu",
|
||||
attributeValue: "id-of-menu",
|
||||
expected: [
|
||||
{value: "id-of-menu", type: "idref"}
|
||||
]
|
||||
}, {
|
||||
tagName: "img",
|
||||
namespaceURI: "http://www.w3.org/1999/xhtml",
|
||||
attributeName: "src",
|
||||
attributeValue: "omg-thats-so-funny.gif",
|
||||
expected: [
|
||||
{value: "omg-thats-so-funny.gif", type: "uri"}
|
||||
]
|
||||
}, {
|
||||
tagName: "key",
|
||||
namespaceURI: "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
|
||||
attributeName: "command",
|
||||
attributeValue: "some_command_id",
|
||||
expected: [
|
||||
{value: "some_command_id", type: "idref"}
|
||||
]
|
||||
}, {
|
||||
tagName: "script",
|
||||
namespaceURI: "whatever",
|
||||
attributeName: "src",
|
||||
attributeValue: "script.js",
|
||||
expected: [
|
||||
{value: "script.js", type: "jsresource"}
|
||||
]
|
||||
}];
|
||||
|
||||
function run_test() {
|
||||
for (let {tagName, namespaceURI, attributeName,
|
||||
otherAttributes, attributeValue, expected} of TEST_DATA) {
|
||||
do_print("Testing <" + tagName + " " + attributeName + "='" + attributeValue + "'>");
|
||||
|
||||
let attributes = [
|
||||
...otherAttributes || [],
|
||||
{ name: attributeName, value: attributeValue }
|
||||
];
|
||||
let tokens = parseAttribute(namespaceURI, tagName, attributes, attributeName);
|
||||
if (!expected) {
|
||||
do_check_true(!tokens);
|
||||
continue;
|
||||
}
|
||||
|
||||
do_print("Checking that the number of parsed tokens is correct");
|
||||
do_check_eq(tokens.length, expected.length);
|
||||
|
||||
for (let i = 0; i < tokens.length; i++) {
|
||||
do_print("Checking the data in token " + i);
|
||||
do_check_eq(tokens[i].value, expected[i].value);
|
||||
do_check_eq(tokens[i].type, expected[i].type);
|
||||
}
|
||||
}
|
||||
}
|
||||
117
devtools/client/shared/test/unit/test_bezierCanvas.js
Normal file
117
devtools/client/shared/test/unit/test_bezierCanvas.js
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests the BezierCanvas API in the CubicBezierWidget module
|
||||
|
||||
var Cu = Components.utils;
|
||||
var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
var {CubicBezier, BezierCanvas} = require("devtools/client/shared/widgets/CubicBezierWidget");
|
||||
|
||||
function run_test() {
|
||||
offsetsGetterReturnsData();
|
||||
convertsOffsetsToCoordinates();
|
||||
plotsCanvas();
|
||||
}
|
||||
|
||||
function offsetsGetterReturnsData() {
|
||||
do_print("offsets getter returns an array of 2 offset objects");
|
||||
|
||||
let b = new BezierCanvas(getCanvasMock(), getCubicBezier(), [.25, 0]);
|
||||
let offsets = b.offsets;
|
||||
|
||||
do_check_eq(offsets.length, 2);
|
||||
|
||||
do_check_true("top" in offsets[0]);
|
||||
do_check_true("left" in offsets[0]);
|
||||
do_check_true("top" in offsets[1]);
|
||||
do_check_true("left" in offsets[1]);
|
||||
|
||||
do_check_eq(offsets[0].top, "300px");
|
||||
do_check_eq(offsets[0].left, "0px");
|
||||
do_check_eq(offsets[1].top, "100px");
|
||||
do_check_eq(offsets[1].left, "200px");
|
||||
|
||||
do_print("offsets getter returns data according to current padding");
|
||||
|
||||
b = new BezierCanvas(getCanvasMock(), getCubicBezier(), [0, 0]);
|
||||
offsets = b.offsets;
|
||||
|
||||
do_check_eq(offsets[0].top, "400px");
|
||||
do_check_eq(offsets[0].left, "0px");
|
||||
do_check_eq(offsets[1].top, "0px");
|
||||
do_check_eq(offsets[1].left, "200px");
|
||||
}
|
||||
|
||||
function convertsOffsetsToCoordinates() {
|
||||
do_print("Converts offsets to coordinates");
|
||||
|
||||
let b = new BezierCanvas(getCanvasMock(), getCubicBezier(), [.25, 0]);
|
||||
|
||||
let coordinates = b.offsetsToCoordinates({style: {
|
||||
left: "0px",
|
||||
top: "0px"
|
||||
}});
|
||||
do_check_eq(coordinates.length, 2);
|
||||
do_check_eq(coordinates[0], 0);
|
||||
do_check_eq(coordinates[1], 1.5);
|
||||
|
||||
coordinates = b.offsetsToCoordinates({style: {
|
||||
left: "0px",
|
||||
top: "300px"
|
||||
}});
|
||||
do_check_eq(coordinates[0], 0);
|
||||
do_check_eq(coordinates[1], 0);
|
||||
|
||||
coordinates = b.offsetsToCoordinates({style: {
|
||||
left: "200px",
|
||||
top: "100px"
|
||||
}});
|
||||
do_check_eq(coordinates[0], 1);
|
||||
do_check_eq(coordinates[1], 1);
|
||||
}
|
||||
|
||||
function plotsCanvas() {
|
||||
do_print("Plots the curve to the canvas");
|
||||
|
||||
let hasDrawnCurve = false;
|
||||
let b = new BezierCanvas(getCanvasMock(), getCubicBezier(), [.25, 0]);
|
||||
b.ctx.bezierCurveTo = () => {
|
||||
hasDrawnCurve = true;
|
||||
};
|
||||
b.plot();
|
||||
|
||||
do_check_true(hasDrawnCurve);
|
||||
}
|
||||
|
||||
function getCubicBezier() {
|
||||
return new CubicBezier([0, 0, 1, 1]);
|
||||
}
|
||||
|
||||
function getCanvasMock(w = 200, h = 400) {
|
||||
return {
|
||||
getContext: function () {
|
||||
return {
|
||||
scale: () => {},
|
||||
translate: () => {},
|
||||
clearRect: () => {},
|
||||
beginPath: () => {},
|
||||
closePath: () => {},
|
||||
moveTo: () => {},
|
||||
lineTo: () => {},
|
||||
stroke: () => {},
|
||||
arc: () => {},
|
||||
fill: () => {},
|
||||
bezierCurveTo: () => {},
|
||||
save: () => {},
|
||||
restore: () => {},
|
||||
setTransform: () => {}
|
||||
};
|
||||
},
|
||||
width: w,
|
||||
height: h
|
||||
};
|
||||
}
|
||||
33
devtools/client/shared/test/unit/test_cssAngle.js
Normal file
33
devtools/client/shared/test/unit/test_cssAngle.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test classifyAngle.
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cu = Components.utils;
|
||||
var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
|
||||
const {angleUtils} = require("devtools/client/shared/css-angle");
|
||||
|
||||
const CLASSIFY_TESTS = [
|
||||
{ input: "180deg", output: "deg" },
|
||||
{ input: "-180deg", output: "deg" },
|
||||
{ input: "180DEG", output: "deg" },
|
||||
{ input: "200rad", output: "rad" },
|
||||
{ input: "-200rad", output: "rad" },
|
||||
{ input: "200RAD", output: "rad" },
|
||||
{ input: "0.5grad", output: "grad" },
|
||||
{ input: "-0.5grad", output: "grad" },
|
||||
{ input: "0.5GRAD", output: "grad" },
|
||||
{ input: "0.33turn", output: "turn" },
|
||||
{ input: "0.33TURN", output: "turn" },
|
||||
{ input: "-0.33turn", output: "turn" }
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
for (let test of CLASSIFY_TESTS) {
|
||||
let result = angleUtils.classifyAngle(test.input);
|
||||
equal(result, test.output, "test classifyAngle(" + test.input + ")");
|
||||
}
|
||||
}
|
||||
76
devtools/client/shared/test/unit/test_cssColor-01.js
Normal file
76
devtools/client/shared/test/unit/test_cssColor-01.js
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test classifyColor.
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cu = Components.utils;
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
var {require, loader} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {colorUtils} = require("devtools/shared/css/color");
|
||||
|
||||
loader.lazyGetter(this, "DOMUtils", function () {
|
||||
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||
});
|
||||
|
||||
const CLASSIFY_TESTS = [
|
||||
{ input: "rgb(255,0,192)", output: "rgb" },
|
||||
{ input: "RGB(255,0,192)", output: "rgb" },
|
||||
{ input: "RGB(100%,0%,83%)", output: "rgb" },
|
||||
{ input: "rgba(255,0,192, 0.25)", output: "rgb" },
|
||||
{ input: "hsl(5, 5%, 5%)", output: "hsl" },
|
||||
{ input: "hsla(5, 5%, 5%, 0.25)", output: "hsl" },
|
||||
{ input: "hSlA(5, 5%, 5%, 0.25)", output: "hsl" },
|
||||
{ input: "#f0c", output: "hex" },
|
||||
{ input: "#f0c0", output: "hex" },
|
||||
{ input: "#fe01cb", output: "hex" },
|
||||
{ input: "#fe01cb80", output: "hex" },
|
||||
{ input: "#FE01CB", output: "hex" },
|
||||
{ input: "#FE01CB80", output: "hex" },
|
||||
{ input: "blue", output: "name" },
|
||||
{ input: "orange", output: "name" }
|
||||
];
|
||||
|
||||
function compareWithDomutils(input, isColor) {
|
||||
let ours = colorUtils.colorToRGBA(input);
|
||||
let platform = DOMUtils.colorToRGBA(input);
|
||||
deepEqual(ours, platform, "color " + input + " matches DOMUtils");
|
||||
if (isColor) {
|
||||
ok(ours !== null, "'" + input + "' is a color");
|
||||
} else {
|
||||
ok(ours === null, "'" + input + "' is not a color");
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
for (let test of CLASSIFY_TESTS) {
|
||||
let result = colorUtils.classifyColor(test.input);
|
||||
equal(result, test.output, "test classifyColor(" + test.input + ")");
|
||||
|
||||
let obj = new colorUtils.CssColor("purple");
|
||||
obj.setAuthoredUnitFromColor(test.input);
|
||||
equal(obj.colorUnit, test.output,
|
||||
"test setAuthoredUnitFromColor(" + test.input + ")");
|
||||
|
||||
// Check that our implementation matches DOMUtils.
|
||||
compareWithDomutils(test.input, true);
|
||||
|
||||
// And check some obvious errors.
|
||||
compareWithDomutils("mumble" + test.input, false);
|
||||
compareWithDomutils(test.input + "trailingstuff", false);
|
||||
}
|
||||
|
||||
// Regression test for bug 1303826.
|
||||
let black = new colorUtils.CssColor("#000");
|
||||
black.colorUnit = "name";
|
||||
equal(black.toString(), "black", "test non-upper-case color cycling");
|
||||
|
||||
let upper = new colorUtils.CssColor("BLACK");
|
||||
upper.colorUnit = "hex";
|
||||
equal(upper.toString(), "#000", "test upper-case color cycling");
|
||||
upper.colorUnit = "name";
|
||||
equal(upper.toString(), "BLACK", "test upper-case color preservation");
|
||||
}
|
||||
45
devtools/client/shared/test/unit/test_cssColor-02.js
Normal file
45
devtools/client/shared/test/unit/test_cssColor-02.js
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test color cycling regression - Bug 1303748.
|
||||
*
|
||||
* Values should cycle from a starting value, back to their original values. This can
|
||||
* potentially be a little flaky due to the precision of different color representations.
|
||||
*/
|
||||
|
||||
const {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {colorUtils} = require("devtools/shared/css/color");
|
||||
const getFixtureColorData = require("resource://test/helper_color_data.js");
|
||||
|
||||
function run_test() {
|
||||
getFixtureColorData().forEach(({authored, name, hex, hsl, rgb, cycle}) => {
|
||||
if (cycle) {
|
||||
const nameCycled = runCycle(name, cycle);
|
||||
const hexCycled = runCycle(hex, cycle);
|
||||
const hslCycled = runCycle(hsl, cycle);
|
||||
const rgbCycled = runCycle(rgb, cycle);
|
||||
// Cut down on log output by only reporting a single pass/fail for the color.
|
||||
ok(nameCycled && hexCycled && hslCycled && rgbCycled,
|
||||
`${authored} was able to cycle back to the original value`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test a color cycle to see if a color cycles back to its original value in a fixed
|
||||
* number of steps.
|
||||
*
|
||||
* @param {string} value - The color value, e.g. "#000".
|
||||
* @param {integer) times - The number of times it takes to cycle back to the
|
||||
* original color.
|
||||
*/
|
||||
function runCycle(value, times) {
|
||||
let color = new colorUtils.CssColor(value);
|
||||
for (let i = 0; i < times; i++) {
|
||||
color.nextColorUnit();
|
||||
color = new colorUtils.CssColor(color.toString());
|
||||
}
|
||||
return color.toString() === value;
|
||||
}
|
||||
61
devtools/client/shared/test/unit/test_cssColor-03.js
Normal file
61
devtools/client/shared/test/unit/test_cssColor-03.js
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test css-color-4 color function syntax and old-style syntax.
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cu = Components.utils;
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
var {require, loader} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {colorUtils} = require("devtools/shared/css/color");
|
||||
|
||||
loader.lazyGetter(this, "DOMUtils", function () {
|
||||
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||
});
|
||||
|
||||
const OLD_STYLE_TESTS = [
|
||||
"rgb(255,0,192)",
|
||||
"RGB(255,0,192)",
|
||||
"RGB(100%,0%,83%)",
|
||||
"rgba(255,0,192,0.25)",
|
||||
"hsl(120, 100%, 40%)",
|
||||
"hsla(120, 100%, 40%, 0.25)",
|
||||
"hSlA(240, 100%, 50%, 0.25)",
|
||||
];
|
||||
|
||||
const CSS_COLOR_4_TESTS = [
|
||||
"rgb(255.0,0.0,192.0)",
|
||||
"RGB(255 0 192)",
|
||||
"RGB(100% 0% 83% / 0.5)",
|
||||
"RGB(100%,0%,83%,0.5)",
|
||||
"RGB(100%,0%,83%,50%)",
|
||||
"rgba(255,0,192)",
|
||||
"hsl(50deg,15%,25%)",
|
||||
"hsl(240 25% 33%)",
|
||||
"hsl(50deg 25% 33% / 0.25)",
|
||||
"hsl(60 120% 60% / 0.25)",
|
||||
"hSlA(5turn 40% 4%)",
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
for (let test of OLD_STYLE_TESTS) {
|
||||
let ours = colorUtils.colorToRGBA(test, true);
|
||||
let platform = DOMUtils.colorToRGBA(test);
|
||||
deepEqual(ours, platform, "color " + test + " matches DOMUtils");
|
||||
ok(ours !== null, "'" + test + "' is a color");
|
||||
}
|
||||
|
||||
for (let test of CSS_COLOR_4_TESTS) {
|
||||
let oursOld = colorUtils.colorToRGBA(test, true);
|
||||
let oursNew = colorUtils.colorToRGBA(test, false);
|
||||
let platform = DOMUtils.colorToRGBA(test);
|
||||
notEqual(oursOld, platform, "old style parser for color " + test +
|
||||
" should not match DOMUtils");
|
||||
ok(oursOld === null, "'" + test + "' is not a color with old parser");
|
||||
deepEqual(oursNew, platform, `css-color-4 parser for color ${test} matches DOMUtils`);
|
||||
ok(oursNew !== null, "'" + test + "' is a color with css-color-4 parser");
|
||||
}
|
||||
}
|
||||
63
devtools/client/shared/test/unit/test_cssColorDatabase.js
Normal file
63
devtools/client/shared/test/unit/test_cssColorDatabase.js
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that css-color-db matches platform.
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cu = Components.utils;
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
|
||||
var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
|
||||
const DOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||
|
||||
const {colorUtils} = require("devtools/shared/css/color");
|
||||
const {cssColors} = require("devtools/shared/css/color-db");
|
||||
|
||||
function isValid(colorName) {
|
||||
ok(colorUtils.isValidCSSColor(colorName),
|
||||
colorName + " is valid in database");
|
||||
ok(DOMUtils.isValidCSSColor(colorName),
|
||||
colorName + " is valid in DOMUtils");
|
||||
}
|
||||
|
||||
function checkOne(colorName, checkName) {
|
||||
let ours = colorUtils.colorToRGBA(colorName);
|
||||
let fromDom = DOMUtils.colorToRGBA(colorName);
|
||||
deepEqual(ours, fromDom, colorName + " agrees with DOMUtils");
|
||||
|
||||
isValid(colorName);
|
||||
|
||||
if (checkName) {
|
||||
let {r, g, b} = ours;
|
||||
|
||||
// The color we got might not map back to the same name; but our
|
||||
// implementation should agree with DOMUtils about which name is
|
||||
// canonical.
|
||||
let ourName = colorUtils.rgbToColorName(r, g, b);
|
||||
let domName = DOMUtils.rgbToColorName(r, g, b);
|
||||
|
||||
equal(ourName, domName,
|
||||
colorName + " canonical name agrees with DOMUtils");
|
||||
}
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
for (let name in cssColors) {
|
||||
checkOne(name, true);
|
||||
}
|
||||
checkOne("transparent", false);
|
||||
|
||||
// Now check that platform didn't add a new name when we weren't
|
||||
// looking.
|
||||
let names = DOMUtils.getCSSValuesForProperty("background-color");
|
||||
for (let name of names) {
|
||||
if (name !== "hsl" && name !== "hsla" &&
|
||||
name !== "rgb" && name !== "rgba" &&
|
||||
name !== "inherit" && name !== "initial" && name !== "unset") {
|
||||
checkOne(name, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
146
devtools/client/shared/test/unit/test_cubicBezier.js
Normal file
146
devtools/client/shared/test/unit/test_cubicBezier.js
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests the CubicBezier API in the CubicBezierWidget module
|
||||
|
||||
var Cu = Components.utils;
|
||||
var {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
var {CubicBezier, _parseTimingFunction} = require("devtools/client/shared/widgets/CubicBezierWidget");
|
||||
|
||||
function run_test() {
|
||||
throwsWhenMissingCoordinates();
|
||||
throwsWhenIncorrectCoordinates();
|
||||
convertsStringCoordinates();
|
||||
coordinatesToStringOutputsAString();
|
||||
pointGettersReturnPointCoordinatesArrays();
|
||||
toStringOutputsCubicBezierValue();
|
||||
toStringOutputsCssPresetValues();
|
||||
testParseTimingFunction();
|
||||
}
|
||||
|
||||
function throwsWhenMissingCoordinates() {
|
||||
do_check_throws(() => {
|
||||
new CubicBezier();
|
||||
}, "Throws an exception when coordinates are missing");
|
||||
}
|
||||
|
||||
function throwsWhenIncorrectCoordinates() {
|
||||
do_check_throws(() => {
|
||||
new CubicBezier([]);
|
||||
}, "Throws an exception when coordinates are incorrect (empty array)");
|
||||
|
||||
do_check_throws(() => {
|
||||
new CubicBezier([0, 0]);
|
||||
}, "Throws an exception when coordinates are incorrect (incomplete array)");
|
||||
|
||||
do_check_throws(() => {
|
||||
new CubicBezier(["a", "b", "c", "d"]);
|
||||
}, "Throws an exception when coordinates are incorrect (invalid type)");
|
||||
|
||||
do_check_throws(() => {
|
||||
new CubicBezier([1.5, 0, 1.5, 0]);
|
||||
}, "Throws an exception when coordinates are incorrect (time range invalid)");
|
||||
|
||||
do_check_throws(() => {
|
||||
new CubicBezier([-0.5, 0, -0.5, 0]);
|
||||
}, "Throws an exception when coordinates are incorrect (time range invalid)");
|
||||
}
|
||||
|
||||
function convertsStringCoordinates() {
|
||||
do_print("Converts string coordinates to numbers");
|
||||
let c = new CubicBezier(["0", "1", ".5", "-2"]);
|
||||
|
||||
do_check_eq(c.coordinates[0], 0);
|
||||
do_check_eq(c.coordinates[1], 1);
|
||||
do_check_eq(c.coordinates[2], .5);
|
||||
do_check_eq(c.coordinates[3], -2);
|
||||
}
|
||||
|
||||
function coordinatesToStringOutputsAString() {
|
||||
do_print("coordinates.toString() outputs a string representation");
|
||||
|
||||
let c = new CubicBezier(["0", "1", "0.5", "-2"]);
|
||||
let string = c.coordinates.toString();
|
||||
do_check_eq(string, "0,1,.5,-2");
|
||||
|
||||
c = new CubicBezier([1, 1, 1, 1]);
|
||||
string = c.coordinates.toString();
|
||||
do_check_eq(string, "1,1,1,1");
|
||||
}
|
||||
|
||||
function pointGettersReturnPointCoordinatesArrays() {
|
||||
do_print("Points getters return arrays of coordinates");
|
||||
|
||||
let c = new CubicBezier([0, .2, .5, 1]);
|
||||
do_check_eq(c.P1[0], 0);
|
||||
do_check_eq(c.P1[1], .2);
|
||||
do_check_eq(c.P2[0], .5);
|
||||
do_check_eq(c.P2[1], 1);
|
||||
}
|
||||
|
||||
function toStringOutputsCubicBezierValue() {
|
||||
do_print("toString() outputs the cubic-bezier() value");
|
||||
|
||||
let c = new CubicBezier([0, 1, 1, 0]);
|
||||
do_check_eq(c.toString(), "cubic-bezier(0,1,1,0)");
|
||||
}
|
||||
|
||||
function toStringOutputsCssPresetValues() {
|
||||
do_print("toString() outputs the css predefined values");
|
||||
|
||||
let c = new CubicBezier([0, 0, 1, 1]);
|
||||
do_check_eq(c.toString(), "linear");
|
||||
|
||||
c = new CubicBezier([0.25, 0.1, 0.25, 1]);
|
||||
do_check_eq(c.toString(), "ease");
|
||||
|
||||
c = new CubicBezier([0.42, 0, 1, 1]);
|
||||
do_check_eq(c.toString(), "ease-in");
|
||||
|
||||
c = new CubicBezier([0, 0, 0.58, 1]);
|
||||
do_check_eq(c.toString(), "ease-out");
|
||||
|
||||
c = new CubicBezier([0.42, 0, 0.58, 1]);
|
||||
do_check_eq(c.toString(), "ease-in-out");
|
||||
}
|
||||
|
||||
function testParseTimingFunction() {
|
||||
do_print("test parseTimingFunction");
|
||||
|
||||
for (let test of ["ease", "linear", "ease-in", "ease-out", "ease-in-out"]) {
|
||||
ok(_parseTimingFunction(test), test);
|
||||
}
|
||||
|
||||
ok(!_parseTimingFunction("something"), "non-function token");
|
||||
ok(!_parseTimingFunction("something()"), "non-cubic-bezier function");
|
||||
ok(!_parseTimingFunction("cubic-bezier(something)",
|
||||
"cubic-bezier with non-numeric argument"));
|
||||
ok(!_parseTimingFunction("cubic-bezier(1,2,3:7)",
|
||||
"did not see comma"));
|
||||
ok(!_parseTimingFunction("cubic-bezier(1,2,3,7:",
|
||||
"did not see close paren"));
|
||||
ok(!_parseTimingFunction("cubic-bezier(1,2", "early EOF after number"));
|
||||
ok(!_parseTimingFunction("cubic-bezier(1,2,", "early EOF after comma"));
|
||||
deepEqual(_parseTimingFunction("cubic-bezier(1,2,3,7)"), [1, 2, 3, 7],
|
||||
"correct invocation");
|
||||
deepEqual(_parseTimingFunction("cubic-bezier(1, /* */ 2,3, 7 )"),
|
||||
[1, 2, 3, 7],
|
||||
"correct with comments and whitespace");
|
||||
}
|
||||
|
||||
function do_check_throws(cb, info) {
|
||||
do_print(info);
|
||||
|
||||
let hasThrown = false;
|
||||
try {
|
||||
cb();
|
||||
} catch (e) {
|
||||
hasThrown = true;
|
||||
}
|
||||
|
||||
do_check_true(hasThrown);
|
||||
}
|
||||
40
devtools/client/shared/test/unit/test_escapeCSSComment.js
Normal file
40
devtools/client/shared/test/unit/test_escapeCSSComment.js
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cu = Components.utils;
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {escapeCSSComment, _unescapeCSSComment} = require("devtools/shared/css/parsing-utils");
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
input: "simple",
|
||||
expected: "simple"
|
||||
},
|
||||
{
|
||||
input: "/* comment */",
|
||||
expected: "/\\* comment *\\/"
|
||||
},
|
||||
{
|
||||
input: "/* two *//* comments */",
|
||||
expected: "/\\* two *\\//\\* comments *\\/"
|
||||
},
|
||||
{
|
||||
input: "/* nested /\\* comment *\\/ */",
|
||||
expected: "/\\* nested /\\\\* comment *\\\\/ *\\/",
|
||||
}
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
let i = 0;
|
||||
for (let test of TEST_DATA) {
|
||||
++i;
|
||||
do_print("Test #" + i);
|
||||
|
||||
let escaped = escapeCSSComment(test.input);
|
||||
equal(escaped, test.expected);
|
||||
let unescaped = _unescapeCSSComment(escaped);
|
||||
equal(unescaped, test.input);
|
||||
}
|
||||
}
|
||||
439
devtools/client/shared/test/unit/test_parseDeclarations.js
Normal file
439
devtools/client/shared/test/unit/test_parseDeclarations.js
Normal file
|
|
@ -0,0 +1,439 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {parseDeclarations, _parseCommentDeclarations} = require("devtools/shared/css/parsing-utils");
|
||||
const {isCssPropertyKnown} = require("devtools/server/actors/css-properties");
|
||||
|
||||
const TEST_DATA = [
|
||||
// Simple test
|
||||
{
|
||||
input: "p:v;",
|
||||
expected: [{name: "p", value: "v", priority: "", offsets: [0, 4]}]
|
||||
},
|
||||
// Simple test
|
||||
{
|
||||
input: "this:is;a:test;",
|
||||
expected: [
|
||||
{name: "this", value: "is", priority: "", offsets: [0, 8]},
|
||||
{name: "a", value: "test", priority: "", offsets: [8, 15]}
|
||||
]
|
||||
},
|
||||
// Test a single declaration with semi-colon
|
||||
{
|
||||
input: "name:value;",
|
||||
expected: [{name: "name", value: "value", priority: "", offsets: [0, 11]}]
|
||||
},
|
||||
// Test a single declaration without semi-colon
|
||||
{
|
||||
input: "name:value",
|
||||
expected: [{name: "name", value: "value", priority: "", offsets: [0, 10]}]
|
||||
},
|
||||
// Test multiple declarations separated by whitespaces and carriage
|
||||
// returns and tabs
|
||||
{
|
||||
input: "p1 : v1 ; \t\t \n p2:v2; \n\n\n\n\t p3 : v3;",
|
||||
expected: [
|
||||
{name: "p1", value: "v1", priority: "", offsets: [0, 9]},
|
||||
{name: "p2", value: "v2", priority: "", offsets: [16, 22]},
|
||||
{name: "p3", value: "v3", priority: "", offsets: [32, 45]},
|
||||
]
|
||||
},
|
||||
// Test simple priority
|
||||
{
|
||||
input: "p1: v1; p2: v2 !important;",
|
||||
expected: [
|
||||
{name: "p1", value: "v1", priority: "", offsets: [0, 7]},
|
||||
{name: "p2", value: "v2", priority: "important", offsets: [8, 26]}
|
||||
]
|
||||
},
|
||||
// Test simple priority
|
||||
{
|
||||
input: "p1: v1 !important; p2: v2",
|
||||
expected: [
|
||||
{name: "p1", value: "v1", priority: "important", offsets: [0, 18]},
|
||||
{name: "p2", value: "v2", priority: "", offsets: [19, 25]}
|
||||
]
|
||||
},
|
||||
// Test simple priority
|
||||
{
|
||||
input: "p1: v1 ! important; p2: v2 ! important;",
|
||||
expected: [
|
||||
{name: "p1", value: "v1", priority: "important", offsets: [0, 20]},
|
||||
{name: "p2", value: "v2", priority: "important", offsets: [21, 40]}
|
||||
]
|
||||
},
|
||||
// Test invalid priority
|
||||
{
|
||||
input: "p1: v1 important;",
|
||||
expected: [
|
||||
{name: "p1", value: "v1 important", priority: "", offsets: [0, 17]}
|
||||
]
|
||||
},
|
||||
// Test various types of background-image urls
|
||||
{
|
||||
input: "background-image: url(../../relative/image.png)",
|
||||
expected: [{
|
||||
name: "background-image",
|
||||
value: "url(../../relative/image.png)",
|
||||
priority: "",
|
||||
offsets: [0, 47]
|
||||
}]
|
||||
},
|
||||
{
|
||||
input: "background-image: url(http://site.com/test.png)",
|
||||
expected: [{
|
||||
name: "background-image",
|
||||
value: "url(http://site.com/test.png)",
|
||||
priority: "",
|
||||
offsets: [0, 47]
|
||||
}]
|
||||
},
|
||||
{
|
||||
input: "background-image: url(wow.gif)",
|
||||
expected: [{
|
||||
name: "background-image",
|
||||
value: "url(wow.gif)",
|
||||
priority: "",
|
||||
offsets: [0, 30]
|
||||
}]
|
||||
},
|
||||
// Test that urls with :;{} characters in them are parsed correctly
|
||||
{
|
||||
input: "background: red url(\"http://site.com/image{}:;.png?id=4#wat\") "
|
||||
+ "repeat top right",
|
||||
expected: [{
|
||||
name: "background",
|
||||
value: "red url(\"http://site.com/image{}:;.png?id=4#wat\") " +
|
||||
"repeat top right",
|
||||
priority: "",
|
||||
offsets: [0, 78]
|
||||
}]
|
||||
},
|
||||
// Test that an empty string results in an empty array
|
||||
{input: "", expected: []},
|
||||
// Test that a string comprised only of whitespaces results in an empty array
|
||||
{input: " \n \n \n \n \t \t\t\t ", expected: []},
|
||||
// Test that a null input throws an exception
|
||||
{input: null, throws: true},
|
||||
// Test that a undefined input throws an exception
|
||||
{input: undefined, throws: true},
|
||||
// Test that :;{} characters in quoted content are not parsed as multiple
|
||||
// declarations
|
||||
{
|
||||
input: "content: \";color:red;}selector{color:yellow;\"",
|
||||
expected: [{
|
||||
name: "content",
|
||||
value: "\";color:red;}selector{color:yellow;\"",
|
||||
priority: "",
|
||||
offsets: [0, 45]
|
||||
}]
|
||||
},
|
||||
// Test that rules aren't parsed, just declarations. So { and } found after a
|
||||
// property name should be part of the property name, same for values.
|
||||
{
|
||||
input: "body {color:red;} p {color: blue;}",
|
||||
expected: [
|
||||
{name: "body {color", value: "red", priority: "", offsets: [0, 16]},
|
||||
{name: "} p {color", value: "blue", priority: "", offsets: [16, 33]},
|
||||
{name: "}", value: "", priority: "", offsets: [33, 34]}
|
||||
]
|
||||
},
|
||||
// Test unbalanced : and ;
|
||||
{
|
||||
input: "color :red : font : arial;",
|
||||
expected: [
|
||||
{name: "color", value: "red : font : arial", priority: "",
|
||||
offsets: [0, 26]}
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "background: red;;;;;",
|
||||
expected: [{name: "background", value: "red", priority: "",
|
||||
offsets: [0, 16]}]
|
||||
},
|
||||
{
|
||||
input: "background:;",
|
||||
expected: [{name: "background", value: "", priority: "",
|
||||
offsets: [0, 12]}]
|
||||
},
|
||||
{input: ";;;;;", expected: []},
|
||||
{input: ":;:;", expected: []},
|
||||
// Test name only
|
||||
{input: "color", expected: [
|
||||
{name: "color", value: "", priority: "", offsets: [0, 5]}
|
||||
]},
|
||||
// Test trailing name without :
|
||||
{input: "color:blue;font", expected: [
|
||||
{name: "color", value: "blue", priority: "", offsets: [0, 11]},
|
||||
{name: "font", value: "", priority: "", offsets: [11, 15]}
|
||||
]},
|
||||
// Test trailing name with :
|
||||
{input: "color:blue;font:", expected: [
|
||||
{name: "color", value: "blue", priority: "", offsets: [0, 11]},
|
||||
{name: "font", value: "", priority: "", offsets: [11, 16]}
|
||||
]},
|
||||
// Test leading value
|
||||
{input: "Arial;color:blue;", expected: [
|
||||
{name: "", value: "Arial", priority: "", offsets: [0, 6]},
|
||||
{name: "color", value: "blue", priority: "", offsets: [6, 17]}
|
||||
]},
|
||||
// Test hex colors
|
||||
{
|
||||
input: "color: #333",
|
||||
expected: [{name: "color", value: "#333", priority: "", offsets: [0, 11]}]
|
||||
},
|
||||
{
|
||||
input: "color: #456789",
|
||||
expected: [{name: "color", value: "#456789", priority: "",
|
||||
offsets: [0, 14]}]
|
||||
},
|
||||
{
|
||||
input: "wat: #XYZ",
|
||||
expected: [{name: "wat", value: "#XYZ", priority: "", offsets: [0, 9]}]
|
||||
},
|
||||
// Test string/url quotes escaping
|
||||
{
|
||||
input: "content: \"this is a 'string'\"",
|
||||
expected: [{name: "content", value: "\"this is a 'string'\"", priority: "",
|
||||
offsets: [0, 29]}]
|
||||
},
|
||||
{
|
||||
input: 'content: "this is a \\"string\\""',
|
||||
expected: [{
|
||||
name: "content",
|
||||
value: '"this is a \\"string\\""',
|
||||
priority: "",
|
||||
offsets: [0, 31]}]
|
||||
},
|
||||
{
|
||||
input: "content: 'this is a \"string\"'",
|
||||
expected: [{
|
||||
name: "content",
|
||||
value: '\'this is a "string"\'',
|
||||
priority: "",
|
||||
offsets: [0, 29]
|
||||
}]
|
||||
},
|
||||
{
|
||||
input: "content: 'this is a \\'string\\''",
|
||||
expected: [{
|
||||
name: "content",
|
||||
value: "'this is a \\'string\\''",
|
||||
priority: "",
|
||||
offsets: [0, 31],
|
||||
}]
|
||||
},
|
||||
{
|
||||
input: "content: 'this \\' is a \" really strange string'",
|
||||
expected: [{
|
||||
name: "content",
|
||||
value: "'this \\' is a \" really strange string'",
|
||||
priority: "",
|
||||
offsets: [0, 47]
|
||||
}]
|
||||
},
|
||||
{
|
||||
input: "content: \"a not s\\ o very long title\"",
|
||||
expected: [{
|
||||
name: "content",
|
||||
value: '"a not s\\ o very long title"',
|
||||
priority: "",
|
||||
offsets: [0, 46]
|
||||
}]
|
||||
},
|
||||
// Test calc with nested parentheses
|
||||
{
|
||||
input: "width: calc((100% - 3em) / 2)",
|
||||
expected: [{name: "width", value: "calc((100% - 3em) / 2)", priority: "",
|
||||
offsets: [0, 29]}]
|
||||
},
|
||||
|
||||
// Simple embedded comment test.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "width: 5; /* background: green; */ background: red;",
|
||||
expected: [{name: "width", value: "5", priority: "", offsets: [0, 9]},
|
||||
{name: "background", value: "green", priority: "",
|
||||
offsets: [13, 31], commentOffsets: [10, 34]},
|
||||
{name: "background", value: "red", priority: "",
|
||||
offsets: [35, 51]}]
|
||||
},
|
||||
|
||||
// Embedded comment where the parsing heuristic fails.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "width: 5; /* background something: green; */ background: red;",
|
||||
expected: [{name: "width", value: "5", priority: "", offsets: [0, 9]},
|
||||
{name: "background", value: "red", priority: "",
|
||||
offsets: [45, 61]}]
|
||||
},
|
||||
|
||||
// Embedded comment where the parsing heuristic is a bit funny.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "width: 5; /* background: */ background: red;",
|
||||
expected: [{name: "width", value: "5", priority: "", offsets: [0, 9]},
|
||||
{name: "background", value: "", priority: "",
|
||||
offsets: [13, 24], commentOffsets: [10, 27]},
|
||||
{name: "background", value: "red", priority: "",
|
||||
offsets: [28, 44]}]
|
||||
},
|
||||
|
||||
// Another case where the parsing heuristic says not to bother; note
|
||||
// that there is no ";" in the comment.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "width: 5; /* background: yellow */ background: red;",
|
||||
expected: [{name: "width", value: "5", priority: "", offsets: [0, 9]},
|
||||
{name: "background", value: "yellow", priority: "",
|
||||
offsets: [13, 31], commentOffsets: [10, 34]},
|
||||
{name: "background", value: "red", priority: "",
|
||||
offsets: [35, 51]}]
|
||||
},
|
||||
|
||||
// Parsing a comment should yield text that has been unescaped, and
|
||||
// the offsets should refer to the original text.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "/* content: '*\\/'; */",
|
||||
expected: [{name: "content", value: "'*/'", priority: "",
|
||||
offsets: [3, 18], commentOffsets: [0, 21]}]
|
||||
},
|
||||
|
||||
// Parsing a comment should yield text that has been unescaped, and
|
||||
// the offsets should refer to the original text. This variant
|
||||
// tests the no-semicolon path.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "/* content: '*\\/' */",
|
||||
expected: [{name: "content", value: "'*/'", priority: "",
|
||||
offsets: [3, 17], commentOffsets: [0, 20]}]
|
||||
},
|
||||
|
||||
// A comment-in-a-comment should yield the correct offsets.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "/* color: /\\* comment *\\/ red; */",
|
||||
expected: [{name: "color", value: "red", priority: "",
|
||||
offsets: [3, 30], commentOffsets: [0, 33]}]
|
||||
},
|
||||
|
||||
// HTML comments are ignored.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "<!-- color: red; --> color: blue;",
|
||||
expected: [{name: "color", value: "red", priority: "",
|
||||
offsets: [5, 16]},
|
||||
{name: "color", value: "blue", priority: "",
|
||||
offsets: [21, 33]}]
|
||||
},
|
||||
|
||||
// Don't error on an empty comment.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "/**/",
|
||||
expected: []
|
||||
},
|
||||
|
||||
// Parsing our special comments skips the name-check heuristic.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "/*! walrus: zebra; */",
|
||||
expected: [{name: "walrus", value: "zebra", priority: "",
|
||||
offsets: [4, 18], commentOffsets: [0, 21]}]
|
||||
},
|
||||
|
||||
// Regression test for bug 1287620.
|
||||
{
|
||||
input: "color: blue \\9 no\\_need",
|
||||
expected: [{name: "color", value: "blue \\9 no_need", priority: "", offsets: [0, 23]}]
|
||||
},
|
||||
|
||||
// Regression test for bug 1297890 - don't paste tokens.
|
||||
{
|
||||
parseComments: true,
|
||||
input: "stroke-dasharray: 1/*ThisIsAComment*/2;",
|
||||
expected: [{name: "stroke-dasharray", value: "1 2", priority: "", offsets: [0, 39]}]
|
||||
},
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
run_basic_tests();
|
||||
run_comment_tests();
|
||||
}
|
||||
|
||||
// Test parseDeclarations.
|
||||
function run_basic_tests() {
|
||||
for (let test of TEST_DATA) {
|
||||
do_print("Test input string " + test.input);
|
||||
let output;
|
||||
try {
|
||||
output = parseDeclarations(isCssPropertyKnown, test.input,
|
||||
test.parseComments);
|
||||
} catch (e) {
|
||||
do_print("parseDeclarations threw an exception with the given input " +
|
||||
"string");
|
||||
if (test.throws) {
|
||||
do_print("Exception expected");
|
||||
do_check_true(true);
|
||||
} else {
|
||||
do_print("Exception unexpected\n" + e);
|
||||
do_check_true(false);
|
||||
}
|
||||
}
|
||||
if (output) {
|
||||
assertOutput(output, test.expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const COMMENT_DATA = [
|
||||
{
|
||||
input: "content: 'hi",
|
||||
expected: [{name: "content", value: "'hi", priority: "", terminator: "';",
|
||||
offsets: [2, 14], colonOffsets: [9, 11],
|
||||
commentOffsets: [0, 16]}],
|
||||
},
|
||||
{
|
||||
input: "text that once confounded the parser;",
|
||||
expected: []
|
||||
},
|
||||
];
|
||||
|
||||
// Test parseCommentDeclarations.
|
||||
function run_comment_tests() {
|
||||
for (let test of COMMENT_DATA) {
|
||||
do_print("Test input string " + test.input);
|
||||
let output = _parseCommentDeclarations(isCssPropertyKnown, test.input, 0,
|
||||
test.input.length + 4);
|
||||
deepEqual(output, test.expected);
|
||||
}
|
||||
}
|
||||
|
||||
function assertOutput(actual, expected) {
|
||||
if (actual.length === expected.length) {
|
||||
for (let i = 0; i < expected.length; i++) {
|
||||
do_check_true(!!actual[i]);
|
||||
do_print("Check that the output item has the expected name, " +
|
||||
"value and priority");
|
||||
do_check_eq(expected[i].name, actual[i].name);
|
||||
do_check_eq(expected[i].value, actual[i].value);
|
||||
do_check_eq(expected[i].priority, actual[i].priority);
|
||||
deepEqual(expected[i].offsets, actual[i].offsets);
|
||||
if ("commentOffsets" in expected[i]) {
|
||||
deepEqual(expected[i].commentOffsets, actual[i].commentOffsets);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let prop of actual) {
|
||||
do_print("Actual output contained: {name: " + prop.name + ", value: " +
|
||||
prop.value + ", priority: " + prop.priority + "}");
|
||||
}
|
||||
do_check_eq(actual.length, expected.length);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,213 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cu = Components.utils;
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {
|
||||
parsePseudoClassesAndAttributes,
|
||||
SELECTOR_ATTRIBUTE,
|
||||
SELECTOR_ELEMENT,
|
||||
SELECTOR_PSEUDO_CLASS
|
||||
} = require("devtools/shared/css/parsing-utils");
|
||||
|
||||
const TEST_DATA = [
|
||||
// Test that a null input throws an exception
|
||||
{
|
||||
input: null,
|
||||
throws: true
|
||||
},
|
||||
// Test that a undefined input throws an exception
|
||||
{
|
||||
input: undefined,
|
||||
throws: true
|
||||
},
|
||||
{
|
||||
input: ":root",
|
||||
expected: [
|
||||
{ value: ":root", type: SELECTOR_PSEUDO_CLASS }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: ".testclass",
|
||||
expected: [
|
||||
{ value: ".testclass", type: SELECTOR_ELEMENT }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "div p",
|
||||
expected: [
|
||||
{ value: "div p", type: SELECTOR_ELEMENT }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "div > p",
|
||||
expected: [
|
||||
{ value: "div > p", type: SELECTOR_ELEMENT }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "a[hidden]",
|
||||
expected: [
|
||||
{ value: "a", type: SELECTOR_ELEMENT },
|
||||
{ value: "[hidden]", type: SELECTOR_ATTRIBUTE }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "a[hidden=true]",
|
||||
expected: [
|
||||
{ value: "a", type: SELECTOR_ELEMENT },
|
||||
{ value: "[hidden=true]", type: SELECTOR_ATTRIBUTE }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "a[hidden=true] p:hover",
|
||||
expected: [
|
||||
{ value: "a", type: SELECTOR_ELEMENT },
|
||||
{ value: "[hidden=true]", type: SELECTOR_ATTRIBUTE },
|
||||
{ value: " p", type: SELECTOR_ELEMENT },
|
||||
{ value: ":hover", type: SELECTOR_PSEUDO_CLASS }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "a[checked=\"true\"]",
|
||||
expected: [
|
||||
{ value: "a", type: SELECTOR_ELEMENT },
|
||||
{ value: "[checked=\"true\"]", type: SELECTOR_ATTRIBUTE }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "a[title~=test]",
|
||||
expected: [
|
||||
{ value: "a", type: SELECTOR_ELEMENT },
|
||||
{ value: "[title~=test]", type: SELECTOR_ATTRIBUTE }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "h1[hidden=\"true\"][title^=\"Important\"]",
|
||||
expected: [
|
||||
{ value: "h1", type: SELECTOR_ELEMENT },
|
||||
{ value: "[hidden=\"true\"]", type: SELECTOR_ATTRIBUTE },
|
||||
{ value: "[title^=\"Important\"]", type: SELECTOR_ATTRIBUTE}
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "p:hover",
|
||||
expected: [
|
||||
{ value: "p", type: SELECTOR_ELEMENT },
|
||||
{ value: ":hover", type: SELECTOR_PSEUDO_CLASS }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "p + .testclass:hover",
|
||||
expected: [
|
||||
{ value: "p + .testclass", type: SELECTOR_ELEMENT },
|
||||
{ value: ":hover", type: SELECTOR_PSEUDO_CLASS }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "p::before",
|
||||
expected: [
|
||||
{ value: "p", type: SELECTOR_ELEMENT },
|
||||
{ value: "::before", type: SELECTOR_PSEUDO_CLASS }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "p:nth-child(2)",
|
||||
expected: [
|
||||
{ value: "p", type: SELECTOR_ELEMENT },
|
||||
{ value: ":nth-child(2)", type: SELECTOR_PSEUDO_CLASS }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "p:not([title=\"test\"]) .testclass",
|
||||
expected: [
|
||||
{ value: "p", type: SELECTOR_ELEMENT },
|
||||
{ value: ":not([title=\"test\"])", type: SELECTOR_PSEUDO_CLASS },
|
||||
{ value: " .testclass", type: SELECTOR_ELEMENT }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "a\\:hover",
|
||||
expected: [
|
||||
{ value: "a\\:hover", type: SELECTOR_ELEMENT }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: ":not(:lang(it))",
|
||||
expected: [
|
||||
{ value: ":not(:lang(it))", type: SELECTOR_PSEUDO_CLASS }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "p:not(:lang(it))",
|
||||
expected: [
|
||||
{ value: "p", type: SELECTOR_ELEMENT },
|
||||
{ value: ":not(:lang(it))", type: SELECTOR_PSEUDO_CLASS }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: "p:not(p:lang(it))",
|
||||
expected: [
|
||||
{ value: "p", type: SELECTOR_ELEMENT },
|
||||
{ value: ":not(p:lang(it))", type: SELECTOR_PSEUDO_CLASS }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: ":not(:lang(it)",
|
||||
expected: [
|
||||
{ value: ":not(:lang(it)", type: SELECTOR_ELEMENT }
|
||||
]
|
||||
},
|
||||
{
|
||||
input: ":not(:lang(it)))",
|
||||
expected: [
|
||||
{ value: ":not(:lang(it))", type: SELECTOR_PSEUDO_CLASS },
|
||||
{ value: ")", type: SELECTOR_ELEMENT }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
for (let test of TEST_DATA) {
|
||||
dump("Test input string " + test.input + "\n");
|
||||
let output;
|
||||
|
||||
try {
|
||||
output = parsePseudoClassesAndAttributes(test.input);
|
||||
} catch (e) {
|
||||
dump("parsePseudoClassesAndAttributes threw an exception with the " +
|
||||
"given input string\n");
|
||||
if (test.throws) {
|
||||
ok(true, "Exception expected");
|
||||
} else {
|
||||
dump();
|
||||
ok(false, "Exception unexpected\n" + e);
|
||||
}
|
||||
}
|
||||
|
||||
if (output) {
|
||||
assertOutput(output, test.expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertOutput(actual, expected) {
|
||||
if (actual.length === expected.length) {
|
||||
for (let i = 0; i < expected.length; i++) {
|
||||
dump("Check that the output item has the expected value and type\n");
|
||||
ok(!!actual[i]);
|
||||
equal(expected[i].value, actual[i].value);
|
||||
equal(expected[i].type, actual[i].type);
|
||||
}
|
||||
} else {
|
||||
for (let prop of actual) {
|
||||
dump("Actual output contained: {value: " + prop.value + ", type: " +
|
||||
prop.type + "}\n");
|
||||
}
|
||||
equal(actual.length, expected.length);
|
||||
}
|
||||
}
|
||||
93
devtools/client/shared/test/unit/test_parseSingleValue.js
Normal file
93
devtools/client/shared/test/unit/test_parseSingleValue.js
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cu = Components.utils;
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {parseSingleValue} = require("devtools/shared/css/parsing-utils");
|
||||
const {isCssPropertyKnown} = require("devtools/server/actors/css-properties");
|
||||
|
||||
const TEST_DATA = [
|
||||
{input: null, throws: true},
|
||||
{input: undefined, throws: true},
|
||||
{input: "", expected: {value: "", priority: ""}},
|
||||
{input: " \t \t \n\n ", expected: {value: "", priority: ""}},
|
||||
{input: "blue", expected: {value: "blue", priority: ""}},
|
||||
{input: "blue !important", expected: {value: "blue", priority: "important"}},
|
||||
{input: "blue!important", expected: {value: "blue", priority: "important"}},
|
||||
{input: "blue ! important", expected: {value: "blue", priority: "important"}},
|
||||
{
|
||||
input: "blue ! important",
|
||||
expected: {value: "blue", priority: "important"}
|
||||
},
|
||||
{input: "blue !", expected: {value: "blue", priority: ""}},
|
||||
{input: "blue !mportant", expected: {value: "blue !mportant", priority: ""}},
|
||||
{
|
||||
input: " blue !important ",
|
||||
expected: {value: "blue", priority: "important"}
|
||||
},
|
||||
{
|
||||
input: "url(\"http://url.com/whyWouldYouDoThat!important.png\") !important",
|
||||
expected: {
|
||||
value: "url(\"http://url.com/whyWouldYouDoThat!important.png\")",
|
||||
priority: "important"
|
||||
}
|
||||
},
|
||||
{
|
||||
input: "url(\"http://url.com/whyWouldYouDoThat!important.png\")",
|
||||
expected: {
|
||||
value: "url(\"http://url.com/whyWouldYouDoThat!important.png\")",
|
||||
priority: ""
|
||||
}
|
||||
},
|
||||
{
|
||||
input: "\"content!important\" !important",
|
||||
expected: {
|
||||
value: "\"content!important\"",
|
||||
priority: "important"
|
||||
}
|
||||
},
|
||||
{
|
||||
input: "\"content!important\"",
|
||||
expected: {
|
||||
value: "\"content!important\"",
|
||||
priority: ""
|
||||
}
|
||||
},
|
||||
{
|
||||
input: "\"all the \\\"'\\\\ special characters\"",
|
||||
expected: {
|
||||
value: "\"all the \\\"'\\\\ special characters\"",
|
||||
priority: ""
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
function run_test() {
|
||||
for (let test of TEST_DATA) {
|
||||
do_print("Test input value " + test.input);
|
||||
try {
|
||||
let output = parseSingleValue(isCssPropertyKnown, test.input);
|
||||
assertOutput(output, test.expected);
|
||||
} catch (e) {
|
||||
do_print("parseSingleValue threw an exception with the given input " +
|
||||
"value");
|
||||
if (test.throws) {
|
||||
do_print("Exception expected");
|
||||
do_check_true(true);
|
||||
} else {
|
||||
do_print("Exception unexpected\n" + e);
|
||||
do_check_true(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assertOutput(actual, expected) {
|
||||
do_print("Check that the output has the expected value and priority");
|
||||
do_check_eq(expected.value, actual.value);
|
||||
do_check_eq(expected.priority, actual.priority);
|
||||
}
|
||||
529
devtools/client/shared/test/unit/test_rewriteDeclarations.js
Normal file
529
devtools/client/shared/test/unit/test_rewriteDeclarations.js
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
var Cu = Components.utils;
|
||||
const {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {RuleRewriter} = require("devtools/shared/css/parsing-utils");
|
||||
const {isCssPropertyKnown} = require("devtools/server/actors/css-properties");
|
||||
|
||||
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:#f0c; */\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:#f0c; background-color: seagreen; */\n e:f;",
|
||||
instruction: {type: "remove", name: "color", index: 1},
|
||||
expected: "\n a:b;\n /* background-color: seagreen; */\n e:f;",
|
||||
},
|
||||
];
|
||||
|
||||
function rewriteDeclarations(inputString, instruction, defaultIndentation) {
|
||||
let 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 (let test of TEST_DATA) {
|
||||
let {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);
|
||||
}
|
||||
}
|
||||
181
devtools/client/shared/test/unit/test_source-utils.js
Normal file
181
devtools/client/shared/test/unit/test_source-utils.js
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests utility functions contained in `source-utils.js`
|
||||
*/
|
||||
|
||||
const { require } = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const sourceUtils = require("devtools/client/shared/source-utils");
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
const CHROME_URLS = [
|
||||
"chrome://foo", "resource://baz", "jar:file:///Users/root"
|
||||
];
|
||||
|
||||
const CONTENT_URLS = [
|
||||
"http://mozilla.org", "https://mozilla.org", "file:///Users/root", "app://fxosapp"
|
||||
];
|
||||
|
||||
// Test `sourceUtils.parseURL`
|
||||
add_task(function* () {
|
||||
let parsed = sourceUtils.parseURL("https://foo.com:8888/boo/bar.js?q=query");
|
||||
equal(parsed.fileName, "bar.js", "parseURL parsed valid fileName");
|
||||
equal(parsed.host, "foo.com:8888", "parseURL parsed valid host");
|
||||
equal(parsed.hostname, "foo.com", "parseURL parsed valid hostname");
|
||||
equal(parsed.port, "8888", "parseURL parsed valid port");
|
||||
equal(parsed.href, "https://foo.com:8888/boo/bar.js?q=query", "parseURL parsed valid href");
|
||||
|
||||
parsed = sourceUtils.parseURL("https://foo.com");
|
||||
equal(parsed.host, "foo.com", "parseURL parsed valid host when no port given");
|
||||
equal(parsed.hostname, "foo.com", "parseURL parsed valid hostname when no port given");
|
||||
|
||||
equal(sourceUtils.parseURL("self-hosted"), null,
|
||||
"parseURL returns `null` for invalid URLs");
|
||||
});
|
||||
|
||||
// Test `sourceUtils.isContentScheme`.
|
||||
add_task(function* () {
|
||||
for (let url of CHROME_URLS) {
|
||||
ok(!sourceUtils.isContentScheme(url),
|
||||
`${url} correctly identified as not content scheme`);
|
||||
}
|
||||
for (let url of CONTENT_URLS) {
|
||||
ok(sourceUtils.isContentScheme(url), `${url} correctly identified as content scheme`);
|
||||
}
|
||||
});
|
||||
|
||||
// Test `sourceUtils.isChromeScheme`.
|
||||
add_task(function* () {
|
||||
for (let url of CHROME_URLS) {
|
||||
ok(sourceUtils.isChromeScheme(url), `${url} correctly identified as chrome scheme`);
|
||||
}
|
||||
for (let url of CONTENT_URLS) {
|
||||
ok(!sourceUtils.isChromeScheme(url),
|
||||
`${url} correctly identified as not chrome scheme`);
|
||||
}
|
||||
});
|
||||
|
||||
// Test `sourceUtils.isDataScheme`.
|
||||
add_task(function* () {
|
||||
let dataURI = "data:text/html;charset=utf-8,<!DOCTYPE html></html>";
|
||||
ok(sourceUtils.isDataScheme(dataURI), `${dataURI} correctly identified as data scheme`);
|
||||
|
||||
for (let url of CHROME_URLS) {
|
||||
ok(!sourceUtils.isDataScheme(url), `${url} correctly identified as not data scheme`);
|
||||
}
|
||||
for (let url of CONTENT_URLS) {
|
||||
ok(!sourceUtils.isDataScheme(url), `${url} correctly identified as not data scheme`);
|
||||
}
|
||||
});
|
||||
|
||||
// Test `sourceUtils.getSourceNames`.
|
||||
add_task(function* () {
|
||||
testAbbreviation("http://example.com/foo/bar/baz/boo.js",
|
||||
"boo.js",
|
||||
"http://example.com/foo/bar/baz/boo.js",
|
||||
"example.com");
|
||||
});
|
||||
|
||||
// Test `sourceUtils.isScratchpadTheme`
|
||||
add_task(function* () {
|
||||
ok(sourceUtils.isScratchpadScheme("Scratchpad/1"),
|
||||
"Scratchpad/1 identified as scratchpad");
|
||||
ok(sourceUtils.isScratchpadScheme("Scratchpad/20"),
|
||||
"Scratchpad/20 identified as scratchpad");
|
||||
ok(!sourceUtils.isScratchpadScheme("http://www.mozilla.org"), "http://www.mozilla.org not identified as scratchpad");
|
||||
});
|
||||
|
||||
// Test `sourceUtils.getSourceNames`.
|
||||
add_task(function* () {
|
||||
// Check length
|
||||
let longMalformedURL = `example.com${new Array(100).fill("/a").join("")}/file.js`;
|
||||
ok(sourceUtils.getSourceNames(longMalformedURL).short.length <= 100,
|
||||
"`short` names are capped at 100 characters");
|
||||
|
||||
testAbbreviation("self-hosted", "self-hosted", "self-hosted");
|
||||
testAbbreviation("", "(unknown)", "(unknown)");
|
||||
|
||||
// Test shortening data URIs, stripping mime/charset
|
||||
testAbbreviation("data:text/html;charset=utf-8,<!DOCTYPE html></html>",
|
||||
"data:<!DOCTYPE html></html>",
|
||||
"data:text/html;charset=utf-8,<!DOCTYPE html></html>");
|
||||
|
||||
let longDataURI = `data:image/png;base64,${new Array(100).fill("a").join("")}`;
|
||||
let longDataURIShort = sourceUtils.getSourceNames(longDataURI).short;
|
||||
|
||||
// Test shortening data URIs and that the `short` result is capped
|
||||
ok(longDataURIShort.length <= 100,
|
||||
"`short` names are capped at 100 characters for data URIs");
|
||||
equal(longDataURIShort.substr(0, 10), "data:aaaaa",
|
||||
"truncated data URI short names still have `data:...`");
|
||||
|
||||
// Test simple URL and cache retrieval by calling the same input multiple times.
|
||||
let testUrl = "http://example.com/foo/bar/baz/boo.js";
|
||||
testAbbreviation(testUrl, "boo.js", testUrl, "example.com");
|
||||
testAbbreviation(testUrl, "boo.js", testUrl, "example.com");
|
||||
|
||||
// Check query and hash and port
|
||||
testAbbreviation("http://example.com:8888/foo/bar/baz.js?q=query#go",
|
||||
"baz.js",
|
||||
"http://example.com:8888/foo/bar/baz.js",
|
||||
"example.com:8888");
|
||||
|
||||
// Trailing "/" with nothing beyond host
|
||||
testAbbreviation("http://example.com/",
|
||||
"/",
|
||||
"http://example.com/",
|
||||
"example.com");
|
||||
|
||||
// Trailing "/"
|
||||
testAbbreviation("http://example.com/foo/bar/",
|
||||
"bar",
|
||||
"http://example.com/foo/bar/",
|
||||
"example.com");
|
||||
|
||||
// Non-extension ending
|
||||
testAbbreviation("http://example.com/bar",
|
||||
"bar",
|
||||
"http://example.com/bar",
|
||||
"example.com");
|
||||
|
||||
// Check query
|
||||
testAbbreviation("http://example.com/foo.js?bar=1&baz=2",
|
||||
"foo.js",
|
||||
"http://example.com/foo.js",
|
||||
"example.com");
|
||||
|
||||
// Check query with trailing slash
|
||||
testAbbreviation("http://example.com/foo/?bar=1&baz=2",
|
||||
"foo",
|
||||
"http://example.com/foo/",
|
||||
"example.com");
|
||||
});
|
||||
|
||||
// Test for source mapped file name
|
||||
add_task(function* () {
|
||||
const { getSourceMappedFile } = sourceUtils;
|
||||
const source = "baz.js";
|
||||
const output = getSourceMappedFile(source);
|
||||
equal(output, "baz.js", "correctly formats file name");
|
||||
// Test for OSX file path
|
||||
const source1 = "/foo/bar/baz.js";
|
||||
const output1 = getSourceMappedFile(source1);
|
||||
equal(output1, "baz.js", "correctly formats Linux file path");
|
||||
// Test for Windows file path
|
||||
const source2 = "Z:\\foo\\bar\\baz.js";
|
||||
const output2 = getSourceMappedFile(source2);
|
||||
equal(output2, "baz.js", "correctly formats Windows file path");
|
||||
});
|
||||
|
||||
function testAbbreviation(source, short, long, host) {
|
||||
let results = sourceUtils.getSourceNames(source);
|
||||
equal(results.short, short, `${source} has correct "short" name`);
|
||||
equal(results.long, long, `${source} has correct "long" name`);
|
||||
equal(results.host, host, `${source} has correct "host" name`);
|
||||
}
|
||||
149
devtools/client/shared/test/unit/test_suggestion-picker.js
Normal file
149
devtools/client/shared/test/unit/test_suggestion-picker.js
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test the suggestion-picker helper methods.
|
||||
*/
|
||||
const {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
|
||||
const {
|
||||
findMostRelevantIndex,
|
||||
findMostRelevantCssPropertyIndex
|
||||
} = require("devtools/client/shared/suggestion-picker");
|
||||
|
||||
/**
|
||||
* Run all tests defined below.
|
||||
*/
|
||||
function run_test() {
|
||||
ensureMostRelevantIndexProvidedByHelperFunction();
|
||||
ensureMostRelevantIndexProvidedByClassMethod();
|
||||
ensureErrorThrownWithInvalidArguments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic test data.
|
||||
*/
|
||||
const TEST_DATA = [
|
||||
{
|
||||
// Match in sortedItems array.
|
||||
items: ["chrome", "edge", "firefox"],
|
||||
sortedItems: ["firefox", "chrome", "edge"],
|
||||
expectedIndex: 2
|
||||
}, {
|
||||
// No match in sortedItems array.
|
||||
items: ["apple", "oranges", "banana"],
|
||||
sortedItems: ["kiwi", "pear", "peach"],
|
||||
expectedIndex: 0
|
||||
}, {
|
||||
// Empty items array.
|
||||
items: [],
|
||||
sortedItems: ["empty", "arrays", "can't", "have", "relevant", "indexes"],
|
||||
expectedIndex: -1
|
||||
}
|
||||
];
|
||||
|
||||
function ensureMostRelevantIndexProvidedByHelperFunction() {
|
||||
do_print("Running ensureMostRelevantIndexProvidedByHelperFunction()");
|
||||
|
||||
for (let testData of TEST_DATA) {
|
||||
let { items, sortedItems, expectedIndex } = testData;
|
||||
let mostRelevantIndex = findMostRelevantIndex(items, sortedItems);
|
||||
strictEqual(mostRelevantIndex, expectedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS properties test data.
|
||||
*/
|
||||
const CSS_TEST_DATA = [
|
||||
{
|
||||
items: [
|
||||
"backface-visibility",
|
||||
"background",
|
||||
"background-attachment",
|
||||
"background-blend-mode",
|
||||
"background-clip",
|
||||
"background-color",
|
||||
"background-image",
|
||||
"background-origin",
|
||||
"background-position",
|
||||
"background-repeat"
|
||||
],
|
||||
expectedIndex: 1
|
||||
},
|
||||
{
|
||||
items: [
|
||||
"caption-side",
|
||||
"clear",
|
||||
"clip",
|
||||
"clip-path",
|
||||
"clip-rule",
|
||||
"color",
|
||||
"color-interpolation",
|
||||
"color-interpolation-filters",
|
||||
"content",
|
||||
"counter-increment"
|
||||
],
|
||||
expectedIndex: 5
|
||||
},
|
||||
{
|
||||
items: [
|
||||
"direction",
|
||||
"display",
|
||||
"dominant-baseline"
|
||||
],
|
||||
expectedIndex: 1
|
||||
},
|
||||
{
|
||||
items: [
|
||||
"object-fit",
|
||||
"object-position",
|
||||
"offset-block-end",
|
||||
"offset-block-start",
|
||||
"offset-inline-end",
|
||||
"offset-inline-start",
|
||||
"opacity",
|
||||
"order",
|
||||
"orphans",
|
||||
"outline"
|
||||
],
|
||||
expectedIndex: 6
|
||||
},
|
||||
{
|
||||
items: [
|
||||
"white-space",
|
||||
"widows",
|
||||
"width",
|
||||
"will-change",
|
||||
"word-break",
|
||||
"word-spacing",
|
||||
"word-wrap",
|
||||
"writing-mode"
|
||||
],
|
||||
expectedIndex: 2
|
||||
}
|
||||
];
|
||||
|
||||
function ensureMostRelevantIndexProvidedByClassMethod() {
|
||||
do_print("Running ensureMostRelevantIndexProvidedByClassMethod()");
|
||||
|
||||
for (let testData of CSS_TEST_DATA) {
|
||||
let { items, expectedIndex } = testData;
|
||||
let mostRelevantIndex = findMostRelevantCssPropertyIndex(items);
|
||||
strictEqual(mostRelevantIndex, expectedIndex);
|
||||
}
|
||||
}
|
||||
|
||||
function ensureErrorThrownWithInvalidArguments() {
|
||||
do_print("Running ensureErrorThrownWithInvalidTypeArgument()");
|
||||
|
||||
let expectedError = "Please provide valid items and sortedItems arrays.";
|
||||
// No arguments passed.
|
||||
throws(() => findMostRelevantIndex(), expectedError);
|
||||
// Invalid arguments passed.
|
||||
throws(() => findMostRelevantIndex([]), expectedError);
|
||||
throws(() => findMostRelevantIndex(null, []), expectedError);
|
||||
throws(() => findMostRelevantIndex([], "string"), expectedError);
|
||||
throws(() => findMostRelevantIndex("string", []), expectedError);
|
||||
}
|
||||
98
devtools/client/shared/test/unit/test_undoStack.js
Normal file
98
devtools/client/shared/test/unit/test_undoStack.js
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {Loader} = Components.utils.import("resource://gre/modules/commonjs/toolkit/loader.js", {});
|
||||
|
||||
const loader = new Loader.Loader({
|
||||
paths: {
|
||||
"": "resource://gre/modules/commonjs/",
|
||||
"devtools": "resource://devtools",
|
||||
},
|
||||
globals: {},
|
||||
});
|
||||
const require = Loader.Require(loader, { id: "undo-test" });
|
||||
|
||||
const {UndoStack} = require("devtools/client/shared/undo");
|
||||
|
||||
const MAX_SIZE = 5;
|
||||
|
||||
function run_test() {
|
||||
let str = "";
|
||||
let stack = new UndoStack(MAX_SIZE);
|
||||
|
||||
function add(ch) {
|
||||
stack.do(function () {
|
||||
str += ch;
|
||||
}, function () {
|
||||
str = str.slice(0, -1);
|
||||
});
|
||||
}
|
||||
|
||||
do_check_false(stack.canUndo());
|
||||
do_check_false(stack.canRedo());
|
||||
|
||||
// Check adding up to the limit of the size
|
||||
add("a");
|
||||
do_check_true(stack.canUndo());
|
||||
do_check_false(stack.canRedo());
|
||||
|
||||
add("b");
|
||||
add("c");
|
||||
add("d");
|
||||
add("e");
|
||||
|
||||
do_check_eq(str, "abcde");
|
||||
|
||||
// Check a simple undo+redo
|
||||
stack.undo();
|
||||
|
||||
do_check_eq(str, "abcd");
|
||||
do_check_true(stack.canRedo());
|
||||
|
||||
stack.redo();
|
||||
do_check_eq(str, "abcde");
|
||||
do_check_false(stack.canRedo());
|
||||
|
||||
// Check an undo followed by a new action
|
||||
stack.undo();
|
||||
do_check_eq(str, "abcd");
|
||||
|
||||
add("q");
|
||||
do_check_eq(str, "abcdq");
|
||||
do_check_false(stack.canRedo());
|
||||
|
||||
stack.undo();
|
||||
do_check_eq(str, "abcd");
|
||||
stack.redo();
|
||||
do_check_eq(str, "abcdq");
|
||||
|
||||
// Revert back to the beginning of the queue...
|
||||
while (stack.canUndo()) {
|
||||
stack.undo();
|
||||
}
|
||||
do_check_eq(str, "");
|
||||
|
||||
// Now put it all back....
|
||||
while (stack.canRedo()) {
|
||||
stack.redo();
|
||||
}
|
||||
do_check_eq(str, "abcdq");
|
||||
|
||||
// Now go over the undo limit...
|
||||
add("1");
|
||||
add("2");
|
||||
add("3");
|
||||
|
||||
do_check_eq(str, "abcdq123");
|
||||
|
||||
// And now undoing the whole stack should only undo 5 actions.
|
||||
while (stack.canUndo()) {
|
||||
stack.undo();
|
||||
}
|
||||
|
||||
do_check_eq(str, "abc");
|
||||
}
|
||||
30
devtools/client/shared/test/unit/xpcshell.ini
Normal file
30
devtools/client/shared/test/unit/xpcshell.ini
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
[DEFAULT]
|
||||
tags = devtools
|
||||
head =
|
||||
tail =
|
||||
firefox-appdir = browser
|
||||
skip-if = toolkit == 'android'
|
||||
|
||||
support-files =
|
||||
../helper_color_data.js
|
||||
|
||||
[test_advanceValidate.js]
|
||||
[test_attribute-parsing-01.js]
|
||||
[test_attribute-parsing-02.js]
|
||||
[test_bezierCanvas.js]
|
||||
[test_cssAngle.js]
|
||||
[test_cssColor-01.js]
|
||||
[test_cssColor-02.js]
|
||||
[test_cssColor-03.js]
|
||||
[test_cssColorDatabase.js]
|
||||
[test_cubicBezier.js]
|
||||
[test_escapeCSSComment.js]
|
||||
[test_parseDeclarations.js]
|
||||
[test_parsePseudoClassesAndAttributes.js]
|
||||
[test_parseSingleValue.js]
|
||||
[test_rewriteDeclarations.js]
|
||||
[test_source-utils.js]
|
||||
[test_suggestion-picker.js]
|
||||
[test_undoStack.js]
|
||||
[test_VariablesView_filtering-without-controller.js]
|
||||
[test_VariablesView_getString_promise.js]
|
||||
Loading…
Add table
Add a link
Reference in a new issue