From 3d50b765521dc3c103c603bba90a81243e17ad0e Mon Sep 17 00:00:00 2001 From: Nathan Harkenrider Date: Fri, 3 May 2013 20:50:49 +0000 Subject: [PATCH] Add the ability to specify the input encoding for the LessCompiler. Defaults to the default encoding if not specified. --- src/main/java/org/lesscss/LessCompiler.java | 50 +++++++++++++---- src/main/java/org/lesscss/LessSource.java | 7 ++- .../java/org/lesscss/LessCompilerTest.java | 56 +++++++++---------- src/test/java/org/lesscss/LessSourceTest.java | 5 +- 4 files changed, 74 insertions(+), 44 deletions(-) diff --git a/src/main/java/org/lesscss/LessCompiler.java b/src/main/java/org/lesscss/LessCompiler.java index 1f3541e..b020375 100644 --- a/src/main/java/org/lesscss/LessCompiler.java +++ b/src/main/java/org/lesscss/LessCompiler.java @@ -21,6 +21,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; + +import org.apache.commons.io.Charsets; import org.apache.commons.io.FileUtils; import org.lesscss.logging.LessLogger; import org.lesscss.logging.LessLoggerFactory; @@ -66,7 +68,8 @@ public class LessCompiler { private URL lessJs = LessCompiler.class.getClassLoader().getResource("META-INF/less.js"); private List customJs = Collections.emptyList(); private boolean compress = false; - private String encoding = null; + private String outputEncoding = null; + private String inputEncoding = null; private Function doIt; @@ -113,7 +116,7 @@ public URL getLessJs() { * Sets the LESS JavaScript file used by the compiler. * Must be set before {@link #init()} is called. * - * @param The LESS JavaScript file used by the compiler. + * @param lessJs The LESS JavaScript file used by the compiler. */ public synchronized void setLessJs(URL lessJs) { if (scope != null) { @@ -181,12 +184,12 @@ public synchronized void setCompress(boolean compress) { } /** - * Returns the character encoding used by the compiler when writing the output File. + * Returns the character outputEncoding used by the compiler when writing the output File. * - * @return The character encoding used by the compiler when writing the output File. + * @return The character outputEncoding used by the compiler when writing the output File. */ - public String getEncoding() { - return encoding; + public String getOutputEncoding() { + return outputEncoding; } /** @@ -194,13 +197,36 @@ public String getEncoding() { * If not set the platform default will be used. * Must be set before {@link #init()} is called. * - * @param The character encoding used by the compiler when writing the output File. + * @param outputEncoding The character encoding used by the compiler when writing the output File. + */ + public synchronized void setOutputEncoding(String outputEncoding) { + if (scope != null) { + throw new IllegalStateException("This method can only be called before init()"); + } + this.outputEncoding = outputEncoding; + } + + /** + * Returns the character encoding used by the compiler when reading the input File. + * + * @return The character encoding used by the compiler when reading the input File. + */ + public String getInputEncoding() { + return inputEncoding; + } + + /** + * Sets the character encoding used by the compiler when reading the input File. + * If not set the platform default will be used. + * Must be set before {@link #init()} is called. + * + * @param inputEncoding The character encoding used by the compiler when reading the input File. */ - public synchronized void setEncoding(String encoding) { + public synchronized void setInputEncoding(String inputEncoding) { if (scope != null) { throw new IllegalStateException("This method can only be called before init()"); } - this.encoding = encoding; + this.inputEncoding = inputEncoding; } /** @@ -298,7 +324,7 @@ public String compile(String input) throws LessException { * @throws IOException If the LESS file cannot be read. */ public String compile(File input) throws IOException, LessException { - LessSource lessSource = new LessSource(input); + LessSource lessSource = new LessSource(input, Charsets.toCharset(inputEncoding)); return compile(lessSource); } @@ -322,7 +348,7 @@ public void compile(File input, File output) throws IOException, LessException { * @throws IOException If the LESS file cannot be read or the output file cannot be written. */ public void compile(File input, File output, boolean force) throws IOException, LessException { - LessSource lessSource = new LessSource(input); + LessSource lessSource = new LessSource(input, Charsets.toCharset(inputEncoding)); compile(lessSource, output, force); } @@ -358,7 +384,7 @@ public void compile(LessSource input, File output) throws IOException, LessExcep public void compile(LessSource input, File output, boolean force) throws IOException, LessException { if (force || !output.exists() || output.lastModified() < input.getLastModifiedIncludingImports()) { String data = compile(input); - FileUtils.writeStringToFile(output, data, encoding); + FileUtils.writeStringToFile(output, data, outputEncoding); } } } diff --git a/src/main/java/org/lesscss/LessSource.java b/src/main/java/org/lesscss/LessSource.java index ea3276b..1ad1308 100644 --- a/src/main/java/org/lesscss/LessSource.java +++ b/src/main/java/org/lesscss/LessSource.java @@ -43,6 +43,7 @@ public class LessSource { private String content; private String normalizedContent; private Map imports = new LinkedHashMap(); + private Charset inputCharset; /** * Constructs a new LessSource. @@ -76,10 +77,14 @@ public LessSource(File file, Charset charset) throws IOException { if (file == null) { throw new IllegalArgumentException("File must not be null."); } + if(charset == null) { + throw new IllegalArgumentException("Charset must not be null"); + } if (!file.exists()) { throw new FileNotFoundException("File " + file.getAbsolutePath() + " not found."); } this.file = file; + this.inputCharset = charset; this.content = this.normalizedContent = FileUtils.readFileToString(file, charset); resolveImports(); } @@ -163,7 +168,7 @@ private void resolveImports() throws FileNotFoundException, IOException { importedFile = importedFile.matches(".*\\.(le?|c)ss$") ? importedFile : importedFile + ".less"; boolean css = importedFile.matches(".*css$"); if (!css) { - LessSource importedLessSource = new LessSource(new File(file.getParentFile(), importedFile)); + LessSource importedLessSource = new LessSource(new File(file.getParentFile(), importedFile), inputCharset); imports.put(importedFile, importedLessSource); normalizedContent = normalizedContent.substring(0, importMatcher.start()) + importedLessSource.getNormalizedContent() + normalizedContent.substring(importMatcher.end()); importMatcher = IMPORT_PATTERN.matcher(normalizedContent); diff --git a/src/test/java/org/lesscss/LessCompilerTest.java b/src/test/java/org/lesscss/LessCompilerTest.java index 4b4d6cf..1c4650b 100644 --- a/src/test/java/org/lesscss/LessCompilerTest.java +++ b/src/test/java/org/lesscss/LessCompilerTest.java @@ -33,6 +33,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; + +import org.apache.commons.io.Charsets; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.junit.Before; @@ -48,10 +50,6 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import org.lesscss.LessCompiler; -import org.lesscss.LessException; -import org.lesscss.LessSource; - @PrepareForTest({Context.class, FileUtils.class, LessCompiler.class}) @RunWith(PowerMockRunner.class) public class LessCompilerTest { @@ -275,14 +273,14 @@ public void testCompileFileToString() throws Exception { FieldUtils.writeField(lessCompiler, "scope", scope, true); FieldUtils.writeField(lessCompiler, "doIt", doIt, true); - whenNew(LessSource.class).withArguments(inputFile).thenReturn(lessSource); + whenNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String) null)).thenReturn(lessSource); when(lessSource.getNormalizedContent()).thenReturn(less); when(doIt.call(cx, scope, null, new Object[]{less, false})).thenReturn(css); assertEquals(css, lessCompiler.compile(inputFile)); - verifyNew(LessSource.class).withArguments(inputFile); + verifyNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)); verify(lessSource).getNormalizedContent(); verify(doIt).call(cx, scope, null, new Object[]{less, false}); @@ -294,8 +292,8 @@ public void testCompileFileToFile() throws Exception { when(Context.enter()).thenReturn(cx); FieldUtils.writeField(lessCompiler, "scope", scope, true); FieldUtils.writeField(lessCompiler, "doIt", doIt, true); - - whenNew(LessSource.class).withArguments(inputFile).thenReturn(lessSource); + + whenNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)).thenReturn(lessSource); when(lessSource.getNormalizedContent()).thenReturn(less); when(doIt.call(cx, scope, null, new Object[]{less, false})).thenReturn(css); @@ -303,8 +301,8 @@ public void testCompileFileToFile() throws Exception { mockStatic(FileUtils.class); lessCompiler.compile(inputFile, outputFile); - - verifyNew(LessSource.class).withArguments(inputFile); + + verifyNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)); verify(lessSource).getNormalizedContent(); verify(doIt).call(cx, scope, null, new Object[]{less, false}); @@ -319,8 +317,8 @@ public void testCompileFileToFileWithForceTrue() throws Exception { when(Context.enter()).thenReturn(cx); FieldUtils.writeField(lessCompiler, "scope", scope, true); FieldUtils.writeField(lessCompiler, "doIt", doIt, true); - - whenNew(LessSource.class).withArguments(inputFile).thenReturn(lessSource); + + whenNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)).thenReturn(lessSource); when(lessSource.getNormalizedContent()).thenReturn(less); when(doIt.call(cx, scope, null, new Object[]{less, false})).thenReturn(css); @@ -328,8 +326,8 @@ public void testCompileFileToFileWithForceTrue() throws Exception { mockStatic(FileUtils.class); lessCompiler.compile(inputFile, outputFile, true); - - verifyNew(LessSource.class).withArguments(inputFile); + + verifyNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)); verify(lessSource).getNormalizedContent(); verify(doIt).call(cx, scope, null, new Object[]{less, false}); @@ -346,8 +344,8 @@ public void testCompileFileToFileWithForceFalseAndOutputNotExists() throws Excep FieldUtils.writeField(lessCompiler, "doIt", doIt, true); when(outputFile.exists()).thenReturn(false); - - whenNew(LessSource.class).withArguments(inputFile).thenReturn(lessSource); + + whenNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)).thenReturn(lessSource); when(lessSource.getNormalizedContent()).thenReturn(less); when(doIt.call(cx, scope, null, new Object[]{less, false})).thenReturn(css); @@ -355,8 +353,8 @@ public void testCompileFileToFileWithForceFalseAndOutputNotExists() throws Excep mockStatic(FileUtils.class); lessCompiler.compile(inputFile, outputFile, false); - - verifyNew(LessSource.class).withArguments(inputFile); + + verifyNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)); verify(outputFile).exists(); @@ -374,8 +372,8 @@ public void testCompileFileToFileWithForceFalseAndOutputExistsAndLessSourceModif when(Context.enter()).thenReturn(cx); FieldUtils.writeField(lessCompiler, "scope", scope, true); FieldUtils.writeField(lessCompiler, "doIt", doIt, true); - - whenNew(LessSource.class).withArguments(inputFile).thenReturn(lessSource); + + whenNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)).thenReturn(lessSource); when(outputFile.exists()).thenReturn(true); when(outputFile.lastModified()).thenReturn(1l); @@ -388,8 +386,8 @@ public void testCompileFileToFileWithForceFalseAndOutputExistsAndLessSourceModif mockStatic(FileUtils.class); lessCompiler.compile(inputFile, outputFile, false); - - verifyNew(LessSource.class).withArguments(inputFile); + + verifyNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)); verify(outputFile).exists(); verify(outputFile).lastModified(); @@ -409,8 +407,8 @@ public void testCompileFileToFileWithForceFalseAndOutputExistsAndLessSourceNotMo when(Context.enter()).thenReturn(cx); FieldUtils.writeField(lessCompiler, "scope", scope, true); FieldUtils.writeField(lessCompiler, "doIt", doIt, true); - - whenNew(LessSource.class).withArguments(inputFile).thenReturn(lessSource); + + whenNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)).thenReturn(lessSource); when(outputFile.exists()).thenReturn(true); when(outputFile.lastModified()).thenReturn(2l); @@ -418,8 +416,8 @@ public void testCompileFileToFileWithForceFalseAndOutputExistsAndLessSourceNotMo when(lessSource.getLastModifiedIncludingImports()).thenReturn(1l); lessCompiler.compile(inputFile, outputFile, false); - - verifyNew(LessSource.class).withArguments(inputFile); + + verifyNew(LessSource.class).withArguments(inputFile, Charsets.toCharset((String)null)); verify(outputFile).exists(); verify(outputFile).lastModified(); @@ -601,11 +599,11 @@ public void testCompress() throws Exception { public void testEncoding() throws Exception { mockStatic(Context.class); when(Context.enter()).thenReturn(cx); - lessCompiler.setEncoding("utf-8"); + lessCompiler.setOutputEncoding("utf-8"); FieldUtils.writeField(lessCompiler, "scope", scope, true); FieldUtils.writeField(lessCompiler, "doIt", doIt, true); - whenNew(LessSource.class).withArguments(inputFile).thenReturn(lessSource); + whenNew(LessSource.class).withArguments(inputFile, Charsets.toCharset(lessCompiler.getInputEncoding())).thenReturn(lessSource); when(lessSource.getNormalizedContent()).thenReturn(less); when(doIt.call(cx, scope, null, new Object[]{less, false})).thenReturn(css); @@ -614,7 +612,7 @@ public void testEncoding() throws Exception { lessCompiler.compile(inputFile, outputFile); - verifyNew(LessSource.class).withArguments(inputFile); + verifyNew(LessSource.class).withArguments(inputFile, Charsets.toCharset(lessCompiler.getInputEncoding())); verify(lessSource).getNormalizedContent(); verify(doIt).call(cx, scope, null, new Object[]{less, false}); diff --git a/src/test/java/org/lesscss/LessSourceTest.java b/src/test/java/org/lesscss/LessSourceTest.java index 9deb957..758f584 100644 --- a/src/test/java/org/lesscss/LessSourceTest.java +++ b/src/test/java/org/lesscss/LessSourceTest.java @@ -14,6 +14,7 @@ */ package org.lesscss; +import org.apache.commons.io.Charsets; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.reflect.FieldUtils; import org.junit.Before; @@ -75,7 +76,7 @@ public void testNewLessSourceWithoutImports() throws Exception { assertEquals(0, lessSource.getImports().size()); verifyStatic(); - FileUtils.readFileToString(file); + FileUtils.readFileToString(file, Charset.defaultCharset()); } @Test(expected = IllegalArgumentException.class) @@ -140,7 +141,7 @@ private String readLessSourceWithEncoding(String encoding) throws IOException, I private File mockFile(boolean fileExists, String content, String absolutePath) throws IOException { when(file.exists()).thenReturn(fileExists); mockStatic(FileUtils.class); - when(FileUtils.readFileToString(file)).thenReturn(content); + when(FileUtils.readFileToString(file, Charset.defaultCharset())).thenReturn(content); when(file.getAbsolutePath()).thenReturn(absolutePath); when(file.lastModified()).thenReturn(lastModified); when(file.getParent()).thenReturn("folder");