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