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());
}
}