diff --git a/mendable-app/src/main/kotlin/com/jayasuryat/mendable/app/ProgressPrinter.kt b/mendable-app/src/main/kotlin/com/jayasuryat/mendable/app/ProgressPrinter.kt index c608adb..8c1bb63 100644 --- a/mendable-app/src/main/kotlin/com/jayasuryat/mendable/app/ProgressPrinter.kt +++ b/mendable-app/src/main/kotlin/com/jayasuryat/mendable/app/ProgressPrinter.kt @@ -78,7 +78,10 @@ internal class ProgressPrinter( files.forEachIndexed { index, file -> val modIndex = (index + 1).toString().padStart(padStart) val module = file.module - builder.append("$modIndex. :${module.name} (${module.buildVariant}) \n") + val variant = module.buildVariant + .takeIf { name -> name.isNullOrEmpty().not() } + ?.let { name -> "($name)" } ?: "" + builder.append("$modIndex. :${module.name} $variant\n") } return builder.toString() } diff --git a/mendable/src/main/java/com/jayasuryat/mendable/export/html/ModuleUtil.kt b/mendable/src/main/java/com/jayasuryat/mendable/export/html/ModuleUtil.kt index 9cdcf63..aabbe66 100644 --- a/mendable/src/main/java/com/jayasuryat/mendable/export/html/ModuleUtil.kt +++ b/mendable/src/main/java/com/jayasuryat/mendable/export/html/ModuleUtil.kt @@ -21,4 +21,9 @@ internal val Module.id: String get() = "${name}_$buildVariant" internal val Module.displayName: String - get() = "$name ($buildVariant)" + get() { + val variant = buildVariant + .takeIf { name -> name.isNullOrEmpty().not() } + ?.let { name -> "($name)" } ?: "" + return "$name $variant" + } diff --git a/mendable/src/main/java/com/jayasuryat/mendable/export/html/Overview.kt b/mendable/src/main/java/com/jayasuryat/mendable/export/html/Overview.kt index cfeda7e..2d51358 100644 --- a/mendable/src/main/java/com/jayasuryat/mendable/export/html/Overview.kt +++ b/mendable/src/main/java/com/jayasuryat/mendable/export/html/Overview.kt @@ -77,9 +77,11 @@ private fun BODY.ModuleOverviews( span("module-overview-title") { +":${module.module.name}\n" } br { - span("module-overview-details") { - setStyle(fontSize = "18px") - +"(${module.module.buildVariant})" + if (module.module.buildVariant.isNullOrEmpty().not()) { + span("module-overview-details") { + setStyle(fontSize = "18px") + +"(${module.module.buildVariant})" + } } } diff --git a/mendable/src/test/java/com/jayasuryat/mendable/MendableReportGeneratorTest.kt b/mendable/src/test/java/com/jayasuryat/mendable/MendableReportGeneratorTest.kt index d9e548b..0c53c69 100644 --- a/mendable/src/test/java/com/jayasuryat/mendable/MendableReportGeneratorTest.kt +++ b/mendable/src/test/java/com/jayasuryat/mendable/MendableReportGeneratorTest.kt @@ -21,6 +21,7 @@ import com.jayasuryat.mendable.MendableReportGeneratorRequest.ExportType import com.jayasuryat.mendable.MendableReportGeneratorRequest.IncludeModules import com.jayasuryat.mendable.metricsfile.Module import com.jayasuryat.mendable.model.ComposeCompilerMetricsExportModel +import io.kotest.assertions.throwables.shouldNotThrow import io.kotest.matchers.file.shouldBeAFile import io.kotest.matchers.file.shouldExist import io.kotest.matchers.ints.shouldBeGreaterThan @@ -324,4 +325,40 @@ internal class MendableReportGeneratorTest { outputModel.totalModulesReported shouldBe 1 outputModel.totalModulesFiltered shouldBe 1 } + + @Test + fun `should not throw exception for null build variant`() = runTest { + + val path = this::class.java.classLoader?.getResource("app_release-composables.txt")?.path + require(!path.isNullOrEmpty()) + + val resourceRoot = File(path).parent + + val request = MendableReportGeneratorRequest( + scanPaths = listOf(resourceRoot), + outputPath = temporaryFolder.root.path, + scanRecursively = false, + outputFileName = "report", + exportType = ExportType.HTML, + includeModules = IncludeModules.ALL, + moduleProducer = { + Module( + name = "resources", + buildVariant = null, + ) + }, + ) + + shouldNotThrow { + + var filesFound: Progress.MetricsFilesFound? = null + generator.generate(request = request) { progress -> + if (progress is Progress.MetricsFilesFound) filesFound = progress + } + + val metricsFiles = filesFound?.files + metricsFiles.shouldNotBeNull() + metricsFiles.size shouldBeGreaterThan 0 + } + } } diff --git a/metrics-file/src/main/java/com/jayasuryat/mendable/metricsfile/Module.kt b/metrics-file/src/main/java/com/jayasuryat/mendable/metricsfile/Module.kt index 35b3a32..20ed8cc 100644 --- a/metrics-file/src/main/java/com/jayasuryat/mendable/metricsfile/Module.kt +++ b/metrics-file/src/main/java/com/jayasuryat/mendable/metricsfile/Module.kt @@ -23,7 +23,7 @@ import dev.drewhamilton.poko.Poko @Poko public class Module( public val name: String, - public val buildVariant: String, + public val buildVariant: String?, ) { public companion object diff --git a/scanner/src/main/java/com/jayasuryat/mendable/scanner/ModuleFactory.kt b/scanner/src/main/java/com/jayasuryat/mendable/scanner/ModuleFactory.kt index 8838f6b..db88ae3 100644 --- a/scanner/src/main/java/com/jayasuryat/mendable/scanner/ModuleFactory.kt +++ b/scanner/src/main/java/com/jayasuryat/mendable/scanner/ModuleFactory.kt @@ -30,15 +30,24 @@ public fun interface ModuleFactory { } /** - * A default implementation of [ModuleFactory]. Parses [Module] using underscore and hyphens ('_' & '-') as delimiters. - * For example: For "app_qaRelease-composables.txt", a [Module] with "app" as [Module.name] and "qaRelease" as - * [Module.buildVariant] would be produced. + * Default implementation of [ModuleFactory]. * - * Note : While this implementation should work for most of the cases, this will not generate expected outputs for files - * whose original module's build variants' name have underscores in them. - * For example: "feature_a_build_variant-composables.txt"; here expectation is "feature_a" should be the [Module.name] - * and "build_variant" should be [Module.buildVariant]. But due to the nature of this implementation, "feature_a_build" - * and "variant" would be [Module.name] and [Module.buildVariant] respectively for this case. + * This implementation parses a [Module] from a file name using underscores ('_') and hyphens ('-') + * as delimiters. It assumes a convention where: + * - The file name is structured as "_-.". + * - The [Module.name] is derived from the part of the file name before the last underscore ('_'). + * - The [Module.buildVariant] is derived from the part of the file name between the last underscore + * ('_') and the last hyphen ('-'). Build variant is considered optional, if build variant is + * missing in the file name, the resulting [Module] will have [Module.buildVariant] as `null`. + * + * ### Example + * For a file named `app_qaRelease-composables.txt`: + * - [Module.name] would be `"app"` + * - [Module.buildVariant] would be `"qaRelease"` + * + * ### Limitations + * This implementation may produce unexpected results for file names where the build variant or the + * module name contains hyphens or underscores. */ public class DefaultModuleFactory : ModuleFactory { @@ -48,8 +57,18 @@ public class DefaultModuleFactory : ModuleFactory { val fileName = file.name val partialFileName = fileName.take(fileName.lastIndexOf('-')) val separatorIndex: Int = partialFileName.lastIndexOf('_') - val moduleName: String = partialFileName.take(separatorIndex) - val buildVariant: String = partialFileName.removePrefix(moduleName).drop(1) + + val hasBuildVariant = separatorIndex != -1 + val moduleName: String + val buildVariant: String? + if (hasBuildVariant) { + moduleName = partialFileName.take(separatorIndex) + buildVariant = partialFileName.removePrefix(moduleName).drop(1) + } else { + moduleName = partialFileName + buildVariant = null + } + return Module( name = moduleName, buildVariant = buildVariant, diff --git a/scanner/src/test/java/com/jayasuryat/mendable/scanner/DefaultModuleFactoryTest.kt b/scanner/src/test/java/com/jayasuryat/mendable/scanner/DefaultModuleFactoryTest.kt index 5da9d4c..9f0272d 100644 --- a/scanner/src/test/java/com/jayasuryat/mendable/scanner/DefaultModuleFactoryTest.kt +++ b/scanner/src/test/java/com/jayasuryat/mendable/scanner/DefaultModuleFactoryTest.kt @@ -119,4 +119,16 @@ internal class DefaultModuleFactoryTest { } } } + + @Test + fun `should parse correctly for file name without build variant`() { + + val file = File("resources-composables.txt") + val module: Module = factory.parseModule( + file = file, + ) + + module.name shouldBe "resources" + module.buildVariant shouldBe null + } }