1/*
2 * Copyright (C) 2014 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 */
16package dagger.internal.codegen;
17
18import com.google.testing.compile.JavaFileObjects;
19import javax.tools.JavaFileObject;
20import org.junit.Test;
21import org.junit.runner.RunWith;
22import org.junit.runners.JUnit4;
23
24import static com.google.common.truth.Truth.assertAbout;
25import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
26
27@RunWith(JUnit4.class)
28public class ProductionComponentProcessorTest {
29  @Test public void componentOnConcreteClass() {
30    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
31        "package test;",
32        "",
33        "import dagger.producers.ProductionComponent;",
34        "",
35        "@ProductionComponent",
36        "final class NotAComponent {}");
37    assertAbout(javaSource()).that(componentFile)
38        .processedWith(new ComponentProcessor())
39        .failsToCompile()
40        .withErrorContaining("interface");
41  }
42
43  @Test public void componentOnEnum() {
44    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
45        "package test;",
46        "",
47        "import dagger.producers.ProductionComponent;",
48        "",
49        "@ProductionComponent",
50        "enum NotAComponent {",
51        "  INSTANCE",
52        "}");
53    assertAbout(javaSource()).that(componentFile)
54        .processedWith(new ComponentProcessor())
55        .failsToCompile()
56        .withErrorContaining("interface");
57  }
58
59  @Test public void componentOnAnnotation() {
60    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
61        "package test;",
62        "",
63        "import dagger.producers.ProductionComponent;",
64        "",
65        "@ProductionComponent",
66        "@interface NotAComponent {}");
67    assertAbout(javaSource()).that(componentFile)
68        .processedWith(new ComponentProcessor())
69        .failsToCompile()
70        .withErrorContaining("interface");
71  }
72
73  @Test public void nonModuleModule() {
74    JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.NotAComponent",
75        "package test;",
76        "",
77        "import dagger.producers.ProductionComponent;",
78        "",
79        "@ProductionComponent(modules = Object.class)",
80        "interface NotAComponent {}");
81    assertAbout(javaSource()).that(componentFile)
82        .processedWith(new ComponentProcessor())
83        .failsToCompile()
84        .withErrorContaining("is not annotated with @Module or @ProducerModule");
85  }
86
87  @Test public void simpleComponent() {
88    JavaFileObject component = JavaFileObjects.forSourceLines("test.TestClass",
89        "package test;",
90        "",
91        "import com.google.common.util.concurrent.ListenableFuture;",
92        "import dagger.Module;",
93        "import dagger.Provides;",
94        "import dagger.producers.ProducerModule;",
95        "import dagger.producers.Produces;",
96        "import dagger.producers.ProductionComponent;",
97        "import javax.inject.Inject;",
98        "",
99        "final class TestClass {",
100        "  static final class C {",
101        "    @Inject C() {}",
102        "  }",
103        "",
104        "  interface A {}",
105        "  interface B {}",
106        "",
107        "  @Module",
108        "  static final class BModule {",
109        "    @Provides B b(C c) {",
110        "      return null;",
111        "    }",
112        "  }",
113        "",
114        "  @ProducerModule",
115        "  static final class AModule {",
116        "    @Produces ListenableFuture<A> a(B b) {",
117        "      return null;",
118        "    }",
119        "  }",
120        "",
121        "  @ProductionComponent(modules = {AModule.class, BModule.class})",
122        "  interface SimpleComponent {",
123        "    ListenableFuture<A> a();",
124        "  }",
125        "}");
126    JavaFileObject generatedComponent =
127        JavaFileObjects.forSourceLines(
128            "test.DaggerTestClass_SimpleComponent",
129            "package test;",
130            "",
131            "import com.google.common.util.concurrent.ListenableFuture;",
132            "import dagger.internal.InstanceFactory;",
133            "import dagger.internal.SetFactory;",
134            "import dagger.producers.Producer;",
135            "import dagger.producers.internal.Producers;",
136            "import dagger.producers.monitoring.ProductionComponentMonitor;",
137            "import dagger.producers.monitoring.ProductionComponentMonitor.Factory;",
138            "import java.util.Set;",
139            "import java.util.concurrent.Executor;",
140            "import javax.annotation.Generated;",
141            "import javax.inject.Provider;",
142            "import test.TestClass.A;",
143            "import test.TestClass.AModule;",
144            "import test.TestClass.B;",
145            "import test.TestClass.BModule;",
146            "import test.TestClass.SimpleComponent;",
147            "",
148            "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
149            "public final class DaggerTestClass_SimpleComponent implements SimpleComponent {",
150            "  private Provider<SimpleComponent> simpleComponentProvider;",
151            "  private Provider<Set<Factory>> setOfFactoryContribution1Provider;",
152            "  private Provider<Set<Factory>> setOfFactoryProvider;",
153            "  private Provider<ProductionComponentMonitor> monitorProvider;",
154            "  private Provider<B> bProvider;",
155            "  private Producer<A> aProducer;",
156            "",
157            "  private DaggerTestClass_SimpleComponent(Builder builder) {",
158            "    assert builder != null;",
159            "    initialize(builder);",
160            "  }",
161            "",
162            "  public static Builder builder() {",
163            "    return new Builder();",
164            "  }",
165            "",
166            "  @SuppressWarnings(\"unchecked\")",
167            "  private void initialize(final Builder builder) {",
168            "    this.simpleComponentProvider = InstanceFactory.<SimpleComponent>create(this);",
169            "    this.setOfFactoryContribution1Provider =",
170            "        TestClass$SimpleComponent_MonitoringModule_DefaultSetOfFactoriesFactory",
171            "            .create();",
172            "    this.setOfFactoryProvider = SetFactory.create(setOfFactoryContribution1Provider);",
173            "    this.monitorProvider =",
174            "        TestClass$SimpleComponent_MonitoringModule_MonitorFactory.create(",
175            "            builder.testClass$SimpleComponent_MonitoringModule,",
176            "            simpleComponentProvider,",
177            "            setOfFactoryProvider);",
178            "    this.bProvider = TestClass$BModule_BFactory.create(",
179            "        builder.bModule, TestClass$C_Factory.create());",
180            "    this.aProducer = new TestClass$AModule_AFactory(",
181            "        builder.aModule,",
182            "        builder.executor,",
183            "        monitorProvider,",
184            "        Producers.producerFromProvider(bProvider));",
185            "  }",
186            "",
187            "  @Override",
188            "  public ListenableFuture<A> a() {",
189            "    return aProducer.get();",
190            "  }",
191            "",
192            "  public static final class Builder {",
193            "    private TestClass$SimpleComponent_MonitoringModule",
194            "        testClass$SimpleComponent_MonitoringModule;",
195            "    private BModule bModule;",
196            "    private AModule aModule;",
197            "    private Executor executor;",
198            "",
199            "    private Builder() {",
200            "    }",
201            "",
202            "    public SimpleComponent build() {",
203            "      if (testClass$SimpleComponent_MonitoringModule == null) {",
204            "        this.testClass$SimpleComponent_MonitoringModule =",
205            "            new TestClass$SimpleComponent_MonitoringModule();",
206            "      }",
207            "      if (bModule == null) {",
208            "        this.bModule = new BModule();",
209            "      }",
210            "      if (aModule == null) {",
211            "        this.aModule = new AModule();",
212            "      }",
213            "      if (executor == null) {",
214            "        throw new IllegalStateException(Executor.class.getCanonicalName()",
215            "            + \" must be set\");",
216            "      }",
217            "      return new DaggerTestClass_SimpleComponent(this);",
218            "    }",
219            "",
220            "    public Builder aModule(AModule aModule) {",
221            "      if (aModule == null) {",
222            "        throw new NullPointerException();",
223            "      }",
224            "      this.aModule = aModule;",
225            "      return this;",
226            "    }",
227            "",
228            "    public Builder bModule(BModule bModule) {",
229            "      if (bModule == null) {",
230            "        throw new NullPointerException();",
231            "      }",
232            "      this.bModule = bModule;",
233            "      return this;",
234            "    }",
235            "",
236            "    public Builder testClass$SimpleComponent_MonitoringModule(",
237            "        TestClass$SimpleComponent_MonitoringModule",
238            "        testClass$SimpleComponent_MonitoringModule) {",
239            "      if (testClass$SimpleComponent_MonitoringModule == null) {",
240            "        throw new NullPointerException();",
241            "      }",
242            "      this.testClass$SimpleComponent_MonitoringModule =",
243            "          testClass$SimpleComponent_MonitoringModule;",
244            "      return this;",
245            "    }",
246            "",
247            "    public Builder executor(Executor executor) {",
248            "      if (executor == null) {",
249            "        throw new NullPointerException();",
250            "      }",
251            "      this.executor = executor;",
252            "      return this;",
253            "    }",
254            "  }",
255            "}");
256    assertAbout(javaSource()).that(component)
257        .processedWith(new ComponentProcessor())
258        .compilesWithoutError()
259        .and().generatesSources(generatedComponent);
260  }
261}
262