@@ -2,10 +2,12 @@ package ftl.run.platform.android
22
33import com.linkedin.dex.parser.DecodedValue
44import com.linkedin.dex.parser.DexParser
5+ import com.linkedin.dex.parser.TestAnnotation
6+ import com.linkedin.dex.parser.TestMethod
57import com.linkedin.dex.parser.formatClassName
68import com.linkedin.dex.parser.getAnnotationsDirectory
79import com.linkedin.dex.parser.getClassAnnotationValues
8- import com.linkedin.dex.spec.AnnotationsDirectoryItem
10+ import com.linkedin.dex.spec.ClassDefItem
911import com.linkedin.dex.spec.DexFile
1012import ftl.args.AndroidArgs
1113import ftl.args.ArgsHelper
@@ -56,48 +58,37 @@ private fun InstrumentationTestContext.calculateShards(
5658
5759private fun InstrumentationTestContext.getFlankTestMethods (
5860 testFilter : TestFilter
59- ): List <FlankTestMethod > {
60- val parameterizedClasses = getParametrizedClasses()
61- return getNonParametrizedClassesTests(testFilter, parameterizedClasses) + parameterizedClasses.toFlankTestMethods()
62- }
61+ ): List <FlankTestMethod > =
62+ getParametrizedClasses().let { parameterizedClasses: List <String > ->
63+ DexParser .findTestMethods(test.local).asSequence()
64+ .distinct()
65+ .filter(testFilter.shouldRun)
66+ .filterNot(parameterizedClasses::belong)
67+ .map(TestMethod ::toFlankTestMethod).toList()
68+ .plus(parameterizedClasses.map(String ::toFlankTestMethod))
69+ }
6370
64- private fun InstrumentationTestContext.getParametrizedClasses () =
65- DexParser .readDexFiles(test.local)
66- .fold(mutableListOf<String >()) { parameterizedClasses, file ->
67- file.classDefs.forEach { classDef ->
68- val directory = file.getAnnotationsDirectory(classDef)
69- if (file.hasRunWithAnnotation(directory) && file.isAnnotationParameterIsParametrized(directory)) {
70- parameterizedClasses + = file.formatClassName(classDef).dropLast(1 )
71- }
72- }
73- parameterizedClasses
74- }
71+ private fun List<String>.belong (method : TestMethod ) = any { className -> method.testName.startsWith(className) }
7572
76- private fun DexFile.hasRunWithAnnotation (directory : AnnotationsDirectoryItem ? ) =
77- getClassAnnotationValues(directory).map { it.name }.any { it.toLowerCase().contains(" RunWith" .toLowerCase()) }
73+ private fun TestMethod.toFlankTestMethod () = FlankTestMethod (" class $testName " , ignored = annotations.any { it.name == " org.junit.Ignore" })
7874
79- private fun DexFile.isAnnotationParameterIsParametrized (directory : AnnotationsDirectoryItem ? ) =
80- getClassAnnotationValues(directory)
81- .flatMap { annotations -> annotations.values.values }
82- .filterIsInstance<DecodedValue .DecodedType >()
83- .map { it.value }
84- .any { it.toLowerCase().contains(" Parameterized" .toLowerCase()) }
75+ private fun String.toFlankTestMethod () = FlankTestMethod (" class $this " , ignored = false )
8576
86- private fun InstrumentationTestContext.getNonParametrizedClassesTests (
87- testFilter : TestFilter ,
88- parameterizedClasses : List <String >
89- ) = DexParser .findTestMethods(test.local).asSequence()
90- .distinct()
91- .filter(testFilter.shouldRun)
92- .filter { method -> parameterizedClasses.none { method.testName.contains(it) } }
93- .map { testMethod ->
94- FlankTestMethod (
95- testName = " class ${testMethod.testName} " ,
96- ignored = testMethod.annotations.any { it.name == " org.junit.Ignore" }
97- )
98- }.toList()
77+ private fun InstrumentationTestContext.getParametrizedClasses (): List <String > =
78+ DexParser .readDexFiles(test.local).fold(emptyList()) { accumulator, file: DexFile ->
79+ accumulator + file.classDefs
80+ .filter(file::isParametrizedClass)
81+ .map(file::formatClassName) // returns class name + '#'
82+ .map { it.dropLast(1 ) } // so drop '#'
83+ }
9984
100- private fun List<String>.toFlankTestMethods () = map { FlankTestMethod (" class $it " , false ) }
85+ private fun DexFile.isParametrizedClass (classDef : ClassDefItem ): Boolean =
86+ getClassAnnotationValues(getAnnotationsDirectory(classDef)).let { annotations: List <TestAnnotation > ->
87+ annotations.any { it.name.contains(" RunWith" , ignoreCase = true ) } && annotations
88+ .flatMap { it.values.values }
89+ .filterIsInstance<DecodedValue .DecodedType >()
90+ .any { it.value.contains(" Parameterized" , ignoreCase = true ) }
91+ }
10192
10293private fun List<AndroidTestContext>.dropEmptyInstrumentationTest (): List <AndroidTestContext > =
10394 filterIsInstance<InstrumentationTestContext >().filter { it.shards.isEmpty() }.let { withoutTests ->
0 commit comments