/* * Copyright 2008-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codehaus.griffon.runtime.core; import griffon.core.ApplicationClassLoader; import griffon.core.GriffonApplication; import griffon.core.injection.Binding; import griffon.core.injection.InstanceBinding; import griffon.core.injection.Key; import griffon.core.injection.Module; import griffon.core.injection.ProviderBinding; import griffon.core.injection.ProviderTypeBinding; import griffon.core.injection.TargetBinding; import org.junit.Test; import javax.annotation.Nonnull; import javax.inject.Named; import javax.inject.Provider; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class TestApplicationBootstrapperTest { private enum BindingTypes { TARGET("No binding of type " + TargetBinding.class.getName() + " was found"), INSTANCE("No named binding of type " + InstanceBinding.class.getName() + " was found"), NAMED_TARGET("No binding of type " + TargetBinding.class.getName() + " was found"), NAMED_INSTANCE("No named binding of type " + InstanceBinding.class.getName() + " was found"), PROVIDER("No binding of type " + ProviderBinding.class.getName() + " was found"), NAMED_PROVIDER("No named binding of type " + ProviderTypeBinding.class.getName() + " was found"), PROVIDER_TYPE("No binding of type " + ProviderBinding.class.getName() + " was found"), NAMED_PROVIDER_TYPE("No named binding of type " + ProviderTypeBinding.class.getName() + " was found"); private String label; BindingTypes(String label) { this.label = label; } public String getLabel() { return label; } } @Test public void modulesMethodSuppliesAllBindings() { // given: GriffonApplication application = new DefaultGriffonApplication(); TestApplicationBootstrapper bootstrapper = new TestApplicationBootstrapper(application); Object testCase = new ModulesMethodTestcase(); bootstrapper.setTestCase(testCase); // when: List<Module> modules = bootstrapper.loadModules(); // then: assertEquals(1, modules.size()); Map<Key, Binding<?>> bindings = getBindings(modules); for (Map.Entry<Key, Binding<?>> e : bindings.entrySet()) { if (e.getValue() instanceof TargetBinding) { TargetBinding tb = (TargetBinding) e.getValue(); if (ApplicationClassLoader.class.isAssignableFrom(tb.getSource())) { assertTrue(TestApplicationClassLoader.class.isAssignableFrom(tb.getTarget())); return; } } } fail("Test case did not provide an overriding binding for " + ApplicationClassLoader.class.getName()); } @Test public void modulesMethodSuppliesAllBindings_subclass() { // given: GriffonApplication application = new DefaultGriffonApplication(); TestApplicationBootstrapper bootstrapper = new TestApplicationBootstrapper(application); Object testCase = new ChildModulesMethodTestcase(); bootstrapper.setTestCase(testCase); // when: List<Module> modules = bootstrapper.loadModules(); // then: assertEquals(1, modules.size()); Map<Key, Binding<?>> bindings = getBindings(modules); for (Map.Entry<Key, Binding<?>> e : bindings.entrySet()) { if (e.getValue() instanceof TargetBinding) { TargetBinding tb = (TargetBinding) e.getValue(); if (ApplicationClassLoader.class.isAssignableFrom(tb.getSource())) { assertTrue(TestApplicationClassLoader.class.isAssignableFrom(tb.getTarget())); return; } } } fail("Test case did not provide an overriding binding for " + ApplicationClassLoader.class.getName()); } @Test public void annotatedModulesMethodSuppliesAllBindings() { // given: GriffonApplication application = new DefaultGriffonApplication(); TestApplicationBootstrapper bootstrapper = new TestApplicationBootstrapper(application); Object testCase = new AnnotatedModulesMethodTestcase(); bootstrapper.setTestCase(testCase); // when: List<Module> modules = bootstrapper.loadModules(); // then: assertEquals(1, modules.size()); Map<Key, Binding<?>> bindings = getBindings(modules); for (Map.Entry<Key, Binding<?>> e : bindings.entrySet()) { if (e.getValue() instanceof TargetBinding) { TargetBinding tb = (TargetBinding) e.getValue(); if (ApplicationClassLoader.class.isAssignableFrom(tb.getSource())) { assertTrue(TestApplicationClassLoader.class.isAssignableFrom(tb.getTarget())); return; } } } fail("Test case did not provide an overriding binding for " + ApplicationClassLoader.class.getName()); } @Test public void annotatedModulesMethodSuppliesAllBindings_subclass() { // given: GriffonApplication application = new DefaultGriffonApplication(); TestApplicationBootstrapper bootstrapper = new TestApplicationBootstrapper(application); Object testCase = new AnnotatedChildModulesMethodTestcase(); bootstrapper.setTestCase(testCase); // when: List<Module> modules = bootstrapper.loadModules(); // then: assertEquals(1, modules.size()); Map<Key, Binding<?>> bindings = getBindings(modules); for (Map.Entry<Key, Binding<?>> e : bindings.entrySet()) { if (e.getValue() instanceof TargetBinding) { TargetBinding tb = (TargetBinding) e.getValue(); if (ApplicationClassLoader.class.isAssignableFrom(tb.getSource())) { assertTrue(TestApplicationClassLoader.class.isAssignableFrom(tb.getTarget())); return; } } } fail("Test case did not provide an overriding binding for " + ApplicationClassLoader.class.getName()); } @Test public void moduleOverridesMethodConfiguresCustomApplicationClassLoader() { // given: GriffonApplication application = new DefaultGriffonApplication(); TestApplicationBootstrapper bootstrapper = new TestApplicationBootstrapper(application); Object testCase = new ModuleOverridesMethodTestcase(); bootstrapper.setTestCase(testCase); // when: List<Module> modules = bootstrapper.loadModules(); // then: Map<Key, Binding<?>> bindings = getBindings(modules); for (Map.Entry<Key, Binding<?>> e : bindings.entrySet()) { if (e.getValue() instanceof TargetBinding) { TargetBinding tb = (TargetBinding) e.getValue(); if (ApplicationClassLoader.class.isAssignableFrom(tb.getSource())) { assertTrue(TestApplicationClassLoader.class.isAssignableFrom(tb.getTarget())); return; } } } fail("Test case did not provide an overriding binding for " + ApplicationClassLoader.class.getName()); } @Test public void moduleOverridesMethodConfiguresCustomApplicationClassLoader_subclass() { // given: GriffonApplication application = new DefaultGriffonApplication(); TestApplicationBootstrapper bootstrapper = new TestApplicationBootstrapper(application); Object testCase = new ChildModuleOverridesMethodTestcase(); bootstrapper.setTestCase(testCase); // when: List<Module> modules = bootstrapper.loadModules(); // then: Map<Key, Binding<?>> bindings = getBindings(modules); for (Map.Entry<Key, Binding<?>> e : bindings.entrySet()) { if (e.getValue() instanceof TargetBinding) { TargetBinding tb = (TargetBinding) e.getValue(); if (ApplicationClassLoader.class.isAssignableFrom(tb.getSource())) { assertTrue(TestApplicationClassLoader.class.isAssignableFrom(tb.getTarget())); return; } } } fail("Test case did not provide an overriding binding for " + ApplicationClassLoader.class.getName()); } @Test public void annotatedModuleOverridesMethodConfiguresCustomApplicationClassLoader() { // given: GriffonApplication application = new DefaultGriffonApplication(); TestApplicationBootstrapper bootstrapper = new TestApplicationBootstrapper(application); Object testCase = new AnnotatedModuleOverridesMethodTestcase(); bootstrapper.setTestCase(testCase); // when: List<Module> modules = bootstrapper.loadModules(); // then: Map<Key, Binding<?>> bindings = getBindings(modules); for (Map.Entry<Key, Binding<?>> e : bindings.entrySet()) { if (e.getValue() instanceof TargetBinding) { TargetBinding tb = (TargetBinding) e.getValue(); if (ApplicationClassLoader.class.isAssignableFrom(tb.getSource())) { assertTrue(TestApplicationClassLoader.class.isAssignableFrom(tb.getTarget())); return; } } } fail("Test case did not provide an overriding binding for " + ApplicationClassLoader.class.getName()); } @Test public void annotatedModuleOverridesMethodConfiguresCustomApplicationClassLoader_subclass() { // given: GriffonApplication application = new DefaultGriffonApplication(); TestApplicationBootstrapper bootstrapper = new TestApplicationBootstrapper(application); Object testCase = new AnnotatedChildModuleOverridesMethodTestcase(); bootstrapper.setTestCase(testCase); // when: List<Module> modules = bootstrapper.loadModules(); // then: Map<Key, Binding<?>> bindings = getBindings(modules); for (Map.Entry<Key, Binding<?>> e : bindings.entrySet()) { if (e.getValue() instanceof TargetBinding) { TargetBinding tb = (TargetBinding) e.getValue(); if (ApplicationClassLoader.class.isAssignableFrom(tb.getSource())) { assertTrue(TestApplicationClassLoader.class.isAssignableFrom(tb.getTarget())); return; } } } fail("Test case did not provide an overriding binding for " + ApplicationClassLoader.class.getName()); } @Test @SuppressWarnings("unchecked") public void singletonTargetsInnerClassModule() throws Exception { List<BindingTypes> bindingTypes = new ArrayList<>(); bindingTypes.add(BindingTypes.TARGET); bindingTypes.add(BindingTypes.NAMED_TARGET); assertBindingTypes(new InnerClassModuleTestcase.SingletonTargets(), bindingTypes, true); } @Test @SuppressWarnings("unchecked") public void targetsInnerClassModule() throws Exception { List<BindingTypes> bindingTypes = new ArrayList<>(); bindingTypes.add(BindingTypes.TARGET); bindingTypes.add(BindingTypes.NAMED_TARGET); assertBindingTypes(new InnerClassModuleTestcase.Targets(), bindingTypes, false); } @Test @SuppressWarnings("unchecked") public void singletonProviderTypesInnerClassModule() throws Exception { List<BindingTypes> bindingTypes = new ArrayList<>(); bindingTypes.add(BindingTypes.PROVIDER_TYPE); bindingTypes.add(BindingTypes.NAMED_PROVIDER_TYPE); assertBindingTypes(new InnerClassModuleTestcase.SingletonProviders(), bindingTypes, true); } @Test @SuppressWarnings("unchecked") public void providerTypesInnerClassModule() throws Exception { List<BindingTypes> bindingTypes = new ArrayList<>(); bindingTypes.add(BindingTypes.PROVIDER_TYPE); bindingTypes.add(BindingTypes.NAMED_PROVIDER_TYPE); assertBindingTypes(new InnerClassModuleTestcase.Providers(), bindingTypes, false); } @Test @SuppressWarnings("unchecked") public void singletonTargetsFieldsModule() throws Exception { List<BindingTypes> bindingTypes = new ArrayList<>(); bindingTypes.add(BindingTypes.TARGET); bindingTypes.add(BindingTypes.NAMED_TARGET); assertBindingTypes(new FieldsModuleTestcase.SingletonTargets(), bindingTypes, true); } @Test @SuppressWarnings("unchecked") public void targetsFieldsModule() throws Exception { List<BindingTypes> bindingTypes = new ArrayList<>(); bindingTypes.add(BindingTypes.TARGET); bindingTypes.add(BindingTypes.NAMED_TARGET); assertBindingTypes(new FieldsModuleTestcase.Targets(), bindingTypes, false); } @Test @SuppressWarnings("unchecked") public void singletonProviderTypesFieldsModule() throws Exception { List<BindingTypes> bindingTypes = new ArrayList<>(); bindingTypes.add(BindingTypes.PROVIDER_TYPE); bindingTypes.add(BindingTypes.NAMED_PROVIDER_TYPE); assertBindingTypes(new FieldsModuleTestcase.SingletonProviderTypes(), bindingTypes, true); } @Test @SuppressWarnings("unchecked") public void providerTypesFieldsModule() throws Exception { List<BindingTypes> bindingTypes = new ArrayList<>(); bindingTypes.add(BindingTypes.PROVIDER_TYPE); bindingTypes.add(BindingTypes.NAMED_PROVIDER_TYPE); assertBindingTypes(new FieldsModuleTestcase.ProviderTypes(), bindingTypes, false); } @Test @SuppressWarnings("unchecked") public void instancesFieldsModule() throws Exception { List<BindingTypes> bindings = new ArrayList<>(); bindings.add(BindingTypes.INSTANCE); bindings.add(BindingTypes.NAMED_INSTANCE); assertBindingTypes(new FieldsModuleTestcase.Instances(), bindings, false); } @Test @SuppressWarnings("unchecked") public void singletonProvidersFieldsModule() throws Exception { List<BindingTypes> bindings = new ArrayList<>(); bindings.add(BindingTypes.PROVIDER); bindings.add(BindingTypes.NAMED_PROVIDER); assertBindingTypes(new FieldsModuleTestcase.SingletonProviders(), bindings, true); } @Test @SuppressWarnings("unchecked") public void providersFieldsModule() throws Exception { List<BindingTypes> bindings = new ArrayList<>(); bindings.add(BindingTypes.PROVIDER); bindings.add(BindingTypes.NAMED_PROVIDER); assertBindingTypes(new FieldsModuleTestcase.Providers(), bindings, false); } @SuppressWarnings("unchecked") private void assertBindingTypes(Object testCase, List<BindingTypes> bindingTypes, boolean singleton) throws Exception { // given: GriffonApplication application = new DefaultGriffonApplication(); TestApplicationBootstrapper bootstrapper = new TestApplicationBootstrapper(application); bootstrapper.setTestCase(testCase); // when: List<Module> modules = bootstrapper.loadModules(); // then: Map<Key, Binding<?>> bindings = getBindings(modules); assertTrue(bindings.size() > 1); for (Map.Entry<Key, Binding<?>> e : bindings.entrySet()) { Binding<?> binding = e.getValue(); if (Atom.class.isAssignableFrom(binding.getSource())) { if (binding instanceof TargetBinding) { assertTargetBinding((TargetBinding) binding, bindingTypes, singleton); } else if (binding instanceof ProviderTypeBinding) { assertProviderTypeBinding((ProviderTypeBinding) binding, bindingTypes, singleton); } else if (binding instanceof InstanceBinding) { assertInstanceBinding((InstanceBinding) binding, bindingTypes); } else if (binding instanceof ProviderBinding) { assertProviderBinding((ProviderBinding) binding, bindingTypes, singleton); } else { fail("Did not expect a binding of type " + binding.getClass().getName()); } } } if (!bindingTypes.isEmpty()) { StringBuilder b = new StringBuilder(); for (BindingTypes fb : bindingTypes) { b.append(fb.getLabel()).append("\n"); } fail(b.toString()); } } @SuppressWarnings("unchecked") private void assertTargetBinding(TargetBinding binding, List<BindingTypes> bindingTypes, boolean singleton) throws Exception { if (singleton) { assertTrue(binding.isSingleton()); } if (binding.getClassifier() == null) { // Hydrogen ? Atom atom = instantiate(binding.getTarget()); assertEquals("Expected a binding for Hydrogen", 1, atom.getNumElectrons()); bindingTypes.remove(BindingTypes.TARGET); } else { // Helium ? assertName(binding.getClassifier(), "Helium"); Atom atom = instantiate(binding.getTarget()); assertEquals("Expected a binding for Helium", 2, atom.getNumElectrons()); bindingTypes.remove(BindingTypes.NAMED_TARGET); } } @SuppressWarnings("unchecked") private void assertProviderTypeBinding(ProviderTypeBinding binding, List<BindingTypes> bindingTypes, boolean singleton) throws Exception { if (singleton) { assertTrue(binding.isSingleton()); } if (binding.getClassifier() == null) { // Litium ? Atom atom = instantiateProvider(binding.getProviderType()); assertEquals("Expected a binding for Litium", 3, atom.getNumElectrons()); bindingTypes.remove(BindingTypes.PROVIDER_TYPE); } else { // Berilium ? assertName(binding.getClassifier(), "Berilium"); Atom atom = instantiateProvider(binding.getProviderType()); assertEquals("Expected a binding for Berilium", 4, atom.getNumElectrons()); bindingTypes.remove(BindingTypes.NAMED_PROVIDER_TYPE); } } @SuppressWarnings("unchecked") private void assertInstanceBinding(InstanceBinding<Atom> binding, List<BindingTypes> bindingTypes) throws Exception { if (binding.getClassifier() == null) { // Boron ? Atom atom = binding.getInstance(); assertEquals("Expected a binding for Boron", 5, atom.getNumElectrons()); bindingTypes.remove(BindingTypes.INSTANCE); } else { // Carbon ? assertName(binding.getClassifier(), "Carbon"); Atom atom = binding.getInstance(); assertEquals("Expected a binding for Carbon", 6, atom.getNumElectrons()); bindingTypes.remove(BindingTypes.NAMED_INSTANCE); } } @SuppressWarnings("unchecked") private void assertProviderBinding(ProviderBinding<Atom> binding, List<BindingTypes> bindingTypes, boolean singleton) throws Exception { if (singleton) { assertTrue(binding.isSingleton()); } if (binding.getClassifier() == null) { // Nitrogen ? Atom atom = binding.getProvider().get(); assertEquals("Expected a binding for Nitrogen", 7, atom.getNumElectrons()); bindingTypes.remove(BindingTypes.PROVIDER); } else { // Oxygen ? assertName(binding.getClassifier(), "Oxygen"); Atom atom = binding.getProvider().get(); assertEquals("Expected a binding for Oxygen", 8, atom.getNumElectrons()); bindingTypes.remove(BindingTypes.NAMED_PROVIDER); } } private static Atom instantiate(Class<? extends Atom> atomClass) throws Exception { return atomClass.newInstance(); } private static Atom instantiateProvider(Class<Provider<? extends Atom>> providerClass) throws Exception { return providerClass.newInstance().get(); } private static void assertName(Annotation annotation, String name) { assertTrue(annotation instanceof Named); Named named = (Named) annotation; assertEquals(name, named.value()); } @Nonnull protected Map<Key, Binding<?>> getBindings(@Nonnull Collection<Module> modules) { Map<Key, Binding<?>> map = new LinkedHashMap<>(); for (Module module : modules) { for (Binding<?> binding : module.getBindings()) { map.put(Key.of(binding), binding); } } return map; } }