Skip to content

Commit

Permalink
Add repro test for #3136.
Browse files Browse the repository at this point in the history
This CL adds some infrastructure to run multi-module Gradle build tests to javatests/artifacts/dagger, and creates a repro test for issue #3136.

RELNOTES=N/A
PiperOrigin-RevId: 418853078
  • Loading branch information
bcorso authored and Dagger Team committed Dec 29, 2021
1 parent 8ff7d6b commit f37b9a1
Show file tree
Hide file tree
Showing 4 changed files with 309 additions and 0 deletions.
31 changes: 31 additions & 0 deletions javatests/artifacts/dagger/build-tests/build.gradle
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2021 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.
*/

plugins {
id 'java'
id 'application'
}

// Set the versions in a system property so that tests can access it.
test {
systemProperty 'dagger_version', "$dagger_version"
}

dependencies {
testImplementation "com.google.truth:truth:$truth_version"
testImplementation "junit:junit:$junit_version"
testImplementation gradleTestKit()
}
@@ -0,0 +1,81 @@
/*
* Copyright (C) 2021 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 buildtests;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

/** Used to create files for a Gradle module in a particular directory. */
public final class GradleModule {
public static GradleModule create(File moduleDir) {
return new GradleModule(moduleDir);
}

public static GradleModule create(File projectDir, String moduleName) {
return new GradleModule(new File(projectDir, moduleName));
}

private final File moduleDir;
private final File moduleSrcDir;

private GradleModule(File moduleDir) {
this.moduleDir = moduleDir;
this.moduleSrcDir = new File(moduleDir, "src/main/java/");
}

public GradleModule addBuildFile(String... content) throws IOException {
writeFile(createFile(moduleDir, "build.gradle"), content);
return this;
}

public GradleModule addSettingsFile(String... content) throws IOException {
writeFile(createFile(moduleDir, "settings.gradle"), content);
return this;
}

public GradleModule addFile(String fileName, String... content) throws IOException {
writeFile(createFile(moduleDir, fileName), content);
return this;
}

public GradleModule addSrcFile(String fileName, String... content) throws IOException {
writeFile(createFile(moduleSrcDir, fileName), content);
return this;
}

private static File createFile(File dir, String fileName) {
File file = new File(dir, fileName);
file.getParentFile().mkdirs();
return file;
}

private static void writeFile(File destination, String... content) throws IOException {
BufferedWriter output = null;
try {
output = new BufferedWriter(new FileWriter(destination));
for (String line : content) {
output.write(line + "\n");
}
} finally {
if (output != null) {
output.close();
}
}
}
}
@@ -0,0 +1,196 @@
/*
* Copyright (C) 2021 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 buildtests;

import static com.google.common.truth.Truth.assertThat;
import static org.gradle.testkit.runner.TaskOutcome.SUCCESS;

import java.io.File;
import java.io.IOException;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

// This is a regression test for https://github.com/google/dagger/issues/3136
@RunWith(JUnit4.class)
public class TransitiveScopeTest {
@Rule public TemporaryFolder folder = new TemporaryFolder();

@Test
public void testTransitiveScope_WithImplementation() throws IOException {
BuildResult result = setupBuildWith("implementation");

// TODO(bcorso): This is a repro of https://github.com/google/dagger/issues/3136.
// Once the issue is fixed, this test case should fail to build.
assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
assertThat(result.getOutput()).contains("@Inject library1.Foo(): UNSCOPED");
}

@Test
public void testTransitiveScope_WithApi() throws IOException {
BuildResult result = setupBuildWith("api");
assertThat(result.task(":app:assemble").getOutcome()).isEqualTo(SUCCESS);
assertThat(result.getOutput()).contains("@Inject library1.Foo(): SCOPED");
}

private BuildResult setupBuildWith(String dependencyType) throws IOException {
File projectDir = folder.getRoot();
GradleModule.create(projectDir)
.addSettingsFile(
"include 'app'",
"include 'library1'",
"include 'library2'",
"include 'spi-plugin'")
.addBuildFile(
"buildscript {",
" ext {",
String.format("dagger_version = \"%s\"", System.getProperty("dagger_version")),
" }",
"}",
"",
"allprojects {",
" repositories {",
" jcenter()",
" mavenCentral()",
" mavenLocal()",
" }",
"}");

GradleModule.create(projectDir, "app")
.addBuildFile(
"plugins {",
" id 'java'",
" id 'application'",
"}",
"dependencies {",
" implementation project(':library1')",
" annotationProcessor project(':spi-plugin')",
" implementation \"com.google.dagger:dagger:$dagger_version\"",
" annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
"}")
.addSrcFile(
"MyComponent.java",
"package app;",
"",
"import dagger.Component;",
"import library1.MySubcomponent;",
"",
"@Component",
"public interface MyComponent {",
" MySubcomponent subcomponent();",
"}");

GradleModule.create(projectDir, "library1")
.addBuildFile(
"plugins {",
" id 'java'",
" id 'java-library'",
"}",
"dependencies {",
dependencyType + " project(':library2')",
" implementation \"com.google.dagger:dagger:$dagger_version\"",
" annotationProcessor \"com.google.dagger:dagger-compiler:$dagger_version\"",
"}")
.addSrcFile(
"Foo.java",
"package library1;",
"",
"import javax.inject.Inject;",
"import library2.MyScope;",
"",
"@MyScope",
"public class Foo {",
" @Inject Foo() {}",
"}")
// Note: In order to repro the issue we place MyScope on a subcomponent so that it can be a
// transitive dependency of the component. If MyScope was placed on directly on the
// component, it would need to be a direct dependency of the component.
.addSrcFile(
"MySubcomponent.java",
"package library1;",
"",
"import dagger.Subcomponent;",
"import library2.MyScope;",
"",
"@MyScope",
"@Subcomponent",
"public interface MySubcomponent {",
" Foo foo();",
"}");

GradleModule.create(projectDir, "library2")
.addBuildFile(
"plugins {",
" id 'java'",
" id 'java-library'",
"}",
"dependencies {",
" implementation 'javax.inject:javax.inject:1'",
"}")
.addSrcFile(
"MyScope.java",
"package library2;",
"",
"import javax.inject.Scope;",
"",
"@Scope",
"public @interface MyScope {}");

// This plugin is used to print output about bindings that we can assert on in tests.
GradleModule.create(projectDir, "spi-plugin")
.addBuildFile(
"plugins {",
" id 'java'",
"}",
"dependencies {",
" implementation \"com.google.dagger:dagger-spi:$dagger_version\"",
" implementation 'com.google.auto.service:auto-service-annotations:1.0.1'",
" annotationProcessor 'com.google.auto.service:auto-service:1.0.1'",
"}")
.addSrcFile(
"TestBindingGraphPlugin.java",
"package spiplugin;",
"",
"import com.google.auto.service.AutoService;",
"import dagger.model.BindingGraph;",
"import dagger.spi.BindingGraphPlugin;",
"import dagger.spi.DiagnosticReporter;",
"",
"@AutoService(BindingGraphPlugin.class)",
"public class TestBindingGraphPlugin implements BindingGraphPlugin {",
" @Override",
" public void visitGraph(BindingGraph bindingGraph, DiagnosticReporter"
+ " diagnosticReporter) {",
" bindingGraph.bindings().stream()",
" .filter(binding -> binding.scope().isPresent())",
" .forEach(binding -> System.out.println(binding + \": SCOPED\"));",
" bindingGraph.bindings().stream()",
" .filter(binding -> !binding.scope().isPresent())",
" .forEach(binding -> System.out.println(binding + \": UNSCOPED\"));",
" }",
"}");

return GradleRunner.create()
.withArguments("--stacktrace", "build")
.withProjectDir(projectDir)
.build();
}
}
1 change: 1 addition & 0 deletions javatests/artifacts/dagger/settings.gradle
@@ -1,4 +1,5 @@
rootProject.name = 'Dagger Apps'
include ':build-tests'
include ':java-app'
include ':kotlin-app'
include ':kotlin-app:kotlin-library'

0 comments on commit f37b9a1

Please sign in to comment.