Home | History | Annotate | Download | only in spi
      1 package com.google.inject.spi;
      2 
      3 import static com.google.inject.internal.InternalFlags.getIncludeStackTraceOption;
      4 import static java.lang.annotation.RetentionPolicy.RUNTIME;
      5 
      6 import com.google.inject.AbstractModule;
      7 import com.google.inject.Binder;
      8 import com.google.inject.Binding;
      9 import com.google.inject.BindingAnnotation;
     10 import com.google.inject.Module;
     11 
     12 import junit.framework.TestCase;
     13 
     14 import java.lang.annotation.Annotation;
     15 import java.lang.annotation.ElementType;
     16 import java.lang.annotation.Retention;
     17 import java.lang.annotation.Target;
     18 import java.util.List;
     19 
     20 /**
     21  * Tests for {@link ElementSource}.
     22  */
     23 public class ElementSourceTest extends TestCase {
     24 
     25   private static final StackTraceElement BINDER_INSTALL =
     26       new StackTraceElement("com.google.inject.spi.Elements$RecordingBinder", "install",
     27           "Unknown Source", 234 /* line number*/);
     28 
     29   public void testCallStackSize() {
     30     ModuleSource moduleSource = createModuleSource();
     31     StackTraceElement[] bindingCallStack = new StackTraceElement[3];
     32     bindingCallStack[0] = new StackTraceElement(
     33         "com.google.inject.spi.Elements$RecordingBinder", "bind", "Unknown Source", 200);
     34     bindingCallStack[1] = new StackTraceElement(
     35         "com.google.inject.spi.Elements$RecordingBinder", "bind", "Unknown Source", 100);
     36     bindingCallStack[2] = new StackTraceElement(
     37         "com.google.inject.spi.moduleSourceTest$C", "configure", "Unknown Source", 100);
     38     ElementSource elementSource = new ElementSource(
     39         null /* No original element source */, "" /* Don't care */, moduleSource, bindingCallStack);
     40     assertEquals(10 /* call stack size */, elementSource.getStackTrace().length);
     41   }
     42 
     43   public void testGetCallStack_IntegrationTest() throws Exception {
     44     List<Element> elements = Elements.getElements(new A());
     45     for (Element element : elements) {
     46       if (element instanceof Binding) {
     47         Binding<?> binding = (Binding<?>) element;
     48         Class<? extends Annotation> annotationType = binding.getKey().getAnnotationType();
     49         if (annotationType != null && annotationType.equals(SampleAnnotation.class)) {
     50           ElementSource elementSource = (ElementSource) binding.getSource();
     51           List<String> moduleClassNames = elementSource.getModuleClassNames();
     52           // Check module class names
     53           // Module C
     54           assertEquals("com.google.inject.spi.ElementSourceTest$C", moduleClassNames.get(0));
     55           // Module B
     56           assertEquals("com.google.inject.spi.ElementSourceTest$B", moduleClassNames.get(1));
     57           // Module A
     58           assertEquals("com.google.inject.spi.ElementSourceTest$A", moduleClassNames.get(2));
     59           StackTraceElement[] callStack = elementSource.getStackTrace();
     60           switch(getIncludeStackTraceOption()) {
     61             case OFF:
     62               // Check declaring source
     63               StackTraceElement stackTraceElement =
     64                   (StackTraceElement) elementSource.getDeclaringSource();
     65               assertEquals(new StackTraceElement(
     66                   "com.google.inject.spi.ElementSourceTest$C", "configure", null, -1),
     67                   stackTraceElement);
     68               // Check call stack
     69               assertEquals(0, callStack.length);
     70               return;
     71             case ONLY_FOR_DECLARING_SOURCE:
     72                 // Check call stack
     73                 assertEquals(0, callStack.length);
     74                 return;
     75             case COMPLETE:
     76               // Check call stack
     77               int skippedCallStackSize = new Throwable().getStackTrace().length - 1;
     78               assertEquals(skippedCallStackSize + 15, elementSource.getStackTrace().length);
     79               assertEquals("com.google.inject.spi.Elements$RecordingBinder",
     80                   callStack[0].getClassName());
     81               assertEquals("com.google.inject.spi.Elements$RecordingBinder",
     82                   callStack[1].getClassName());
     83               assertEquals("com.google.inject.AbstractModule",
     84                   callStack[2].getClassName());
     85               // Module C
     86               assertEquals("com.google.inject.spi.ElementSourceTest$C",
     87                   callStack[3].getClassName());
     88               assertEquals("configure",
     89                   callStack[3].getMethodName());
     90               assertEquals("Unknown Source",
     91                   callStack[3].getFileName());
     92               assertEquals("com.google.inject.AbstractModule",
     93                   callStack[4].getClassName());
     94               assertEquals("com.google.inject.spi.Elements$RecordingBinder",
     95                   callStack[5].getClassName());
     96               // Module B
     97               assertEquals("com.google.inject.spi.ElementSourceTest$B",
     98                   callStack[6].getClassName());
     99               assertEquals("com.google.inject.spi.Elements$RecordingBinder",
    100                   callStack[7].getClassName());
    101               // Module A
    102               assertEquals("com.google.inject.AbstractModule",
    103                   callStack[8].getClassName());
    104               assertEquals("com.google.inject.spi.ElementSourceTest$A",
    105                   callStack[9].getClassName());
    106               assertEquals("com.google.inject.AbstractModule",
    107                   callStack[10].getClassName());
    108               assertEquals("com.google.inject.spi.Elements$RecordingBinder",
    109                   callStack[11].getClassName());
    110               assertEquals("com.google.inject.spi.Elements",
    111                   callStack[12].getClassName());
    112               assertEquals("com.google.inject.spi.Elements",
    113                   callStack[13].getClassName());
    114               assertEquals("com.google.inject.spi.ElementSourceTest",
    115                   callStack[14].getClassName());
    116               // Check modules index
    117               List<Integer> indexes = elementSource.getModuleConfigurePositionsInStackTrace();
    118               assertEquals((int) indexes.get(0), 4);
    119               assertEquals((int) indexes.get(1), 6);
    120               assertEquals((int) indexes.get(2), 10);
    121               return;
    122           }
    123         }
    124       }
    125     }
    126     fail("The test should not reach this line.");
    127   }
    128 
    129   private ModuleSource createModuleSource() {
    130     // First module
    131     StackTraceElement[] partialCallStack = new StackTraceElement[1];
    132     partialCallStack[0] = BINDER_INSTALL;
    133     ModuleSource moduleSource = new ModuleSource(new A(), partialCallStack);
    134     // Second module
    135     partialCallStack = new StackTraceElement[2];
    136     partialCallStack[0] = BINDER_INSTALL;
    137     partialCallStack[1] = new StackTraceElement(
    138         "com.google.inject.spi.moduleSourceTest$A", "configure", "Unknown Source", 100);
    139     moduleSource = moduleSource.createChild(new B(), partialCallStack);
    140     // Third module
    141     partialCallStack = new StackTraceElement[4];
    142     partialCallStack[0] = BINDER_INSTALL;
    143     partialCallStack[1] = new StackTraceElement("class1", "method1", "Class1.java", 1);
    144     partialCallStack[2] = new StackTraceElement("class2", "method2", "Class2.java", 2);
    145     partialCallStack[3] = new StackTraceElement(
    146         "com.google.inject.spi.moduleSourceTest$B", "configure", "Unknown Source", 200);
    147     return moduleSource.createChild(new C(), partialCallStack);
    148   }
    149 
    150   private static class A extends AbstractModule {
    151     @Override
    152     public void configure() {
    153       install(new B());
    154     }
    155   }
    156 
    157   private static class B implements Module {
    158     @Override
    159     public void configure(Binder binder) {
    160       binder.install(new C());
    161     }
    162   }
    163 
    164   @Retention(RUNTIME)
    165   @Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
    166   @BindingAnnotation
    167   @interface SampleAnnotation { }
    168 
    169   private static class C extends AbstractModule {
    170     @Override
    171     public void configure() {
    172       bind(String.class).annotatedWith(SampleAnnotation.class).toInstance("the value");
    173     }
    174   }
    175 }
    176