1 /*
2  * Copyright (C) 2015 The Dagger Authors.
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 dagger.functional.nullables;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static org.junit.Assert.fail;
21 
22 import javax.inject.Provider;
23 import org.junit.Test;
24 import org.junit.runner.RunWith;
25 import org.junit.runners.JUnit4;
26 
27 @RunWith(JUnit4.class)
28 public class NullabilityTest {
testNullability_provides()29   @Test public void testNullability_provides() {
30     NullModule module = new NullModule();
31     NullComponent component = DaggerNullComponent.builder().nullModule(module).build();
32 
33     // Can't construct NullFoo because it depends on Number, and Number was null.
34     try {
35       component.nullFoo();
36       fail();
37     } catch (NullPointerException npe) {
38       assertThat(npe)
39           .hasMessageThat()
40           .isEqualTo("Cannot return null from a non-@Nullable @Provides method");
41     }
42 
43     // set number to non-null so we can create
44     module.numberValue = 1;
45     NullFoo nullFoo = component.nullFoo();
46 
47     // Then set it back to null so we can test its providers.
48     module.numberValue = null;
49     validate(true, nullFoo.string, nullFoo.stringProvider, nullFoo.numberProvider);
50     validate(true, nullFoo.methodInjectedString, nullFoo.methodInjectedStringProvider,
51         nullFoo.methodInjectedNumberProvider);
52     validate(true, nullFoo.fieldInjectedString, nullFoo.fieldInjectedStringProvider,
53         nullFoo.fieldInjectedNumberProvider);
54   }
55 
testNullability_reusuable()56   @Test public void testNullability_reusuable() {
57     NullModule module = new NullModule();
58     NullComponent component = DaggerNullComponent.builder().nullModule(module).build();
59 
60     // Test that the @Nullable @Reusuable binding is cached properly even when the value is null.
61     assertThat(module.integerCallCount).isEqualTo(0);
62     assertThat(component.integer()).isNull();
63     assertThat(module.integerCallCount).isEqualTo(1);
64     assertThat(component.integer()).isNull();
65     assertThat(module.integerCallCount).isEqualTo(1);
66   }
67 
testNullability_components()68   @Test public void testNullability_components() {
69     NullComponent nullComponent = new NullComponent() {
70       @Override public Provider<String> stringProvider() {
71         return new Provider<String>() {
72           @Override public String get() {
73             return null;
74           }
75         };
76       }
77 
78       @Override public String string() {
79         return null;
80       }
81 
82       @Override public Provider<Number> numberProvider() {
83         return new Provider<Number>() {
84           @Override public Number get() {
85             return null;
86           }
87         };
88       }
89 
90       @Override public Number number() {
91         return null;
92       }
93 
94       @Override public NullFoo nullFoo() {
95         return null;
96       }
97 
98       @Override public Integer integer() {
99         return null;
100       }
101     };
102     NullComponentWithDependency component =
103         DaggerNullComponentWithDependency.builder().nullComponent(nullComponent).build();
104     validate(false, component.string(), component.stringProvider(), component.numberProvider());
105 
106     // Also validate that the component's number() method fails
107     try {
108       component.number();
109       fail();
110     } catch (NullPointerException npe) {
111       assertThat(npe)
112           .hasMessageThat()
113           .isEqualTo("Cannot return null from a non-@Nullable component method");
114     }
115   }
116 
validate(boolean fromProvides, String string, Provider<String> stringProvider, Provider<Number> numberProvider)117   private void validate(boolean fromProvides,
118       String string,
119       Provider<String> stringProvider,
120       Provider<Number> numberProvider) {
121     assertThat(string).isNull();
122     assertThat(numberProvider).isNotNull();
123     try {
124       numberProvider.get();
125       fail();
126     } catch (NullPointerException npe) {
127       assertThat(npe)
128           .hasMessageThat()
129           .isEqualTo(
130               "Cannot return null from a non-@Nullable "
131                   + (fromProvides ? "@Provides" : "component")
132                   + " method");
133     }
134     assertThat(stringProvider.get()).isNull();
135   }
136 }
137