Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android test variant support #194

Merged
merged 3 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,8 @@ public static List<GradleSourceSet> getBuildVariantsAsGradleSourceSets(Project p
try {
Set<Object> variants = (Set<Object>) invokeMethod(androidExtension, methodName);
for (Object variant : variants) {
GradleSourceSet sourceSet = convertVariantToGradleSourceSet(project, variant);
GradleSourceSet sourceSet =
convertVariantToGradleSourceSet(project, variant, sourceSets, false);
if (sourceSet == null) {
continue;
}
Expand All @@ -116,9 +117,15 @@ public static List<GradleSourceSet> getBuildVariantsAsGradleSourceSets(Project p
*
* @param project Gradle project to populate GradleSourceSet properties
* @param variant Android Build Variant object to populate GradleSourceSet properties
* @param sourceSets List of source sets to which test variants will be added
* @param isUnitTest Indicates if the given variant is a unit test variant
*/
@SuppressWarnings("unchecked")
private static GradleSourceSet convertVariantToGradleSourceSet(Project project, Object variant) {
private static GradleSourceSet convertVariantToGradleSourceSet(
jdneo marked this conversation as resolved.
Show resolved Hide resolved
Project project,
Object variant,
List<GradleSourceSet> sourceSets,
boolean isUnitTest
) {

try {

Expand Down Expand Up @@ -156,8 +163,57 @@ private static GradleSourceSet convertVariantToGradleSourceSet(Project project,
gradleSourceSet.setDisplayName(displayName);

// module dependencies
Set<GradleModuleDependency> moduleDependencies =
AndroidDependencyCollector.getModuleDependencies(project, variant);
addModuleDependencies(gradleSourceSet, project, variant);

// source and resource
addSourceAndResources(gradleSourceSet, variant, isUnitTest);

// resource outputs
addResourceOutputs(gradleSourceSet, variant, isUnitTest);

List<String> compilerArgs = new ArrayList<>();

// generated sources and source outputs
addGeneratedSourceAndSourceOutputs(gradleSourceSet, variant, compilerArgs);

// classpath
addClasspath(gradleSourceSet, variant);

// Archive output dirs (not relevant in case of android build variants)
gradleSourceSet.setArchiveOutputFiles(new HashMap<>());

// has tests
addTests(gradleSourceSet, project, variant, sourceSets);

// extensions
addExtensions(gradleSourceSet, compilerArgs);

return gradleSourceSet;

} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
return null;
}

}

/**
* Add module dependencies to the given GradleSourceSet.
*
* @param gradleSourceSet Instance of DefaultGradleSourceSet
* @param project Instance of Project
* @param variant Instance of Build Variant
*/
@SuppressWarnings("unchecked")
private static void addModuleDependencies(
DefaultGradleSourceSet gradleSourceSet,
Project project,
Object variant
) {

Set<GradleModuleDependency> moduleDependencies =
AndroidDependencyCollector.getModuleDependencies(project, variant);

try {
// add Android SDK
Object androidComponents = getAndroidComponentExtension(project);
if (androidComponents != null) {
Expand All @@ -178,7 +234,7 @@ private static GradleSourceSet convertVariantToGradleSourceSet(Project project,
}
}
// add R.jar file
String taskName = "process" + capitalize(variantName) + "Resources";
String taskName = "process" + capitalize(gradleSourceSet.getSourceSetName()) + "Resources";
Task processResourcesTask = project.getTasks().findByName(taskName);
if (processResourcesTask != null) {
Object output = invokeMethod(processResourcesTask, "getRClassOutputJar");
Expand All @@ -188,53 +244,116 @@ private static GradleSourceSet convertVariantToGradleSourceSet(Project project,
moduleDependencies.add(mockModuleDependency(jarFile.toURI()));
}
}
gradleSourceSet.setModuleDependencies(moduleDependencies);
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
// do nothing
}

// source and resource
gradleSourceSet.setModuleDependencies(moduleDependencies);

}

/**
* Add source and resource directories to the given GradleSourceSet.
*
* @param gradleSourceSet Instance of DefaultGradleSourceSet
* @param variant Instance of Build Variant
* @param isUnitTest Indicates if the given variant is a unit test variant
*/
@SuppressWarnings("unchecked")
private static void addSourceAndResources(
DefaultGradleSourceSet gradleSourceSet,
Object variant,
boolean isUnitTest
) {

Set<File> sourceDirs = new HashSet<>();
Set<File> resourceDirs = new HashSet<>();

try {
Object sourceSets = getProperty(variant, "sourceSets");
Set<File> sourceDirs = new HashSet<>();
Set<File> resourceDirs = new HashSet<>();
if (sourceSets instanceof Iterable) {
for (Object sourceSet : (Iterable<?>) sourceSets) {
Set<File> javaDirectories =
(Set<File>) getProperty(sourceSet, "javaDirectories");
Set<File> resDirectories =
(Set<File>) getProperty(sourceSet, "resDirectories");
Set<File> resourceDirectories =
(Set<File>) getProperty(sourceSet, "resourcesDirectories");
sourceDirs.addAll(javaDirectories);
resourceDirs.addAll(resDirectories);
resourceDirs.addAll(resourceDirectories);
if (!isUnitTest) {
resourceDirs.addAll((Set<File>) getProperty(sourceSet, "resDirectories"));
}
resourceDirs.addAll((Set<File>) getProperty(sourceSet, "resourcesDirectories"));
}
}
gradleSourceSet.setSourceDirs(sourceDirs);
gradleSourceSet.setResourceDirs(resourceDirs);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
// do nothing
}

// resource outputs
Set<File> resourceOutputs = new HashSet<>();
gradleSourceSet.setSourceDirs(sourceDirs);
gradleSourceSet.setResourceDirs(resourceDirs);

}

/**
* Add resource output directories to the given GradleSourceSet.
*
* @param gradleSourceSet Instance of DefaultGradleSourceSet
* @param variant Instance of Build Variant
* @param isUnitTest Indicates if the given variant is a unit test variant
*/
@SuppressWarnings("unchecked")
private static void addResourceOutputs(
DefaultGradleSourceSet gradleSourceSet,
Object variant,
boolean isUnitTest
) {

Set<File> resourceOutputs = new HashSet<>();

try {
Provider<Task> resourceProvider =
(Provider<Task>) getProperty(variant, "processJavaResourcesProvider");
if (resourceProvider != null) {
Task resTask = resourceProvider.get();
File outputDir = (File) invokeMethod(resTask, "getDestinationDir");
resourceOutputs.add(outputDir);
}
Provider<Task> resProvider =
(Provider<Task>) getProperty(variant, "mergeResourcesProvider");
if (resProvider != null) {
Task resTask = resProvider.get();
Object outputDir = invokeMethod(resTask, "getOutputDir");
File output = ((Provider<File>) invokeMethod(outputDir, "getAsFile")).get();
resourceOutputs.add(output);

if (!isUnitTest) {
Provider<Task> resProvider =
(Provider<Task>) getProperty(variant, "mergeResourcesProvider");
if (resProvider != null) {
Task resTask = resProvider.get();
Object outputDir = invokeMethod(resTask, "getOutputDir");
File output = ((Provider<File>) invokeMethod(outputDir, "getAsFile")).get();
resourceOutputs.add(output);
}
}
gradleSourceSet.setResourceOutputDirs(resourceOutputs);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
// do nothing
}

// generated sources and source outputs
Set<File> generatedSources = new HashSet<>();
Set<File> sourceOutputs = new HashSet<>();
gradleSourceSet.setResourceOutputDirs(resourceOutputs);

}

/**
* Add source output and generated source output directories to the given GradleSourceSet.
*
* @param gradleSourceSet Instance of DefaultGradleSourceSet
* @param variant Instance of Build Variant
* @param compilerArgs List to be populated from the java compiler arguments.
*/
@SuppressWarnings("unchecked")
private static void addGeneratedSourceAndSourceOutputs(
DefaultGradleSourceSet gradleSourceSet,
Object variant,
List<String> compilerArgs
) {

Set<File> generatedSources = new HashSet<>();
Set<File> sourceOutputs = new HashSet<>();

try {
Provider<Task> javaCompileProvider =
(Provider<Task>) getProperty(variant, "javaCompileProvider");
List<String> compilerArgs = new ArrayList<>();
if (javaCompileProvider != null) {
Task javaCompileTask = javaCompileProvider.get();

Expand All @@ -248,7 +367,7 @@ private static GradleSourceSet convertVariantToGradleSourceSet(Project project,

// generated = compile source - source
for (File compileSource : compileSources) {
boolean inSourceDir = sourceDirs.stream()
boolean inSourceDir = gradleSourceSet.getSourceDirs().stream()
.anyMatch(dir -> compileSource.getAbsolutePath().startsWith(dir.getAbsolutePath()));
if (inSourceDir) {
continue;
Expand All @@ -261,43 +380,99 @@ private static GradleSourceSet convertVariantToGradleSourceSet(Project project,
generatedSources.add(compileSource);
}
}
gradleSourceSet.setGeneratedSourceDirs(generatedSources);
gradleSourceSet.setSourceOutputDirs(sourceOutputs);
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
// do nothing
}

// classpath
gradleSourceSet.setGeneratedSourceDirs(generatedSources);
gradleSourceSet.setSourceOutputDirs(sourceOutputs);

}

/**
* Add classpath files to the given GradleSourceSet.
*
* @param gradleSourceSet Instance of DefaultGradleSourceSet
* @param variant Instance of Build Variant
*/
@SuppressWarnings("unchecked")
private static void addClasspath(DefaultGradleSourceSet gradleSourceSet, Object variant) {

Set<File> classpathFiles = new HashSet<>();

try {
Object compileConfig = invokeMethod(variant, "getCompileConfiguration");
Set<File> classpathFiles = (Set<File>) invokeMethod(compileConfig, "getFiles");
gradleSourceSet.setCompileClasspath(new LinkedList<>(classpathFiles));
classpathFiles.addAll((Set<File>) invokeMethod(compileConfig, "getFiles"));
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
// do nothing
}

// Archive output dirs (not relevant in case of android build variants)
gradleSourceSet.setArchiveOutputFiles(new HashMap<>());
gradleSourceSet.setCompileClasspath(new LinkedList<>(classpathFiles));

// has tests
}

/**
* Add classpath files to the given GradleSourceSet.
*
* @param gradleSourceSet Instance of DefaultGradleSourceSet
* @param project Instance of Project
* @param variant Instance of Build Variant
* @param sourceSets List of source sets to which test variants will be added
*/
private static void addTests(
DefaultGradleSourceSet gradleSourceSet,
Project project,
Object variant,
List<GradleSourceSet> sourceSets
) {
try {
Object unitTestVariant = invokeMethod(variant, "getUnitTestVariant");
Object testVariant = invokeMethod(variant, "getTestVariant");
gradleSourceSet.setHasTests(unitTestVariant != null || testVariant != null);

// extensions
Map<String, LanguageExtension> extensions = new HashMap<>();
boolean isJavaSupported = Arrays.stream(SourceSetUtils.getSupportedLanguages())
.anyMatch(l -> Objects.equals(l, SupportedLanguages.JAVA.getBspName()));
if (isJavaSupported) {
DefaultJavaExtension extension = new DefaultJavaExtension();

extension.setCompilerArgs(compilerArgs);
extension.setSourceCompatibility(getSourceCompatibility(compilerArgs));
extension.setTargetCompatibility(getTargetCompatibility(compilerArgs));

extensions.put(SupportedLanguages.JAVA.getBspName(), extension);
if (unitTestVariant != null) {
GradleSourceSet unitTestSourceSet =
convertVariantToGradleSourceSet(project, unitTestVariant, sourceSets, true);
if (unitTestSourceSet != null) {
sourceSets.add(unitTestSourceSet);
}
}
gradleSourceSet.setExtensions(extensions);

return gradleSourceSet;

if (testVariant != null) {
GradleSourceSet androidTestSourceSet =
convertVariantToGradleSourceSet(project, testVariant, sourceSets, false);
if (androidTestSourceSet != null) {
sourceSets.add(androidTestSourceSet);
}
}
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
return null;
// do nothing
}
}

/**
* Add language extension to the given GradleSourceSet.
*
* @param gradleSourceSet Instance of DefaultGradleSourceSet
* @param compilerArgs List of compiler arguments needed to build the language extension.
*/
private static void addExtensions(
DefaultGradleSourceSet gradleSourceSet,
List<String> compilerArgs
) {
Map<String, LanguageExtension> extensions = new HashMap<>();
boolean isJavaSupported = Arrays.stream(SourceSetUtils.getSupportedLanguages())
.anyMatch(l -> Objects.equals(l, SupportedLanguages.JAVA.getBspName()));
if (isJavaSupported) {
DefaultJavaExtension extension = new DefaultJavaExtension();

extension.setCompilerArgs(compilerArgs);
extension.setSourceCompatibility(getSourceCompatibility(compilerArgs));
extension.setTargetCompatibility(getTargetCompatibility(compilerArgs));

extensions.put(SupportedLanguages.JAVA.getBspName(), extension);
}
gradleSourceSet.setExtensions(extensions);
}

/**
Expand Down Expand Up @@ -426,6 +601,7 @@ private static Object invokeMethod(Object object, String methodName)
}

// region TODO: Duplicate code from JavaLanguageModelBuilder

/**
* Get the compilation arguments of the build variant.
*/
Expand Down
Loading