| /* |
| * Copyright (C) 2016 The Dagger Authors. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package dagger.internal.codegen; |
| |
| import static com.google.common.truth.Truth.assertAbout; |
| |
| import androidx.room.compiler.processing.util.Source; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.truth.FailureMetadata; |
| import com.google.common.truth.Subject; |
| import com.google.common.truth.Truth; |
| import dagger.Module; |
| import dagger.producers.ProducerModule; |
| import dagger.testing.compile.CompilerTests; |
| import java.io.PrintWriter; |
| import java.io.StringWriter; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| /** A {@link Truth} subject for testing Dagger module methods. */ |
| final class DaggerModuleMethodSubject extends Subject { |
| |
| /** A {@link Truth} subject factory for testing Dagger module methods. */ |
| static final class Factory implements Subject.Factory<DaggerModuleMethodSubject, String> { |
| |
| /** Starts a clause testing a Dagger {@link Module @Module} method. */ |
| static DaggerModuleMethodSubject assertThatModuleMethod(String method) { |
| return assertAbout(new Factory()) |
| .that(method) |
| .withDeclaration("@Module abstract class %s { %s }"); |
| } |
| |
| /** Starts a clause testing a Dagger {@link ProducerModule @ProducerModule} method. */ |
| static DaggerModuleMethodSubject assertThatProductionModuleMethod(String method) { |
| return assertAbout(new Factory()) |
| .that(method) |
| .withDeclaration("@ProducerModule abstract class %s { %s }"); |
| } |
| |
| /** Starts a clause testing a method in an unannotated class. */ |
| static DaggerModuleMethodSubject assertThatMethodInUnannotatedClass(String method) { |
| return assertAbout(new Factory()) |
| .that(method) |
| .withDeclaration("abstract class %s { %s }"); |
| } |
| |
| private Factory() {} |
| |
| @Override |
| public DaggerModuleMethodSubject createSubject(FailureMetadata failureMetadata, String that) { |
| return new DaggerModuleMethodSubject(failureMetadata, that); |
| } |
| } |
| |
| private final String actual; |
| private final ImmutableList.Builder<String> imports = |
| new ImmutableList.Builder<String>() |
| .add( |
| // explicitly import Module so it's not ambiguous with java.lang.Module |
| "import dagger.Module;", |
| "import dagger.*;", |
| "import dagger.multibindings.*;", |
| "import dagger.producers.*;", |
| "import java.util.*;", |
| "import javax.inject.*;"); |
| private String declaration; |
| private ImmutableList<Source> additionalSources = ImmutableList.of(); |
| |
| private DaggerModuleMethodSubject(FailureMetadata failureMetadata, String subject) { |
| super(failureMetadata, subject); |
| this.actual = subject; |
| } |
| |
| /** |
| * Imports classes and interfaces. Note that all types in the following packages are already |
| * imported:<ul> |
| * <li>{@code dagger.*} |
| * <li>{@code dagger.multibindings.*} |
| * <li>(@code dagger.producers.*} |
| * <li>{@code java.util.*} |
| * <li>{@code javax.inject.*} |
| * </ul> |
| */ |
| DaggerModuleMethodSubject importing(Class<?>... imports) { |
| return importing(Arrays.asList(imports)); |
| } |
| |
| /** |
| * Imports classes and interfaces. Note that all types in the following packages are already |
| * imported:<ul> |
| * <li>{@code dagger.*} |
| * <li>{@code dagger.multibindings.*} |
| * <li>(@code dagger.producers.*} |
| * <li>{@code java.util.*} |
| * <li>{@code javax.inject.*} |
| * </ul> |
| */ |
| DaggerModuleMethodSubject importing(List<? extends Class<?>> imports) { |
| imports.stream() |
| .map(clazz -> String.format("import %s;", clazz.getCanonicalName())) |
| .forEachOrdered(this.imports::add); |
| return this; |
| } |
| |
| /** |
| * Sets the declaration of the module. Must be a string with two {@code %s} parameters. The first |
| * will be replaced with the name of the type, and the second with the method declaration, which |
| * must be within paired braces. |
| */ |
| DaggerModuleMethodSubject withDeclaration(String declaration) { |
| this.declaration = declaration; |
| return this; |
| } |
| |
| /** Additional source files that must be compiled with the module. */ |
| DaggerModuleMethodSubject withAdditionalSources(Source... sources) { |
| this.additionalSources = ImmutableList.copyOf(sources); |
| return this; |
| } |
| |
| /** |
| * Fails if compiling the module with the method doesn't report an error at the method |
| * declaration whose message contains {@code errorSubstring}. |
| */ |
| void hasError(String errorSubstring) { |
| String source = moduleSource(); |
| Source module = CompilerTests.javaSource("test.TestModule", source); |
| CompilerTests.daggerCompiler( |
| ImmutableList.<Source>builder().add(module).addAll(additionalSources).build()) |
| .compile( |
| subject -> |
| subject |
| .hasErrorContaining(errorSubstring) |
| .onSource(module) |
| .onLine(methodLine(source))); |
| } |
| |
| private int methodLine(String source) { |
| String beforeMethod = source.substring(0, source.indexOf(actual)); |
| int methodLine = 1; |
| for (int nextNewlineIndex = beforeMethod.indexOf('\n'); |
| nextNewlineIndex >= 0; |
| nextNewlineIndex = beforeMethod.indexOf('\n', nextNewlineIndex + 1)) { |
| methodLine++; |
| } |
| return methodLine; |
| } |
| |
| private String moduleSource() { |
| StringWriter stringWriter = new StringWriter(); |
| PrintWriter writer = new PrintWriter(stringWriter); |
| writer.println("package test;"); |
| writer.println(); |
| for (String importLine : imports.build()) { |
| writer.println(importLine); |
| } |
| writer.println(); |
| writer.printf(declaration, "TestModule", "\n" + actual + "\n"); |
| writer.println(); |
| return stringWriter.toString(); |
| } |
| } |