blob: 3ae81d401afc902e080f2fb10dcb9b14318b4cb8 [file] [log] [blame]
var initialize_SassTest = function() {
InspectorTest.preloadModule("sass");
var sassSourceMapFactory = null;
InspectorTest.sassSourceMapFactory = function()
{
if (!sassSourceMapFactory)
sassSourceMapFactory = new Sass.SASSSourceMapFactory();
return sassSourceMapFactory;
}
InspectorTest.parseSCSS = function(url, text)
{
return Sass.SASSSupport.parseSCSS(url, text);
}
InspectorTest.parseCSS = InspectorTest.parseSCSS;
InspectorTest.loadASTMapping = function(header, callback)
{
var sourceMapManager = header.cssModel().sourceMapManager();
var sourceMap = sourceMapManager.sourceMapForClient(header);
if (sourceMap) {
callback(sourceMap.editable() ? sourceMap : null);
return;
}
sourceMapManager.addEventListener(SDK.SourceMapManager.Events.SourceMapAttached, onAttached);
function onAttached(event) {
if (event.data.client !== header)
return;
sourceMapManager.removeEventListener(SDK.SourceMapManager.Events.SourceMapAttached, onAttached);
var sourceMap = event.data.sourceMap;
callback(sourceMap.editable()? sourceMap : null);
}
}
InspectorTest.dumpAST = function(ast)
{
var lines = [String.sprintf("=== AST === %s", ast.document.url)];
for (var i = 0; i < ast.rules.length; ++i) {
var rule = ast.rules[i];
lines.push(String.sprintf("rule %d", i));
var ruleLines = dumpRule(rule);
lines = lines.concat(indent(ruleLines));
}
lines.push("======");
InspectorTest.addResult(lines.join("\n"));
return ast;
function dumpRule(rule)
{
var lines = [];
for (var i = 0; i < rule.selectors.length; ++i) {
var selector = rule.selectors[i];
lines.push(`selector ${i}: "${selector.text}"`);
var selectorLines = dumpTextNode(selector);
lines = lines.concat(indent(selectorLines));
}
for (var i = 0; i < rule.properties.length; ++i) {
var property = rule.properties[i];
lines.push("property " + i);
var propertyLines = dumpProperty(property);
lines = lines.concat(indent(propertyLines));
}
return lines;
}
function dumpProperty(property)
{
var lines = [];
lines.push(String.sprintf("name: \"%s\"", property.name.text));
lines = lines.concat(indent(dumpTextNode(property.name)));
lines.push(String.sprintf("value: \"%s\"", property.value.text));
lines = lines.concat(indent(dumpTextNode(property.value)));
lines.push(String.sprintf("range: %s", property.range.toString()));
lines.push(String.sprintf("disabled: %s", property.disabled));
return lines;
}
function dumpTextNode(textNode)
{
return [String.sprintf("range: %s", textNode.range.toString())];
}
}
function indent(lines)
{
return lines.map(line => " " + line);
}
InspectorTest.dumpASTDiff = function(diff)
{
InspectorTest.addResult("=== Diff ===");
var changesPerRule = new Map();
for (var change of diff.changes) {
var oldRule = change.oldRule;
var ruleChanges = changesPerRule.get(oldRule);
if (!ruleChanges) {
ruleChanges = [];
changesPerRule.set(oldRule, ruleChanges);
}
ruleChanges.push(change);
}
var T = Sass.SASSSupport.PropertyChangeType;
for (var rule of changesPerRule.keys()) {
var changes = changesPerRule.get(rule);
var names = [];
var values = [];
for (var property of rule.properties) {
names.push(str(property.name, " "));
values.push(str(property.value));
}
for (var i = changes.length - 1; i >= 0; --i) {
var change = changes[i];
var newProperty = change.newRule.properties[change.newPropertyIndex];
var oldProperty = change.oldRule.properties[change.oldPropertyIndex];
switch (change.type) {
case T.PropertyAdded:
names.splice(change.oldPropertyIndex, 0, str(newProperty.name, "[+] "));
values.splice(change.oldPropertyIndex, 0, str(newProperty.value));
break;
case T.PropertyRemoved:
names[change.oldPropertyIndex] = str(oldProperty.name, "[-] ");
break;
case T.PropertyToggled:
names[change.oldPropertyIndex] = str(oldProperty.name, "[T] ");
break;
case T.NameChanged:
names[change.oldPropertyIndex] = str(oldProperty.name, "[M] ");
break;
case T.ValueChanged:
values[change.oldPropertyIndex] = str(oldProperty.value, "[M] ");
break;
}
}
var selectorText = rule.selectors.map(selector => selector.text).join(",");
InspectorTest.addResult("Changes for rule: " + selectorText);
names = indent(names);
for (var i = 0; i < names.length; ++i)
InspectorTest.addResult(names[i] + ": " + values[i]);
}
function str(node, prefix)
{
prefix = prefix || "";
return prefix + node.text.trim();
}
}
InspectorTest.validateASTRanges = function(ast)
{
var invalidNodes = [];
for (var rule of ast.rules) {
for (var property of rule.properties) {
validate(property.name);
validate(property.value);
}
}
if (invalidNodes.length) {
InspectorTest.addResult("Bad ranges: " + invalidNodes.length);
for (var node of invalidNodes)
InspectorTest.addResult(String.sprintf(" - range: %s text: %s", node.range.toString(), node.text));
} else {
InspectorTest.addResult("Ranges OK.");
}
return ast;
function validate(textNode)
{
if (textNode.document.text.extract(textNode.range) !== textNode.text)
invalidNodes.push(textNode);
}
}
InspectorTest.validateMapping = function(mapping)
{
InspectorTest.addResult("Mapped CSS: " + mapping._compiledToSource.size);
InspectorTest.addResult("Mapped SCSS: " + mapping._sourceToCompiled.size);
var cssNodes = mapping._compiledToSource.keysArray();
var staleCSS = 0;
var staleSASS = 0;
for (var i = 0; i < cssNodes.length; ++i) {
var cssNode = cssNodes[i];
staleCSS += cssNode.document !== mapping.compiledModel().document ? 1 : 0;
var sassNode = mapping.toSourceNode(cssNode);
var sassAST = mapping.sourceModels().get(sassNode.document.url);
staleSASS += sassNode.document !== sassAST.document ? 1 : 0;
}
if (staleCSS || staleSASS) {
InspectorTest.addResult("ERROR: found stale entries");
InspectorTest.addResult(" -stale CSS: " + staleCSS);
InspectorTest.addResult(" -stale SASS: " + staleSASS);
} else {
InspectorTest.addResult("No stale entries found.");
}
}
InspectorTest.updateCSSText = function(url, newText)
{
var styleSheetIds = InspectorTest.cssModel.styleSheetIdsForURL(url)
var promises = styleSheetIds.map(id => InspectorTest.cssModel.setStyleSheetText(id, newText, true));
return Promise.all(promises);
}
InspectorTest.updateSASSText = function(url, newText)
{
var uiSourceCode = Workspace.workspace.uiSourceCodeForURL(url);
uiSourceCode.addRevision(newText);
}
InspectorTest.runCSSEditTests = function(header, tests)
{
var astSourceMap;
InspectorTest.loadASTMapping(header, onMapping);
function onMapping(map)
{
astSourceMap = map;
InspectorTest.addResult("INITIAL MODELS");
logASTText(map.compiledModel(), true);
for (var ast of map.sourceModels().values())
logASTText(ast, true);
runTests();
}
function runTests()
{
if (!tests.length) {
InspectorTest.completeTest();
return;
}
var test = tests.shift();
logTestName(test.name);
var text = astSourceMap.compiledModel().document.text.value();
var edits = test(text);
logSourceEdits(text, edits);
var ranges = edits.map(edit => edit.oldRange);
var texts = edits.map(edit => edit.newText);
astSourceMap.editCompiled(ranges, texts)
.then(onEditsDone);
}
function onEditsDone(result)
{
if (!result.map) {
InspectorTest.addResult("SASSProcessor failed to process edits.");
runTests();
return;
}
logASTText(result.map.compiledModel());
for (var sassURL of result.newSources.keys()) {
var ast = result.map.sourceModels().get(sassURL);
logASTText(ast);
}
runTests();
}
function logASTText(ast, avoidIndent, customTitle)
{
customTitle = customTitle || ast.document.url.split("/").pop();
InspectorTest.addResult("===== " + customTitle + " =====");
var text = ast.document.text.value().replace(/ /g, ".");
var lines = text.split("\n");
if (!avoidIndent)
lines = indent(lines);
InspectorTest.addResult(lines.join("\n"));
}
function logTestName(testName)
{
var titleText = " TEST: " + testName + " ";
var totalLength = 80;
var prefixLength = ((totalLength - titleText.length) / 2)|0;
var suffixLength = totalLength - titleText.length - prefixLength;
var prefix = new Array(prefixLength).join("-");
var suffix = new Array(suffixLength).join("-");
InspectorTest.addResult("\n" + prefix + titleText + suffix + "\n");
}
function logSourceEdits(text, edits)
{
var lines = [];
for (var i = 0; i < edits.length; ++i) {
var edit = edits[i];
var range = edit.oldRange;
var line = String.sprintf("{%d, %d, %d, %d}", range.startLine, range.startColumn, range.endLine, range.endColumn);
line += String.sprintf(" '%s' => '%s'", (new TextUtils.Text(text)).extract(range), edit.newText);
lines.push(line);
}
lines = indent(lines);
lines.unshift("Edits:");
InspectorTest.addResult(lines.join("\n"));
}
}
InspectorTest.createEdit = function(source, pattern, newText, matchNumber)
{
matchNumber = matchNumber || 0;
var re = new RegExp(pattern.escapeForRegExp(), "g");
var match;
while ((match = re.exec(source)) !== null && matchNumber) {
--matchNumber;
}
if (!match)
return null;
var sourceRange = new TextUtils.SourceRange(match.index, match[0].length);
var textRange = new TextUtils.Text(source).toTextRange(sourceRange);
return new TextUtils.SourceEdit("", textRange, newText);
}
}