Home | History | Annotate | Download | only in inject
      1 /*
      2  * Copyright (C) 2010 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.inject;
     18 
     19 import static com.google.common.collect.ImmutableSet.of;
     20 import static com.google.inject.Asserts.assertContains;
     21 import static com.google.inject.JitBindingsTest.GetBindingCheck.ALLOW_BINDING;
     22 import static com.google.inject.JitBindingsTest.GetBindingCheck.FAIL_ALL;
     23 
     24 import java.util.Set;
     25 import junit.framework.TestCase;
     26 
     27 /**
     28  * Some tests for {@link Binder#requireExplicitBindings()}
     29  *
     30  * @author sberlin (at) gmail.com (Sam Berlin)
     31  */
     32 public class JitBindingsTest extends TestCase {
     33 
     34   private String jitFailed(Class<?> clazz) {
     35     return jitFailed(TypeLiteral.get(clazz));
     36   }
     37 
     38   private String jitFailed(TypeLiteral<?> clazz) {
     39     return "Explicit bindings are required and " + clazz + " is not explicitly bound.";
     40   }
     41 
     42   private String jitInParentFailed(Class<?> clazz) {
     43     return jitInParentFailed(TypeLiteral.get(clazz));
     44   }
     45 
     46   private String jitInParentFailed(TypeLiteral<?> clazz) {
     47     return "Explicit bindings are required and " + clazz + " would be bound in a parent injector.";
     48   }
     49 
     50   private String inChildMessage(Class<?> clazz) {
     51     return "Unable to create binding for "
     52         + clazz.getName()
     53         + ". It was already configured on one or more child injectors or private modules";
     54   }
     55 
     56   public void testLinkedBindingWorks() {
     57     Injector injector =
     58         Guice.createInjector(
     59             new AbstractModule() {
     60               @Override
     61               protected void configure() {
     62                 binder().requireExplicitBindings();
     63                 bind(Foo.class).to(FooImpl.class);
     64               }
     65             });
     66     // Foo was explicitly bound
     67     ensureWorks(injector, Foo.class);
     68     // FooImpl was implicitly bound, it is an error to call getInstance or getProvider,
     69     // It is OK to call getBinding for introspection, but an error to get the provider
     70     // of the binding
     71     ensureFails(injector, ALLOW_BINDING, FooImpl.class);
     72   }
     73 
     74   public void testMoreBasicsWork() {
     75     Injector injector =
     76         Guice.createInjector(
     77             new AbstractModule() {
     78               @Override
     79               protected void configure() {
     80                 binder().requireExplicitBindings();
     81                 bind(Foo.class).to(FooImpl.class);
     82                 bind(Bar.class);
     83                 bind(FooBar.class);
     84               }
     85             });
     86     // Foo, Bar & FooBar was explicitly bound
     87     ensureWorks(injector, FooBar.class, Bar.class, Foo.class);
     88     // FooImpl was implicitly bound, it is an error to call getInstance or getProvider,
     89     // It is OK to call getBinding for introspection, but an error to get the provider
     90     // of the binding
     91     ensureFails(injector, ALLOW_BINDING, FooImpl.class);
     92   }
     93 
     94   public void testLinkedEagerSingleton() {
     95     Injector injector =
     96         Guice.createInjector(
     97             new AbstractModule() {
     98               @Override
     99               protected void configure() {
    100                 binder().requireExplicitBindings();
    101                 bind(Foo.class).to(FooImpl.class).asEagerSingleton();
    102               }
    103             });
    104     // Foo was explicitly bound
    105     ensureWorks(injector, Foo.class);
    106     // FooImpl was implicitly bound, it is an error to call getInstance or getProvider,
    107     // It is OK to call getBinding for introspection, but an error to get the provider
    108     // of the binding
    109     ensureFails(injector, ALLOW_BINDING, FooImpl.class);
    110   }
    111 
    112   public void testBasicsWithEagerSingleton() {
    113     Injector injector =
    114         Guice.createInjector(
    115             new AbstractModule() {
    116               @Override
    117               protected void configure() {
    118                 binder().requireExplicitBindings();
    119                 bind(Foo.class).to(FooImpl.class).asEagerSingleton();
    120                 bind(Bar.class);
    121                 bind(FooBar.class);
    122               }
    123             });
    124     // Foo, Bar & FooBar was explicitly bound
    125     ensureWorks(injector, FooBar.class, Bar.class, Foo.class);
    126     // FooImpl was implicitly bound, it is an error to call getInstance or getProvider,
    127     // It is OK to call getBinding for introspection, but an error to get the provider
    128     // of the binding
    129     ensureFails(injector, ALLOW_BINDING, FooImpl.class);
    130   }
    131 
    132   public void testLinkedToScoped() {
    133     Injector injector =
    134         Guice.createInjector(
    135             new AbstractModule() {
    136               @Override
    137               protected void configure() {
    138                 binder.requireExplicitBindings();
    139                 bind(Foo.class).to(ScopedFooImpl.class);
    140               }
    141             });
    142     // Foo was explicitly bound
    143     ensureWorks(injector, Foo.class);
    144     // FooSingletonImpl was implicitly bound, it is an error to call getInstance or getProvider,
    145     // It is OK to call getBinding for introspection, but an error to get the provider
    146     // of the binding
    147     ensureFails(injector, ALLOW_BINDING, ScopedFooImpl.class);
    148   }
    149 
    150   public void testBasicsWithScoped() {
    151     Injector injector =
    152         Guice.createInjector(
    153             new AbstractModule() {
    154               @Override
    155               protected void configure() {
    156                 binder().requireExplicitBindings();
    157                 bind(Foo.class).to(ScopedFooImpl.class);
    158                 bind(Bar.class);
    159                 bind(FooBar.class);
    160               }
    161             });
    162     // Foo, Bar & FooBar was explicitly bound
    163     ensureWorks(injector, FooBar.class, Bar.class, Foo.class);
    164     // FooSingletonImpl was implicitly bound, it is an error to call getInstance or getProvider,
    165     // It is OK to call getBinding for introspection, but an error to get the provider
    166     // of the binding
    167     ensureFails(injector, ALLOW_BINDING, ScopedFooImpl.class);
    168   }
    169 
    170   public void testFailsIfInjectingScopedDirectlyWhenItIsntBound() {
    171     try {
    172       Guice.createInjector(
    173           new AbstractModule() {
    174             @Override
    175             protected void configure() {
    176               binder().requireExplicitBindings();
    177               bind(Foo.class).to(ScopedFooImpl.class);
    178               bind(WantsScopedFooImpl.class);
    179             }
    180           });
    181       fail();
    182     } catch (CreationException expected) {
    183       assertContains(expected.getMessage(), jitFailed(ScopedFooImpl.class));
    184       assertEquals(1, expected.getErrorMessages().size());
    185     }
    186   }
    187 
    188   public void testLinkedProviderBindingWorks() {
    189     Injector injector =
    190         Guice.createInjector(
    191             new AbstractModule() {
    192               @Override
    193               protected void configure() {
    194                 binder().requireExplicitBindings();
    195                 bind(Foo.class).toProvider(FooProvider.class);
    196               }
    197             });
    198     // Foo was explicitly bound
    199     ensureWorks(injector, Foo.class);
    200     // FooImpl was not bound at all (even implicitly), it is an error
    201     // to call getInstance, getProvider, or getBinding.
    202     ensureFails(injector, FAIL_ALL, FooImpl.class);
    203   }
    204 
    205   public void testJitGetFails() {
    206     try {
    207       Guice.createInjector(
    208               new AbstractModule() {
    209                 @Override
    210                 protected void configure() {
    211                   binder().requireExplicitBindings();
    212                 }
    213               })
    214           .getInstance(Bar.class);
    215       fail("should have failed");
    216     } catch (ConfigurationException expected) {
    217       assertContains(expected.getMessage(), jitFailed(Bar.class));
    218       assertEquals(1, expected.getErrorMessages().size());
    219     }
    220   }
    221 
    222   public void testJitInjectionFails() {
    223     try {
    224       Guice.createInjector(
    225           new AbstractModule() {
    226             @Override
    227             protected void configure() {
    228               binder().requireExplicitBindings();
    229               bind(Foo.class).to(FooImpl.class);
    230               bind(FooBar.class);
    231             }
    232           });
    233       fail("should have failed");
    234     } catch (CreationException expected) {
    235       assertContains(expected.getMessage(), jitFailed(Bar.class));
    236       assertEquals(1, expected.getErrorMessages().size());
    237     }
    238   }
    239 
    240   public void testJitProviderGetFails() {
    241     try {
    242       Guice.createInjector(
    243               new AbstractModule() {
    244                 @Override
    245                 protected void configure() {
    246                   binder().requireExplicitBindings();
    247                 }
    248               })
    249           .getProvider(Bar.class);
    250       fail("should have failed");
    251     } catch (ConfigurationException expected) {
    252       assertContains(expected.getMessage(), jitFailed(Bar.class));
    253       assertEquals(1, expected.getErrorMessages().size());
    254     }
    255   }
    256 
    257   public void testJitProviderInjectionFails() {
    258     try {
    259       Guice.createInjector(
    260           new AbstractModule() {
    261             @Override
    262             protected void configure() {
    263               binder().requireExplicitBindings();
    264               bind(Foo.class).to(FooImpl.class);
    265               bind(ProviderFooBar.class);
    266             }
    267           });
    268       fail("should have failed");
    269     } catch (CreationException expected) {
    270       assertContains(expected.getMessage(), jitFailed(Bar.class));
    271       assertEquals(1, expected.getErrorMessages().size());
    272     }
    273   }
    274 
    275   public void testImplementedBy() {
    276     Injector injector =
    277         Guice.createInjector(
    278             new AbstractModule() {
    279               @Override
    280               protected void configure() {
    281                 binder().requireExplicitBindings();
    282                 bind(ImplBy.class);
    283               }
    284             });
    285     ensureWorks(injector, ImplBy.class);
    286     ensureFails(injector, ALLOW_BINDING, ImplByImpl.class);
    287   }
    288 
    289   public void testImplementedBySomethingThatIsAnnotated() {
    290     Injector injector =
    291         Guice.createInjector(
    292             new AbstractModule() {
    293               @Override
    294               protected void configure() {
    295                 binder().requireExplicitBindings();
    296                 bind(ImplByScoped.class);
    297               }
    298             });
    299     ensureWorks(injector, ImplByScoped.class);
    300     ensureFails(injector, ALLOW_BINDING, ImplByScopedImpl.class);
    301   }
    302 
    303   public void testProvidedBy() {
    304     Injector injector =
    305         Guice.createInjector(
    306             new AbstractModule() {
    307               @Override
    308               protected void configure() {
    309                 binder().requireExplicitBindings();
    310                 bind(ProvBy.class);
    311               }
    312             });
    313     ensureWorks(injector, ProvBy.class);
    314     ensureFails(injector, ALLOW_BINDING, ProvByProvider.class);
    315   }
    316 
    317   public void testProviderMethods() {
    318     Injector injector =
    319         Guice.createInjector(
    320             new AbstractModule() {
    321               @Override
    322               protected void configure() {
    323                 binder().requireExplicitBindings();
    324               }
    325 
    326               @SuppressWarnings("unused")
    327               @Provides
    328               Foo foo() {
    329                 return new FooImpl();
    330               }
    331             });
    332     ensureWorks(injector, Foo.class);
    333   }
    334 
    335   public void testChildInjectorInheritsOption() {
    336     Injector parent =
    337         Guice.createInjector(
    338             new AbstractModule() {
    339               @Override
    340               protected void configure() {
    341                 binder().requireExplicitBindings();
    342                 bind(Bar.class);
    343               }
    344             });
    345     ensureWorks(parent, Bar.class);
    346     ensureFails(parent, FAIL_ALL, FooImpl.class, FooBar.class, Foo.class);
    347 
    348     try {
    349       parent.createChildInjector(
    350           new AbstractModule() {
    351             @Override
    352             protected void configure() {
    353               bind(FooBar.class);
    354             }
    355           });
    356       fail("should have failed");
    357     } catch (CreationException expected) {
    358       assertContains(expected.getMessage(), jitFailed(Foo.class));
    359       assertEquals(1, expected.getErrorMessages().size());
    360     }
    361 
    362     Injector child =
    363         parent.createChildInjector(
    364             new AbstractModule() {
    365               @Override
    366               protected void configure() {
    367                 bind(Foo.class).to(FooImpl.class);
    368               }
    369             });
    370     ensureWorks(child, Foo.class, Bar.class);
    371     ensureFails(child, ALLOW_BINDING, FooImpl.class);
    372     ensureInChild(parent, FooImpl.class, Foo.class);
    373     // TODO(sameb): FooBar may or may not be in a child injector, depending on if GC has run.
    374     // We should fix failed child injectors to remove their contents from the parent blacklist
    375     // immediately, rather than waiting on GC to do it.
    376     // FooBar was succesfully inserted into the child injector (and parent blacklist), but then
    377     // JIT bindings it depended on failed, making the child injector invalid.
    378 
    379     Injector grandchild =
    380         child.createChildInjector(
    381             new AbstractModule() {
    382               @Override
    383               protected void configure() {
    384                 bind(FooBar.class);
    385               }
    386             });
    387     ensureWorks(grandchild, FooBar.class, Foo.class, Bar.class);
    388     ensureFails(grandchild, ALLOW_BINDING, FooImpl.class);
    389     ensureFails(child, ALLOW_BINDING, FooImpl.class);
    390     ensureInChild(parent, FooImpl.class, FooBar.class, Foo.class);
    391   }
    392 
    393   public void testChildInjectorAddsOption() {
    394     Injector parent =
    395         Guice.createInjector(
    396             new AbstractModule() {
    397               @Override
    398               protected void configure() {
    399                 bind(Bar.class);
    400               }
    401             });
    402     int totalParentBindings = parent.getAllBindings().size();
    403 
    404     try {
    405       parent.createChildInjector(
    406           new AbstractModule() {
    407             @Override
    408             protected void configure() {
    409               binder().requireExplicitBindings();
    410               bind(FooBar.class);
    411             }
    412           });
    413       fail("should have failed");
    414     } catch (CreationException expected) {
    415       assertContains(expected.getMessage(), jitFailed(Foo.class));
    416       assertEquals(1, expected.getErrorMessages().size());
    417     }
    418     assertEquals(totalParentBindings, parent.getAllBindings().size());
    419 
    420     Injector child =
    421         parent.createChildInjector(
    422             new AbstractModule() {
    423               @Override
    424               protected void configure() {
    425                 binder().requireExplicitBindings();
    426                 bind(Foo.class).to(FooImpl.class);
    427                 bind(FooImpl.class);
    428               }
    429             });
    430     assertEquals(totalParentBindings, parent.getAllBindings().size());
    431     ensureWorks(child, Foo.class, Bar.class);
    432 
    433     Injector grandchild =
    434         child.createChildInjector(
    435             new AbstractModule() {
    436               @Override
    437               protected void configure() {
    438                 bind(FooBar.class);
    439               }
    440             });
    441     assertEquals(totalParentBindings, parent.getAllBindings().size());
    442     ensureWorks(grandchild, FooBar.class, Foo.class, Bar.class);
    443 
    444     // Make sure siblings of children don't inherit each others settings...
    445     // a new child should be able to get FooImpl.
    446     child = parent.createChildInjector();
    447     ensureWorks(child, FooImpl.class);
    448   }
    449 
    450   public void testPrivateModulesInheritOptions() {
    451     try {
    452       Guice.createInjector(
    453           new AbstractModule() {
    454             @Override
    455             protected void configure() {
    456               binder().requireExplicitBindings();
    457               bind(Foo.class).to(FooImpl.class);
    458 
    459               install(
    460                   new PrivateModule() {
    461                     @Override
    462                     public void configure() {
    463                       bind(FooBar.class);
    464                       expose(FooBar.class);
    465                     }
    466                   });
    467             }
    468           });
    469       fail("should have failed");
    470     } catch (CreationException expected) {
    471       assertContains(expected.getMessage(), jitFailed(Bar.class));
    472       assertEquals(1, expected.getErrorMessages().size());
    473     }
    474 
    475     Injector injector =
    476         Guice.createInjector(
    477             new AbstractModule() {
    478               @Override
    479               protected void configure() {
    480                 binder().requireExplicitBindings();
    481 
    482                 install(
    483                     new PrivateModule() {
    484                       @Override
    485                       public void configure() {
    486                         bind(Foo.class).to(FooImpl.class);
    487                         expose(Foo.class);
    488                       }
    489                     });
    490               }
    491             });
    492     ensureInChild(injector, FooImpl.class);
    493   }
    494 
    495   public void testPrivateModuleAddsOption() {
    496     try {
    497       Guice.createInjector(
    498           new AbstractModule() {
    499             @Override
    500             protected void configure() {
    501               bind(Foo.class).to(FooImpl.class);
    502 
    503               // Fails because FooBar is in the private module,
    504               // and it wants Bar, but Bar would be JIT.
    505               install(
    506                   new PrivateModule() {
    507                     @Override
    508                     public void configure() {
    509                       binder().requireExplicitBindings();
    510                       bind(FooBar.class);
    511                       expose(FooBar.class);
    512                     }
    513                   });
    514             }
    515           });
    516       fail("should have failed");
    517     } catch (CreationException expected) {
    518       assertContains(expected.getMessage(), jitFailed(Bar.class));
    519       assertEquals(1, expected.getErrorMessages().size());
    520     }
    521   }
    522 
    523   public void testPrivateModuleSiblingsDontShareOption() {
    524     Guice.createInjector(
    525         new AbstractModule() {
    526           @Override
    527           protected void configure() {
    528             bind(Foo.class).to(FooImpl.class);
    529 
    530             install(
    531                 new PrivateModule() {
    532                   @Override
    533                   public void configure() {
    534                     binder().requireExplicitBindings();
    535                   }
    536                 });
    537 
    538             // This works, even though Bar is JIT,
    539             // because the requireExplicitBindings isn't shared
    540             // between sibling private modules.
    541             install(
    542                 new PrivateModule() {
    543                   @Override
    544                   public void configure() {
    545                     bind(FooBar.class);
    546                     expose(FooBar.class);
    547                   }
    548                 });
    549           }
    550         });
    551   }
    552 
    553   public void testTypeLiteralsCanBeInjected() {
    554     Injector injector =
    555         Guice.createInjector(
    556             new AbstractModule() {
    557               @Override
    558               protected void configure() {
    559                 binder().requireExplicitBindings();
    560                 bind(new TypeLiteral<WantsTypeLiterals<String>>() {});
    561                 bind(new TypeLiteral<Set<String>>() {}).toInstance(of("bar"));
    562               }
    563             });
    564 
    565     WantsTypeLiterals<String> foo = injector.getInstance(new Key<WantsTypeLiterals<String>>() {});
    566     assertEquals(foo.literal.getRawType(), String.class);
    567     assertEquals(of("bar"), foo.set);
    568   }
    569 
    570   public void testMembersInjectorsCanBeInjected() {
    571     Injector injector =
    572         Guice.createInjector(
    573             new AbstractModule() {
    574               @Override
    575               protected void configure() {
    576                 binder().requireExplicitBindings();
    577               }
    578 
    579               @Provides
    580               String data(MembersInjector<String> mi) {
    581                 String data = "foo";
    582                 mi.injectMembers(data);
    583                 return data;
    584               }
    585             });
    586 
    587     String data = injector.getInstance(String.class);
    588     assertEquals("foo", data);
    589   }
    590 
    591   public void testJitLinkedBindingInParentFails() {
    592     try {
    593       Guice.createInjector(
    594           new AbstractModule() {
    595             @Override
    596             protected void configure() {
    597               install(
    598                   new PrivateModule() {
    599                     @Override
    600                     protected void configure() {
    601                       binder().requireExplicitBindings();
    602                       bind(Foo.class).to(FooImpl.class);
    603                     }
    604                   });
    605             }
    606           });
    607       fail("should have failed");
    608     } catch (CreationException expected) {
    609       assertContains(expected.getMessage(), jitInParentFailed(FooImpl.class));
    610       assertEquals(1, expected.getErrorMessages().size());
    611     }
    612   }
    613 
    614   public void testJitProviderBindingInParentFails() {
    615     try {
    616       Guice.createInjector(
    617           new AbstractModule() {
    618             @Override
    619             protected void configure() {
    620               install(
    621                   new PrivateModule() {
    622                     @Override
    623                     protected void configure() {
    624                       binder().requireExplicitBindings();
    625                       bind(Foo.class).toProvider(FooProvider.class);
    626                     }
    627                   });
    628             }
    629           });
    630       fail("should have failed");
    631     } catch (CreationException expected) {
    632       assertContains(expected.getMessage(), jitInParentFailed(FooProvider.class));
    633       assertEquals(1, expected.getErrorMessages().size());
    634     }
    635   }
    636 
    637   public void testJitImplementedByBindingInParentFails() {
    638     try {
    639       Guice.createInjector(
    640           new AbstractModule() {
    641             @Override
    642             protected void configure() {
    643               install(
    644                   new PrivateModule() {
    645                     @Override
    646                     protected void configure() {
    647                       binder().requireExplicitBindings();
    648                       bind(ImplBy.class);
    649                     }
    650                   });
    651             }
    652           });
    653       fail("should have failed");
    654     } catch (CreationException expected) {
    655       assertContains(expected.getMessage(), jitInParentFailed(ImplByImpl.class));
    656       assertEquals(1, expected.getErrorMessages().size());
    657     }
    658   }
    659 
    660   public void testJitProvidedByBindingInParentFails() {
    661     try {
    662       Guice.createInjector(
    663           new AbstractModule() {
    664             @Override
    665             protected void configure() {
    666               install(
    667                   new PrivateModule() {
    668                     @Override
    669                     protected void configure() {
    670                       binder().requireExplicitBindings();
    671                       bind(ProvBy.class);
    672                     }
    673                   });
    674             }
    675           });
    676       fail("should have failed");
    677     } catch (CreationException expected) {
    678       assertContains(expected.getMessage(), jitInParentFailed(ProvByProvider.class));
    679       assertEquals(1, expected.getErrorMessages().size());
    680     }
    681   }
    682 
    683   private void ensureWorks(Injector injector, Class<?>... classes) {
    684     for (int i = 0; i < classes.length; i++) {
    685       injector.getInstance(classes[i]);
    686       injector.getProvider(classes[i]).get();
    687       injector.getBinding(classes[i]).getProvider().get();
    688     }
    689   }
    690 
    691   enum GetBindingCheck {
    692     FAIL_ALL,
    693     ALLOW_BINDING,
    694     ALLOW_BINDING_PROVIDER
    695   }
    696 
    697   private void ensureFails(Injector injector, GetBindingCheck getBinding, Class<?>... classes) {
    698     for (int i = 0; i < classes.length; i++) {
    699       try {
    700         injector.getInstance(classes[i]);
    701         fail("should have failed tring to retrieve class: " + classes[i]);
    702       } catch (ConfigurationException expected) {
    703         assertContains(expected.getMessage(), jitFailed(classes[i]));
    704         assertEquals(1, expected.getErrorMessages().size());
    705       }
    706 
    707       try {
    708         injector.getProvider(classes[i]);
    709         fail("should have failed tring to retrieve class: " + classes[i]);
    710       } catch (ConfigurationException expected) {
    711         assertContains(expected.getMessage(), jitFailed(classes[i]));
    712         assertEquals(1, expected.getErrorMessages().size());
    713       }
    714 
    715       if (getBinding == GetBindingCheck.ALLOW_BINDING
    716           || getBinding == GetBindingCheck.ALLOW_BINDING_PROVIDER) {
    717         Binding<?> binding = injector.getBinding(classes[i]);
    718         try {
    719           binding.getProvider();
    720           if (getBinding != GetBindingCheck.ALLOW_BINDING_PROVIDER) {
    721             fail("should have failed trying to retrieve class: " + classes[i]);
    722           }
    723         } catch (ConfigurationException expected) {
    724           if (getBinding == GetBindingCheck.ALLOW_BINDING_PROVIDER) {
    725             throw expected;
    726           }
    727           assertContains(expected.getMessage(), jitFailed(classes[i]));
    728           assertEquals(1, expected.getErrorMessages().size());
    729         }
    730       } else {
    731         try {
    732           injector.getBinding(classes[i]);
    733           fail("should have failed tring to retrieve class: " + classes[i]);
    734         } catch (ConfigurationException expected) {
    735           assertContains(expected.getMessage(), jitFailed(classes[i]));
    736           assertEquals(1, expected.getErrorMessages().size());
    737         }
    738       }
    739     }
    740   }
    741 
    742   private void ensureInChild(Injector injector, Class<?>... classes) {
    743     for (int i = 0; i < classes.length; i++) {
    744       try {
    745         injector.getInstance(classes[i]);
    746         fail("should have failed tring to retrieve class: " + classes[i]);
    747       } catch (ConfigurationException expected) {
    748         assertContains(expected.getMessage(), inChildMessage(classes[i]));
    749         assertEquals(1, expected.getErrorMessages().size());
    750       }
    751 
    752       try {
    753         injector.getProvider(classes[i]);
    754         fail("should have failed tring to retrieve class: " + classes[i]);
    755       } catch (ConfigurationException expected) {
    756         assertContains(expected.getMessage(), inChildMessage(classes[i]));
    757         assertEquals(1, expected.getErrorMessages().size());
    758       }
    759 
    760       try {
    761         injector.getBinding(classes[i]);
    762         fail("should have failed tring to retrieve class: " + classes[i]);
    763       } catch (ConfigurationException expected) {
    764         assertContains(expected.getMessage(), inChildMessage(classes[i]));
    765         assertEquals(1, expected.getErrorMessages().size());
    766       }
    767     }
    768   }
    769 
    770   private static interface Foo {}
    771 
    772   private static class FooImpl implements Foo {}
    773 
    774   @Singleton
    775   private static class ScopedFooImpl implements Foo {}
    776 
    777   private static class WantsScopedFooImpl {
    778     @SuppressWarnings("unused")
    779     @Inject
    780     ScopedFooImpl scopedFoo;
    781   }
    782 
    783   private static class Bar {}
    784 
    785   private static class FooBar {
    786     @SuppressWarnings("unused")
    787     @Inject
    788     Foo foo;
    789 
    790     @SuppressWarnings("unused")
    791     @Inject
    792     Bar bar;
    793   }
    794 
    795   private static class ProviderFooBar {
    796     @SuppressWarnings("unused")
    797     @Inject
    798     Provider<Foo> foo;
    799 
    800     @SuppressWarnings("unused")
    801     @Inject
    802     Provider<Bar> bar;
    803   }
    804 
    805   private static class FooProvider implements Provider<Foo> {
    806     @Override
    807     public Foo get() {
    808       return new FooImpl();
    809     }
    810   }
    811 
    812   @ImplementedBy(ImplByImpl.class)
    813   private static interface ImplBy {}
    814 
    815   private static class ImplByImpl implements ImplBy {}
    816 
    817   @ImplementedBy(ImplByScopedImpl.class)
    818   private static interface ImplByScoped {}
    819 
    820   @Singleton
    821   private static class ImplByScopedImpl implements ImplByScoped {}
    822 
    823   @ProvidedBy(ProvByProvider.class)
    824   private static interface ProvBy {}
    825 
    826   private static class ProvByProvider implements Provider<ProvBy> {
    827     @Override
    828     public ProvBy get() {
    829       return new ProvBy() {};
    830     }
    831   }
    832 
    833   private static class WantsTypeLiterals<T> {
    834     TypeLiteral<T> literal;
    835     Set<T> set;
    836 
    837     @Inject
    838     WantsTypeLiterals(TypeLiteral<T> literal, Set<T> set) {
    839       this.literal = literal;
    840       this.set = set;
    841     }
    842   }
    843 }
    844