@FactoryTest public void compareScssWithCss(String scssResourceName) throws Exception { File scssFile = getSassLangResourceFile(scssResourceName); SCSSDocumentHandler documentHandler = new SCSSDocumentHandlerImpl(); SCSSErrorHandler errorHandler = new SCSSErrorHandler() { @Override public void error(CSSParseException arg0) throws CSSException { super.error(arg0); Assert.fail(arg0.getMessage()); } @Override public void fatalError(CSSParseException arg0) throws CSSException { super.error(arg0); Assert.fail(arg0.getMessage()); } @Override public void traverseError(Exception e) { super.traverseError(e); Assert.fail(e.getMessage()); } @Override public void traverseError(String message) { super.traverseError(message); Assert.fail(message); } }; ScssStylesheet scssStylesheet = ScssStylesheet.get(scssFile.getCanonicalPath(), null, documentHandler, errorHandler); scssStylesheet.compile(); String parsedCss = scssStylesheet.printState(); if (getCssFile(scssFile) != null) { String referenceCss = IOUtils.toString(new FileInputStream(getCssFile(scssFile))); String normalizedReference = normalize(referenceCss); String normalizedParsed = normalize(parsedCss); Assert.assertEquals( "Original CSS and parsed CSS do not match for " + scssResourceName, normalizedReference, normalizedParsed); } }
@Override public void traverse() { try { // limit variable scope to the mixin Map<String, VariableNode> variableScope = ScssStylesheet.openVariableScope(); replaceVariables(ScssStylesheet.getVariables()); replaceVariablesForChildren(); MixinNodeHandler.traverse(this); ScssStylesheet.closeVariableScope(variableScope); } catch (Exception e) { Logger.getLogger(MixinNode.class.getName()).log(Level.SEVERE, null, e); } }
protected void replaceVariablesForChildren() { for (Node child : getChildren()) { if (child instanceof IVariableNode) { ((IVariableNode) child).replaceVariables(ScssStylesheet.getVariables()); } } }
@Override public void traverse() { /* * "replaceVariables(ScssStylesheet.getVariables());" seems duplicated * and can be extracted out of if, but it is not. * containsArithmeticalOperator must be called before replaceVariables. * Because for the "/" operator, it needs to see if its predecessor or * successor is a Variable or not, to determine it is an arithmetic * operator. */ if (ArithmeticExpressionEvaluator.get().containsArithmeticalOperator(value)) { replaceVariables(ScssStylesheet.getVariables()); value = ArithmeticExpressionEvaluator.get().evaluate(value); } else { replaceVariables(ScssStylesheet.getVariables()); } }
@Test public void test() { /* * Read initial css code */ CssParser cssParserInputFile = new Css3Parser(); try { cssParserInputFile.parse(Config.getInstance().inputFile()); cssParserInputFile.removeDuplicates(); } catch (CssParsingException e) { IoUtils.printErrorAndExit(e); } /* * Generate sass code from initial css code */ Pair<List<SslMixin>, List<SslRuleset>> statements = null; try { statements = CssToSsl.compute(cssParserInputFile.getRulesets()); } catch (Exception e) { IoUtils.printErrorAndExit(e); } /* * Write generated sass code */ try { SslWriter sslWriter = new SassWriterDebug(); sslWriter.writeGeneratedCode(statements, Config.getInstance().outputFile()); } catch (IOException e) { IoUtils.printErrorAndExit(e); } /* * Generate css code from generated sass code */ try { ScssStylesheet stylesheet = ScssStylesheet.get(this.sassGeneratedFile.toString()); stylesheet.compile(); Files.write(this.cssGeneratedFile.toPath(), stylesheet.printState().getBytes()); } catch (Exception e) { IoUtils.printErrorAndExit(e); } /* * Read generated css code */ CssParser cssParserGeneratedFile = new Css3Parser(); try { cssParserGeneratedFile.parse(this.cssGeneratedFile); if (!Config.getInstance().noDuplicatesInRuleset()) { cssParserGeneratedFile.removeDuplicates(); } } catch (CssParsingException e) { IoUtils.printErrorAndExit(e); } /* * Compare initial css file and generated css file, * according to the configuration */ List<CssRuleset> initialRulesets = cssParserInputFile.getRulesets(); List<CssRuleset> generatedRulesets = cssParserGeneratedFile.getRulesets(); if (Config.getInstance().preserveSemantic()) { Consumer<List<CssRuleset>> rulesetsSorting = r -> { Collections.sort( r, (CssRuleset r1, CssRuleset r2) -> { Selector s1 = r1.getSelector(); Selector s2 = r2.getSelector(); int firstRulesetPosition = s1.getPosition().getLineNumber(); int secondRulesetPosition = s2.getPosition().getLineNumber(); if (firstRulesetPosition < secondRulesetPosition) { return -1; } else if (firstRulesetPosition == secondRulesetPosition) { return s1.getSelector().compareTo(s2.getSelector()); } else { return 1; } }); }; assertEquals(initialRulesets.size(), generatedRulesets.size()); rulesetsSorting.accept(initialRulesets); rulesetsSorting.accept(generatedRulesets); for (int i = 0; i < initialRulesets.size(); i++) { CssRuleset initialRuleset = initialRulesets.get(i); CssRuleset generatedRuleset = generatedRulesets.get(i); String initialSelector = initialRuleset.getSelector().getSelector(); String generatedSelector = generatedRuleset.getSelector().getSelector(); List<DeclarationConcrete> initialDeclarations = initialRuleset.getDeclarations(); List<DeclarationConcrete> generatedDeclarations = generatedRuleset.getDeclarations(); assertEquals(initialSelector, generatedSelector); if (Config.getInstance().noDuplicatesInRuleset()) { assertEquals(initialDeclarations.size(), generatedDeclarations.size()); } assertEquals(Sets.newHashSet(initialDeclarations), Sets.newHashSet(generatedDeclarations)); } } else { Function<List<CssRuleset>, Map<String, List<DeclarationConcrete>>> mergeIdenticalSelectors = rulesets -> { Map<String, List<DeclarationConcrete>> result = new HashMap<>(); rulesets.forEach( ruleset -> { String selector = ruleset.getSelector().getSelector(); List<DeclarationConcrete> declarations = ruleset.getDeclarations(); if (!result.containsKey(selector)) { result.put(selector, Lists.newArrayList()); } result.get(selector).addAll(declarations); }); return result; }; Map<String, List<DeclarationConcrete>> initialData = mergeIdenticalSelectors.apply(initialRulesets); Map<String, List<DeclarationConcrete>> generatedData = mergeIdenticalSelectors.apply(generatedRulesets); assertEquals(initialData.keySet(), generatedData.keySet()); initialData.forEach( (initialSelector, initialDeclarations) -> { List<DeclarationConcrete> generatedDeclarations = generatedData.get(initialSelector); if (Config.getInstance().noDuplicatesInRuleset()) { assertEquals(initialDeclarations.size(), generatedDeclarations.size()); } assertEquals( Sets.newHashSet(initialDeclarations), Sets.newHashSet(generatedDeclarations)); }); } }