1 /*
2  * Copyright (C) 2020 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.internal.codegen;
18 
19 import static com.google.testing.compile.CompilationSubject.assertThat;
20 import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE;
21 import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE;
22 import static dagger.internal.codegen.Compilers.compilerWithOptions;
23 import static dagger.internal.codegen.GeneratedLines.GENERATED_CODE_ANNOTATIONS;
24 
25 import com.google.common.collect.ImmutableCollection;
26 import com.google.testing.compile.Compilation;
27 import com.google.testing.compile.JavaFileObjects;
28 import javax.tools.JavaFileObject;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.junit.runners.Parameterized;
32 import org.junit.runners.Parameterized.Parameters;
33 
34 @RunWith(Parameterized.class)
35 public class AssistedFactoryTest {
36   @Parameters(name = "{0}")
parameters()37   public static ImmutableCollection<Object[]> parameters() {
38     return CompilerMode.TEST_PARAMETERS;
39   }
40 
41   private final CompilerMode compilerMode;
42 
AssistedFactoryTest(CompilerMode compilerMode)43   public AssistedFactoryTest(CompilerMode compilerMode) {
44     this.compilerMode = compilerMode;
45   }
46 
47   @Test
testAssistedFactory()48   public void testAssistedFactory() {
49     JavaFileObject foo =
50         JavaFileObjects.forSourceLines(
51             "test.Foo",
52             "package test;",
53             "",
54             "import dagger.assisted.Assisted;",
55             "import dagger.assisted.AssistedInject;",
56             "",
57             "class Foo {",
58             "  @AssistedInject",
59             "  Foo(@Assisted String str, Bar bar) {}",
60             "}");
61     JavaFileObject fooFactory =
62         JavaFileObjects.forSourceLines(
63             "test.FooFactory",
64             "package test;",
65             "",
66             "import dagger.assisted.AssistedFactory;",
67             "",
68             "@AssistedFactory",
69             "interface FooFactory {",
70             "  Foo create(String factoryStr);",
71             "}");
72     JavaFileObject bar =
73         JavaFileObjects.forSourceLines(
74             "test.Bar",
75             "package test;",
76             "",
77             "import javax.inject.Inject;",
78             "",
79             "class Bar {",
80             "  @Inject Bar() {}",
81             "}");
82     JavaFileObject component =
83         JavaFileObjects.forSourceLines(
84             "test.TestComponent",
85             "package test;",
86             "",
87             "import dagger.Component;",
88             "",
89             "@Component",
90             "interface TestComponent {",
91             "  FooFactory fooFactory();",
92             "}");
93     Compilation compilation =
94         compilerWithOptions(compilerMode.javacopts()).compile(foo, bar, fooFactory, component);
95     assertThat(compilation).succeeded();
96     JavaFileObject generatedComponent =
97         compilerMode
98             .javaFileBuilder("test.DaggerTestComponent")
99             .addLines("package test;", "", GENERATED_CODE_ANNOTATIONS)
100             .addLinesIn(
101                 FAST_INIT_MODE,
102                 "final class DaggerTestComponent implements TestComponent {",
103                 "",
104                 "  private Foo foo(String str) {",
105                 "    return new Foo(str, new Bar());",
106                 "  }",
107                 "",
108                 "  @Override",
109                 "  public FooFactory fooFactory() {",
110                 "    return new FooFactory() {",
111                 "      @Override",
112                 "      public Foo create(String str) {",
113                 "        return DaggerTestComponent.this.foo(str);",
114                 "      }",
115                 "    };",
116                 "  }",
117                 "}")
118             .addLinesIn(
119                 DEFAULT_MODE,
120                 "final class DaggerTestComponent implements TestComponent {",
121                 "",
122                 "  private Foo_Factory fooProvider;",
123                 "",
124                 "  private Provider<FooFactory> fooFactoryProvider;",
125                 "",
126                 "  @SuppressWarnings(\"unchecked\")",
127                 "  private void initialize() {",
128                 "    this.fooProvider = Foo_Factory.create(Bar_Factory.create());",
129                 "    this.fooFactoryProvider = FooFactory_Impl.create(fooProvider);",
130                 "  }",
131                 "",
132                 "  @Override",
133                 "  public FooFactory fooFactory() {",
134                 "    return fooFactoryProvider.get();",
135                 "  }",
136                 "}")
137             .build();
138     assertThat(compilation)
139         .generatedSourceFile("test.DaggerTestComponent")
140         .containsElementsIn(generatedComponent);
141   }
142 
143   @Test
testAssistedFactoryCycle()144   public void testAssistedFactoryCycle() {
145     JavaFileObject foo =
146         JavaFileObjects.forSourceLines(
147             "test.Foo",
148             "package test;",
149             "",
150             "import dagger.assisted.Assisted;",
151             "import dagger.assisted.AssistedInject;",
152             "",
153             "class Foo {",
154             "  @AssistedInject",
155             "  Foo(@Assisted String str, Bar bar) {}",
156             "}");
157     JavaFileObject fooFactory =
158         JavaFileObjects.forSourceLines(
159             "test.FooFactory",
160             "package test;",
161             "",
162             "import dagger.assisted.AssistedFactory;",
163             "",
164             "@AssistedFactory",
165             "interface FooFactory {",
166             "  Foo create(String factoryStr);",
167             "}");
168     JavaFileObject bar =
169         JavaFileObjects.forSourceLines(
170             "test.Bar",
171             "package test;",
172             "",
173             "import javax.inject.Inject;",
174             "",
175             "class Bar {",
176             "  @Inject Bar(FooFactory fooFactory) {}",
177             "}");
178     JavaFileObject component =
179         JavaFileObjects.forSourceLines(
180             "test.TestComponent",
181             "package test;",
182             "",
183             "import dagger.Component;",
184             "",
185             "@Component",
186             "interface TestComponent {",
187             "  FooFactory fooFactory();",
188             "}");
189     Compilation compilation =
190         compilerWithOptions(compilerMode.javacopts()).compile(foo, bar, fooFactory, component);
191     assertThat(compilation).succeeded();
192     JavaFileObject generatedComponent =
193         compilerMode
194             .javaFileBuilder("test.DaggerTestComponent")
195             .addLines("package test;", "", GENERATED_CODE_ANNOTATIONS)
196             .addLinesIn(
197                 FAST_INIT_MODE,
198                 "final class DaggerTestComponent implements TestComponent {",
199                 "",
200                 "  private Bar bar() {",
201                 "    return new Bar(fooFactory());",
202                 "  }",
203                 "",
204                 "  private Foo foo(String str) {",
205                 "    return new Foo(str, bar());",
206                 "  }",
207                 "",
208                 "  @Override",
209                 "  public FooFactory fooFactory() {",
210                 "    return new FooFactory() {",
211                 "      @Override",
212                 "      public Foo create(String str) {",
213                 "        return DaggerTestComponent.this.foo(str);",
214                 "      }",
215                 "    };",
216                 "  }",
217                 "}")
218             .addLinesIn(
219                 DEFAULT_MODE,
220                 "final class DaggerTestComponent implements TestComponent {",
221                 "",
222                 "  private Provider<FooFactory> fooFactoryProvider;",
223                 "",
224                 "  private Provider<Bar> barProvider;",
225                 "",
226                 "  private Foo_Factory fooProvider;",
227                 "",
228                 "  @SuppressWarnings(\"unchecked\")",
229                 "  private void initialize() {",
230                 "    this.fooFactoryProvider = new DelegateFactory<>();",
231                 "    this.barProvider = Bar_Factory.create(fooFactoryProvider);",
232                 "    this.fooProvider = Foo_Factory.create(barProvider);",
233                 "    DelegateFactory.setDelegate(",
234                 "        fooFactoryProvider, FooFactory_Impl.create(fooProvider));",
235                 "  }",
236                 "",
237                 "  @Override",
238                 "  public FooFactory fooFactory() {",
239                 "    return fooFactoryProvider.get();",
240                 "  }",
241                 "}")
242             .build();
243     assertThat(compilation)
244         .generatedSourceFile("test.DaggerTestComponent")
245         .containsElementsIn(generatedComponent);
246   }
247 }
248