/* * Grapht, an open source dependency injector. * Copyright 2014-2015 various contributors (see CONTRIBUTORS.txt) * Copyright 2010-2014 Regents of the University of Minnesota * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.grouplens.grapht; import org.grouplens.grapht.annotation.DefaultImplementation; import org.grouplens.grapht.context.ContextElements; import org.grouplens.grapht.context.ContextPattern; import org.grouplens.grapht.context.Multiplicity; import org.junit.Before; import org.junit.Test; import javax.annotation.Nullable; import javax.inject.Inject; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.assertThat; /** * Test using multiple context bindings to separate components. * * @author <a href="http://grouplens.org">GroupLens Research</a> */ public class ContextOverrideTest { private InjectorBuilder build; @Before public void setup() { build = InjectorBuilder.create(); } /** * Test bindings with a null, and a deeper context using a binding. To make things * interesting, the thing tweaked is a concrete class. */ @Test public void testDeeperOverride() throws InjectionException { build.within(Outer.class) .bind(IPlug.class) .to(PlugH.class); build.within(Inner.class) .bind(IPlug.class) .to(PlugA.class); Injector inj = build.build(); Inner in = inj.getInstance(Inner.class); assertThat(in, notNullValue()); assertThat(in.plug, instanceOf(PlugA.class)); Outer out = inj.getInstance(Outer.class); assertThat(out, notNullValue()); assertThat(out.plug, instanceOf(PlugH.class)); assertThat(out.inner, notNullValue()); assertThat(out.inner.plug, instanceOf(PlugA.class)); } /** * Test bindings with a null, and a deeper context using a binding. */ @Test public void testNullDeepConcrete() throws InjectionException { // this can be with or without the context // use context to match target use in LensKit build.within(COuter.class) .bind(Plug.class) .toNull(); build.within(CInner.class) .bind(Plug.class) .to(Plug.class, false); Injector inj = build.build(); CInner in = inj.getInstance(CInner.class); assertThat(in, notNullValue()); assertThat(in.plug, notNullValue()); COuter out = inj.getInstance(COuter.class); assertThat(out, notNullValue()); assertThat(out.plug, nullValue()); assertThat(out.inner, notNullValue()); assertThat(out.inner.plug, notNullValue()); assertThat(out.inner.plug, instanceOf(Plug.class)); } /** * Test bindings with a null, and a deeper context using a binding, with * an anchored matcher. */ @Test public void testNullDeepConcreteAnchored() throws InjectionException { // immediate binding should allow inner to get a plug build.at(COuter.class) .bind(Plug.class) .toNull(); Injector inj = build.build(); CInner in = inj.getInstance(CInner.class); assertThat(in, notNullValue()); assertThat(in.plug, notNullValue()); COuter out = inj.getInstance(COuter.class); assertThat(out, notNullValue()); assertThat(out.plug, nullValue()); assertThat(out.inner, notNullValue()); assertThat(out.inner.plug, notNullValue()); assertThat(out.inner.plug, instanceOf(Plug.class)); } /** * Test anchored root binding. */ @Test public void testAnchoredToRoot() throws InjectionException { build.bind(IPlug.class) .to(PlugA.class); build.at(null) .bind(IPlug.class) .to(PlugH.class); Injector inj = build.build(); // Does directly requesting a plug get us the anchored binding? assertThat(inj.getInstance(IPlug.class), instanceOf(PlugH.class)); // Is the non-anchored binding used for dependencies? Outer out = inj.getInstance(Outer.class); assertThat(out.plug, instanceOf(PlugA.class)); assertThat(out.inner.plug, instanceOf(PlugA.class)); assertThat(out.plug, sameInstance(out.inner.plug)); // quick check this again, make sure nothing changed assertThat(inj.getInstance(IPlug.class), instanceOf(PlugH.class)); } @Test public void testPatternForPlug() throws InjectionException { build.matching(ContextPattern.any() .append(CInner.class) .append(ContextElements.invertMatch(ContextElements.matchType(PlugW.class)), Multiplicity.ZERO_OR_MORE)) .bind(Plug.class) .to(PlugW.class); Injector inj = build.build(); CInner c = inj.getInstance(CInner.class); assertThat(c.plug, instanceOf(PlugW.class)); assert c.plug != null; assertThat(((PlugW) c.plug).inner.getClass(), equalTo((Class) Plug.class)); } @DefaultImplementation(PlugA.class) public static interface IPlug {} public static class PlugA implements IPlug {} public static class PlugH implements IPlug {} public static class Inner { final IPlug plug; @Inject public Inner(IPlug p) { plug = p; } } public static class Outer { final IPlug plug; final Inner inner; @Inject public Outer(Inner in, @Nullable IPlug p) { plug = p; inner = in; } } public static class Plug {} public static class CInner { final Plug plug; @Inject public CInner(@Nullable Plug p) { plug = p; } } public static class COuter { final Plug plug; final CInner inner; @Inject public COuter(CInner in, @Nullable Plug p) { plug = p; inner = in; } } public static class PlugW extends Plug { private final Plug inner; @Inject public PlugW(Plug wrapped) { inner = wrapped; } } }