package org.jooby.ftl; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.expectLastCall; import static org.easymock.EasyMock.isA; import static org.junit.Assert.assertEquals; import java.util.Properties; import java.util.function.BiConsumer; import org.jooby.Env; import org.jooby.Renderer; import org.jooby.internal.ftl.Engine; import org.jooby.internal.ftl.GuavaCacheStorage; import org.jooby.internal.ftl.XssDirective; import org.jooby.test.MockUnit; import org.jooby.test.MockUnit.Block; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import com.google.inject.Binder; import com.google.inject.binder.AnnotatedBindingBuilder; import com.google.inject.binder.LinkedBindingBuilder; import com.google.inject.multibindings.Multibinder; import com.typesafe.config.Config; import com.typesafe.config.ConfigFactory; import com.typesafe.config.ConfigValueFactory; import freemarker.cache.ClassTemplateLoader; import freemarker.cache.NullCacheStorage; import freemarker.template.Configuration; import freemarker.template.TemplateException; import freemarker.template.Version; @RunWith(PowerMockRunner.class) @PrepareForTest({Ftl.class, Configuration.class, ClassTemplateLoader.class, Multibinder.class, XssDirective.class }) public class FtlTest { private Block xss = unit -> { Env env = unit.get(Env.class); XssDirective xss = unit.constructor(XssDirective.class) .build(env); unit.registerMock(XssDirective.class, xss); }; @SuppressWarnings("unchecked") @Test public void defaults() throws Exception { String prefix = "/"; String suffix = ".html"; Properties props = new Properties(); props.setProperty("default_encoding", "UTF-8"); Config freemarker = ConfigFactory.empty() .withValue("default_encoding", ConfigValueFactory.fromAnyRef("UTF-8")); new MockUnit(Env.class, Config.class, Binder.class) .expect(unit -> { Config config = unit.get(Config.class); expect(config.getConfig("freemarker")).andReturn(freemarker); }) .expect(xss) .expect(unit -> { ClassTemplateLoader loader = unit.mockConstructor(ClassTemplateLoader.class, new Class[]{ClassLoader.class, String.class }, Ftl.class.getClassLoader(), prefix); Configuration config = unit.mockConstructor(Configuration.class, new Class[]{Version.class }, Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); config.setSettings(props); config.setTemplateLoader(loader); config.setCacheStorage(NullCacheStorage.INSTANCE); AnnotatedBindingBuilder<Configuration> configBB = unit .mock(AnnotatedBindingBuilder.class); configBB.toInstance(config); Binder binder = unit.get(Binder.class); expect(binder.bind(Configuration.class)).andReturn(configBB); XssDirective xss = unit.get(XssDirective.class); Engine engine = unit.mockConstructor( Engine.class, new Class[]{Configuration.class, String.class, XssDirective.class }, config, suffix, xss); LinkedBindingBuilder<Renderer> ffLBB = unit.mock(LinkedBindingBuilder.class); ffLBB.toInstance(engine); Multibinder<Renderer> formatter = unit.mock(Multibinder.class); expect(formatter.addBinding()).andReturn(ffLBB); unit.mockStatic(Multibinder.class); expect(Multibinder.newSetBinder(binder, Renderer.class)).andReturn(formatter); }) .expect(unit -> { Env env = unit.get(Env.class); expect(env.name()).andReturn("dev"); }) .run(unit -> { new Ftl() .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void defaultsNoDev() throws Exception { String prefix = "/"; String suffix = ".html"; Properties props = new Properties(); props.setProperty("default_encoding", "UTF-8"); Config freemarker = ConfigFactory.empty() .withValue("default_encoding", ConfigValueFactory.fromAnyRef("UTF-8")); new MockUnit(Env.class, Config.class, Binder.class) .expect(unit -> { Config config = unit.get(Config.class); expect(config.getConfig("freemarker")).andReturn(freemarker); expect(config.getString("freemarker.cache")).andReturn("maximumSize=100").times(2); }) .expect(xss) .expect(unit -> { ClassTemplateLoader loader = unit.mockConstructor(ClassTemplateLoader.class, new Class[]{ClassLoader.class, String.class }, Ftl.class.getClassLoader(), prefix); Configuration config = unit.mockConstructor(Configuration.class, new Class[]{Version.class }, Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); config.setSettings(props); config.setTemplateLoader(loader); config.setCacheStorage(isA(GuavaCacheStorage.class)); AnnotatedBindingBuilder<Configuration> configBB = unit .mock(AnnotatedBindingBuilder.class); configBB.toInstance(config); Binder binder = unit.get(Binder.class); expect(binder.bind(Configuration.class)).andReturn(configBB); XssDirective xss = unit.get(XssDirective.class); Engine engine = unit.mockConstructor( Engine.class, new Class[]{Configuration.class, String.class, XssDirective.class }, config, suffix, xss); LinkedBindingBuilder<Renderer> ffLBB = unit.mock(LinkedBindingBuilder.class); ffLBB.toInstance(engine); Multibinder<Renderer> formatter = unit.mock(Multibinder.class); expect(formatter.addBinding()).andReturn(ffLBB); unit.mockStatic(Multibinder.class); expect(Multibinder.newSetBinder(binder, Renderer.class)).andReturn(formatter); }) .expect(unit -> { Env env = unit.get(Env.class); expect(env.name()).andReturn("prod"); }) .run(unit -> { new Ftl() .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @Test(expected = TemplateException.class) public void err() throws Exception { Properties props = new Properties(); props.setProperty("default_encoding", "UTF-8"); Config freemarker = ConfigFactory.empty() .withValue("default_encoding", ConfigValueFactory.fromAnyRef("UTF-8")); new MockUnit(Env.class, Config.class, Binder.class) .expect(unit -> { Config config = unit.get(Config.class); expect(config.getConfig("freemarker")).andReturn(freemarker); }) .expect(unit -> { Configuration config = unit.mockConstructor(Configuration.class, new Class[]{Version.class }, Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); config.setSettings(props); expectLastCall().andThrow(new TemplateException("intentional err", null)); }) .expect(unit -> { Env env = unit.get(Env.class); expect(env.name()).andReturn("dev"); }) .run(unit -> { new Ftl() .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void withPrefix() throws Exception { String prefix = "/x"; String suffix = ".html"; Properties props = new Properties(); props.setProperty("default_encoding", "UTF-8"); Config freemarker = ConfigFactory.empty() .withValue("default_encoding", ConfigValueFactory.fromAnyRef("UTF-8")); new MockUnit(Env.class, Config.class, Binder.class) .expect(unit -> { Config config = unit.get(Config.class); expect(config.getConfig("freemarker")).andReturn(freemarker); }) .expect(xss) .expect(unit -> { ClassTemplateLoader loader = unit.mockConstructor(ClassTemplateLoader.class, new Class[]{ClassLoader.class, String.class }, Ftl.class.getClassLoader(), prefix); Configuration config = unit.mockConstructor(Configuration.class, new Class[]{Version.class }, Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); config.setSettings(props); config.setTemplateLoader(loader); config.setCacheStorage(NullCacheStorage.INSTANCE); AnnotatedBindingBuilder<Configuration> configBB = unit .mock(AnnotatedBindingBuilder.class); configBB.toInstance(config); Binder binder = unit.get(Binder.class); expect(binder.bind(Configuration.class)).andReturn(configBB); XssDirective xss = unit.get(XssDirective.class); Engine engine = unit.mockConstructor( Engine.class, new Class[]{Configuration.class, String.class, XssDirective.class }, config, suffix, xss); LinkedBindingBuilder<Renderer> ffLBB = unit.mock(LinkedBindingBuilder.class); ffLBB.toInstance(engine); Multibinder<Renderer> formatter = unit.mock(Multibinder.class); expect(formatter.addBinding()).andReturn(ffLBB); unit.mockStatic(Multibinder.class); expect(Multibinder.newSetBinder(binder, Renderer.class)).andReturn(formatter); }) .expect(unit -> { Env env = unit.get(Env.class); expect(env.name()).andReturn("dev"); }) .run(unit -> { new Ftl(prefix) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void withPrefixAndSuffix() throws Exception { String prefix = "/x"; String suffix = ".ftl"; Properties props = new Properties(); props.setProperty("default_encoding", "UTF-8"); Config freemarker = ConfigFactory.empty() .withValue("default_encoding", ConfigValueFactory.fromAnyRef("UTF-8")); new MockUnit(Env.class, Config.class, Binder.class) .expect(unit -> { Config config = unit.get(Config.class); expect(config.getConfig("freemarker")).andReturn(freemarker); }) .expect(xss) .expect(unit -> { ClassTemplateLoader loader = unit.mockConstructor(ClassTemplateLoader.class, new Class[]{ClassLoader.class, String.class }, Ftl.class.getClassLoader(), prefix); Configuration config = unit.mockConstructor(Configuration.class, new Class[]{Version.class }, Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); config.setSettings(props); config.setTemplateLoader(loader); config.setCacheStorage(NullCacheStorage.INSTANCE); AnnotatedBindingBuilder<Configuration> configBB = unit .mock(AnnotatedBindingBuilder.class); configBB.toInstance(config); Binder binder = unit.get(Binder.class); expect(binder.bind(Configuration.class)).andReturn(configBB); XssDirective xss = unit.get(XssDirective.class); Engine engine = unit.mockConstructor( Engine.class, new Class[]{Configuration.class, String.class, XssDirective.class }, config, suffix, xss); LinkedBindingBuilder<Renderer> ffLBB = unit.mock(LinkedBindingBuilder.class); ffLBB.toInstance(engine); Multibinder<Renderer> formatter = unit.mock(Multibinder.class); expect(formatter.addBinding()).andReturn(ffLBB); unit.mockStatic(Multibinder.class); expect(Multibinder.newSetBinder(binder, Renderer.class)).andReturn(formatter); }) .expect(unit -> { Env env = unit.get(Env.class); expect(env.name()).andReturn("dev"); }) .run(unit -> { new Ftl(prefix, suffix) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @SuppressWarnings("unchecked") @Test public void withConfigurer() throws Exception { String prefix = "/x"; String suffix = ".ftl"; Properties props = new Properties(); props.setProperty("default_encoding", "UTF-8"); Config freemarker = ConfigFactory.empty() .withValue("default_encoding", ConfigValueFactory.fromAnyRef("UTF-8")); new MockUnit(Env.class, Config.class, Binder.class, BiConsumer.class) .expect(unit -> { Config config = unit.get(Config.class); expect(config.getConfig("freemarker")).andReturn(freemarker); }) .expect(xss) .expect(unit -> { ClassTemplateLoader loader = unit.mockConstructor(ClassTemplateLoader.class, new Class[]{ClassLoader.class, String.class }, Ftl.class.getClassLoader(), prefix); Configuration config = unit.mockConstructor(Configuration.class, new Class[]{Version.class }, Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS); unit.get(BiConsumer.class).accept(config, unit.get(Config.class)); config.setSettings(props); config.setTemplateLoader(loader); config.setCacheStorage(NullCacheStorage.INSTANCE); AnnotatedBindingBuilder<Configuration> configBB = unit .mock(AnnotatedBindingBuilder.class); configBB.toInstance(config); Binder binder = unit.get(Binder.class); expect(binder.bind(Configuration.class)).andReturn(configBB); XssDirective xss = unit.get(XssDirective.class); Engine engine = unit.mockConstructor( Engine.class, new Class[]{Configuration.class, String.class, XssDirective.class }, config, suffix, xss); LinkedBindingBuilder<Renderer> ffLBB = unit.mock(LinkedBindingBuilder.class); ffLBB.toInstance(engine); Multibinder<Renderer> formatter = unit.mock(Multibinder.class); expect(formatter.addBinding()).andReturn(ffLBB); unit.mockStatic(Multibinder.class); expect(Multibinder.newSetBinder(binder, Renderer.class)).andReturn(formatter); }) .expect(unit -> { Env env = unit.get(Env.class); expect(env.name()).andReturn("dev"); }) .run(unit -> { new Ftl(prefix, suffix) .doWith(unit.get(BiConsumer.class)) .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class)); }); } @Test public void config() throws Exception { Config config = new Ftl().config(); assertEquals("org/jooby/ftl/freemarker.conf", config.root().origin().resource()); } }