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 testCallStackSize()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 testGetCallStack_IntegrationTest()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 createModuleSource()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 configure()152 public void configure() { 153 install(new B()); 154 } 155 } 156 157 private static class B implements Module { 158 @Override configure(Binder binder)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 configure()171 public void configure() { 172 bind(String.class).annotatedWith(SampleAnnotation.class).toInstance("the value"); 173 } 174 } 175 } 176