1 /*
2  * Copyright (C) 2010 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject;
18 
19 import com.google.inject.internal.Messages;
20 import com.google.inject.name.Named;
21 import com.google.inject.name.Names;
22 import java.io.IOException;
23 import junit.framework.TestCase;
24 
25 /**
26  * Tests that ProvisionExceptions are readable and clearly indicate to the user what went wrong with
27  * their code.
28  *
29  * @author sameb@google.com (Sam Berlin)
30  */
31 public class ProvisionExceptionsTest extends TestCase {
32 
testConstructorRuntimeException()33   public void testConstructorRuntimeException() {
34     Injector injector =
35         Guice.createInjector(
36             new AbstractModule() {
37               @Override
38               protected void configure() {
39                 bindConstant().annotatedWith(Names.named("runtime")).to(true);
40                 bind(Exploder.class).to(Explosion.class);
41                 bind(Tracer.class).to(TracerImpl.class);
42               }
43             });
44     try {
45       injector.getInstance(Tracer.class);
46       fail();
47     } catch (ProvisionException pe) {
48       // Make sure our initial error message gives the user exception.
49       Asserts.assertContains(
50           pe.getMessage(),
51           "1) Error injecting constructor",
52           "java.lang.IllegalStateException: boom!");
53       assertEquals(1, pe.getErrorMessages().size());
54       assertEquals(IllegalStateException.class, pe.getCause().getClass());
55       assertEquals(
56           IllegalStateException.class, Messages.getOnlyCause(pe.getErrorMessages()).getClass());
57     }
58   }
59 
testConstructorCheckedException()60   public void testConstructorCheckedException() {
61     Injector injector =
62         Guice.createInjector(
63             new AbstractModule() {
64               @Override
65               protected void configure() {
66                 bindConstant().annotatedWith(Names.named("runtime")).to(false);
67                 bind(Exploder.class).to(Explosion.class);
68                 bind(Tracer.class).to(TracerImpl.class);
69               }
70             });
71     try {
72       injector.getInstance(Tracer.class);
73       fail();
74     } catch (ProvisionException pe) {
75       // Make sure our initial error message gives the user exception.
76       Asserts.assertContains(
77           pe.getMessage(), "1) Error injecting constructor", "java.io.IOException: boom!");
78       assertEquals(1, pe.getErrorMessages().size());
79       assertEquals(IOException.class, pe.getCause().getClass());
80       assertEquals(IOException.class, Messages.getOnlyCause(pe.getErrorMessages()).getClass());
81     }
82   }
83 
testCustomProvidersRuntimeException()84   public void testCustomProvidersRuntimeException() {
85     Injector injector =
86         Guice.createInjector(
87             new AbstractModule() {
88               @Override
89               protected void configure() {
90                 bind(Exploder.class)
91                     .toProvider(
92                         new Provider<Exploder>() {
93                           @Override
94                           public Exploder get() {
95                             return Explosion.createRuntime();
96                           }
97                         });
98                 bind(Tracer.class).to(TracerImpl.class);
99               }
100             });
101     try {
102       injector.getInstance(Tracer.class);
103       fail();
104     } catch (ProvisionException pe) {
105       // Make sure our initial error message gives the user exception.
106       Asserts.assertContains(
107           pe.getMessage(), "1) Error in custom provider", "java.lang.IllegalStateException: boom!");
108       assertEquals(1, pe.getErrorMessages().size());
109       assertEquals(IllegalStateException.class, pe.getCause().getClass());
110       assertEquals(
111           IllegalStateException.class, Messages.getOnlyCause(pe.getErrorMessages()).getClass());
112     }
113   }
114 
testProviderMethodRuntimeException()115   public void testProviderMethodRuntimeException() {
116     Injector injector =
117         Guice.createInjector(
118             new AbstractModule() {
119               @Override
120               protected void configure() {
121                 bind(Tracer.class).to(TracerImpl.class);
122               }
123 
124               @Provides
125               Exploder exploder() {
126                 return Explosion.createRuntime();
127               }
128             });
129     try {
130       injector.getInstance(Tracer.class);
131       fail();
132     } catch (ProvisionException pe) {
133       // Make sure our initial error message gives the user exception.
134       Asserts.assertContains(
135           pe.getMessage(), "1) Error in custom provider", "java.lang.IllegalStateException: boom!");
136       assertEquals(1, pe.getErrorMessages().size());
137       assertEquals(IllegalStateException.class, pe.getCause().getClass());
138       assertEquals(
139           IllegalStateException.class, Messages.getOnlyCause(pe.getErrorMessages()).getClass());
140     }
141   }
142 
testProviderMethodCheckedException()143   public void testProviderMethodCheckedException() {
144     Injector injector =
145         Guice.createInjector(
146             new AbstractModule() {
147               @Override
148               protected void configure() {
149                 bind(Tracer.class).to(TracerImpl.class);
150               }
151 
152               @Provides
153               Exploder exploder() throws IOException {
154                 return Explosion.createChecked();
155               }
156             });
157     try {
158       injector.getInstance(Tracer.class);
159       fail();
160     } catch (ProvisionException pe) {
161       pe.printStackTrace();
162       // Make sure our initial error message gives the user exception.
163       Asserts.assertContains(
164           pe.getMessage(), "1) Error in custom provider", "java.io.IOException: boom!");
165       assertEquals(1, pe.getErrorMessages().size());
166       assertEquals(IOException.class, pe.getCause().getClass());
167       assertEquals(IOException.class, Messages.getOnlyCause(pe.getErrorMessages()).getClass());
168     }
169   }
170 
171   private static interface Exploder {}
172 
173   public static class Explosion implements Exploder {
174     @Inject
Explosion(@amed"runtime") boolean runtime)175     public Explosion(@Named("runtime") boolean runtime) throws IOException {
176       if (runtime) {
177         throw new IllegalStateException("boom!");
178       } else {
179         throw new IOException("boom!");
180       }
181     }
182 
createRuntime()183     public static Explosion createRuntime() {
184       try {
185         return new Explosion(true);
186       } catch (IOException iox) {
187         throw new RuntimeException();
188       }
189     }
190 
createChecked()191     public static Explosion createChecked() throws IOException {
192       return new Explosion(false);
193     }
194   }
195 
196   private static interface Tracer {}
197 
198   private static class TracerImpl implements Tracer {
199     @Inject
TracerImpl(Exploder explosion)200     TracerImpl(Exploder explosion) {}
201   }
202 }
203