-
Notifications
You must be signed in to change notification settings - Fork 4.6k
/
DefaultJvmTestSuite.java
322 lines (274 loc) · 12.3 KB
/
DefaultJvmTestSuite.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/*
* Copyright 2021 the original author or 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 org.gradle.api.plugins.jvm.internal;
import com.google.common.base.Preconditions;
import org.gradle.api.Action;
import org.gradle.api.ExtensiblePolymorphicDomainObjectContainer;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.dsl.DependencyAdder;
import org.gradle.api.artifacts.dsl.DependencyFactory;
import org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyAdder;
import org.gradle.api.internal.tasks.AbstractTaskDependency;
import org.gradle.api.internal.tasks.TaskDependencyResolveContext;
import org.gradle.api.internal.tasks.testing.filter.DefaultTestFilter;
import org.gradle.api.internal.tasks.testing.junit.JUnitTestFramework;
import org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestFramework;
import org.gradle.api.internal.tasks.testing.testng.TestNGTestFramework;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JvmTestSuitePlugin;
import org.gradle.api.plugins.jvm.JvmComponentDependencies;
import org.gradle.api.plugins.jvm.JvmTestSuite;
import org.gradle.api.plugins.jvm.JvmTestSuiteTarget;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.SourceSetContainer;
import org.gradle.api.tasks.TaskDependency;
import javax.annotation.Nullable;
import javax.inject.Inject;
public abstract class DefaultJvmTestSuite implements JvmTestSuite {
public enum Frameworks {
JUNIT4("junit:junit", "4.13.2"),
JUNIT_JUPITER("org.junit.jupiter:junit-jupiter", "5.8.2"),
SPOCK("org.spockframework:spock-core", "2.1-groovy-3.0"),
KOTLIN_TEST("org.jetbrains.kotlin:kotlin-test-junit5", "1.7.10"),
TESTNG("org.testng:testng", "7.5"),
NONE(null, null);
@Nullable
private final String module;
@Nullable
private final String defaultVersion;
Frameworks(@Nullable String module, @Nullable String defaultVersion) {
Preconditions.checkArgument(module != null && defaultVersion != null || module == null && defaultVersion == null, "Either module and version must both be null, or neither be null.");
this.module = module;
this.defaultVersion = defaultVersion;
}
@Nullable
public String getDefaultVersion() {
return defaultVersion;
}
@Nullable
public String getDependency() {
return getDependency(getDefaultVersion());
}
@Nullable
public String getDependency(String version) {
if (null != module) {
return module + ":" + version;
} else {
return null;
}
}
}
private static class VersionedTestingFramework {
private final Frameworks type;
private final String version;
private VersionedTestingFramework(Frameworks type, String version) {
Preconditions.checkNotNull(version);
this.type = type;
this.version = version;
}
}
private final static VersionedTestingFramework NO_OPINION = new VersionedTestingFramework(Frameworks.NONE, "unset");
private final ExtensiblePolymorphicDomainObjectContainer<JvmTestSuiteTarget> targets;
private final SourceSet sourceSet;
private final String name;
private final JvmComponentDependencies dependencies;
private boolean attachedDependencies;
private final Action<Void> attachDependencyAction;
protected abstract Property<VersionedTestingFramework> getVersionedTestingFramework();
@Inject
public DefaultJvmTestSuite(String name, DependencyFactory dependencyFactory, ConfigurationContainer configurations, SourceSetContainer sourceSets) {
this.name = name;
this.sourceSet = sourceSets.create(getName());
Configuration compileOnly = configurations.getByName(sourceSet.getCompileOnlyConfigurationName());
Configuration implementation = configurations.getByName(sourceSet.getImplementationConfigurationName());
Configuration runtimeOnly = configurations.getByName(sourceSet.getRuntimeOnlyConfigurationName());
Configuration annotationProcessor = configurations.getByName(sourceSet.getAnnotationProcessorConfigurationName());
this.targets = getObjectFactory().polymorphicDomainObjectContainer(JvmTestSuiteTarget.class);
this.targets.registerBinding(JvmTestSuiteTarget.class, DefaultJvmTestSuiteTarget.class);
this.dependencies = getObjectFactory().newInstance(
DefaultJvmComponentDependencies.class,
getObjectFactory().newInstance(DefaultDependencyAdder.class, implementation),
getObjectFactory().newInstance(DefaultDependencyAdder.class, compileOnly),
getObjectFactory().newInstance(DefaultDependencyAdder.class, runtimeOnly),
getObjectFactory().newInstance(DefaultDependencyAdder.class, annotationProcessor)
);
this.attachedDependencies = false;
// This complexity is to keep the built-in test suite from automatically adding dependencies
// unless a user explicitly calls one of the useXXX methods
// Eventually, we should deprecate this behavior and provide a way for users to opt out
// We could then always add these dependencies.
this.attachDependencyAction = x -> attachDependenciesForTestFramework(dependencyFactory, dependencies.getImplementation());
if (!name.equals(JvmTestSuitePlugin.DEFAULT_TEST_SUITE_NAME)) {
useJUnitJupiter();
} else {
// for the built-in test suite, we don't express an opinion, so we will not add any dependencies
// if a user explicitly calls useJUnit or useJUnitJupiter, the built-in test suite will behave like a custom one
// and add dependencies automatically.
getVersionedTestingFramework().convention(NO_OPINION);
}
addDefaultTestTarget();
// The values here can now be considered finalized upon the user setting them (see the org.gradle.api.tasks.testing.Test#testFramework(Closure) method). So
// there is now no need to use a map to ensure a given test framework is only created once.
this.targets.withType(JvmTestSuiteTarget.class).configureEach(target -> {
target.getTestTask().configure(task -> {
task.getTestFrameworkProperty().convention(getVersionedTestingFramework().map(vtf -> {
switch(vtf.type) {
case NONE: // fall-through
case JUNIT4:
return new JUnitTestFramework(task, (DefaultTestFilter) task.getFilter());
case KOTLIN_TEST: // fall-through
case JUNIT_JUPITER: // fall-through
case SPOCK:
return new JUnitPlatformTestFramework((DefaultTestFilter) task.getFilter());
case TESTNG:
return new TestNGTestFramework(task, task.getClasspath(), (DefaultTestFilter) task.getFilter(), getObjectFactory());
default:
throw new IllegalStateException("do not know how to handle " + vtf);
}
}));
});
});
}
private void attachDependenciesForTestFramework(DependencyFactory dependencyFactory, DependencyAdder implementation) {
if (!attachedDependencies) {
implementation.add(getVersionedTestingFramework().map(framework -> {
switch (framework.type) {
case JUNIT4: // fall-through
case JUNIT_JUPITER: // fall-through
case SPOCK: // fall-through
case TESTNG: // fall-through
case KOTLIN_TEST:
return dependencyFactory.create(framework.type.getDependency(framework.version));
default:
throw new IllegalStateException("do not know how to handle " + framework);
}
}));
attachedDependencies = true;
}
}
@Override
public String getName() {
return name;
}
@Inject
public abstract ObjectFactory getObjectFactory();
@Inject
public abstract ProviderFactory getProviderFactory();
public SourceSet getSources() {
return sourceSet;
}
public void sources(Action<? super SourceSet> configuration) {
configuration.execute(getSources());
}
public ExtensiblePolymorphicDomainObjectContainer<JvmTestSuiteTarget> getTargets() {
return targets;
}
public void addDefaultTestTarget() {
final String target;
if (getName().equals(JvmTestSuitePlugin.DEFAULT_TEST_SUITE_NAME)) {
target = JavaPlugin.TEST_TASK_NAME;
} else {
target = getName(); // For now, we'll just name the test task for the single target for the suite with the suite name
}
targets.register(target);
}
@Override
public void useJUnit() {
useJUnit(Frameworks.JUNIT4.defaultVersion);
}
@Override
public void useJUnit(String version) {
useJUnit(getProviderFactory().provider(() -> version));
}
@Override
public void useJUnit(Provider<String> version) {
setFrameworkTo(Frameworks.JUNIT4, version);
}
@Override
public void useJUnitJupiter() {
useJUnitJupiter(Frameworks.JUNIT_JUPITER.defaultVersion);
}
@Override
public void useJUnitJupiter(String version) {
useJUnitJupiter(getProviderFactory().provider(() -> version));
}
@Override
public void useJUnitJupiter(Provider<String> version) {
setFrameworkTo(Frameworks.JUNIT_JUPITER, version);
}
@Override
public void useSpock() {
useSpock(Frameworks.SPOCK.defaultVersion);
}
@Override
public void useSpock(String version) {
useSpock(getProviderFactory().provider(() -> version));
}
@Override
public void useSpock(Provider<String> version) {
setFrameworkTo(Frameworks.SPOCK, version);
}
@Override
public void useKotlinTest() {
useKotlinTest(Frameworks.KOTLIN_TEST.defaultVersion);
}
@Override
public void useKotlinTest(String version) {
useKotlinTest(getProviderFactory().provider(() -> version));
}
@Override
public void useKotlinTest(Provider<String> version) {
setFrameworkTo(Frameworks.KOTLIN_TEST, version);
}
@Override
public void useTestNG() {
useTestNG(Frameworks.TESTNG.defaultVersion);
}
@Override
public void useTestNG(String version) {
useTestNG(getProviderFactory().provider(() -> version));
}
@Override
public void useTestNG(Provider<String> version) {
setFrameworkTo(Frameworks.TESTNG, version);
}
private void setFrameworkTo(Frameworks framework, Provider<String> versionProvider) {
getVersionedTestingFramework().set(versionProvider.map(v -> new VersionedTestingFramework(framework, v)));
attachDependencyAction.execute(null);
}
@Override
public JvmComponentDependencies getDependencies() {
return dependencies;
}
@Override
public void dependencies(Action<? super JvmComponentDependencies> action) {
action.execute(dependencies);
}
@Override
public TaskDependency getBuildDependencies() {
return new AbstractTaskDependency() {
@Override
public void visitDependencies(TaskDependencyResolveContext context) {
getTargets().forEach(context::add);
}
};
}
}