You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@reef.apache.org by we...@apache.org on 2015/01/23 00:46:42 UTC
[09/51] [partial] incubator-reef git commit: [REEF-93] Move java
sources to lang/java
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/TestTang.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/TestTang.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/TestTang.java
new file mode 100644
index 0000000..fcb0ad6
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/TestTang.java
@@ -0,0 +1,1356 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang;
+
+import org.apache.reef.tang.ThreeConstructors.TCFloat;
+import org.apache.reef.tang.ThreeConstructors.TCInt;
+import org.apache.reef.tang.ThreeConstructors.TCString;
+import org.apache.reef.tang.annotations.*;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+import org.apache.reef.tang.exceptions.InjectionException;
+import org.apache.reef.tang.exceptions.NameResolutionException;
+import org.apache.reef.tang.formats.ConfigurationFile;
+import org.apache.reef.tang.util.ReflectionUtilities;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import javax.inject.Inject;
+
+interface SMC {
+}
+
+@DefaultImplementation(HaveDefaultImplImpl.class)
+interface HaveDefaultImpl {
+}
+
+@DefaultImplementation(name = "org.apache.reef.tang.HaveDefaultStringImplImpl")
+interface HaveDefaultStringImpl {
+}
+
+interface Interf {
+}
+
+interface IfaceWithDefault {
+}
+
+interface X<T> {
+}
+
+interface Bottle<Y> {
+
+}
+
+interface EventHandler<T> {
+}
+
+@DefaultImplementation(MyEventHandler.class)
+interface MyEventHandlerIface extends EventHandler<Foo> {
+}
+
+interface SomeIface {
+}
+
+@DefaultImplementation(AHandlerImpl.class)
+interface AHandler extends EventHandler<AH> {
+}
+
+@DefaultImplementation(BHandlerImpl.class)
+interface BHandler extends EventHandler<BH> {
+}
+
+interface CheckChildIface {
+}
+
+public class TestTang {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+ Tang tang;
+
+ @Before
+ public void setUp() throws Exception {
+ MustBeSingleton.alreadyInstantiated = false;
+ tang = Tang.Factory.getTang();
+ }
+
+ @Test
+ public void testSingleton() throws InjectionException {
+ Injector injector = tang.newInjector();
+ Assert.assertNotNull(injector.getInstance(TwoSingletons.class));
+ Assert.assertNotNull(injector.getInstance(TwoSingletons.class));
+ }
+
+ @Test
+ public void testNotSingleton() throws InjectionException {
+ thrown.expect(InjectionException.class);
+ thrown.expectMessage("Could not invoke constructor");
+ Assert.assertNotNull(tang.newInjector().getInstance(TwoSingletons.class));
+ tang.newInjector().getInstance(TwoSingletons.class);
+ }
+
+ // TODO: Delete this? (It is handled in TestClassHierarchy!)
+ @Test(expected = ClassHierarchyException.class)
+ public void testRepeatedAmbiguousArgs() throws BindException, NameResolutionException {
+ JavaConfigurationBuilder t = tang.newConfigurationBuilder();
+ t.getClassHierarchy().getNode(ReflectionUtilities.getFullName(RepeatedAmbiguousArgs.class));
+ }
+
+ @Test
+ public void testRepeatedOKArgs() throws BindException, InjectionException {
+ JavaConfigurationBuilder t = tang.newConfigurationBuilder();
+ t.bindNamedParameter(RepeatedNamedArgs.A.class, "1");
+ t.bindNamedParameter(RepeatedNamedArgs.B.class, "2");
+ Injector injector = tang.newInjector(t.build());
+ injector.getInstance(RepeatedNamedArgs.class);
+ }
+
+ // NamedParameter A has no default_value, so this should throw.
+ @Test
+ public void testOneNamedFailArgs() throws InjectionException {
+ thrown.expect(InjectionException.class);
+ thrown.expectMessage("Cannot inject org.apache.reef.tang.OneNamedSingletonArgs: org.apache.reef.tang.OneNamedSingletonArgs missing argument org.apache.reef.tang.OneNamedSingletonArgs$A");
+ tang.newInjector().getInstance(OneNamedSingletonArgs.class);
+ }
+
+ @Test
+ public void testOneNamedOKArgs() throws InjectionException {
+ thrown.expect(InjectionException.class);
+ thrown.expectMessage("Cannot inject org.apache.reef.tang.OneNamedSingletonArgs: org.apache.reef.tang.OneNamedSingletonArgs missing argument org.apache.reef.tang.OneNamedSingletonArgs$A");
+ tang.newInjector().getInstance(OneNamedSingletonArgs.class);
+ }
+
+ // NamedParameter A has no default_value
+ @Test
+ public void testOneNamedSingletonFailArgs() throws InjectionException {
+ thrown.expect(InjectionException.class);
+ thrown.expectMessage("Cannot inject org.apache.reef.tang.OneNamedSingletonArgs: org.apache.reef.tang.OneNamedSingletonArgs missing argument org.apache.reef.tang.OneNamedSingletonArgs$A");
+ tang.newInjector().getInstance(OneNamedSingletonArgs.class);
+ }
+
+ // NamedParameter A get's bound to a volatile, so this should succeed.
+ @Test
+ public void testOneNamedSingletonOKArgs() throws BindException, InjectionException {
+ final Injector i = tang.newInjector();
+ i.bindVolatileParameter(OneNamedSingletonArgs.A.class,
+ i.getInstance(MustBeSingleton.class));
+ i.getInstance(OneNamedSingletonArgs.class);
+ }
+
+ @Test
+ public void testRepeatedNamedOKArgs() throws BindException,
+ InjectionException {
+ final Injector i = tang.newInjector();
+ i.bindVolatileParameter(RepeatedNamedSingletonArgs.A.class,
+ i.getInstance(MustBeSingleton.class));
+ i.bindVolatileParameter(RepeatedNamedSingletonArgs.B.class,
+ i.getInstance(MustBeSingleton.class));
+ i.getInstance(RepeatedNamedSingletonArgs.class);
+ }
+
+ @Test
+ public void testRepeatedNamedArgs() throws BindException,
+ InjectionException {
+ Injector i = tang.newInjector();
+ i.bindVolatileParameter(RepeatedNamedSingletonArgs.A.class,
+ i.getInstance(MustBeSingleton.class));
+ i.bindVolatileParameter(RepeatedNamedSingletonArgs.B.class,
+ i.getInstance(MustBeSingleton.class));
+ i.getInstance(RepeatedNamedSingletonArgs.class);
+ }
+
+ @Test
+ public void testStraightforwardBuild() throws BindException,
+ InjectionException {
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ cb.bind(Interf.class, Impl.class);
+ tang.newInjector(cb.build()).getInstance(Interf.class);
+ }
+
+ @Test
+ public void testOneNamedStringArgCantRebind() throws BindException,
+ InjectionException {
+ thrown.expect(BindException.class);
+ thrown.expectMessage("Attempt to re-bind named parameter org.apache.reef.tang.OneNamedStringArg$A. Old value was [not default] new value is [volatile]");
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ OneNamedStringArg a = tang.newInjector(cb.build()).getInstance(
+ OneNamedStringArg.class);
+ Assert.assertEquals("default", a.s);
+ cb.bindNamedParameter(OneNamedStringArg.A.class, "not default");
+ Injector i = tang.newInjector(cb.build());
+ Assert
+ .assertEquals("not default", i.getInstance(OneNamedStringArg.class).s);
+ i.bindVolatileParameter(OneNamedStringArg.A.class, "volatile");
+ Assert.assertEquals("volatile", i.getInstance(OneNamedStringArg.class).s);
+ }
+
+ @Test
+ public void testOneNamedStringArgBind() throws BindException,
+ InjectionException {
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ OneNamedStringArg a = tang.newInjector(cb.build()).getInstance(
+ OneNamedStringArg.class);
+ Assert.assertEquals("default", a.s);
+ cb.bindNamedParameter(OneNamedStringArg.A.class, "not default");
+ Injector i = tang.newInjector(cb.build());
+ Assert
+ .assertEquals("not default", i.getInstance(OneNamedStringArg.class).s);
+ }
+
+ @Test
+ public void testOneNamedStringArgVolatile() throws BindException,
+ InjectionException {
+ OneNamedStringArg a = tang.newInjector().getInstance(
+ OneNamedStringArg.class);
+ Assert.assertEquals("default", a.s);
+ Injector i = tang.newInjector();
+ i.bindVolatileParameter(OneNamedStringArg.A.class, "volatile");
+ Assert.assertEquals("volatile", i.getInstance(OneNamedStringArg.class).s);
+ }
+
+ @Test
+ public void testTwoNamedStringArgsBind() throws BindException,
+ InjectionException {
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ TwoNamedStringArgs a = tang.newInjector(cb.build()).getInstance(
+ TwoNamedStringArgs.class);
+ Assert.assertEquals("defaultA", a.a);
+ Assert.assertEquals("defaultB", a.b);
+ cb.bindNamedParameter(TwoNamedStringArgs.A.class, "not defaultA");
+ cb.bindNamedParameter(TwoNamedStringArgs.B.class, "not defaultB");
+ Injector i = tang.newInjector(cb.build());
+ Assert.assertEquals("not defaultA",
+ i.getInstance(TwoNamedStringArgs.class).a);
+ Assert.assertEquals("not defaultB",
+ i.getInstance(TwoNamedStringArgs.class).b);
+ }
+
+ @Test
+ public void testTwoNamedStringArgsBindVolatile() throws BindException,
+ InjectionException {
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ TwoNamedStringArgs a = tang.newInjector(cb.build()).getInstance(
+ TwoNamedStringArgs.class);
+ Assert.assertEquals("defaultA", a.a);
+ Assert.assertEquals("defaultB", a.b);
+ final Injector i = tang.newInjector(cb.build());
+ i.bindVolatileParameter(TwoNamedStringArgs.A.class, "not defaultA");
+ i.bindVolatileParameter(TwoNamedStringArgs.B.class, "not defaultB");
+ Assert.assertEquals("not defaultA",
+ i.getInstance(TwoNamedStringArgs.class).a);
+ Assert.assertEquals("not defaultB",
+ i.getInstance(TwoNamedStringArgs.class).b);
+
+ }
+
+ @Test//(expected = BindException.class)
+ public void testTwoNamedStringArgsReBindVolatileFail() throws BindException,
+ InjectionException {
+ thrown.expect(BindException.class);
+ thrown.expectMessage("Attempt to re-bind named parameter org.apache.reef.tang.TwoNamedStringArgs$A. Old value was [not defaultA] new value is [not defaultA]");
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ TwoNamedStringArgs a = tang.newInjector(cb.build()).getInstance(
+ TwoNamedStringArgs.class);
+ Assert.assertEquals("defaultA", a.a);
+ Assert.assertEquals("defaultB", a.b);
+ cb.bindNamedParameter(TwoNamedStringArgs.A.class, "not defaultA");
+ cb.bindNamedParameter(TwoNamedStringArgs.B.class, "not defaultB");
+ Injector i = tang.newInjector(cb.build());
+ i.bindVolatileParameter(TwoNamedStringArgs.A.class, "not defaultA");
+ i.bindVolatileParameter(TwoNamedStringArgs.B.class, "not defaultB");
+ }
+
+ @Test
+ public void testBextendsAinjectA() throws BindException, InjectionException {
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ cb.bind(BextendsAinjectA.A.class, BextendsAinjectA.A.class);
+ tang.newInjector(cb.build()).getInstance(BextendsAinjectA.A.class);
+ }
+
+ @Test
+ public void testExternalConstructor() throws BindException,
+ InjectionException {
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ cb.bindConstructor(ExternalConstructorExample.Legacy.class,
+ ExternalConstructorExample.LegacyWrapper.class);
+ Injector i = tang.newInjector(cb.build());
+ i.bindVolatileInstance(Integer.class, 42);
+ i.bindVolatileInstance(String.class, "The meaning of life is ");
+ ExternalConstructorExample.Legacy l = i
+ .getInstance(ExternalConstructorExample.Legacy.class);
+ Assert.assertEquals(new Integer(42), l.x);
+ Assert.assertEquals("The meaning of life is ", l.y);
+
+ }
+
+ @Test
+ public void testLegacyConstructor() throws BindException, InjectionException {
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ cb.registerLegacyConstructor(
+ ReflectionUtilities.getFullName(LegacyConstructor.class),
+ ReflectionUtilities.getFullName(Integer.class),
+ ReflectionUtilities.getFullName(String.class));
+ cb.bind(LegacyConstructor.class, LegacyConstructor.class);
+ String confString = ConfigurationFile.toConfigurationString(cb.build());
+ JavaConfigurationBuilder cb2 = tang.newConfigurationBuilder();
+ // System.err.println(confString);
+ ConfigurationFile.addConfiguration(cb2, confString);
+ Injector i = tang.newInjector(cb2.build());
+ i.bindVolatileInstance(Integer.class, 42);
+ i.bindVolatileInstance(String.class, "The meaning of life is ");
+ LegacyConstructor l = i.getInstance(LegacyConstructor.class);
+ Assert.assertEquals(new Integer(42), l.x);
+ Assert.assertEquals("The meaning of life is ", l.y);
+
+ }
+
+ @Test
+ public void testNamedImpl() throws BindException, InjectionException {
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ cb.bindNamedParameter(NamedImpl.AImplName.class, NamedImpl.Aimpl.class);
+ cb.bindNamedParameter(NamedImpl.BImplName.class, NamedImpl.Bimpl.class);
+ Injector i = tang.newInjector(cb.build());
+ NamedImpl.Aimpl a1 = (NamedImpl.Aimpl) i
+ .getNamedInstance(NamedImpl.AImplName.class);
+ NamedImpl.Aimpl a2 = (NamedImpl.Aimpl) i
+ .getNamedInstance(NamedImpl.AImplName.class);
+ NamedImpl.Bimpl b1 = (NamedImpl.Bimpl) i
+ .getNamedInstance(NamedImpl.BImplName.class);
+ NamedImpl.Bimpl b2 = (NamedImpl.Bimpl) i
+ .getNamedInstance(NamedImpl.BImplName.class);
+ Assert.assertSame(a1, a2);
+ Assert.assertSame(b1, b2);
+ }
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ @Test
+ public void testWrongNamedImpl() throws BindException {
+ thrown.expect(BindException.class);
+ thrown.expectMessage("Name<org.apache.reef.tang.NamedImpl$A> org.apache.reef.tang.NamedImpl$AImplName cannot take non-subclass org.apache.reef.tang.NamedImpl$Cimpl");
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ cb.bindNamedParameter((Class) NamedImpl.AImplName.class, (Class) NamedImpl.Cimpl.class);
+ }
+
+ @Test
+ public void testUnit() throws BindException, InjectionException {
+ Injector inj = tang.newInjector();
+ OuterUnit.InA a = inj.getInstance(OuterUnit.InA.class);
+ OuterUnit.InB b = inj.getInstance(OuterUnit.InB.class);
+ Assert.assertEquals(a.slf, b.slf);
+ }
+
+ @Test
+ public void testMissedUnit() throws BindException, InjectionException {
+ thrown.expect(InjectionException.class);
+ thrown.expectMessage("Cannot inject org.apache.reef.tang.MissOuterUnit$InA: No known implementations / injectable constructors for org.apache.reef.tang.MissOuterUnit$InA");
+ Injector inj = tang.newInjector();
+ MissOuterUnit.InA a = inj.getInstance(MissOuterUnit.InA.class);
+ }
+
+ @Test
+ public void testMissedUnitButWithInjectInnerClass() throws BindException, InjectionException {
+ thrown.expect(ClassHierarchyException.class);
+ thrown.expectMessage("Cannot @Inject non-static member class unless the enclosing class an @Unit. Nested class is:org.apache.reef.tang.MissOuterUnit$InB");
+ Injector inj = tang.newInjector();
+ MissOuterUnit.InB b = inj.getInstance(MissOuterUnit.InB.class);
+ }
+
+ @Test
+ public void testThreeConstructors() throws BindException, InjectionException {
+ JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ cb.bindNamedParameter(TCInt.class, "1");
+ cb.bindNamedParameter(TCString.class, "s");
+ ThreeConstructors tc = tang.newInjector(cb.build()).getInstance(ThreeConstructors.class);
+ Assert.assertEquals(1, tc.i);
+ Assert.assertEquals("s", tc.s);
+
+ cb = tang.newConfigurationBuilder();
+ cb.bindNamedParameter(TCInt.class, "1");
+ tc = tang.newInjector(cb.build()).getInstance(ThreeConstructors.class);
+ Assert.assertEquals(1, tc.i);
+ Assert.assertEquals("default", tc.s);
+
+ cb = tang.newConfigurationBuilder();
+ cb.bindNamedParameter(TCString.class, "s");
+ tc = tang.newInjector(cb.build()).getInstance(ThreeConstructors.class);
+ Assert.assertEquals(-1, tc.i);
+ Assert.assertEquals("s", tc.s);
+
+ cb = tang.newConfigurationBuilder();
+ cb.bindNamedParameter(TCFloat.class, "2");
+ tc = tang.newInjector(cb.build()).getInstance(ThreeConstructors.class);
+ Assert.assertEquals(-1, tc.i);
+ Assert.assertEquals("default", tc.s);
+ Assert.assertEquals(2.0f, tc.f, 1e-9);
+ }
+
+ @Test
+ public void testThreeConstructorsAmbiguous() throws BindException, InjectionException {
+ thrown.expect(InjectionException.class);
+ thrown.expectMessage("Cannot inject org.apache.reef.tang.ThreeConstructors Ambigous subplan org.apache.reef.tang.ThreeConstructors");
+// thrown.expectMessage("Cannot inject org.apache.reef.tang.ThreeConstructors Multiple ways to inject org.apache.reef.tang.ThreeConstructors");
+
+ final JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ cb.bindNamedParameter(TCString.class, "s");
+ cb.bindNamedParameter(TCFloat.class, "-2");
+
+ // Ambiguous; there is a constructor that takes a string, and another that
+ // takes a float, but none that takes both.
+ tang.newInjector(cb.build()).getInstance(ThreeConstructors.class);
+ }
+
+ @Test
+ public void testTwoConstructorsAmbiguous() throws BindException, InjectionException {
+ thrown.expect(InjectionException.class);
+ thrown.expectMessage("Cannot inject org.apache.reef.tang.TwoConstructors: Multiple infeasible plans: org.apache.reef.tang.TwoConstructors:");
+ final JavaConfigurationBuilder cb = tang.newConfigurationBuilder();
+ cb.bindNamedParameter(TCString.class, "s");
+ cb.bindNamedParameter(TCInt.class, "1");
+
+ tang.newInjector(cb.build()).getInstance(TwoConstructors.class);
+ }
+
+ @Test
+ public void testDefaultImplementation() throws BindException, ClassHierarchyException, InjectionException {
+ ConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ Injector i = Tang.Factory.getTang().newInjector(cb.build());
+ @SuppressWarnings("unused")
+ IfaceWithDefault iwd = i.getNamedInstance(IfaceWithDefaultName.class);
+ }
+
+ @Test
+ public void testCantGetInstanceOfNamedParameter() throws BindException, InjectionException {
+ thrown.expect(InjectionException.class);
+ thrown.expectMessage("getInstance() called on Name org.apache.reef.tang.IfaceWithDefaultName Did you mean to call getNamedInstance() instead?");
+ ConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ Injector i = Tang.Factory.getTang().newInjector(cb.build());
+ @SuppressWarnings("unused")
+ IfaceWithDefaultName iwd = i.getInstance(IfaceWithDefaultName.class);
+ }
+
+ @Test
+ public void testCanGetDefaultedInterface() throws BindException, InjectionException {
+ Assert.assertNotNull(Tang.Factory.getTang().newInjector().getInstance(HaveDefaultImpl.class));
+ }
+
+ @Test
+ public void testCanOverrideDefaultedInterface() throws BindException, InjectionException {
+ JavaConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ cb.bindImplementation(HaveDefaultImpl.class, OverrideDefaultImpl.class);
+ Assert.assertTrue(Tang.Factory.getTang().newInjector(cb.build())
+ .getInstance(HaveDefaultImpl.class) instanceof OverrideDefaultImpl);
+ }
+
+ @Test
+ public void testCanGetStringDefaultedInterface() throws BindException, InjectionException {
+ Assert.assertNotNull(Tang.Factory.getTang().newInjector().getInstance(HaveDefaultStringImpl.class));
+ }
+
+ @Test
+ public void testCanOverrideStringDefaultedInterface() throws BindException, InjectionException {
+ JavaConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ cb.bindImplementation(HaveDefaultStringImpl.class, OverrideDefaultStringImpl.class);
+ Assert.assertTrue(Tang.Factory.getTang().newInjector(cb.build())
+ .getInstance(HaveDefaultStringImpl.class) instanceof OverrideDefaultStringImpl);
+ }
+
+ @Test
+ public void testSingletonWithMultipleConstructors() throws BindException, InjectionException {
+ JavaConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ cb.bindImplementation(SMC.class, SingletonMultiConst.class);
+ cb.bindNamedParameter(SingletonMultiConst.A.class, "foo");
+ Injector i = Tang.Factory.getTang().newInjector(cb.build());
+ i.getInstance(SMC.class);
+ }
+
+ @Test
+ public void testInjectInjector() throws InjectionException, BindException {
+ Injector i = Tang.Factory.getTang().newInjector();
+ InjectInjector ii = i.getInstance(InjectInjector.class);
+ Assert.assertSame(i, ii.i);
+ }
+
+ @Test
+ public void testProactiveFutures() throws InjectionException, BindException {
+ Injector i = Tang.Factory.getTang().newInjector();
+ IsFuture.instantiated = false;
+ i.getInstance(NeedsFuture.class);
+ Assert.assertTrue(IsFuture.instantiated);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ @Test
+ public void testGenericEventHandlers() throws BindException, InjectionException {
+ JavaConfigurationBuilder cba = Tang.Factory.getTang().newConfigurationBuilder();
+ cba.bindNamedParameter(XName.class, (Class) XAA.class);
+ Tang.Factory.getTang().newInjector(cba.build()).getNamedInstance(XName.class);
+ JavaConfigurationBuilder cbb = Tang.Factory.getTang().newConfigurationBuilder();
+ cbb.bindNamedParameter(XName.class, XBB.class);
+ Tang.Factory.getTang().newInjector(cbb.build()).getNamedInstance(XName.class);
+ JavaConfigurationBuilder cbc = Tang.Factory.getTang().newConfigurationBuilder();
+ cbc.bindNamedParameter(XName.class, (Class) XCC.class);
+ Tang.Factory.getTang().newInjector(cbc.build()).getNamedInstance(XName.class);
+ }
+
+ @Test
+ public void testGenericEventHandlerDefaults() throws BindException, InjectionException {
+ JavaConfigurationBuilder cba = Tang.Factory.getTang().newConfigurationBuilder();
+ Tang.Factory.getTang().newInjector(cba.build()).getNamedInstance(XNameDA.class);
+ JavaConfigurationBuilder cbb = Tang.Factory.getTang().newConfigurationBuilder();
+ Tang.Factory.getTang().newInjector(cbb.build()).getNamedInstance(XNameDB.class);
+ JavaConfigurationBuilder cbc = Tang.Factory.getTang().newConfigurationBuilder();
+ Tang.Factory.getTang().newInjector(cbc.build()).getNamedInstance(XNameDC.class);
+ }
+
+ @Test
+ public void testGenericEventHandlerDefaultsBadTreeIndirection() throws BindException, InjectionException {
+ thrown.expect(ClassHierarchyException.class);
+ thrown.expectMessage("class org.apache.reef.tang.XNameDAA defines a default class org.apache.reef.tang.XCC with a raw type that does not extend of its target's raw type class org.apache.reef.tang.XBB");
+
+ JavaConfigurationBuilder cba = Tang.Factory.getTang().newConfigurationBuilder();
+ Tang.Factory.getTang().newInjector(cba.build()).getNamedInstance(XNameDAA.class);
+ }
+
+ @Test
+ public void testGenericEventHandlerDefaultsGoodTreeIndirection() throws BindException, InjectionException {
+ JavaConfigurationBuilder cba = Tang.Factory.getTang().newConfigurationBuilder();
+ Tang.Factory.getTang().newInjector(cba.build()).getNamedInstance(XNameDDAA.class);
+ }
+
+ @Test
+ public void testGenericUnrelatedGenericTypeParameters() throws BindException, InjectionException {
+ thrown.expect(ClassHierarchyException.class);
+ thrown.expectMessage("class org.apache.reef.tang.WaterBottleName defines a default class org.apache.reef.tang.GasCan with a type that does not extend its target's type org.apache.reef.tang.Bottle<org.apache.reef.tang.Water");
+
+ JavaConfigurationBuilder cba = Tang.Factory.getTang().newConfigurationBuilder();
+ Tang.Factory.getTang().newInjector(cba.build()).getNamedInstance(WaterBottleName.class);
+ }
+
+ @Test
+ public void testGenericInterfaceUnboundTypeParametersName() throws BindException, InjectionException {
+ JavaConfigurationBuilder cba = Tang.Factory.getTang().newConfigurationBuilder();
+ Tang.Factory.getTang().newInjector(cba.build()).getNamedInstance(FooEventHandler.class);
+ }
+
+ @Test
+ public void testGenericInterfaceUnboundTypeParametersNameIface() throws BindException, InjectionException {
+ JavaConfigurationBuilder cba = Tang.Factory.getTang().newConfigurationBuilder();
+ Tang.Factory.getTang().newInjector(cba.build()).getNamedInstance(IfaceEventHandler.class);
+ }
+
+ @Test
+ public void testGenericInterfaceUnboundTypeParametersIface() throws BindException, InjectionException {
+ thrown.expect(ClassHierarchyException.class);
+ thrown.expectMessage("interface org.apache.reef.tang.MyEventHandlerIface declares its default implementation to be non-subclass class org.apache.reef.tang.MyEventHandler");
+
+ JavaConfigurationBuilder cba = Tang.Factory.getTang().newConfigurationBuilder();
+ Tang.Factory.getTang().newInjector(cba.build()).isInjectable(MyEventHandlerIface.class);
+ }
+
+ @Test
+ public void testWantSomeHandlers() throws BindException, InjectionException {
+ Tang.Factory.getTang().newInjector().getInstance(WantSomeHandlers.class);
+ }
+
+ @Test
+ public void testWantSomeHandlersBadOrder() throws BindException, InjectionException {
+ Injector i = Tang.Factory.getTang().newInjector();
+ i.getInstance(AHandler.class);
+ i.getInstance(BHandler.class);
+ i.getInstance(WantSomeFutureHandlers.class);
+ }
+
+ @Test
+ public void testWantSomeFutureHandlersAlreadyBoundVolatile() throws BindException, InjectionException {
+ Injector i = Tang.Factory.getTang().newInjector();
+ i.bindVolatileInstance(AHandler.class, new AHandlerImpl());
+ i.bindVolatileInstance(BHandler.class, new BHandlerImpl());
+ i.getInstance(WantSomeFutureHandlers.class);
+ }
+
+ @Test
+ public void testWantSomeFutureHandlers() throws BindException, InjectionException {
+ Tang.Factory.getTang().newInjector().getInstance(WantSomeFutureHandlers.class);
+ }
+
+ @Test
+ public void testWantSomeFutureHandlersUnit() throws BindException, InjectionException {
+ Tang.Factory.getTang().newInjector().getInstance(WantSomeFutureHandlersUnit.class);
+ }
+
+ @Test
+ public void testWantSomeFutureHandlersName() throws BindException, InjectionException {
+ Tang.Factory.getTang().newInjector().getInstance(WantSomeFutureHandlersName.class);
+ }
+
+ @Test
+ public void testUnitMixedCanInject() throws BindException, InjectionException {
+ //testing that you should be able to have @Unit and also static inner classes not included
+ JavaConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ Injector i = Tang.Factory.getTang().newInjector(cb.build());
+
+ i.getInstance(OuterUnitWithStatic.InnerStaticClass2.class);
+ }
+
+ @Test
+ public void testUnitMixedCantInject() throws BindException, InjectionException {
+ thrown.expect(InjectionException.class);
+ thrown.expectMessage("Cannot inject org.apache.reef.tang.OuterUnitWithStatic$InnerStaticClass: No known implementations / injectable constructors for org.apache.reef.tang.OuterUnitWithStatic$InnerStaticClass");
+
+ //testing that you should be able to have @Unit and also static inner classes not included
+ JavaConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ Injector i = Tang.Factory.getTang().newInjector(cb.build());
+
+ i.getInstance(OuterUnitWithStatic.InnerStaticClass.class);
+ }
+
+ @Test
+ public void testForkWorks() throws BindException, InjectionException {
+ JavaConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ cb.bind(CheckChildIface.class, CheckChildImpl.class);
+
+ Injector i = Tang.Factory.getTang().newInjector(cb.build());
+ Injector i1 = i.forkInjector();
+ CheckChildIface c1 = i1.getInstance(CheckChildIface.class);
+ Injector i2 = i.forkInjector();
+ CheckChildIface c2 = i2.getInstance(CheckChildIface.class);
+ Assert.assertTrue(c1 != c2);
+ }
+
+ @Test
+ public void testReuseFailedInjector() throws BindException, InjectionException {
+ Injector i = Tang.Factory.getTang().newInjector();
+ try {
+ i.getInstance(Fail.class);
+ Assert.fail("Injecting Fail should not have worked!");
+ } catch (InjectionException e) {
+ i.getInstance(Pass.class);
+ }
+ }
+
+ @Test
+ public void testForksInjectorInConstructor() throws BindException, InjectionException {
+ Injector i = Tang.Factory.getTang().newInjector();
+ i.getInstance(ForksInjectorInConstructor.class);
+ }
+
+ /**
+ * This is to test multiple inheritance case.
+ * When a subclass is bound to an interface, it's instance will be created in injection
+ * When a subsubclass is bound to the interface, the subsubclass instance will be created in injection
+ *
+ * @throws BindException
+ * @throws InjectionException
+ */
+ @Test
+ public void testMultiInheritanceMiddleClassFirst() throws BindException, InjectionException {
+ final JavaConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ cb.bindImplementation(CheckChildIface.class, CheckChildImpl.class);
+ final Injector i = Tang.Factory.getTang().newInjector(cb.build());
+ final CheckChildIface o1 = i.getInstance(CheckChildIface.class);
+ Assert.assertTrue(o1 instanceof CheckChildImpl);
+
+ final JavaConfigurationBuilder cb2 = Tang.Factory.getTang().newConfigurationBuilder();
+ cb2.bindImplementation(CheckChildIface.class, CheckChildImplImpl.class);
+ final Injector i2 = Tang.Factory.getTang().newInjector(cb2.build());
+ final CheckChildIface o2 = i2.getInstance(CheckChildIface.class);
+ Assert.assertTrue(o2 instanceof CheckChildImplImpl);
+ }
+
+ /**
+ * This is to test multiple inheritance case.
+ * When CheckChildImplImpl is bound to an interface, the CheckChildImplImpl instance will be created in injection
+ * When CheckChildImpl is then bound to the same interface, even class hierarchy already knows it has an subclass CheckChildImplImpl,
+ * Tang will only look at the constructors in CheckChildImpl
+ *
+ * @throws BindException
+ * @throws InjectionException
+ */
+ @Test
+ public void testMultiInheritanceSubclassFirst() throws BindException, InjectionException {
+ final JavaConfigurationBuilder cb2 = Tang.Factory.getTang().newConfigurationBuilder();
+ cb2.bindImplementation(CheckChildIface.class, CheckChildImplImpl.class);
+ final Injector i2 = Tang.Factory.getTang().newInjector(cb2.build());
+ final CheckChildIface o2 = i2.getInstance(CheckChildIface.class);
+ Assert.assertTrue(o2 instanceof CheckChildImplImpl);
+
+ final JavaConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ cb.bindImplementation(CheckChildIface.class, CheckChildImpl.class);
+ final Injector i = Tang.Factory.getTang().newInjector(cb.build());
+ final CheckChildIface o1 = i.getInstance(CheckChildIface.class);
+ Assert.assertTrue(o1 instanceof CheckChildImpl);
+ }
+}
+
+class Fail {
+ @Inject
+ public Fail() {
+ throw new UnsupportedOperationException();
+ }
+}
+
+class Pass {
+ @Inject
+ public Pass() {
+ }
+}
+
+class IsFuture {
+ static boolean instantiated;
+
+ @Inject
+ IsFuture(NeedsFuture nf) {
+ instantiated = true;
+ }
+}
+
+class NeedsFuture {
+ @Inject
+ NeedsFuture(InjectionFuture<IsFuture> isFut) {
+ }
+}
+
+class InjectInjector {
+ public final Injector i;
+
+ @Inject
+ InjectInjector(Injector i) {
+ this.i = i;
+ }
+}
+
+class SingletonMultiConst implements SMC {
+ @Inject
+ public SingletonMultiConst(@Parameter(A.class) String a) {
+ }
+
+ @Inject
+ public SingletonMultiConst(@Parameter(A.class) String a, @Parameter(B.class) String b) {
+ }
+
+ @NamedParameter
+ class A implements Name<String> {
+ }
+
+ @NamedParameter
+ class B implements Name<String> {
+ }
+}
+
+class HaveDefaultImplImpl implements HaveDefaultImpl {
+ @Inject
+ HaveDefaultImplImpl() {
+ }
+}
+
+class OverrideDefaultImpl implements HaveDefaultImpl {
+ @Inject
+ public OverrideDefaultImpl() {
+ }
+}
+
+class HaveDefaultStringImplImpl implements HaveDefaultStringImpl {
+ @Inject
+ HaveDefaultStringImplImpl() {
+ }
+}
+
+class OverrideDefaultStringImpl implements HaveDefaultStringImpl {
+ @Inject
+ public OverrideDefaultStringImpl() {
+ }
+}
+
+@NamedParameter(doc = "woo", short_name = "woo", default_value = "42")
+class Param implements Name<Integer> {
+}
+
+class Impl implements Interf {
+ @Inject
+ Impl(@Parameter(Param.class) int p) {
+ }
+}
+
+class MustBeSingleton {
+ static boolean alreadyInstantiated;
+
+ @Inject
+ public MustBeSingleton() {
+ if (alreadyInstantiated) {
+ throw new IllegalStateException("Can't instantiate me twice!");
+ }
+ alreadyInstantiated = true;
+ }
+}
+
+class SubSingleton {
+ @Inject
+ SubSingleton(MustBeSingleton a) {
+ // Does not call super
+ }
+}
+
+class TwoSingletons {
+ @Inject
+ TwoSingletons(SubSingleton a, MustBeSingleton b) {
+ }
+}
+
+class RepeatedAmbiguousArgs {
+ @Inject
+ RepeatedAmbiguousArgs(int x, int y) {
+ }
+}
+
+class RepeatedNamedArgs {
+ @Inject
+ RepeatedNamedArgs(@Parameter(A.class) int x, @Parameter(B.class) int y) {
+ }
+
+ @NamedParameter()
+ class A implements Name<Integer> {
+ }
+
+ @NamedParameter()
+ class B implements Name<Integer> {
+ }
+}
+
+class RepeatedNamedSingletonArgs {
+ @Inject
+ RepeatedNamedSingletonArgs(@Parameter(A.class) MustBeSingleton a,
+ @Parameter(B.class) MustBeSingleton b) {
+ }
+
+ @NamedParameter()
+ class A implements Name<MustBeSingleton> {
+ }
+
+ @NamedParameter()
+ class B implements Name<MustBeSingleton> {
+ }
+}
+
+class OneNamedSingletonArgs {
+ @Inject
+ OneNamedSingletonArgs(@Parameter(A.class) MustBeSingleton a) {
+ }
+
+ @NamedParameter()
+ class A implements Name<MustBeSingleton> {
+ }
+
+ @NamedParameter()
+ class B implements Name<MustBeSingleton> {
+ }
+}
+
+class OneNamedStringArg {
+ public final String s;
+
+ @Inject
+ OneNamedStringArg(@Parameter(A.class) String s) {
+ this.s = s;
+ }
+
+ @NamedParameter(default_value = "default")
+ class A implements Name<String> {
+ }
+}
+
+class TwoNamedStringArgs {
+ public final String a;
+ public final String b;
+
+ @Inject
+ TwoNamedStringArgs(@Parameter(A.class) String a, @Parameter(B.class) String b) {
+ this.a = a;
+ this.b = b;
+ }
+
+ @NamedParameter(default_value = "defaultA")
+ class A implements Name<String> {
+ }
+
+ @NamedParameter(default_value = "defaultB")
+ class B implements Name<String> {
+ }
+}
+
+class BextendsAinjectA {
+ static class A {
+ @Inject
+ A() {
+ }
+ }
+
+ static class B extends A {
+ }
+}
+
+class ExternalConstructorExample {
+ static class LegacyWrapper implements ExternalConstructor<Legacy> {
+ final Integer x;
+ final String y;
+
+ @Inject
+ LegacyWrapper(Integer x, String y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ @Override
+ public Legacy newInstance() {
+ return new ExternalConstructorExample().new Legacy(x, y);
+ }
+
+ }
+
+ class Legacy {
+ final Integer x;
+ final String y;
+
+ public Legacy(Integer x, String y) {
+ this.x = x;
+ this.y = y;
+ }
+ }
+}
+
+class LegacyConstructor {
+ final Integer x;
+ final String y;
+
+ public LegacyConstructor(Integer x, String y) {
+ this.x = x;
+ this.y = y;
+ }
+}
+
+class NamedImpl {
+ static interface A {
+ }
+
+ static interface C {
+
+ }
+
+ @NamedParameter
+ static class AImplName implements Name<A> {
+ }
+
+ @NamedParameter
+ static class BImplName implements Name<A> {
+ }
+
+ @NamedParameter
+ static class CImplName implements Name<C> {
+ }
+
+ static class Aimpl implements A {
+ @Inject
+ Aimpl() {
+ }
+ }
+
+ static class Bimpl implements A {
+ @Inject
+ Bimpl() {
+ }
+ }
+
+ static class Cimpl implements C {
+ @Inject
+ Cimpl() {
+ }
+ }
+
+ static class ABtaker {
+ @Inject
+ ABtaker(@Parameter(AImplName.class) A a, @Parameter(BImplName.class) A b) {
+ Assert.assertTrue("AImplName must be instance of Aimpl",
+ a instanceof Aimpl);
+ Assert.assertTrue("BImplName must be instance of Bimpl",
+ b instanceof Bimpl);
+ }
+ }
+}
+
+@Unit
+class OuterUnit {
+
+ final OuterUnit self;
+
+ @Inject
+ OuterUnit() {
+ self = this;
+ }
+
+ class InA {
+ OuterUnit slf = self;
+ }
+
+ class InB {
+ OuterUnit slf = self;
+ }
+}
+
+class MissOuterUnit {
+
+ final MissOuterUnit self;
+
+ @Inject
+ MissOuterUnit() {
+ self = this;
+ }
+
+ class InA {
+ MissOuterUnit slf = self;
+ }
+
+ class InB {
+ MissOuterUnit slf = self;
+
+ @Inject
+ InB() {
+ }
+ }
+}
+
+class ThreeConstructors {
+
+ final int i;
+ final String s;
+ final Float f;
+
+ @Inject
+ ThreeConstructors(@Parameter(TCInt.class) int i, @Parameter(TCString.class) String s) {
+ this.i = i;
+ this.s = s;
+ this.f = -1.0f;
+ }
+
+ @Inject
+ ThreeConstructors(@Parameter(TCString.class) String s) {
+ this(-1, s);
+ }
+
+ @Inject
+ ThreeConstructors(@Parameter(TCInt.class) int i) {
+ this(i, "default");
+ }
+
+ @Inject
+ ThreeConstructors(@Parameter(TCFloat.class) float f) {
+ this.i = -1;
+ this.s = "default";
+ this.f = f;
+ }
+
+ @NamedParameter
+ static class TCInt implements Name<Integer> {
+ }
+
+ @NamedParameter
+ static class TCString implements Name<String> {
+ }
+
+ @NamedParameter
+ static class TCFloat implements Name<Float> {
+ }
+}
+
+class TwoConstructors {
+
+ final int i;
+ final String s;
+
+ @Inject
+ TwoConstructors(@Parameter(TCInt.class) int i, @Parameter(TCString.class) String s) {
+ this.i = i;
+ this.s = s;
+ }
+
+ @Inject
+ TwoConstructors(@Parameter(TCString.class) String s, @Parameter(TCInt.class) int i) {
+ this.i = i;
+ this.s = s;
+ }
+
+ @NamedParameter
+ static class TCInt implements Name<Integer> {
+ }
+
+ @NamedParameter
+ static class TCString implements Name<String> {
+ }
+}
+
+class IfaceWithDefaultDefaultImpl implements IfaceWithDefault {
+ @Inject
+ IfaceWithDefaultDefaultImpl() {
+ }
+}
+
+@NamedParameter(default_class = IfaceWithDefaultDefaultImpl.class)
+class IfaceWithDefaultName implements Name<IfaceWithDefault> {
+}
+
+@NamedParameter
+class XName implements Name<X<BB>> {
+}
+
+@NamedParameter(default_class = XAA.class)
+class XNameDA implements Name<X<BB>> {
+}
+
+@NamedParameter(default_class = XBB.class)
+class XNameDB implements Name<X<BB>> {
+}
+
+@NamedParameter(default_class = XCC.class)
+class XNameDC implements Name<X<BB>> {
+}
+
+@NamedParameter(default_class = XCC.class)
+class XNameDAA implements Name<XBB> {
+}
+
+@NamedParameter(default_class = XXBB.class)
+class XNameDDAA implements Name<XBB> {
+}
+
+@DefaultImplementation(AA.class)
+class AA {
+ @Inject
+ AA() {
+ }
+}
+
+@DefaultImplementation(BB.class)
+class BB extends AA {
+ @Inject
+ BB() {
+ }
+}
+
+@DefaultImplementation(CC.class)
+class CC extends BB {
+ @Inject
+ CC() {
+ }
+}
+
+class XAA implements X<AA> {
+ @Inject
+ XAA(AA aa) {
+ }
+}
+
+@DefaultImplementation(XBB.class)
+class XBB implements X<BB> {
+ @Inject
+ XBB(BB aa) {
+ }
+}
+
+class XXBB extends XBB {
+ @Inject
+ XXBB(BB aa) {
+ super(aa);
+ }
+}
+
+class XCC implements X<CC> {
+ @Inject
+ XCC(CC aa) {
+ }
+}
+
+class WaterBottle implements Bottle<Water> {
+
+}
+
+class GasCan implements Bottle<Gas> {
+
+}
+
+class Water {
+}
+
+class Gas {
+}
+
+@NamedParameter(default_class = GasCan.class)
+class WaterBottleName implements Name<Bottle<Water>> {
+}
+
+class MyEventHandler<T> implements EventHandler<T> {
+ @Inject
+ MyEventHandler() {
+ }
+}
+
+@NamedParameter(default_class = MyEventHandler.class)
+class FooEventHandler implements Name<EventHandler<Foo>> {
+}
+
+@NamedParameter(default_class = MyEventHandler.class)
+class IfaceEventHandler implements Name<EventHandler<SomeIface>> {
+}
+
+class AH {
+ @Inject
+ AH() {
+ }
+}
+
+class BH {
+ @Inject
+ BH() {
+ }
+}
+
+class AHandlerImpl implements AHandler {
+ @Inject
+ AHandlerImpl() {
+ }
+}
+
+class BHandlerImpl implements BHandler {
+ @Inject
+ BHandlerImpl() {
+ }
+}
+
+@Unit
+class DefaultHandlerUnit {
+ @Inject
+ DefaultHandlerUnit() {
+ }
+
+ @DefaultImplementation(AHandlerImpl.class)
+ interface AHandler extends EventHandler<AH> {
+ }
+
+ @DefaultImplementation(BHandlerImpl.class)
+ interface BHandler extends EventHandler<BH> {
+ }
+
+ class AHandlerImpl implements AHandler {
+ AHandlerImpl() {
+ }
+ }
+
+ class BHandlerImpl implements BHandler {
+ BHandlerImpl() {
+ }
+ }
+}
+
+class WantSomeHandlers {
+ @Inject
+ WantSomeHandlers(AHandler a, BHandler b) {
+ }
+}
+
+class WantSomeFutureHandlers {
+ @Inject
+ WantSomeFutureHandlers(InjectionFuture<AHandler> a, InjectionFuture<BHandler> b) {
+ }
+}
+
+class WantSomeFutureHandlersUnit {
+ @Inject
+ WantSomeFutureHandlersUnit(InjectionFuture<DefaultHandlerUnit.AHandler> a, InjectionFuture<DefaultHandlerUnit.BHandler> b) {
+ }
+}
+
+@NamedParameter(default_class = AHandlerImpl.class)
+class AHandlerName implements Name<EventHandler<AH>> {
+}
+
+@NamedParameter(default_class = BHandlerImpl.class)
+class BHandlerName implements Name<EventHandler<BH>> {
+}
+
+class WantSomeFutureHandlersName {
+ @Inject
+ WantSomeFutureHandlersName(
+ @Parameter(AHandlerName.class) InjectionFuture<EventHandler<AH>> a,
+ @Parameter(BHandlerName.class) InjectionFuture<EventHandler<BH>> b) {
+ }
+}
+
+@Unit
+class OuterUnitWithStatic {
+
+ @Inject
+ public OuterUnitWithStatic() {
+ }
+
+ public void bar() {
+ new InnerStaticClass().baz();
+ }
+
+ static class InnerStaticClass {
+ public InnerStaticClass() {
+ }
+
+ public void baz() {
+ }
+ }
+
+ static class InnerStaticClass2 {
+ @Inject
+ public InnerStaticClass2() {
+ }
+
+ public void baz() {
+ }
+ }
+
+ public class InnerUnitClass {
+ public void foo() {
+ }
+ }
+}
+
+class CheckChildImpl implements CheckChildIface {
+ @Inject
+ CheckChildImpl() {
+ }
+}
+
+class CheckChildImplImpl extends CheckChildImpl {
+ @Inject
+ CheckChildImplImpl() {
+ }
+}
+
+class ForksInjectorInConstructor {
+ @Inject
+ ForksInjectorInConstructor(Injector i) throws BindException {
+ JavaConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ cb.bindImplementation(Number.class, Integer.class);
+ i.forkInjector(cb.build());
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/TestTweetExample.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/TestTweetExample.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/TestTweetExample.java
new file mode 100644
index 0000000..09ba8b4
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/TestTweetExample.java
@@ -0,0 +1,120 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang;
+
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.annotations.NamedParameter;
+import org.apache.reef.tang.annotations.Parameter;
+import org.apache.reef.tang.formats.ConfigurationModule;
+import org.apache.reef.tang.formats.ConfigurationModuleBuilder;
+import org.apache.reef.tang.formats.RequiredParameter;
+import org.junit.*;
+
+import javax.inject.Inject;
+
+public class TestTweetExample {
+ Tang tang;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ }
+
+ @AfterClass
+ public static void tearDownAfterClass() throws Exception {
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ tang = Tang.Factory.getTang();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void test() throws Exception {
+ Tweeter tw = (Tweeter) tang.newInjector(TweetConfig.CONF.set(TweetConfig.PHONE_NUMBER, new Long(867 - 5309)).build()).getInstance(Tweeter.class);
+ tw.sendMessage();
+ }
+
+ static interface TweetFactory {
+ public String getTweet();
+ }
+
+ static interface SMS {
+ public void sendSMS(String msg, long phoneNumber);
+ }
+
+ static class MockTweetFactory implements TweetFactory {
+ @Inject
+ public MockTweetFactory() {
+ }
+
+ @Override
+ public String getTweet() {
+ return "@tw #bbq bbqftw!!! gopher://vuwed.wefd/bbqftw!";
+ }
+ }
+
+ static class MockSMS implements SMS {
+ @Inject
+ public MockSMS() {
+ }
+
+ @Override
+ public void sendSMS(String msg, long phoneNumber) {
+ if (phoneNumber != 867 - 5309) {
+ throw new IllegalArgumentException("Unknown recipient");
+ }
+ // success!
+ }
+ }
+
+ static class Tweeter {
+ final TweetFactory tw;
+ final SMS sms;
+ final long phoneNumber;
+
+ @Inject
+ public Tweeter(TweetFactory tw, SMS sms,
+ @Parameter(PhoneNumber.class) long phoneNumber) {
+ this.tw = tw;
+ this.sms = sms;
+ this.phoneNumber = phoneNumber;
+ }
+
+ public void sendMessage() {
+ sms.sendSMS(tw.getTweet(), phoneNumber);
+ }
+
+ @NamedParameter()
+ class PhoneNumber implements Name<Long> {
+ }
+ }
+
+ public static final class TweetConfig extends ConfigurationModuleBuilder {
+ public static final RequiredParameter<Long> PHONE_NUMBER = new RequiredParameter<>();
+ static final ConfigurationModule CONF = new TweetConfig()
+ .bindImplementation(TweetFactory.class, MockTweetFactory.class)
+ .bindImplementation(SMS.class, MockSMS.class)
+ .bindNamedParameter(Tweeter.PhoneNumber.class, PHONE_NUMBER)
+ .build();
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerAvroRoundtripTest.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerAvroRoundtripTest.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerAvroRoundtripTest.java
new file mode 100644
index 0000000..9ffdee5
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerAvroRoundtripTest.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.formats.avro.AvroConfiguration;
+import org.apache.reef.tang.test.RoundTripTest;
+
+/**
+ * A RoundTripTest that converts to and from AvroConfiguration.
+ */
+public final class AvroConfigurationSerializerAvroRoundtripTest extends RoundTripTest {
+ @Override
+ public Configuration roundTrip(final Configuration configuration) throws Exception {
+ final AvroConfiguration aConf = new AvroConfigurationSerializer().toAvro(configuration);
+ return new AvroConfigurationSerializer().fromAvro(aConf);
+ }
+
+ @Override
+ public Configuration roundTrip(final Configuration configuration, final ClassHierarchy classHierarchy) throws Exception {
+ final AvroConfiguration aConf = new AvroConfigurationSerializer().toAvro(configuration);
+ return new AvroConfigurationSerializer().fromAvro(aConf, classHierarchy);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerByteArrayRoundtripTest.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerByteArrayRoundtripTest.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerByteArrayRoundtripTest.java
new file mode 100644
index 0000000..5de561a
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerByteArrayRoundtripTest.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.test.RoundTripTest;
+
+/**
+ * A RoundTripTest that uses avro to serialize to byte[].
+ */
+public final class AvroConfigurationSerializerByteArrayRoundtripTest extends RoundTripTest {
+ @Override
+ public Configuration roundTrip(Configuration configuration) throws Exception {
+ final AvroConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ final byte[] theBytes = serializer.toByteArray(configuration);
+ return serializer.fromByteArray(theBytes);
+ }
+
+ @Override
+ public Configuration roundTrip(Configuration configuration, final ClassHierarchy classHierarchy) throws Exception {
+ final AvroConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ final byte[] theBytes = serializer.toByteArray(configuration);
+ return serializer.fromByteArray(theBytes, classHierarchy);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerFileRoundtripTest.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerFileRoundtripTest.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerFileRoundtripTest.java
new file mode 100644
index 0000000..6d69576
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerFileRoundtripTest.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.test.RoundTripTest;
+
+import java.io.File;
+
+/**
+ * A RoundTripTest that serializes to and from files generated by Avro.
+ */
+public final class AvroConfigurationSerializerFileRoundtripTest extends RoundTripTest {
+ @Override
+ public Configuration roundTrip(Configuration configuration) throws Exception {
+ final File tempFile = java.io.File.createTempFile("TangTest", "avroconf");
+ final AvroConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ serializer.toFile(configuration, tempFile);
+ final Configuration c = serializer.fromFile(tempFile);
+ tempFile.delete();
+ return c;
+ }
+
+ @Override
+ public Configuration roundTrip(Configuration configuration, final ClassHierarchy classHierarchy) throws Exception {
+ final File tempFile = java.io.File.createTempFile("TangTest", "avroconf");
+ final AvroConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ serializer.toFile(configuration, tempFile);
+ final Configuration c = serializer.fromFile(tempFile, classHierarchy);
+ tempFile.delete();
+ return c;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerStringRoundtripTest.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerStringRoundtripTest.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerStringRoundtripTest.java
new file mode 100644
index 0000000..add5bcf
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerStringRoundtripTest.java
@@ -0,0 +1,40 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.test.RoundTripTest;
+
+/**
+ * A test for Configuration serialization to Strings using AvroConfigurationSerializer.
+ */
+public class AvroConfigurationSerializerStringRoundtripTest extends RoundTripTest {
+ @Override
+ public Configuration roundTrip(final Configuration configuration) throws Exception {
+ final AvroConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ return serializer.fromString(serializer.toString(configuration));
+ }
+
+ @Override
+ public Configuration roundTrip(final Configuration configuration, final ClassHierarchy classHierarchy) throws Exception {
+ final AvroConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ return serializer.fromString(serializer.toString(configuration), classHierarchy);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerTextFileRoundtripTest.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerTextFileRoundtripTest.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerTextFileRoundtripTest.java
new file mode 100644
index 0000000..2220a9c
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/AvroConfigurationSerializerTextFileRoundtripTest.java
@@ -0,0 +1,50 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.test.RoundTripTest;
+
+import java.io.File;
+
+/**
+ * A RoundTripTest that serializes to and from files generated by Avro.
+ */
+public final class AvroConfigurationSerializerTextFileRoundtripTest extends RoundTripTest {
+ @Override
+ public Configuration roundTrip(Configuration configuration) throws Exception {
+ final File tempFile = File.createTempFile("TangTest", "avroconf");
+ final AvroConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ serializer.toTextFile(configuration, tempFile);
+ final Configuration c = serializer.fromTextFile(tempFile);
+ tempFile.delete();
+ return c;
+ }
+
+ @Override
+ public Configuration roundTrip(Configuration configuration, final ClassHierarchy classHierarchy) throws Exception {
+ final File tempFile = File.createTempFile("TangTest", "avroconf");
+ final AvroConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ serializer.toTextFile(configuration, tempFile);
+ final Configuration c = serializer.fromTextFile(tempFile, classHierarchy);
+ tempFile.delete();
+ return c;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/ConfigurationFileTest.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/ConfigurationFileTest.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/ConfigurationFileTest.java
new file mode 100644
index 0000000..9197b85
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/ConfigurationFileTest.java
@@ -0,0 +1,54 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.ClassHierarchy;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.JavaConfigurationBuilder;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.test.RoundTripTest;
+
+import java.io.File;
+
+/**
+ * Tests the file writing routines in ConfigurationFile.
+ */
+public final class ConfigurationFileTest extends RoundTripTest {
+ @Override
+ public Configuration roundTrip(final Configuration configuration) throws Exception {
+ final File tempFile = java.io.File.createTempFile("TangTest", "txt");
+ final ConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ serializer.toTextFile(configuration, tempFile);
+ final JavaConfigurationBuilder configurationBuilder = Tang.Factory.getTang().newConfigurationBuilder();
+ final Configuration conf = serializer.fromTextFile(tempFile);
+ configurationBuilder.addConfiguration(conf);
+ tempFile.delete();
+ return configurationBuilder.build();
+ }
+
+ @Override
+ public Configuration roundTrip(final Configuration configuration, final ClassHierarchy classHierarchy) throws Exception {
+ final File tempFile = java.io.File.createTempFile("TangTest", "txt");
+ final ConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ serializer.toTextFile(configuration, tempFile);
+ final Configuration conf = serializer.fromTextFile(tempFile, classHierarchy);
+ tempFile.delete();
+ return conf;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/NamedParameters.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/NamedParameters.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/NamedParameters.java
new file mode 100644
index 0000000..3dd7cf6
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/NamedParameters.java
@@ -0,0 +1,38 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.annotations.NamedParameter;
+
+/**
+ * Named parameters to be used in tests.
+ */
+public class NamedParameters {
+
+ @NamedParameter(short_name = StringShortNameDefault.SHORT_NAME, default_value = StringShortNameDefault.DEFAULT_VALUE)
+ public static class StringShortNameDefault implements Name<String> {
+ public static final String SHORT_NAME = "string";
+ public static final String DEFAULT_VALUE = "default";
+ }
+
+ @NamedParameter
+ public static class StringNoShortNameNoDefault implements Name<String> {
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/TestCommandLine.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/TestCommandLine.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/TestCommandLine.java
new file mode 100644
index 0000000..0fb3bb3
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/TestCommandLine.java
@@ -0,0 +1,79 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import junit.framework.Assert;
+import org.apache.commons.cli.ParseException;
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.ConfigurationBuilder;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.InjectionException;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+/**
+ * Tests for the CommandLine class.
+ */
+public final class TestCommandLine {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void testNoShortNameToRegister() throws BindException {
+ thrown.expect(BindException.class);
+ final ConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ final CommandLine cl = new CommandLine(cb);
+ cl.registerShortNameOfClass(NamedParameters.StringNoShortNameNoDefault.class);
+ }
+
+ /**
+ * Tests for parseToConfiguration() with a named parameter that is set
+ *
+ * @throws ParseException
+ * @throws InjectionException
+ */
+ @Test
+ public void testParseToConfiguration() throws ParseException, InjectionException {
+ final String expected = "hello";
+ final String[] args = {"-" + NamedParameters.StringShortNameDefault.SHORT_NAME, expected};
+ final Configuration configuration = CommandLine
+ .parseToConfiguration(args, NamedParameters.StringShortNameDefault.class);
+ final String injected = Tang.Factory.getTang().newInjector(configuration)
+ .getNamedInstance(NamedParameters.StringShortNameDefault.class);
+ Assert.assertEquals(expected, injected);
+ }
+
+ /**
+ * Tests for parseToConfiguration() with a named parameter that is not set
+ *
+ * @throws ParseException
+ * @throws InjectionException
+ */
+ @Test
+ public void testParseToConfigurationWithDefault() throws ParseException, InjectionException {
+ final Configuration configuration = CommandLine
+ .parseToConfiguration(new String[0], NamedParameters.StringShortNameDefault.class);
+ final String injected = Tang.Factory.getTang().newInjector(configuration)
+ .getNamedInstance(NamedParameters.StringShortNameDefault.class);
+ Assert.assertEquals(NamedParameters.StringShortNameDefault.DEFAULT_VALUE, injected);
+ }
+
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-reef/blob/53ea32cc/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/TestConfigurationModule.java
----------------------------------------------------------------------
diff --git a/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/TestConfigurationModule.java b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/TestConfigurationModule.java
new file mode 100644
index 0000000..97403d9
--- /dev/null
+++ b/lang/java/reef-tang/tang/src/test/java/org/apache/reef/tang/formats/TestConfigurationModule.java
@@ -0,0 +1,445 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.reef.tang.formats;
+
+import org.apache.reef.tang.Configuration;
+import org.apache.reef.tang.ConfigurationBuilder;
+import org.apache.reef.tang.Injector;
+import org.apache.reef.tang.Tang;
+import org.apache.reef.tang.annotations.Name;
+import org.apache.reef.tang.annotations.NamedParameter;
+import org.apache.reef.tang.annotations.Parameter;
+import org.apache.reef.tang.exceptions.BindException;
+import org.apache.reef.tang.exceptions.ClassHierarchyException;
+import org.apache.reef.tang.exceptions.InjectionException;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import javax.inject.Inject;
+import java.io.File;
+import java.io.IOException;
+import java.util.Set;
+
+/*
+ * Define a configuration module that explains how Foo should be injected.
+ *
+ * A configuration module is like a configuration builder, except that it
+ * is not language independent (it should be defined in the same jar / whatever
+ * as the stuff it configures, and it has a concept of variables that can be
+ * required or optional.
+ *
+ * If you call build() without setting the required variables (or if the
+ * configuration declares variables that it does not use), then it blows up
+ * in your face.
+ *
+ * Note that MyConfigurationModule does not actually subclass
+ * ConfigurationModule. Instead, it has a static final field that contains a
+ * configuration module, and some other ones that define the parameters, and
+ * their types.
+ *
+ * There are some *ahem* non-idiomatic java things going on here.
+ *
+ * Sorry about that; if you can find my java programming license, you can take it
+ * away. :)
+ *
+ * First, you need the " = new RequiredImpl<>()" after each parameter. This is
+ * because you need to pass something into set (other than null). References to
+ * live objects happen to be unique, so that works.
+ *
+ * Second, ConfigurationModule() is abstract, and all of its methods are defined
+ * as final. To instantiate it, you need to put the {}'s between the () and the
+ * .bind stuff. This is so I can call getClass().getEnclosingClass() in its
+ * constructor, and discover all those juicy configuration parameters that
+ * were assigned above it. On the bright side, if you forget the {}'s you get
+ * a compiler error. It used to be that you'd get a cryptic NPE from the
+ * classloader. Also, note that adding methods to ConfigurationModule() won't
+ * work. The bind calls implement immutability by using a secret final clone
+ * method called deepCopy() that strips your subclass off, and uses an anonomyous
+ * inner class instead.
+ *
+ *
+ */
+
+interface Super {
+}
+
+final class MyBadConfigurationModule extends ConfigurationModuleBuilder {
+
+}
+
+final class MyConfigurationModule extends ConfigurationModuleBuilder {
+ // Tell us what implementation you want, or else!!
+ public static final RequiredImpl<TestConfigurationModule.Foo> THE_FOO = new RequiredImpl<>();
+ // If you want, you can change the fooness.
+ public static final OptionalParameter<Integer> FOO_NESS = new OptionalParameter<>();
+
+ public static final ConfigurationModule CONF = new MyConfigurationModule()
+
+ // This binds the above to tang configuration stuff. You can use parameters more than
+ // once, but you'd better use them all at least once, or I'll throw exceptions at you.
+
+ .bindImplementation(TestConfigurationModule.Foo.class, MyConfigurationModule.THE_FOO)
+ .bindNamedParameter(TestConfigurationModule.Fooness.class, MyConfigurationModule.FOO_NESS)
+ .build();
+}
+
+final class MyMissingBindConfigurationModule extends ConfigurationModuleBuilder {
+ // Tell us what implementation you want, or else!!
+ public static final RequiredImpl<TestConfigurationModule.Foo> THE_FOO = new RequiredImpl<>();
+ // If you want, you can change the fooness.
+ public static final OptionalParameter<Integer> FOO_NESS = new OptionalParameter<>();
+
+ // This conf doesn't use FOO_NESS. Expect trouble below
+ public static final ConfigurationModule BAD_CONF = new MyMissingBindConfigurationModule()
+ .bindImplementation(TestConfigurationModule.Foo.class, THE_FOO)
+ .build();
+
+}
+
+public class TestConfigurationModule {
+ /*
+ * Toy class hierarchy: FooImpl implements Foo, has a Fooness named
+ * parameter that defaults to 42.
+ */
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void smokeTest() throws BindException, InjectionException {
+ // Here we set some configuration values. In true tang style,
+ // you won't be able to set them more than once ConfigurationModule's
+ // implementation is complete.
+ Configuration c = MyConfigurationModule.CONF
+ .set(MyConfigurationModule.THE_FOO, FooImpl.class)
+ .set(MyConfigurationModule.FOO_NESS, "" + 12)
+ .build();
+ Foo f = Tang.Factory.getTang().newInjector(c).getInstance(Foo.class);
+ Assert.assertEquals(f.getFooness(), 12);
+ }
+
+ @Test
+ public void smokeTestConfigFile() throws BindException, InjectionException, IOException {
+ // Here we set some configuration values. In true tang style,
+ // you won't be able to set them more than once ConfigurationModule's
+ // implementation is complete.
+ Configuration c = MyConfigurationModule.CONF
+ .set(MyConfigurationModule.THE_FOO, FooImpl.class)
+ .set(MyConfigurationModule.FOO_NESS, "" + 12)
+ .build();
+ Foo f = Tang.Factory.getTang().newInjector(c).getInstance(Foo.class);
+ Assert.assertEquals(f.getFooness(), 12);
+
+ final File tempFile = File.createTempFile("TangTest", ".avroconf");
+ final AvroConfigurationSerializer serializer = new AvroConfigurationSerializer();
+ serializer.toFile(c, tempFile);
+ serializer.fromFile(tempFile);
+
+ }
+
+ @Test
+ public void omitOptionalTest() throws BindException, InjectionException {
+ // Optional is optional.
+ Configuration c = MyConfigurationModule.CONF
+ .set(MyConfigurationModule.THE_FOO, FooImpl.class)
+ .build();
+ Foo f = Tang.Factory.getTang().newInjector(c).getInstance(Foo.class);
+ Assert.assertEquals(f.getFooness(), 42);
+ }
+
+ @Test
+ public void omitRequiredTest() throws Throwable {
+ thrown.expect(BindException.class);
+ thrown.expectMessage("Attempt to build configuration before setting required option(s): { THE_FOO }");
+ try {
+ MyConfigurationModule.CONF
+ .set(MyConfigurationModule.FOO_NESS, "" + 12)
+ .build();
+ } catch (ExceptionInInitializerError e) {
+ throw e.getCause();
+ }
+ }
+
+ @Test
+ public void badConfTest() throws Throwable {
+ thrown.expect(ClassHierarchyException.class);
+ thrown.expectMessage("Found declared options that were not used in binds: { FOO_NESS }");
+ try {
+ // Java's classloader semantics cause it to load a class when executing the
+ // first line that references the class in question.
+ @SuppressWarnings("unused")
+ Object o = MyMissingBindConfigurationModule.BAD_CONF;
+ } catch (ExceptionInInitializerError e) {
+ throw e.getCause();
+ }
+ }
+
+ @Test
+ public void nonExistentStringBindOK() throws BindException, InjectionException {
+ new MyBadConfigurationModule().bindImplementation(Foo.class, "i.do.not.exist");
+ }
+
+ @Test
+ public void nonExistentStringBindNotOK() throws BindException, InjectionException {
+ thrown.expect(ClassHierarchyException.class);
+ thrown.expectMessage("ConfigurationModule refers to unknown class: i.do.not.exist");
+
+ new MyBadConfigurationModule().bindImplementation(Foo.class, "i.do.not.exist").build();
+ }
+
+ @Test
+ public void multiBindTest() throws BindException, InjectionException {
+ // Here we set some configuration values. In true tang style,
+ // you won't be able to set them more than once ConfigurationModule's
+ // implementation is complete.
+ Configuration c = MultiBindConfigurationModule.CONF
+ .set(MultiBindConfigurationModule.THE_FOO, FooImpl.class)
+ .set(MultiBindConfigurationModule.FOO_NESS, "" + 12)
+ .build();
+ Foo f = Tang.Factory.getTang().newInjector(c).getInstance(Foo.class);
+ Foo g = (Foo) Tang.Factory.getTang().newInjector(c).getInstance(Object.class);
+ Assert.assertEquals(f.getFooness(), 12);
+ Assert.assertEquals(g.getFooness(), 12);
+ Assert.assertFalse(f == g);
+ }
+
+ @Test
+ public void foreignSetTest() throws Throwable {
+ thrown.expect(ClassHierarchyException.class);
+ thrown.expectMessage("Unknown Impl/Param when setting RequiredImpl. Did you pass in a field from some other module?");
+ try {
+ // Pass in something from the wrong module, watch it fail.
+ MultiBindConfigurationModule.CONF.set(MyConfigurationModule.THE_FOO, FooImpl.class);
+ } catch (ExceptionInInitializerError e) {
+ throw e.getCause();
+ }
+ }
+
+ @Test
+ public void foreignBindTest() throws Throwable {
+ thrown.expect(ClassHierarchyException.class);
+ thrown.expectMessage("Unknown Impl/Param when binding RequiredImpl. Did you pass in a field from some other module?");
+ try {
+ // Pass in something from the wrong module, watch it fail.
+ new MyConfigurationModule().bindImplementation(Object.class, MultiBindConfigurationModule.THE_FOO);
+ } catch (ExceptionInInitializerError e) {
+ throw e.getCause();
+ }
+ }
+
+ @Test
+ public void singletonTest() throws BindException, InjectionException {
+ Configuration c = new MyConfigurationModule()
+ .bindImplementation(Foo.class, MyConfigurationModule.THE_FOO)
+ .bindNamedParameter(Fooness.class, MyConfigurationModule.FOO_NESS)
+ .build()
+ .set(MyConfigurationModule.THE_FOO, FooImpl.class)
+ .build();
+ Injector i = Tang.Factory.getTang().newInjector(c);
+ Assert.assertTrue(i.getInstance(Foo.class) == i.getInstance(Foo.class));
+ }
+
+ @Test
+ public void immutablilityTest() throws BindException, InjectionException {
+ // builder methods return copies; the original module is immutable
+ ConfigurationModule builder1 = MyConfigurationModule.CONF
+ .set(MyConfigurationModule.THE_FOO, FooImpl.class);
+ Assert.assertFalse(builder1 == MyConfigurationModule.CONF);
+ Configuration config1 = builder1.build();
+
+ // reusable
+ Configuration config2 = MyConfigurationModule.CONF
+ .set(MyConfigurationModule.THE_FOO, FooAltImpl.class)
+ .build();
+
+ // instantiation of each just to be sure everything is fine in this situation
+ Injector i1 = Tang.Factory.getTang().newInjector(config1);
+ Injector i2 = Tang.Factory.getTang().newInjector(config2);
+ Assert.assertEquals(42, i1.getInstance(Foo.class).getFooness());
+ Assert.assertEquals(7, i2.getInstance(Foo.class).getFooness());
+ }
+
+ @Test
+ public void setParamTest() throws BindException, InjectionException {
+ Configuration c = SetConfigurationModule.CONF
+ .set(SetConfigurationModule.P, "a")
+ .set(SetConfigurationModule.P, "b")
+ .build();
+ Set<String> s = Tang.Factory.getTang().newInjector(c).getNamedInstance(SetName.class);
+ Assert.assertEquals(s.size(), 2);
+ Assert.assertTrue(s.contains("a"));
+ Assert.assertTrue(s.contains("b"));
+ }
+
+ @Test
+ public void setClassTest() throws BindException, InjectionException {
+ Configuration c = SetClassConfigurationModule.CONF
+ .set(SetClassConfigurationModule.P, SubA.class)
+ .set(SetClassConfigurationModule.P, SubB.class)
+ .build();
+ Set<Super> s = Tang.Factory.getTang().newInjector(c).getNamedInstance(SetClass.class);
+ Assert.assertEquals(2, s.size());
+ boolean sawA = false, sawB = false;
+ for (Super sup : s) {
+ if (sup instanceof SubA) {
+ sawA = true;
+ } else if (sup instanceof SubB) {
+ sawB = true;
+ } else {
+ Assert.fail();
+ }
+ }
+ Assert.assertTrue(sawA && sawB);
+ }
+
+ @Test
+ public void setClassRoundTripTest() throws BindException, InjectionException {
+ Configuration c = SetClassConfigurationModule.CONF
+ .set(SetClassConfigurationModule.P, SubA.class)
+ .set(SetClassConfigurationModule.P, SubB.class)
+ .build();
+ ConfigurationBuilder cb = Tang.Factory.getTang().newConfigurationBuilder();
+ ConfigurationFile.addConfiguration(cb, ConfigurationFile.toConfigurationString(c));
+ Set<Super> s = Tang.Factory.getTang().newInjector(cb.build()).getNamedInstance(SetClass.class);
+ Assert.assertEquals(2, s.size());
+ boolean sawA = false, sawB = false;
+ for (Super sup : s) {
+ if (sup instanceof SubA) {
+ sawA = true;
+ } else if (sup instanceof SubB) {
+ sawB = true;
+ } else {
+ Assert.fail();
+ }
+ }
+ Assert.assertTrue(sawA && sawB);
+ }
+
+ @Test(expected = ClassHierarchyException.class)
+ public void errorOnStaticTimeSet() throws BindException, InjectionException {
+ StaticTimeSet.CONF.assertStaticClean();
+ }
+
+ @Test(expected = ClassHierarchyException.class)
+ public void errorOnSetMerge() throws BindException, InjectionException {
+ ConfigurationModuleBuilder b = new ConfigurationModuleBuilder() {
+ };
+ b.merge(StaticTimeSet.CONF);
+ }
+
+
+ static interface Foo {
+ public int getFooness();
+ }
+
+ static class FooImpl implements Foo {
+ private final int fooness;
+
+ @Inject
+ FooImpl(@Parameter(Fooness.class) int fooness) {
+ this.fooness = fooness;
+ }
+
+ public int getFooness() {
+ return this.fooness;
+ }
+ }
+
+ static class FooAltImpl implements Foo {
+ @SuppressWarnings("unused")
+ private final int fooness;
+
+ @Inject
+ FooAltImpl(@Parameter(Fooness.class) int fooness) {
+ this.fooness = fooness;
+ }
+
+ public int getFooness() {
+ return 7;
+ }
+ }
+
+ public static final class MultiBindConfigurationModule extends ConfigurationModuleBuilder {
+ // Tell us what implementation you want, or else!!
+ public static final RequiredImpl<Foo> THE_FOO = new RequiredImpl<>();
+ // If you want, you can change the fooness.
+ public static final OptionalParameter<Integer> FOO_NESS = new OptionalParameter<>();
+
+ public static final ConfigurationModule CONF = new MultiBindConfigurationModule()
+
+ // This binds the above to tang configuration stuff. You can use parameters more than
+ // once, but you'd better use them all at least once, or I'll throw exceptions at you.
+
+ .bindImplementation(Foo.class, THE_FOO)
+ .bindImplementation(Object.class, THE_FOO)
+ .bindNamedParameter(Fooness.class, FOO_NESS)
+ .build();
+
+ }
+
+ @NamedParameter(default_value = "42")
+ class Fooness implements Name<Integer> {
+ }
+
+}
+
+@NamedParameter
+class SetName implements Name<Set<String>> {
+}
+
+class SetConfigurationModule extends ConfigurationModuleBuilder {
+ public final static RequiredParameter<String> P = new RequiredParameter<>();
+
+ public static final ConfigurationModule CONF = new SetConfigurationModule()
+ .bindSetEntry(SetName.class, SetConfigurationModule.P)
+ .build();
+}
+
+@NamedParameter
+class SetClass implements Name<Set<Super>> {
+}
+
+class SetClassConfigurationModule extends ConfigurationModuleBuilder {
+ public final static RequiredParameter<Super> P = new RequiredParameter<>();
+ public static final ConfigurationModule CONF = new SetClassConfigurationModule()
+ .bindSetEntry(SetClass.class, SetClassConfigurationModule.P)
+ .build();
+}
+
+class SubA implements Super {
+ @Inject
+ public SubA() {
+ }
+}
+
+class SubB implements Super {
+ @Inject
+ public SubB() {
+ }
+}
+
+class StaticTimeSet extends ConfigurationModuleBuilder {
+ public static final OptionalImpl<Super> X = new OptionalImpl<>();
+ public static final ConfigurationModule CONF = new StaticTimeSet()
+ .bindImplementation(Super.class, X)
+ .build()
+ .set(X, SubA.class);
+}
\ No newline at end of file