package org.jooby.assets; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileNotFoundException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import org.jooby.Asset; import org.jooby.MediaType; import org.jooby.internal.URLAsset; import org.junit.Test; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.google.common.io.ByteStreams; import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import com.typesafe.config.ConfigValueFactory; import javaslang.control.Try; public class AssetCompilerTest { @Test public void newCompiler() throws Exception { assertEquals("{home=[/assets/index.js, /assets/index.css]}", new AssetCompiler(conf("assets-test.conf", "dev")).toString()); } @Test public void fileSet() throws Exception { assertEquals(Sets.newHashSet("home"), new AssetCompiler(conf("assets-test.conf", "dev")).fileset()); assertEquals(Sets.newHashSet(), new AssetCompiler(conf("empty.conf", "dev")).fileset()); assertEquals(Sets.newHashSet("home", "home1", "home2", "home3", "base", "lib", "lib2", "tjs"), new AssetCompiler(conf("assets-fileset.conf", "dev")).fileset()); } @Test public void fileSetAggregator() throws Exception { assertEquals(Lists.newArrayList("/assets/dyn.css", "/assets/index.js", "/assets/index.css"), new AssetCompiler(conf("assets-aggregator.conf", "dev")).assets("mypage")); assertEquals(Lists.newArrayList("/aggregator-missing", "/assets/index.js", "/assets/index.css"), new AssetCompiler(conf("assets-missing-aggregator.conf", "dev")).assets("mypage")); } @Test public void listAggregators() throws Exception { assertEquals("[aggregator-test]", new AssetCompiler(conf("assets-aggregator.conf", "dev")).aggregators().toString()); } @Test public void fileSetContains() throws Exception { assertEquals(true, new AssetCompiler(conf("assets-aggregator.conf", "dev")).contains("/assets/index.js")); } @Test public void fileSetContainsShouldReturnsFalseForAggregatorFileSet() throws Exception { assertEquals(false, new AssetCompiler(conf("assets-aggregator.conf", "dev")).contains("/assets/dyn.css")); } @Test public void basedir() throws Exception { assertEquals( Lists.newArrayList("/assets/base/base.js", "/assets/home.css", "/assets/js/home.js"), new AssetCompiler(conf("assets-basedir.conf", "dev")).assets("home")); } @Test public void patterns() throws Exception { assertEquals(Sets.newHashSet("/assets/**"), new AssetCompiler(conf("assets-pattern-1.conf", "dev")).patterns()); assertEquals(Sets.newHashSet("/js/**", "/css/**"), new AssetCompiler(conf("assets-pattern-2.conf", "dev")).patterns()); } @Test public void assets() throws Exception { assertEquals(Lists.newArrayList("/assets/base.js", "/assets/normalize.css"), new AssetCompiler(conf("assets-fileset.conf", "dev")).assets("base")); assertEquals(Lists.newArrayList("/assets/jquery.js"), new AssetCompiler(conf("assets-fileset.conf", "dev")).assets("lib")); assertEquals(Lists.newArrayList("/assets/jquery.js", "/assets/jquery-ui.js"), new AssetCompiler(conf("assets-fileset.conf", "dev")).assets("lib2")); assertEquals(Lists.newArrayList("/assets/index.js", "/assets/index.css"), new AssetCompiler(conf("assets-fileset.conf", "dev")).assets("home")); assertEquals(Lists.newArrayList("/assets/base.js", "/assets/normalize.css", "/assets/index.js", "/assets/index.css"), new AssetCompiler(conf("assets-fileset.conf", "dev")).assets("home1")); assertEquals(Lists.newArrayList("/assets/base.js", "/assets/normalize.css", "/assets/jquery.js", "/assets/index.js", "/assets/index.css"), new AssetCompiler(conf("assets-fileset.conf", "dev")).assets("home2")); assertEquals(Lists.newArrayList("/assets/jquery.js", "/assets/jquery-ui.js", "/assets/index.js", "/assets/index.css"), new AssetCompiler(conf("assets-fileset.conf", "dev")).assets("home3")); assertEquals(Lists.newArrayList("/assets/tjs.tjs"), new AssetCompiler(conf("assets-fileset.conf", "dev")).assets("tjs")); } @Test public void scripts() throws Exception { assertEquals(Arrays.asList("/assets/base.js"), new AssetCompiler(conf("assets-fileset.conf", "dev")).scripts("base")); assertEquals(Arrays.asList("/assets/normalize.css"), new AssetCompiler(conf("assets-fileset.conf", "dev")).styles("base")); } @Test public void build() throws Exception { assertEquals("processor-test:", compile(new AssetCompiler(conf("assets-test.conf", "dev")), "/assets/index.js")); assertEquals("css-processor-test:", compile(new AssetCompiler(conf("assets-test.conf", "dev")), "/assets/index.css")); } @Test public void bundle() throws Exception { File dir = Paths.get("target", "public").toFile(); Map<String, List<File>> files = new AssetCompiler(conf("assets-compile-all.conf", "dev")) .build("dev", dir); Set<File> expected = Sets.newHashSet( Paths.get("target", "public", "assets", "all.0a36d8bd.css").toFile(), Paths.get("target", "public", "assets", "all.9a92930a.js").toFile()); files.values() .forEach(file -> file .forEach(it -> { assertTrue(it.exists()); expected.remove(it); })); assertEquals(0, expected.size()); } @Test public void bundlenojs() throws Exception { File dir = Paths.get("target", "public", "nojs").toFile(); Map<String, List<File>> files = new AssetCompiler(conf("assets-nojs.conf", "dev")) .build("dev", dir); Set<File> expected = Sets.newHashSet( Paths.get("target", "public", "nojs", "css", "home.9a0e50cb.css").toFile()); files.values() .forEach(file -> file .forEach(it -> { assertTrue(it.exists()); expected.remove(it); })); assertEquals(0, expected.size()); } @Test public void bundlenocss() throws Exception { File dir = Paths.get("target", "public", "nojs").toFile(); Map<String, List<File>> files = new AssetCompiler(conf("assets-nocss.conf", "dev")) .build("dev", dir); Set<File> expected = Sets.newHashSet( Paths.get("target", "public", "nojs", "js", "home.a6c392cb.js").toFile()); files.values() .forEach(file -> file .forEach(it -> { assertTrue(it.exists()); expected.remove(it); })); assertEquals(0, expected.size()); } @Test public void bundleWithAggregator() throws Exception { File dir = Paths.get("target", "public").toFile(); Map<String, List<File>> files = new AssetCompiler(conf("assets-aggregator.conf", "dev")) .build("dev", dir); files.values() .forEach(file -> file .forEach(it -> { assertTrue(it.exists()); if (it.getName().endsWith(".css")) { String css = Try.of(() -> Files.readAllLines(it.toPath()).stream() .collect(Collectors.joining("\n"))).get(); assertTrue(css.contains(".dyn")); } })); } @Test(expected = FileNotFoundException.class) public void fnf() throws Exception { File dir = Paths.get("target", "public").toFile(); Map<String, List<File>> files = new AssetCompiler(conf("assets-fnf.conf", "dev")) .build("dev", dir); files.values() .forEach(file -> file .forEach(it -> assertTrue(it.exists()))); } @Test public void shouldNotProcessWithoutFileSet() throws Exception { Asset asset = asset("/assets/index.js"); assertEquals(asset, new AssetCompiler(conf("missing.conf", "dev")).build(asset)); } @Test public void shouldNotProcessUnknownTypes() throws Exception { Asset asset = asset("/assets/index.none"); assertEquals(asset, new AssetCompiler(conf("assets-test.conf", "dev")).build(asset)); } @Test public void shouldExcludeFiles() throws Exception { assertEquals("processor-test:", compile(new AssetCompiler(conf("assets-excludes.conf", "dev")), "/assets/index.js")); assertEquals("(function () {});", compile(new AssetCompiler(conf("assets-excludes.conf", "dev")), "/assets/lib/lib.js")); assertEquals("(function () {});", compile(new AssetCompiler(conf("assets-exclude-one.conf", "dev")), "/assets/lib/lib.js")); } @Test(expected = ClassNotFoundException.class) public void shouldFaileOnNotFoundProcessor() throws Exception { new AssetCompiler(conf("assets-processor-not-found.conf", "dev")); } @Test public void pipeline() throws Exception { AssetCompiler compiler = new AssetCompiler(conf("assets-pipeline.conf", "dev")); List<AssetProcessor> dev = compiler.pipeline("dev"); assertNotNull(dev); assertEquals(1, dev.size()); assertTrue(dev.iterator().next() instanceof ProcessorTest); assertEquals("bar", dev.iterator().next().get("foo")); assertEquals("file", dev.iterator().next().get("sourceMap.type")); assertEquals(true, dev.iterator().next().get("sourceMap.sources")); List<AssetProcessor> prod = compiler.pipeline("dist"); assertNotNull(prod); assertEquals(2, prod.size()); assertTrue(prod.iterator().next() instanceof ProcessorTest); assertEquals("foo", prod.iterator().next().get("foo")); assertEquals("bar", prod.iterator().next().get("bar")); List<AssetProcessor> pipeline = compiler.pipeline("prod"); assertEquals(Collections.emptyList(), pipeline); } @Test public void humandReadableBytes() throws Exception { withLocale(Locale.US, () -> { assertEquals("1.0kb", AssetCompiler.humanReadableByteCount(1024)); assertEquals("1.0mb", AssetCompiler.humanReadableByteCount(1024 * 1024)); assertEquals("100.0mb", AssetCompiler.humanReadableByteCount(1024 * 1024 * 100)); }); withLocale(Locale.GERMAN, () -> { assertEquals("1,0kb", AssetCompiler.humanReadableByteCount(1024)); assertEquals("1,0mb", AssetCompiler.humanReadableByteCount(1024 * 1024)); assertEquals("100,0mb", AssetCompiler.humanReadableByteCount(1024 * 1024 * 100)); }); } private String compile(final AssetCompiler compiler, final String path) throws Exception { return new String( ByteStreams.toByteArray(compiler.build(asset(path)).stream()), "UTF-8"); } private Asset asset(final String path) throws Exception { return new URLAsset(getClass().getResource(path), path, MediaType.byPath(path).orElse(MediaType.octetstream)); } private Config conf(final String path, final String env) { return ConfigFactory.parseResources(path) .withValue("assets.env", ConfigValueFactory.fromAnyRef(env)) .withValue("assets.charset", ConfigValueFactory.fromAnyRef("UTF-8")); } private void withLocale(final Locale locale, final Runnable block) { Locale systemDefault = Locale.getDefault(); try { Locale.setDefault(locale); block.run(); } finally { Locale.setDefault(systemDefault); } } }