PageRenderTime 546ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/guice/src/test/java/io/cucumber/guice/InjectorSourceFactoryTest.java

http://github.com/cucumber/cucumber-jvm
Java | 206 lines | 152 code | 34 blank | 20 comment | 3 complexity | dd80211200f1d464b0b2a6937684c9aa MD5 | raw file
  1. package io.cucumber.guice;
  2. import com.google.inject.Injector;
  3. import org.junit.jupiter.api.Test;
  4. import org.junit.jupiter.api.function.Executable;
  5. import java.io.ByteArrayOutputStream;
  6. import java.io.File;
  7. import java.io.FileInputStream;
  8. import java.util.Collections;
  9. import java.util.HashMap;
  10. import java.util.Map;
  11. import static org.hamcrest.CoreMatchers.instanceOf;
  12. import static org.hamcrest.MatcherAssert.assertThat;
  13. import static org.hamcrest.core.Is.is;
  14. import static org.hamcrest.core.Is.isA;
  15. import static org.hamcrest.core.IsEqual.equalTo;
  16. import static org.junit.jupiter.api.Assertions.assertAll;
  17. import static org.junit.jupiter.api.Assertions.assertThrows;
  18. class InjectorSourceFactoryTest {
  19. @Test
  20. void createsDefaultInjectorSourceWhenGuiceModulePropertyIsNotSet() {
  21. InjectorSourceFactory injectorSourceFactory = createInjectorSourceFactory(Collections.emptyMap());
  22. assertThat(injectorSourceFactory.create(), is(instanceOf(InjectorSource.class)));
  23. }
  24. private InjectorSourceFactory createInjectorSourceFactory(Map<String, String> properties) {
  25. return new InjectorSourceFactory(properties);
  26. }
  27. @Test
  28. void instantiatesInjectorSourceByFullyQualifiedName() {
  29. Map<String, String> properties = new HashMap<>();
  30. properties.put(InjectorSourceFactory.GUICE_INJECTOR_SOURCE_KEY, CustomInjectorSource.class.getName());
  31. InjectorSourceFactory injectorSourceFactory = createInjectorSourceFactory(properties);
  32. assertThat(injectorSourceFactory.create(), is(instanceOf(CustomInjectorSource.class)));
  33. }
  34. @Test
  35. void failsToInstantiateNonExistantClass() {
  36. Map<String, String> properties = new HashMap<>();
  37. properties.put(InjectorSourceFactory.GUICE_INJECTOR_SOURCE_KEY, "some.bogus.Class");
  38. InjectorSourceFactory injectorSourceFactory = createInjectorSourceFactory(properties);
  39. Executable testMethod = injectorSourceFactory::create;
  40. InjectorSourceInstantiationFailed actualThrown = assertThrows(InjectorSourceInstantiationFailed.class,
  41. testMethod);
  42. assertAll(
  43. () -> assertThat("Unexpected exception message", actualThrown.getMessage(), is(equalTo(
  44. "Instantiation of 'some.bogus.Class' failed. Check the caused by exception and ensure yourInjectorSource implementation is accessible and has a public zero args constructor."))),
  45. () -> assertThat("Unexpected exception cause class", actualThrown.getCause(),
  46. isA(ClassNotFoundException.class)));
  47. }
  48. @Test
  49. void failsToInstantiateClassNotImplementingInjectorSource() {
  50. Map<String, String> properties = new HashMap<>();
  51. properties.put(InjectorSourceFactory.GUICE_INJECTOR_SOURCE_KEY, String.class.getName());
  52. InjectorSourceFactory injectorSourceFactory = createInjectorSourceFactory(properties);
  53. Executable testMethod = injectorSourceFactory::create;
  54. InjectorSourceInstantiationFailed actualThrown = assertThrows(InjectorSourceInstantiationFailed.class,
  55. testMethod);
  56. assertAll(
  57. () -> assertThat("Unexpected exception message", actualThrown.getMessage(), is(equalTo(
  58. "Instantiation of 'java.lang.String' failed. Check the caused by exception and ensure yourInjectorSource implementation is accessible and has a public zero args constructor."))),
  59. () -> assertThat("Unexpected exception cause class", actualThrown.getCause(),
  60. isA(ClassCastException.class)));
  61. }
  62. @Test
  63. void failsToInstantiateClassWithPrivateConstructor() {
  64. Map<String, String> properties = new HashMap<>();
  65. properties.put(InjectorSourceFactory.GUICE_INJECTOR_SOURCE_KEY, PrivateConstructor.class.getName());
  66. InjectorSourceFactory injectorSourceFactory = createInjectorSourceFactory(properties);
  67. Executable testMethod = injectorSourceFactory::create;
  68. InjectorSourceInstantiationFailed actualThrown = assertThrows(InjectorSourceInstantiationFailed.class,
  69. testMethod);
  70. assertAll(
  71. () -> assertThat("Unexpected exception message", actualThrown.getMessage(), is(equalTo(
  72. "Instantiation of 'io.cucumber.guice.InjectorSourceFactoryTest$PrivateConstructor' failed. Check the caused by exception and ensure yourInjectorSource implementation is accessible and has a public zero args constructor."))),
  73. () -> assertThat("Unexpected exception cause class", actualThrown.getCause(),
  74. isA(IllegalAccessException.class)));
  75. }
  76. @Test
  77. void failsToInstantiateClassWithNoDefaultConstructor() {
  78. Map<String, String> properties = new HashMap<>();
  79. properties.put(InjectorSourceFactory.GUICE_INJECTOR_SOURCE_KEY, NoDefaultConstructor.class.getName());
  80. InjectorSourceFactory injectorSourceFactory = createInjectorSourceFactory(properties);
  81. Executable testMethod = injectorSourceFactory::create;
  82. InjectorSourceInstantiationFailed actualThrown = assertThrows(InjectorSourceInstantiationFailed.class,
  83. testMethod);
  84. assertAll(
  85. () -> assertThat("Unexpected exception message", actualThrown.getMessage(), is(equalTo(
  86. "Instantiation of 'io.cucumber.guice.InjectorSourceFactoryTest$NoDefaultConstructor' failed. Check the caused by exception and ensure yourInjectorSource implementation is accessible and has a public zero args constructor."))),
  87. () -> assertThat("Unexpected exception cause class", actualThrown.getCause(),
  88. isA(InstantiationException.class)));
  89. }
  90. /**
  91. * <p>
  92. * Simulates enterprise applications which often use a hierarchy of
  93. * classloaders.
  94. * <p>
  95. * MyChildClassLoader is the only classloader with knowledge of
  96. * c.r.j.guice.impl.LivesInChildClassLoader
  97. * <p>
  98. * The bytecode of LivesInChildClassLoader is intentionally renamed to
  99. * 'LivesInChildClassLoader.class.bin.txt' to prevent this test's
  100. * ClassLoader from resolving it.
  101. * <p>
  102. * If InjectorSourceFactory calls Class#forName without an explicit
  103. * ClassLoader argument, which is the behavior of 1.2.4 and earlier,
  104. * Class#forName will default to the test's ClassLoader which has no
  105. * knowledge of class LivesInChildClassLoader and the test will fail.
  106. * <p>
  107. *
  108. * @see https://github.com/cucumber/cucumber-jvm/issues/1036
  109. */
  110. @Test
  111. void instantiateClassInChildClassLoader() {
  112. ClassLoader childClassLoader = new MyChildClassLoader(this.getClass().getClassLoader());
  113. Thread.currentThread().setContextClassLoader(childClassLoader);
  114. Map<String, String> properties = new HashMap<>();
  115. properties.put(InjectorSourceFactory.GUICE_INJECTOR_SOURCE_KEY,
  116. "io.cucumber.guice.impl.LivesInChildClassLoader");
  117. InjectorSourceFactory injectorSourceFactory = createInjectorSourceFactory(properties);
  118. assertThat(injectorSourceFactory.create(), is(instanceOf(InjectorSource.class)));
  119. }
  120. public static class CustomInjectorSource implements InjectorSource {
  121. @Override
  122. public Injector getInjector() {
  123. return null;
  124. }
  125. }
  126. public static class PrivateConstructor implements InjectorSource {
  127. private PrivateConstructor() {
  128. }
  129. @Override
  130. public Injector getInjector() {
  131. return null;
  132. }
  133. }
  134. public static class NoDefaultConstructor implements InjectorSource {
  135. private NoDefaultConstructor(String someParameter) {
  136. }
  137. @Override
  138. public Injector getInjector() {
  139. return null;
  140. }
  141. }
  142. private static class MyChildClassLoader extends ClassLoader {
  143. MyChildClassLoader(ClassLoader parent) {
  144. super(parent);
  145. }
  146. @Override
  147. protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
  148. if (name.equals("io.cucumber.guice.impl.LivesInChildClassLoader")) {
  149. String filename = getClass().getClassLoader()
  150. .getResource("io/cucumber/guice/impl/LivesInChildClassLoader.class.bin").getFile();
  151. File file = new File(filename);
  152. try {
  153. FileInputStream in = new FileInputStream(file);
  154. byte[] bytes = new byte[1024];
  155. ByteArrayOutputStream content = new ByteArrayOutputStream();
  156. while (true) {
  157. int iLen = in.read(bytes);
  158. content.write(bytes, 0, iLen);
  159. if (iLen < 1024) {
  160. break;
  161. }
  162. }
  163. byte[] bytecode = content.toByteArray();
  164. return defineClass(name, bytecode, 0, bytecode.length);
  165. } catch (Exception e) {
  166. throw new RuntimeException(e);
  167. }
  168. }
  169. return super.loadClass(name, resolve);
  170. }
  171. }
  172. }