/* * 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.graph.DAGNode; import org.grouplens.grapht.reflect.Desires; import org.grouplens.grapht.solver.DependencySolver; import org.junit.Test; import javax.inject.Inject; import java.io.ByteArrayInputStream; import java.io.InputStream; import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; /** * Test the dependency solver's graph rewriting capabilities. * @author <a href="http://www.grouplens.org">GroupLens Research</a> */ public class GraphRewritingTest { @Test public void testSimpleRewriteNoTrigger() throws ResolutionException { BindingFunctionBuilder config = new BindingFunctionBuilder(); config.getRootContext() .bind(I.class) .to(C.class); config.getRootContext() .bind(I2.class) .to(A.class); DependencySolver initial = DependencySolver.newBuilder() .addBindingFunction(config.build(BindingFunctionBuilder.RuleSet.EXPLICIT), false) .build(); initial.resolve(Desires.create(null, I.class, false)); DAGNode<Component, Dependency> graph = initial.getGraph(); assertThat(graph.getOutgoingEdges(), hasSize(1)); assertThat(graph.getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) C.class)); DAGNode<Component, Dependency> graph2 = initial.rewrite(graph); assertThat(graph2, sameInstance(graph)); } @Test public void testRewriteToIdentical() throws ResolutionException { BindingFunctionBuilder config = new BindingFunctionBuilder(); config.getRootContext() .bind(I.class) .to(C.class); config.getRootContext() .bind(I2.class) .to(A.class); DependencySolver initial = DependencySolver.newBuilder() .addBindingFunction(config.build(BindingFunctionBuilder.RuleSet.EXPLICIT), true) .build(); initial.resolve(Desires.create(null, I.class, false)); DAGNode<Component, Dependency> graph = initial.getGraph(); assertThat(graph.getOutgoingEdges(), hasSize(1)); assertThat(graph.getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) C.class)); DAGNode<Component, Dependency> graph2 = initial.rewrite(graph); // should trigger a rewrite, but the graph should be unchanged assertThat(graph2, sameInstance(graph)); } @Test public void testRewriteDependency() throws ResolutionException { BindingFunctionBuilder config = new BindingFunctionBuilder(); config.getRootContext() .bind(I.class) .to(C.class); config.getRootContext() .bind(I2.class) .to(A.class); DependencySolver initial = DependencySolver.newBuilder() .addBindingFunction(config.build(BindingFunctionBuilder.RuleSet.EXPLICIT)) .build(); initial.resolve(Desires.create(null, I.class, false)); DAGNode<Component, Dependency> graph = initial.getGraph(); assertThat(graph.getOutgoingEdges(), hasSize(1)); assertThat(graph.getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) C.class)); assertThat(graph.getOutgoingEdges().iterator().next() .getTail().getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) A.class)); BindingFunctionBuilder config2 = new BindingFunctionBuilder(); config2.getRootContext() .bind(I2.class) .to(B.class); DependencySolver rewriter = DependencySolver.newBuilder() .addBindingFunction(config2.build(BindingFunctionBuilder.RuleSet.EXPLICIT), true) .build(); DAGNode<Component, Dependency> graph2 = rewriter.rewrite(graph); // should change the dependency assertThat(graph2, not(sameInstance(graph))); assertThat(graph2.getOutgoingEdges(), hasSize(1)); assertThat(graph2.getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) C.class)); assertThat(graph2.getOutgoingEdges().iterator().next() .getTail().getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) B.class)); } @Test public void testRewriteNoTrigger() throws ResolutionException { BindingFunctionBuilder config = new BindingFunctionBuilder(); config.getRootContext() .bind(I.class) .to(C.class); config.getRootContext() .bind(I2.class) .to(A.class); DependencySolver initial = DependencySolver.newBuilder() .addBindingFunction(config.build(BindingFunctionBuilder.RuleSet.EXPLICIT)) .build(); initial.resolve(Desires.create(null, I.class, false)); DAGNode<Component, Dependency> graph = initial.getGraph(); assertThat(graph.getOutgoingEdges(), hasSize(1)); assertThat(graph.getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) C.class)); assertThat(graph.getOutgoingEdges().iterator().next() .getTail().getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) A.class)); BindingFunctionBuilder trigger = new BindingFunctionBuilder(); trigger.getRootContext() .bind(I2.class) .to(W.class); BindingFunctionBuilder rewriteDeps = new BindingFunctionBuilder(); trigger.getRootContext() .bind(InputStream.class) .to(new ByteArrayInputStream("foo".getBytes())); DependencySolver rewriter = DependencySolver.newBuilder() .addBindingFunction(trigger.build(BindingFunctionBuilder.RuleSet.EXPLICIT), true) .addBindingFunction(rewriteDeps.build(BindingFunctionBuilder.RuleSet.EXPLICIT), false) .build(); DAGNode<Component, Dependency> graph2 = rewriter.rewrite(graph); // should change the dependency assertThat(graph2, not(sameInstance(graph))); assertThat(graph2.getOutgoingEdges(), hasSize(1)); assertThat(graph2.getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) C.class)); assertThat(graph2.getOutgoingEdges().iterator().next() .getTail().getOutgoingEdges().iterator().next() .getTail().getLabel().getSatisfaction().getErasedType(), equalTo((Class) W.class)); } @Test public void testRewriteFixed() throws ResolutionException { // based on testRewriteDependency, but with a fixed binding to prevent rewrite BindingFunctionBuilder config = new BindingFunctionBuilder(); config.getRootContext() .bind(I.class) .to(C.class); config.getRootContext() .bind(I2.class) .fixed() .to(A.class); DependencySolver initial = DependencySolver.newBuilder() .addBindingFunction(config.build(BindingFunctionBuilder.RuleSet.EXPLICIT)) .build(); initial.resolve(Desires.create(null, I.class, false)); DAGNode<Component, Dependency> graph = initial.getGraph(); BindingFunctionBuilder config2 = new BindingFunctionBuilder(); config2.getRootContext() .bind(I2.class) .to(B.class); DependencySolver rewriter = DependencySolver.newBuilder() .addBindingFunction(config2.build(BindingFunctionBuilder.RuleSet.EXPLICIT), true) .build(); DAGNode<Component, Dependency> graph2 = rewriter.rewrite(graph); // should be unchanged, because of fixed binding assertThat(graph2, sameInstance(graph)); } public static interface I {} public static interface I2 {} public static class C implements I { final I2 plug; @Inject public C(I2 plug) { this.plug = plug; } } public static class A implements I2 {} public static class B implements I2 {} public static class W implements I2 { private final InputStream stream; @Inject public W(InputStream s) { stream = s; } } }