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