@Test
 public void subcomponentReleaseThenRestoreThenGcThenRelease() {
   assertBindingCallCounts();
   component.childReleasableScope2Manager().releaseStrongReferences(); // release scope 4
   assertBindingCallCounts(); // no change to scoped bindings
   component.childReleasableScope2Manager().restoreStrongReferences(); // restore scope 4
   gcAndWaitUntilWeakReferencesCleared(ParentModule.class, ChildModule.class); // GC
   assertBindingCallCounts(); // no change to scoped bindings
   component.childReleasableScope2Manager().releaseStrongReferences(); // release scope 4
   gcAndWaitUntilWeakReferencesCleared(
       ParentModule.class, ChildModule.class, ChildReleasableScope2.class); // GC
   childAsserts.expectedCallsForChildReleasableScope2Thing++; // expect scope 4 bindings again
   assertBindingCallCounts();
 }
 @Test
 public void setOfTypedReleasableReferenceManagers() {
   ListMultimap<Class<? extends Annotation>, Metadata1> managers =
       Multimaps.transformValues(
           Multimaps.index(
               component.typedReleasableReferenceManagers1(),
               new Function<TypedReleasableReferenceManager<?>, Class<? extends Annotation>>() {
                 @Override
                 public Class<? extends Annotation> apply(
                     TypedReleasableReferenceManager<?> releasableReferenceManager) {
                   return releasableReferenceManager.scope();
                 }
               }),
           new Function<TypedReleasableReferenceManager<Metadata1>, Metadata1>() {
             @Override
             public Metadata1 apply(TypedReleasableReferenceManager<Metadata1> manager) {
               return manager.metadata();
             }
           });
   assertThat(managers)
       .containsEntry(ParentReleasableScope2.class, metadata1("ParentReleasableScope2"));
   assertThat(managers)
       .containsEntry(ChildReleasableScope2.class, metadata1("ChildReleasableScope2.1"));
   assertThat(managers)
       .containsEntry(ChildReleasableScope3.class, metadata1("ChildReleasableScope3.1"));
 }
  @Test
  public void releaseThenRestoreThenGcThenRelease() {
    assertBindingCallCounts();
    component.parentReleasableScope2Manager().releaseStrongReferences(); // release scope 2
    assertBindingCallCounts(); // no change to scoped bindings
    component.parentReleasableScope2Manager().restoreStrongReferences(); // restore scope 2
    assertBindingCallCounts(); // no change to scoped bindings
    gcAndWaitUntilWeakReferencesCleared(ParentModule.class, ChildModule.class); // GC
    assertBindingCallCounts(); // no change to scoped bindings

    // Releasing again and GCing again means the binding is executed again.
    component.parentReleasableScope2Manager().releaseStrongReferences(); // release scope 2
    assertBindingCallCounts(); // no change to scoped bindings
    gcAndWaitUntilWeakReferencesCleared(
        ParentModule.class, ChildModule.class, ParentReleasableScope2.class); // GC
    parentAsserts.expectedCallsForParentReleasableScope2Thing++; // expect scope 2 bindings again
    assertBindingCallCounts();
  }
 @Test
 public void releaseThenGc() {
   assertBindingCallCounts();
   component.parentReleasableScope1Manager().releaseStrongReferences(); // release scope 1
   assertBindingCallCounts(); // no change to scoped bindings
   gcAndWaitUntilWeakReferencesCleared(
       ParentModule.class, ChildModule.class, ParentReleasableScope1.class); // GC
   parentAsserts.expectedCallsForParentReleasableScope1Thing++; // expect scope 1 bindings again
   assertBindingCallCounts();
 }
 @Test
 public void releasableReferenceManagers() {
   ImmutableMap<Class<? extends Annotation>, ReleasableReferenceManager> managers =
       Maps.uniqueIndex(
           component.managers(),
           new Function<ReleasableReferenceManager, Class<? extends Annotation>>() {
             @Override
             public Class<? extends Annotation> apply(
                 ReleasableReferenceManager releasableReferenceManager) {
               return releasableReferenceManager.scope();
             }
           });
   assertThat(managers)
       .containsEntry(ParentReleasableScope1.class, component.parentReleasableScope1Manager());
   assertThat(managers)
       .containsEntry(ParentReleasableScope2.class, component.parentReleasableScope2Manager());
   assertThat(managers)
       .containsEntry(ChildReleasableScope1.class, component.childReleasableScope1Manager());
   assertThat(managers)
       .containsEntry(ChildReleasableScope2.class, component.childReleasableScope2Manager());
   // Should contain a manager for ChildReleasableScope3 even though
   // @ForReleasableReferences(Scope5.class) isn't needed.
   assertThat(managers).containsKey(ChildReleasableScope3.class);
 }
  @Test
  public void twoInstancesOfSameSubcomponent() {
    // Two instances of the same subcomponent.
    ChildAsserts child2Asserts = parentAsserts.newChildAsserts();
    childAsserts.assertBindingCallCounts();
    child2Asserts.assertBindingCallCounts();

    component.childReleasableScope1Manager().releaseStrongReferences(); // release scope 3
    childAsserts.assertBindingCallCounts(); // no change to scoped bindings in child 1
    child2Asserts.assertBindingCallCounts(); // no change to scoped bindings in child 2
    gcAndWaitUntilWeakReferencesCleared(
        ParentModule.class, ChildModule.class, ChildReleasableScope1.class); // GC
    childAsserts.expectedCallsForChildReleasableScope1Thing++; // expect scope 3 bindings again
    childAsserts.assertBindingCallCounts(); // when calling child.things()
    child2Asserts.expectedCallsForChildReleasableScope1Thing++; // expect scope 3 bindings yet again
    child2Asserts.assertBindingCallCounts(); // when calling child2.things()
  }
 /**
  * Returns an object that can make assertions for the {@link Thing}s returned by {@link
  * Child#things()}.
  */
 ChildAsserts newChildAsserts() {
   return new ChildAsserts(this, parent.child());
 }