xref: /aosp_15_r20/external/dagger2/javatests/dagger/internal/codegen/DaggerModuleMethodSubject.java (revision f585d8a307d0621d6060bd7e80091fdcbf94fe27)
1*f585d8a3SJacky Wang /*
2*f585d8a3SJacky Wang  * Copyright (C) 2016 The Dagger Authors.
3*f585d8a3SJacky Wang  *
4*f585d8a3SJacky Wang  * Licensed under the Apache License, Version 2.0 (the "License");
5*f585d8a3SJacky Wang  * you may not use this file except in compliance with the License.
6*f585d8a3SJacky Wang  * You may obtain a copy of the License at
7*f585d8a3SJacky Wang  *
8*f585d8a3SJacky Wang  * http://www.apache.org/licenses/LICENSE-2.0
9*f585d8a3SJacky Wang  *
10*f585d8a3SJacky Wang  * Unless required by applicable law or agreed to in writing, software
11*f585d8a3SJacky Wang  * distributed under the License is distributed on an "AS IS" BASIS,
12*f585d8a3SJacky Wang  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*f585d8a3SJacky Wang  * See the License for the specific language governing permissions and
14*f585d8a3SJacky Wang  * limitations under the License.
15*f585d8a3SJacky Wang  */
16*f585d8a3SJacky Wang 
17*f585d8a3SJacky Wang package dagger.internal.codegen;
18*f585d8a3SJacky Wang 
19*f585d8a3SJacky Wang import static com.google.common.truth.Truth.assertAbout;
20*f585d8a3SJacky Wang 
21*f585d8a3SJacky Wang import androidx.room.compiler.processing.util.Source;
22*f585d8a3SJacky Wang import com.google.common.collect.ImmutableList;
23*f585d8a3SJacky Wang import com.google.common.truth.FailureMetadata;
24*f585d8a3SJacky Wang import com.google.common.truth.Subject;
25*f585d8a3SJacky Wang import com.google.common.truth.Truth;
26*f585d8a3SJacky Wang import dagger.Module;
27*f585d8a3SJacky Wang import dagger.producers.ProducerModule;
28*f585d8a3SJacky Wang import dagger.testing.compile.CompilerTests;
29*f585d8a3SJacky Wang import java.io.PrintWriter;
30*f585d8a3SJacky Wang import java.io.StringWriter;
31*f585d8a3SJacky Wang import java.util.Arrays;
32*f585d8a3SJacky Wang import java.util.List;
33*f585d8a3SJacky Wang 
34*f585d8a3SJacky Wang /** A {@link Truth} subject for testing Dagger module methods. */
35*f585d8a3SJacky Wang final class DaggerModuleMethodSubject extends Subject {
36*f585d8a3SJacky Wang 
37*f585d8a3SJacky Wang   /** A {@link Truth} subject factory for testing Dagger module methods. */
38*f585d8a3SJacky Wang   static final class Factory implements Subject.Factory<DaggerModuleMethodSubject, String> {
39*f585d8a3SJacky Wang 
40*f585d8a3SJacky Wang     /** Starts a clause testing a Dagger {@link Module @Module} method. */
assertThatModuleMethod(String method)41*f585d8a3SJacky Wang     static DaggerModuleMethodSubject assertThatModuleMethod(String method) {
42*f585d8a3SJacky Wang       return assertAbout(new Factory())
43*f585d8a3SJacky Wang           .that(method)
44*f585d8a3SJacky Wang           .withDeclaration("@Module abstract class %s { %s }");
45*f585d8a3SJacky Wang     }
46*f585d8a3SJacky Wang 
47*f585d8a3SJacky Wang     /** Starts a clause testing a Dagger {@link ProducerModule @ProducerModule} method. */
assertThatProductionModuleMethod(String method)48*f585d8a3SJacky Wang     static DaggerModuleMethodSubject assertThatProductionModuleMethod(String method) {
49*f585d8a3SJacky Wang       return assertAbout(new Factory())
50*f585d8a3SJacky Wang           .that(method)
51*f585d8a3SJacky Wang           .withDeclaration("@ProducerModule abstract class %s { %s }");
52*f585d8a3SJacky Wang     }
53*f585d8a3SJacky Wang 
54*f585d8a3SJacky Wang     /** Starts a clause testing a method in an unannotated class. */
assertThatMethodInUnannotatedClass(String method)55*f585d8a3SJacky Wang     static DaggerModuleMethodSubject assertThatMethodInUnannotatedClass(String method) {
56*f585d8a3SJacky Wang       return assertAbout(new Factory())
57*f585d8a3SJacky Wang           .that(method)
58*f585d8a3SJacky Wang           .withDeclaration("abstract class %s { %s }");
59*f585d8a3SJacky Wang     }
60*f585d8a3SJacky Wang 
Factory()61*f585d8a3SJacky Wang     private Factory() {}
62*f585d8a3SJacky Wang 
63*f585d8a3SJacky Wang     @Override
createSubject(FailureMetadata failureMetadata, String that)64*f585d8a3SJacky Wang     public DaggerModuleMethodSubject createSubject(FailureMetadata failureMetadata, String that) {
65*f585d8a3SJacky Wang       return new DaggerModuleMethodSubject(failureMetadata, that);
66*f585d8a3SJacky Wang     }
67*f585d8a3SJacky Wang   }
68*f585d8a3SJacky Wang 
69*f585d8a3SJacky Wang   private final String actual;
70*f585d8a3SJacky Wang   private final ImmutableList.Builder<String> imports =
71*f585d8a3SJacky Wang       new ImmutableList.Builder<String>()
72*f585d8a3SJacky Wang           .add(
73*f585d8a3SJacky Wang               // explicitly import Module so it's not ambiguous with java.lang.Module
74*f585d8a3SJacky Wang               "import dagger.Module;",
75*f585d8a3SJacky Wang               "import dagger.*;",
76*f585d8a3SJacky Wang               "import dagger.multibindings.*;",
77*f585d8a3SJacky Wang               "import dagger.producers.*;",
78*f585d8a3SJacky Wang               "import java.util.*;",
79*f585d8a3SJacky Wang               "import javax.inject.*;");
80*f585d8a3SJacky Wang   private String declaration;
81*f585d8a3SJacky Wang   private ImmutableList<Source> additionalSources = ImmutableList.of();
82*f585d8a3SJacky Wang 
DaggerModuleMethodSubject(FailureMetadata failureMetadata, String subject)83*f585d8a3SJacky Wang   private DaggerModuleMethodSubject(FailureMetadata failureMetadata, String subject) {
84*f585d8a3SJacky Wang     super(failureMetadata, subject);
85*f585d8a3SJacky Wang     this.actual = subject;
86*f585d8a3SJacky Wang   }
87*f585d8a3SJacky Wang 
88*f585d8a3SJacky Wang   /**
89*f585d8a3SJacky Wang    * Imports classes and interfaces. Note that all types in the following packages are already
90*f585d8a3SJacky Wang    * imported:<ul>
91*f585d8a3SJacky Wang    * <li>{@code dagger.*}
92*f585d8a3SJacky Wang    * <li>{@code dagger.multibindings.*}
93*f585d8a3SJacky Wang    * <li>(@code dagger.producers.*}
94*f585d8a3SJacky Wang    * <li>{@code java.util.*}
95*f585d8a3SJacky Wang    * <li>{@code javax.inject.*}
96*f585d8a3SJacky Wang    * </ul>
97*f585d8a3SJacky Wang    */
importing(Class<?>.... imports)98*f585d8a3SJacky Wang   DaggerModuleMethodSubject importing(Class<?>... imports) {
99*f585d8a3SJacky Wang     return importing(Arrays.asList(imports));
100*f585d8a3SJacky Wang   }
101*f585d8a3SJacky Wang 
102*f585d8a3SJacky Wang   /**
103*f585d8a3SJacky Wang    * Imports classes and interfaces. Note that all types in the following packages are already
104*f585d8a3SJacky Wang    * imported:<ul>
105*f585d8a3SJacky Wang    * <li>{@code dagger.*}
106*f585d8a3SJacky Wang    * <li>{@code dagger.multibindings.*}
107*f585d8a3SJacky Wang    * <li>(@code dagger.producers.*}
108*f585d8a3SJacky Wang    * <li>{@code java.util.*}
109*f585d8a3SJacky Wang    * <li>{@code javax.inject.*}
110*f585d8a3SJacky Wang    * </ul>
111*f585d8a3SJacky Wang    */
importing(List<? extends Class<?>> imports)112*f585d8a3SJacky Wang   DaggerModuleMethodSubject importing(List<? extends Class<?>> imports) {
113*f585d8a3SJacky Wang     imports.stream()
114*f585d8a3SJacky Wang         .map(clazz -> String.format("import %s;", clazz.getCanonicalName()))
115*f585d8a3SJacky Wang         .forEachOrdered(this.imports::add);
116*f585d8a3SJacky Wang     return this;
117*f585d8a3SJacky Wang   }
118*f585d8a3SJacky Wang 
119*f585d8a3SJacky Wang   /**
120*f585d8a3SJacky Wang    * Sets the declaration of the module. Must be a string with two {@code %s} parameters. The first
121*f585d8a3SJacky Wang    * will be replaced with the name of the type, and the second with the method declaration, which
122*f585d8a3SJacky Wang    * must be within paired braces.
123*f585d8a3SJacky Wang    */
withDeclaration(String declaration)124*f585d8a3SJacky Wang   DaggerModuleMethodSubject withDeclaration(String declaration) {
125*f585d8a3SJacky Wang     this.declaration = declaration;
126*f585d8a3SJacky Wang     return this;
127*f585d8a3SJacky Wang   }
128*f585d8a3SJacky Wang 
129*f585d8a3SJacky Wang   /** Additional source files that must be compiled with the module. */
withAdditionalSources(Source... sources)130*f585d8a3SJacky Wang   DaggerModuleMethodSubject withAdditionalSources(Source... sources) {
131*f585d8a3SJacky Wang     this.additionalSources = ImmutableList.copyOf(sources);
132*f585d8a3SJacky Wang     return this;
133*f585d8a3SJacky Wang   }
134*f585d8a3SJacky Wang 
135*f585d8a3SJacky Wang   /**
136*f585d8a3SJacky Wang    * Fails if compiling the module with the method doesn't report an error at the method
137*f585d8a3SJacky Wang    * declaration whose message contains {@code errorSubstring}.
138*f585d8a3SJacky Wang    */
hasError(String errorSubstring)139*f585d8a3SJacky Wang   void hasError(String errorSubstring) {
140*f585d8a3SJacky Wang     String source = moduleSource();
141*f585d8a3SJacky Wang     Source module = CompilerTests.javaSource("test.TestModule", source);
142*f585d8a3SJacky Wang     CompilerTests.daggerCompiler(
143*f585d8a3SJacky Wang             ImmutableList.<Source>builder().add(module).addAll(additionalSources).build())
144*f585d8a3SJacky Wang         .compile(
145*f585d8a3SJacky Wang             subject ->
146*f585d8a3SJacky Wang                 subject
147*f585d8a3SJacky Wang                     .hasErrorContaining(errorSubstring)
148*f585d8a3SJacky Wang                     .onSource(module)
149*f585d8a3SJacky Wang                     .onLine(methodLine(source)));
150*f585d8a3SJacky Wang   }
151*f585d8a3SJacky Wang 
methodLine(String source)152*f585d8a3SJacky Wang   private int methodLine(String source) {
153*f585d8a3SJacky Wang     String beforeMethod = source.substring(0, source.indexOf(actual));
154*f585d8a3SJacky Wang     int methodLine = 1;
155*f585d8a3SJacky Wang     for (int nextNewlineIndex = beforeMethod.indexOf('\n');
156*f585d8a3SJacky Wang         nextNewlineIndex >= 0;
157*f585d8a3SJacky Wang         nextNewlineIndex = beforeMethod.indexOf('\n', nextNewlineIndex + 1)) {
158*f585d8a3SJacky Wang       methodLine++;
159*f585d8a3SJacky Wang     }
160*f585d8a3SJacky Wang     return methodLine;
161*f585d8a3SJacky Wang   }
162*f585d8a3SJacky Wang 
moduleSource()163*f585d8a3SJacky Wang   private String moduleSource() {
164*f585d8a3SJacky Wang     StringWriter stringWriter = new StringWriter();
165*f585d8a3SJacky Wang     PrintWriter writer = new PrintWriter(stringWriter);
166*f585d8a3SJacky Wang     writer.println("package test;");
167*f585d8a3SJacky Wang     writer.println();
168*f585d8a3SJacky Wang     for (String importLine : imports.build()) {
169*f585d8a3SJacky Wang       writer.println(importLine);
170*f585d8a3SJacky Wang     }
171*f585d8a3SJacky Wang     writer.println();
172*f585d8a3SJacky Wang     writer.printf(declaration, "TestModule", "\n" + actual + "\n");
173*f585d8a3SJacky Wang     writer.println();
174*f585d8a3SJacky Wang     return stringWriter.toString();
175*f585d8a3SJacky Wang   }
176*f585d8a3SJacky Wang }
177