From 991d54b685d931065cef40dac6d3241bcf61f0f6 Mon Sep 17 00:00:00 2001 From: Pascal Knecht Date: Sat, 7 Sep 2024 18:02:09 +0200 Subject: [PATCH] Improve transitive dependency resolution for modules --- README.md | 44 +-- app/src/main/kotlin/ch/addere/dga/app/App.kt | 8 +- .../dga/app/domain/service/FilterService.kt | 73 ++-- .../app/infrastructure/factory/CoreModule.kt | 11 + .../app/infrastructure/factory/DgaModule.kt | 8 +- ...e.dga.kotlin-common-conventions.gradle.kts | 7 + .../service/DependencySearchService.kt | 24 ++ .../service/DependencySearchServiceImpl.kt | 70 ++++ .../dga/core/domain/DependencyRepository.kt | 14 + ...ository.kt => DependencyRepositoryImpl.kt} | 16 +- .../domain/model/graph/ModuleDependencyDag.kt | 28 +- .../service/ConfigurationServiceImpl.kt | 1 + .../service/DependencyRelationService.kt | 76 ----- .../service/DependencyRelationServiceImpl.kt | 124 ------- .../domain/service/DependencyServiceImpl.kt | 3 +- .../DependencySearchServiceImplTest.kt | 106 ++++++ .../model/graph/ModuleDependencyDagTest.kt | 4 +- .../DependencyRelationServiceImplTest.kt | 312 ------------------ ...est.kt => DependencyRepositoryImplTest.kt} | 10 +- .../core/service/DependencyServiceImplTest.kt | 6 +- .../domain/service/ModelImporterService.kt | 23 +- 21 files changed, 356 insertions(+), 612 deletions(-) create mode 100644 app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/CoreModule.kt create mode 100644 core/src/main/kotlin/ch/addere/dga/core/application/service/DependencySearchService.kt create mode 100644 core/src/main/kotlin/ch/addere/dga/core/application/service/DependencySearchServiceImpl.kt create mode 100644 core/src/main/kotlin/ch/addere/dga/core/domain/DependencyRepository.kt rename core/src/main/kotlin/ch/addere/dga/core/domain/{service/DependencyRepository.kt => DependencyRepositoryImpl.kt} (54%) delete mode 100644 core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRelationService.kt delete mode 100644 core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRelationServiceImpl.kt create mode 100644 core/src/test/kotlin/ch/addere/dga/core/application/service/DependencySearchServiceImplTest.kt delete mode 100644 core/src/test/kotlin/ch/addere/dga/core/service/DependencyRelationServiceImplTest.kt rename core/src/test/kotlin/ch/addere/dga/core/service/{DependencyRepositoryTest.kt => DependencyRepositoryImplTest.kt} (86%) diff --git a/README.md b/README.md index 1ca6738..e83e965 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Filter Options: -o= Module names in origin. Specify multiple comma-separated module names. -d= Module names in destination. Specify multiple comma-separated module names. -c= Configurations used in dependencies. Specify multiple comma-separated configuration names. - --transitive Also include transitive modules. + -t, --transitive If set, also include transitive module dependencies. This applies only if a module filter is active. Display Options: @@ -59,7 +59,8 @@ Display Options: --modules Shows all modules of the project applying to the specified filters. --configurations Displays all configurations applying to the specified filters and sorted by frequency of occurrence. - --chart-mermaid Generate the Mermaid graph chart source for the dependencies fulfilling the filter criteria. + --mermaid-graph Generate the Mermaid graph chart source for the dependencies fulfilling the filter criteria. + --chart-mermaid Generate the Mermaid graph chart source for the dependencies fulfilling the filter criteria. (deprecated) Options: -h, --help Show this message and exit @@ -87,15 +88,14 @@ cd dependency-graph-analyser/ 4. Publish the Gradle tooling API plugin and its data model to Maven local (available in the directory `~/.m2/repository/ch/addere/dga/`) -Get an overview of this project by running `dga .``: +Get an overview of this project by running `dga .`: ``` ./app/build/install/dga/bin/dga . Analyse project "dependency-graph-analyser" 5 modules - 5 dependencies (1 unique configurations) - + 5 dependency configurations (1 unique dependency configurations) ``` ### Create a Mermaid Chart @@ -103,43 +103,45 @@ Analyse project "dependency-graph-analyser" Use `dga . --chart-mermaid` to generate a Mermaid chart of this project: ``` -./app/build/install/dga/bin/dga . --chart-mermaid +./app/build/install/dga/bin/dga . --mermaid-graph Analyse project "dependency-graph-analyser" - 6 modules - 6 dependencies (2 unique configurations) + 5 modules + 5 dependency configurations (1 unique dependency configurations) graph TD - vd2a57d(app) -->|api| ved7802(exporter) - vd2a57d(app) -->|api| v1bc49d(importer) + vd2a57d(app) -->|implementation| va74ad8(core) + vd2a57d(app) -->|implementation| v1bc49d(importer) v80f88a(dependency-plugin) -->|implementation| v8ebf3d(dependency-model) - ved7802(exporter) -->|api| vf8b0b9(graph) - v1bc49d(importer) -->|api| v8ebf3d(dependency-model) - v1bc49d(importer) -->|api| vf8b0b9(graph) + v1bc49d(importer) -->|implementation| va74ad8(core) + v1bc49d(importer) -->|implementation| v8ebf3d(dependency-model) ``` #### Filter Modules -Use `dga . -o app,exporter --chart-mermaid` to generate a Mermaid chart of this project only -containing the modules `app` and `exporter` in the origin: +Use `dga . -o app --mermaid-graph` to generate a Mermaid graph chart of this project only +containing the dependencies originating from the module `app`: ``` -./app/build/install/dga/bin/dga . -o app,exporter --chart-mermaid +./app/build/install/dga/bin/dga . -o app --mermaid-graph Analyse project "dependency-graph-analyser" 5 modules - 5 dependencies (1 unique configurations) + 5 dependency configurations (1 unique dependency configurations) + +Applying filter on data results in: + 3 modules + 2 dependency configurations (1 unique dependency configurations) graph TD vd2a57d(app) -->|implementation| va74ad8(core) vd2a57d(app) -->|implementation| v1bc49d(importer) - v80f88a(dependency-plugin) -->|implementation| v8ebf3d(dependency-model) - v1bc49d(importer) -->|implementation| va74ad8(core) - v1bc49d(importer) -->|implementation| v8ebf3d(dependency-model) - + ``` +- Use `--transitive` to also include transitive dependencies. + ## How DGA works See [HowItWorks.md](HOWITWORKS.md) diff --git a/app/src/main/kotlin/ch/addere/dga/app/App.kt b/app/src/main/kotlin/ch/addere/dga/app/App.kt index 294c72b..a91a847 100644 --- a/app/src/main/kotlin/ch/addere/dga/app/App.kt +++ b/app/src/main/kotlin/ch/addere/dga/app/App.kt @@ -4,6 +4,7 @@ import ch.addere.dga.app.configuration.OutputOptions import ch.addere.dga.app.domain.model.CommandConfig import ch.addere.dga.app.domain.model.FilterConfig import ch.addere.dga.app.domain.service.DependencyCommandHandler +import ch.addere.dga.app.infrastructure.factory.coreModule import ch.addere.dga.app.infrastructure.factory.dgaModule import ch.addere.dga.app.infrastructure.factory.importerModule import ch.addere.dga.app.infrastructure.factory.userInputModule @@ -70,7 +71,7 @@ private class Dga : CliktCommand(help = "Analyse the module dependency graph of optionsFilter.originModules, optionsFilter.destinationModules, optionsFilter.configurations, - optionsFilter.transitiveModules + optionsFilter.includeTransitiveModules ) val argument = CommandConfig(::echo, gradleProject, filterConfig, outputOption) val command: DependencyCommandHandler = get { parametersOf(argument) } @@ -109,9 +110,9 @@ private class OptionsFilter : OptionGroup( .convert("configuration,...") { Configuration(it) }.split(",").default(emptyList()) .help("Configurations used in dependencies. Specify multiple comma-separated configuration names.") - val transitiveModules: Boolean by option("--transitive") + val includeTransitiveModules: Boolean by option("-t", "--transitive") .flag() - .help("Also include transitive modules.") + .help("If set, also include transitive module dependencies. This applies only if a module filter is active.") } fun main(args: Array) { @@ -121,6 +122,7 @@ fun main(args: Array) { modules(userInputModule) modules(dgaModule) modules(importerModule) + modules(coreModule) } dga.parse(args) diff --git a/app/src/main/kotlin/ch/addere/dga/app/domain/service/FilterService.kt b/app/src/main/kotlin/ch/addere/dga/app/domain/service/FilterService.kt index 9bde2d8..a0da35d 100644 --- a/app/src/main/kotlin/ch/addere/dga/app/domain/service/FilterService.kt +++ b/app/src/main/kotlin/ch/addere/dga/app/domain/service/FilterService.kt @@ -1,11 +1,12 @@ package ch.addere.dga.app.domain.service import ch.addere.dga.app.domain.model.FilterConfig +import ch.addere.dga.core.application.service.DependencySearchService +import ch.addere.dga.core.domain.model.Configuration import ch.addere.dga.core.domain.model.Dependency import ch.addere.dga.core.domain.model.FilteredConfiguration import ch.addere.dga.core.domain.model.FilteredModules import ch.addere.dga.core.domain.service.ConfigurationService -import ch.addere.dga.core.domain.service.DependencyRelationService import ch.addere.dga.core.domain.service.DependencyService import ch.addere.dga.core.domain.service.ModuleService @@ -13,10 +14,9 @@ class FilterService( private val dependencyService: DependencyService, private val moduleService: ModuleService, private val configurationService: ConfigurationService, - private val dependencyRelationService: DependencyRelationService, + private val dependencySearchService: DependencySearchService, ) { - fun allDependencies(): Set { return dependencyService.filteredDependencies( FilteredModules(false, emptyList()), @@ -26,41 +26,58 @@ class FilterService( ) } - fun filter(filterConfig: FilterConfig): Set { - val inputModules = filterConfig.modules - val inputOrigin = filterConfig.originModules - val inputDestination = filterConfig.destinationModules - val inputConfigurations = filterConfig.configurations + val requestedModules = filterConfig.modules + val requestedOriginModules = filterConfig.originModules + val requestedDestinationModules = filterConfig.destinationModules + val requestedConfigurations = filterConfig.configurations - val filteredModules = inputModules.flatMap(moduleService::resolvePartialModuleName).toList() - val filteredOrigin = inputOrigin.flatMap(moduleService::resolvePartialModuleName).toList() - val filteredDestination = - inputDestination.flatMap(moduleService::resolvePartialModuleName).toList() - val filteredConfigurations = - inputConfigurations.flatMap(configurationService::resolvePartialConfigurationName) + val requestedCanonicalModules = + requestedModules.flatMap(moduleService::resolvePartialModuleName).toList() + val requestedCanonicalOriginModules = + requestedOriginModules.flatMap(moduleService::resolvePartialModuleName).toList() + val requestedCanonicalDestinationModules = + requestedDestinationModules.flatMap(moduleService::resolvePartialModuleName).toList() + val requestedCanonicalConfigurations: List = + requestedConfigurations.flatMap(configurationService::resolvePartialConfigurationName) .toList() var filteredDependencies: Set = dependencyService.filteredDependencies( - FilteredModules(inputModules.isNotEmpty(), filteredModules), - FilteredModules(inputOrigin.isNotEmpty(), filteredOrigin), - FilteredModules(inputDestination.isNotEmpty(), filteredDestination), - FilteredConfiguration(inputConfigurations.isNotEmpty(), filteredConfigurations) + FilteredModules(requestedModules.isNotEmpty(), requestedCanonicalModules), + FilteredModules( + requestedOriginModules.isNotEmpty(), + requestedCanonicalOriginModules + ), + FilteredModules( + requestedDestinationModules.isNotEmpty(), + requestedCanonicalDestinationModules + ), + FilteredConfiguration( + requestedConfigurations.isNotEmpty(), + requestedCanonicalConfigurations + ) ) if (filterConfig.includeTransitiveDependencies) { - val configurationSet = filteredDependencies.map { it.configuration }.toSet() - filteredDependencies = filteredDependencies.flatMap { dependency -> - dependencyRelationService.allDependenciesOf( - dependency.origin, - configurationSet - ) union - dependencyRelationService.allDependenciesOf( - dependency.destination, - configurationSet - ) +// val transitiveDependencies: Set = filteredDependencies +// .flatMap { setOf(it.origin, it.destination) } +// .toSet() +// .flatMap { +// dependencyRelationService.allDependenciesOf( +// it, +// requestedCanonicalConfigurations +// ) +// } +// .toSet() + val transitiveDependencies: Set = requestedCanonicalModules.flatMap { + dependencySearchService.findAllDependenciesUsedByModule( + it, + requestedCanonicalConfigurations + ) }.toSet() + + filteredDependencies = filteredDependencies union transitiveDependencies } return filteredDependencies diff --git a/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/CoreModule.kt b/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/CoreModule.kt new file mode 100644 index 0000000..dfae5ad --- /dev/null +++ b/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/CoreModule.kt @@ -0,0 +1,11 @@ +package ch.addere.dga.app.infrastructure.factory + +import ch.addere.dga.core.application.service.DependencySearchService +import ch.addere.dga.core.application.service.DependencySearchServiceImpl +import org.koin.core.module.dsl.bind +import org.koin.core.module.dsl.singleOf +import org.koin.dsl.module + +val coreModule = module { + singleOf(::DependencySearchServiceImpl) { bind() } +} diff --git a/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/DgaModule.kt b/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/DgaModule.kt index 394dae7..ae5086a 100644 --- a/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/DgaModule.kt +++ b/app/src/main/kotlin/ch/addere/dga/app/infrastructure/factory/DgaModule.kt @@ -9,12 +9,11 @@ import ch.addere.dga.app.domain.service.printer.ConsolePrinter import ch.addere.dga.app.domain.service.printer.DependencyPrinter import ch.addere.dga.app.domain.service.printer.MermaidPrinter import ch.addere.dga.app.domain.service.printer.ModulePrinter +import ch.addere.dga.core.domain.DependencyRepository +import ch.addere.dga.core.domain.DependencyRepositoryImpl import ch.addere.dga.core.domain.model.graph.ModuleDependencyDag import ch.addere.dga.core.domain.service.ConfigurationService import ch.addere.dga.core.domain.service.ConfigurationServiceImpl -import ch.addere.dga.core.domain.service.DependencyRelationService -import ch.addere.dga.core.domain.service.DependencyRelationServiceImpl -import ch.addere.dga.core.domain.service.DependencyRepository import ch.addere.dga.core.domain.service.DependencyService import ch.addere.dga.core.domain.service.DependencyServiceImpl import ch.addere.dga.core.domain.service.ModuleRepository @@ -29,8 +28,7 @@ val dgaModule = module { singleOf(::ConsolePrinter) singleOf(::DependencyCommandHandler) singleOf(::DependencyPrinter) - singleOf(::DependencyRelationServiceImpl) { bind() } - singleOf(::DependencyRepository) + singleOf(::DependencyRepositoryImpl) { bind() } singleOf(::DependencyServiceImpl) { bind() } singleOf(::MermaidPrinter) singleOf(::ModuleDependencyDag) diff --git a/build-logic/src/main/kotlin/ch.addere.dga.kotlin-common-conventions.gradle.kts b/build-logic/src/main/kotlin/ch.addere.dga.kotlin-common-conventions.gradle.kts index 08558be..1fee5c3 100644 --- a/build-logic/src/main/kotlin/ch.addere.dga.kotlin-common-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/ch.addere.dga.kotlin-common-conventions.gradle.kts @@ -8,6 +8,9 @@ repositories { dependencies { testImplementation("com.willowtreeapps.assertk:assertk-jvm:0.26.1") + testImplementation("io.kotest:kotest-assertions-core:5.9.1") + testImplementation("io.kotest:kotest-runner-junit5:5.9.1") + testImplementation("io.mockk:mockk:1.13.12") testImplementation("org.mockito.kotlin:mockito-kotlin:5.0.0") } @@ -19,6 +22,10 @@ testing { } } +tasks.withType().configureEach { + useJUnitPlatform() +} + kotlin { jvmToolchain { languageVersion.set(JavaLanguageVersion.of(21)) diff --git a/core/src/main/kotlin/ch/addere/dga/core/application/service/DependencySearchService.kt b/core/src/main/kotlin/ch/addere/dga/core/application/service/DependencySearchService.kt new file mode 100644 index 0000000..266171f --- /dev/null +++ b/core/src/main/kotlin/ch/addere/dga/core/application/service/DependencySearchService.kt @@ -0,0 +1,24 @@ +package ch.addere.dga.core.application.service + +import ch.addere.dga.core.domain.model.Configuration +import ch.addere.dga.core.domain.model.Dependency +import ch.addere.dga.core.domain.model.Module + +interface DependencySearchService { + + /** + * Returns all dependencies that have modules requiring [module]. + */ + fun findAllDependenciesDependingOnModule( + module: Module, + withConfigurations: Collection + ): Set + + /** + * Returns all dependencies which are required in order [module] can work. + */ + fun findAllDependenciesUsedByModule( + module: Module, + withConfigurations: Collection + ): Set +} diff --git a/core/src/main/kotlin/ch/addere/dga/core/application/service/DependencySearchServiceImpl.kt b/core/src/main/kotlin/ch/addere/dga/core/application/service/DependencySearchServiceImpl.kt new file mode 100644 index 0000000..65150d8 --- /dev/null +++ b/core/src/main/kotlin/ch/addere/dga/core/application/service/DependencySearchServiceImpl.kt @@ -0,0 +1,70 @@ +package ch.addere.dga.core.application.service + +import ch.addere.dga.core.domain.DependencyRepository +import ch.addere.dga.core.domain.model.Configuration +import ch.addere.dga.core.domain.model.Dependency +import ch.addere.dga.core.domain.model.Module + +class DependencySearchServiceImpl(private val dependencyRepository: DependencyRepository) : + DependencySearchService { + + override fun findAllDependenciesDependingOnModule( + module: Module, + withConfigurations: Collection + ): Set { + return dependenciesWithDestination(module, withConfigurations) + } + + override fun findAllDependenciesUsedByModule( + module: Module, + withConfigurations: Collection + ): Set { + return dependenciesWithOrigin(module, withConfigurations) + } + + private fun dependenciesWithDestination( + destination: Module, + withConfigurations: Collection + ): Set { + val allDependenciesWithSameDestination: Set = + dependencyRepository.getAllDependencies() + .filter { dependency -> + dependency.destination == destination && withConfigurations.contains( + dependency.configuration + ) + } + .toSet() + + return if (allDependenciesWithSameDestination.isEmpty()) { + emptySet() + } else { + allDependenciesWithSameDestination + .flatMap { dependenciesWithDestination(it.origin, withConfigurations) } + .toSet() union allDependenciesWithSameDestination + } + } + + private fun dependenciesWithOrigin( + origin: Module, + withConfigurations: Collection + ): Set { + println("call with origin = $origin") + val allDependenciesWithSameOrigin: Set = + dependencyRepository.getAllDependencies() + .filter { dependency -> + dependency.origin == origin && withConfigurations.contains( + dependency.configuration + ) + } + .toSet() + println(allDependenciesWithSameOrigin.joinToString(", ")) + + return if (allDependenciesWithSameOrigin.isEmpty()) { + emptySet() + } else { + allDependenciesWithSameOrigin + .flatMap { dependenciesWithOrigin(it.destination, withConfigurations) } + .toSet() union allDependenciesWithSameOrigin + } + } +} diff --git a/core/src/main/kotlin/ch/addere/dga/core/domain/DependencyRepository.kt b/core/src/main/kotlin/ch/addere/dga/core/domain/DependencyRepository.kt new file mode 100644 index 0000000..96e6213 --- /dev/null +++ b/core/src/main/kotlin/ch/addere/dga/core/domain/DependencyRepository.kt @@ -0,0 +1,14 @@ +package ch.addere.dga.core.domain + +import ch.addere.dga.core.domain.model.Configuration +import ch.addere.dga.core.domain.model.Dependency +import ch.addere.dga.core.domain.model.Module + +interface DependencyRepository { + fun addDependency(dependency: Dependency) + fun addDependency(dependencies: Collection) + fun getDependencyByOrigin(module: Module): Set + fun getDependencyByConfiguration(configuration: Configuration): Set + fun getDependencyByDestination(module: Module): Set + fun getAllDependencies(): Set +} diff --git a/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRepository.kt b/core/src/main/kotlin/ch/addere/dga/core/domain/DependencyRepositoryImpl.kt similarity index 54% rename from core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRepository.kt rename to core/src/main/kotlin/ch/addere/dga/core/domain/DependencyRepositoryImpl.kt index b62310c..603ffe6 100644 --- a/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRepository.kt +++ b/core/src/main/kotlin/ch/addere/dga/core/domain/DependencyRepositoryImpl.kt @@ -1,35 +1,35 @@ -package ch.addere.dga.core.domain.service +package ch.addere.dga.core.domain import ch.addere.dga.core.domain.model.Configuration import ch.addere.dga.core.domain.model.Dependency import ch.addere.dga.core.domain.model.Module import java.util.* -class DependencyRepository { +class DependencyRepositoryImpl : DependencyRepository { private val dependencies = mutableSetOf() - fun addDependency(dependency: Dependency) { + override fun addDependency(dependency: Dependency) { dependencies.add(dependency) } - fun addDependency(dependencies: Collection) { + override fun addDependency(dependencies: Collection) { this.dependencies.addAll(dependencies) } - fun getDependencyByOrigin(module: Module): SortedSet { + override fun getDependencyByOrigin(module: Module): SortedSet { return dependencies.filter { it.origin.name == module.name }.toSortedSet() } - fun getDependencyByDestination(module: Module): SortedSet { + override fun getDependencyByDestination(module: Module): SortedSet { return dependencies.filter { it.destination.name == module.name }.toSortedSet() } - fun getDependencyByConfiguration(configuration: Configuration): SortedSet { + override fun getDependencyByConfiguration(configuration: Configuration): SortedSet { return dependencies.filter { it.configuration == configuration }.toSortedSet() } - fun getAllDependencies(): SortedSet { + override fun getAllDependencies(): SortedSet { return dependencies.toSortedSet() } } diff --git a/core/src/main/kotlin/ch/addere/dga/core/domain/model/graph/ModuleDependencyDag.kt b/core/src/main/kotlin/ch/addere/dga/core/domain/model/graph/ModuleDependencyDag.kt index 44e8f95..1330f2d 100644 --- a/core/src/main/kotlin/ch/addere/dga/core/domain/model/graph/ModuleDependencyDag.kt +++ b/core/src/main/kotlin/ch/addere/dga/core/domain/model/graph/ModuleDependencyDag.kt @@ -1,21 +1,17 @@ package ch.addere.dga.core.domain.model.graph +import ch.addere.dga.core.domain.DependencyRepository import ch.addere.dga.core.domain.model.Configuration import ch.addere.dga.core.domain.model.Dependency import ch.addere.dga.core.domain.model.Module -import ch.addere.dga.core.domain.service.DependencyRepository import ch.addere.dga.core.domain.service.ModuleRepository import java.util.* class ModuleDependencyDag( - moduleRepository: ModuleRepository, - dependencyRepository: DependencyRepository + private val moduleRepository: ModuleRepository, + private val dependencyRepository: DependencyRepository ) { - private val vertices = - moduleRepository.getAllModules().map { module: Module -> ModuleVertex(module) }.toSet() - private val edges = dependencyRepository.getAllDependencies().map(::toDependencyEdge).toSet() - private fun toDependencyEdge(dependency: Dependency): DependencyEdge { val origin = resolve(dependency.origin) val destination = resolve(dependency.destination) @@ -28,30 +24,34 @@ class ModuleDependencyDag( } private fun resolve(module: Module): ModuleVertex { - return vertices.first { it.module == module } + return moduleRepository.getAllModules().map(::ModuleVertex).toSet() + .first { it.module == module } } fun nofVertices(): Int { - return vertices.size + return moduleRepository.getAllModules().map(::ModuleVertex).toSet().size } fun nofEdges(): Int { - return edges.size + return dependencyRepository.getAllDependencies().map(::toDependencyEdge).toSet().size } fun vertices(): Set { - return vertices + return moduleRepository.getAllModules().map(::ModuleVertex).toSet() } fun vertex(module: Module): Optional { - return Optional.ofNullable(vertices.firstOrNull { it.module == module }) + return Optional.ofNullable( + moduleRepository.getAllModules().map(::ModuleVertex).toSet() + .firstOrNull { it.module == module }) } fun edges(): Set { - return edges + return dependencyRepository.getAllDependencies().map(::toDependencyEdge).toSet() } fun edge(configuration: Collection): Set { - return edges.filter { configuration.contains(it.configuration) }.toSet() + return dependencyRepository.getAllDependencies().map(::toDependencyEdge).toSet() + .filter { configuration.contains(it.configuration) }.toSet() } } diff --git a/core/src/main/kotlin/ch/addere/dga/core/domain/service/ConfigurationServiceImpl.kt b/core/src/main/kotlin/ch/addere/dga/core/domain/service/ConfigurationServiceImpl.kt index 6ee7095..60bd25e 100644 --- a/core/src/main/kotlin/ch/addere/dga/core/domain/service/ConfigurationServiceImpl.kt +++ b/core/src/main/kotlin/ch/addere/dga/core/domain/service/ConfigurationServiceImpl.kt @@ -1,5 +1,6 @@ package ch.addere.dga.core.domain.service +import ch.addere.dga.core.domain.DependencyRepository import ch.addere.dga.core.domain.model.Configuration import ch.addere.dga.core.domain.model.Dependency diff --git a/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRelationService.kt b/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRelationService.kt deleted file mode 100644 index 5544b63..0000000 --- a/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRelationService.kt +++ /dev/null @@ -1,76 +0,0 @@ -package ch.addere.dga.core.domain.service - -import ch.addere.dga.core.domain.model.Configuration -import ch.addere.dga.core.domain.model.Dependency -import ch.addere.dga.core.domain.model.Module -import java.util.* - -interface DependencyRelationService { - - /** - * All modules with given configuration of the graph sorted by name. - */ - fun allModules(configurations: Collection): SortedSet - - /** - * All dependencies with given configurations of the graph sorted by origin, destination and configuration. - */ - fun allDependencies(configurations: Collection): SortedSet - - /** - * All sorted direct dependencies of a given module within the graph. - */ - fun directDependenciesOf(module: Module): SortedSet - - /** - * All sorted direct dependencies with a given configuration of a given module within the graph. - */ - fun directDependenciesOf(module: Module, configurations: Configuration): SortedSet - - /** - * All sorted direct dependencies with given configurations of a given module within the graph. - */ - fun directDependenciesOf( - module: Module, - configurations: Collection - ): SortedSet - - /** - * All sorted non-direct dependencies of a given module within the graph. - */ - fun nonDirectDependenciesOf(module: Module): SortedSet - - /** - * All sorted non-direct dependencies with a given configuration of a given module within the graph. - */ - fun nonDirectDependenciesOf( - module: Module, - configurations: Configuration - ): SortedSet - - /** - * All sorted non-direct dependencies with given configurations of a given module within the graph. - */ - fun nonDirectDependenciesOf( - module: Module, - configurations: Collection - ): SortedSet - - /** - * All sorted dependencies of a given module within the graph. - */ - fun allDependenciesOf(module: Module): SortedSet - - /** - * All sorted dependencies with given a configuration of a given module within the graph. - */ - fun allDependenciesOf(module: Module, configurations: Configuration): SortedSet - - /** - * All sorted dependencies with given configurations of a given module within the graph. - */ - fun allDependenciesOf( - module: Module, - configurations: Collection - ): SortedSet -} diff --git a/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRelationServiceImpl.kt b/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRelationServiceImpl.kt deleted file mode 100644 index 761ccb9..0000000 --- a/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyRelationServiceImpl.kt +++ /dev/null @@ -1,124 +0,0 @@ -package ch.addere.dga.core.domain.service - -import ch.addere.dga.core.domain.model.Configuration -import ch.addere.dga.core.domain.model.Dependency -import ch.addere.dga.core.domain.model.Module -import ch.addere.dga.core.domain.model.graph.DependencyEdge -import ch.addere.dga.core.domain.model.graph.ModuleDependencyDag -import ch.addere.dga.core.domain.model.graph.ModuleVertex - -import java.util.* - -class DependencyRelationServiceImpl(private val dag: ModuleDependencyDag) : - DependencyRelationService { - - override fun allModules(configurations: Collection): SortedSet { - return findAllModulesWithGivenConfiguration(dag.vertices(), configurations.toSet()) - } - - private fun findAllModulesWithGivenConfiguration( - vertices: Set, - configurations: Set - ): SortedSet { - return vertices - .associate { toModule(it) to toConfiguration(it) } - .filter { hasModuleAtLeastOneConfiguration(it, configurations) } - .map { it.key } - .toSortedSet() - } - - private fun toModule(moduleVertex: ModuleVertex) = moduleVertex.module - - private fun toConfiguration(moduleVertex: ModuleVertex): List = - moduleVertex.getOutgoing().values - .flatten() - .map { it.configuration } - .toList() - - private fun hasModuleAtLeastOneConfiguration( - a: Map.Entry>, - configurations: Set - ) = a.value.intersect(configurations.toSet()).isNotEmpty() - - override fun allDependencies(configurations: Collection): SortedSet { - return dag.edge(configurations).map(::toDependency).toSortedSet() - } - - override fun directDependenciesOf(module: Module): SortedSet { - return dag.vertex(module).map { toDependencies(it) }.orElse(emptyList()).toSortedSet() - } - - override fun directDependenciesOf( - module: Module, - configurations: Configuration - ): SortedSet { - return findAllDependenciesWithConfiguration(directDependenciesOf(module), configurations) - } - - override fun directDependenciesOf( - module: Module, - configurations: Collection - ): SortedSet { - return findAllDependenciesWithConfigurations(directDependenciesOf(module), configurations) - } - - override fun nonDirectDependenciesOf(module: Module): SortedSet { - return directDependenciesOf(module).flatMap { allDependenciesOf(it.destination) } - .toSortedSet() - } - - override fun nonDirectDependenciesOf( - module: Module, - configurations: Configuration - ): SortedSet { - return findAllDependenciesWithConfiguration(nonDirectDependenciesOf(module), configurations) - } - - override fun nonDirectDependenciesOf( - module: Module, - configurations: Collection - ): SortedSet { - return findAllDependenciesWithConfigurations( - nonDirectDependenciesOf(module), - configurations - ) - } - - override fun allDependenciesOf(module: Module): SortedSet { - return nonDirectDependenciesOf(module).plus(directDependenciesOf(module)).toSortedSet() - } - - override fun allDependenciesOf( - module: Module, - configurations: Configuration - ): SortedSet { - return findAllDependenciesWithConfiguration(allDependenciesOf(module), configurations) - } - - override fun allDependenciesOf( - module: Module, - configurations: Collection - ): SortedSet { - return findAllDependenciesWithConfigurations(allDependenciesOf(module), configurations) - } - - private fun toDependencies(vertex: ModuleVertex): List = - vertex.getOutgoing().flatMap { it.value }.map(::toDependency) - - private fun toDependency(edge: DependencyEdge): Dependency = - Dependency(edge.origin.module, edge.destination.module, edge.configuration) - - private fun findAllDependenciesWithConfiguration( - dependencies: Collection, - configuration: Configuration - ): SortedSet { - return dependencies.filter { configuration == it.configuration }.toSortedSet() - } - - private fun findAllDependenciesWithConfigurations( - dependencies: Collection, - configurations: Collection - ): SortedSet { - return dependencies.filter { configurations.contains(it.configuration) }.toSortedSet() - } -} diff --git a/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyServiceImpl.kt b/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyServiceImpl.kt index d89701c..78fec94 100644 --- a/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyServiceImpl.kt +++ b/core/src/main/kotlin/ch/addere/dga/core/domain/service/DependencyServiceImpl.kt @@ -1,10 +1,11 @@ package ch.addere.dga.core.domain.service +import ch.addere.dga.core.domain.DependencyRepositoryImpl import ch.addere.dga.core.domain.model.Dependency import ch.addere.dga.core.domain.model.FilteredConfiguration import ch.addere.dga.core.domain.model.FilteredModules -class DependencyServiceImpl(private val repository: DependencyRepository) : DependencyService { +class DependencyServiceImpl(private val repository: DependencyRepositoryImpl) : DependencyService { override fun nofProjectDependencies(): Int { return repository.getAllDependencies().size diff --git a/core/src/test/kotlin/ch/addere/dga/core/application/service/DependencySearchServiceImplTest.kt b/core/src/test/kotlin/ch/addere/dga/core/application/service/DependencySearchServiceImplTest.kt new file mode 100644 index 0000000..c71f83b --- /dev/null +++ b/core/src/test/kotlin/ch/addere/dga/core/application/service/DependencySearchServiceImplTest.kt @@ -0,0 +1,106 @@ +package ch.addere.dga.core.application.service + +import ch.addere.dga.core.domain.DependencyRepository +import ch.addere.dga.core.domain.model.Configuration +import ch.addere.dga.core.domain.model.Dependency +import ch.addere.dga.core.domain.model.Module +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.mockk.every +import io.mockk.mockk + +class DependencySearchServiceImplTest : FunSpec({ + + lateinit var repository: DependencyRepository + lateinit var service: DependencySearchService + + beforeTest { + repository = mockk() + service = DependencySearchServiceImpl(repository) + } + + test("should not have dependencies on empty repository") { + every { repository.getAllDependencies() } returns emptySet() + + val dependencies = service.findAllDependenciesUsedByModule(Module("any-module"), emptySet()) + + dependencies shouldBe emptySet() + } + + test("should not have dependencies on non-existing configuration") { + every { repository.getAllDependencies() } returns simpleDependency + + val dependencies: Set = service.findAllDependenciesUsedByModule( + Module("A"), + setOf(Configuration("api")) + ) + + dependencies shouldBe emptySet() + } + + test("should have dependencies on existing configuration") { + every { repository.getAllDependencies() } returns simpleDependency + + val dependencies: Set = service.findAllDependenciesUsedByModule( + Module("A"), + setOf(Configuration("implementation")) + ) + + dependencies shouldBe setOf( + Dependency(Module("A"), Module("B"), Configuration("implementation")), + Dependency(Module("B"), Module("D"), Configuration("implementation")), + Dependency(Module("D"), Module("E"), Configuration("implementation")) + ) + } + + test("should have dependencies on existing configurations") { + every { repository.getAllDependencies() } returns simpleDependency + + val dependencies: Set = service.findAllDependenciesUsedByModule( + Module("A"), + setOf(Configuration("implementation"), Configuration("api")) + ) + + dependencies shouldBe setOf( + Dependency(Module("A"), Module("B"), Configuration("implementation")), + Dependency(Module("B"), Module("C"), Configuration("api")), + Dependency(Module("B"), Module("D"), Configuration("implementation")), + Dependency(Module("D"), Module("E"), Configuration("implementation")) + ) + } + + test("should have one dependencies on second last node") { + every { repository.getAllDependencies() } returns simpleDependency + + val dependencies: Set = service.findAllDependenciesUsedByModule( + Module("D"), + setOf(Configuration("implementation")) + ) + + dependencies shouldBe setOf( + Dependency( + Module("D"), + Module("E"), + Configuration("implementation") + ) + ) + } + + test("should not have dependencies on leaf") { + every { repository.getAllDependencies() } returns simpleDependency + + val dependencies: Set = service.findAllDependenciesUsedByModule( + Module("E"), + setOf(Configuration("implementation")) + ) + + dependencies shouldBe emptySet() + } +}) + +private val simpleDependency: Set = setOf( + Dependency(Module("A"), Module("B"), Configuration("implementation")), + Dependency(Module("B"), Module("C"), Configuration("api")), + Dependency(Module("B"), Module("D"), Configuration("implementation")), + Dependency(Module("D"), Module("E"), Configuration("implementation")) +) diff --git a/core/src/test/kotlin/ch/addere/dga/core/model/graph/ModuleDependencyDagTest.kt b/core/src/test/kotlin/ch/addere/dga/core/model/graph/ModuleDependencyDagTest.kt index 73e15e4..8c2f15f 100644 --- a/core/src/test/kotlin/ch/addere/dga/core/model/graph/ModuleDependencyDagTest.kt +++ b/core/src/test/kotlin/ch/addere/dga/core/model/graph/ModuleDependencyDagTest.kt @@ -2,11 +2,11 @@ package ch.addere.dga.core.model.graph import assertk.assertThat import assertk.assertions.isEqualTo +import ch.addere.dga.core.domain.DependencyRepositoryImpl import ch.addere.dga.core.domain.model.Configuration import ch.addere.dga.core.domain.model.Dependency import ch.addere.dga.core.domain.model.Module import ch.addere.dga.core.domain.model.graph.ModuleDependencyDag -import ch.addere.dga.core.domain.service.DependencyRepository import ch.addere.dga.core.domain.service.ModuleRepository import org.junit.jupiter.api.Test @@ -49,7 +49,7 @@ class ModuleDependencyDagTest { private fun dag(modules: Set, dependencies: Set): ModuleDependencyDag { val moduleRepository = ModuleRepository() - val dependencyRepository = DependencyRepository() + val dependencyRepository = DependencyRepositoryImpl() moduleRepository.addModule(modules) dependencyRepository.addDependency(dependencies) diff --git a/core/src/test/kotlin/ch/addere/dga/core/service/DependencyRelationServiceImplTest.kt b/core/src/test/kotlin/ch/addere/dga/core/service/DependencyRelationServiceImplTest.kt deleted file mode 100644 index f078357..0000000 --- a/core/src/test/kotlin/ch/addere/dga/core/service/DependencyRelationServiceImplTest.kt +++ /dev/null @@ -1,312 +0,0 @@ -package ch.addere.dga.core.service - -import assertk.assertThat -import assertk.assertions.contains -import assertk.assertions.containsExactlyInAnyOrder -import assertk.assertions.isEmpty -import ch.addere.dga.core.domain.model.Configuration -import ch.addere.dga.core.domain.model.Dependency -import ch.addere.dga.core.domain.model.Module -import ch.addere.dga.core.domain.model.graph.ModuleDependencyDag -import ch.addere.dga.core.domain.service.DependencyRelationServiceImpl -import ch.addere.dga.core.domain.service.DependencyRepository -import ch.addere.dga.core.domain.service.ModuleRepository -import org.junit.jupiter.api.Test - -class DependencyRelationServiceImplTest { - - /** - * Diagram of the test DAG. - * - * m8 m0 - * | \ / \ m9 - * | m1 \ / | - * | / \ m4 | - * m2 m3 | m7 - * / \ | / - * m6 m5 - * - * Direct Non-direct All - * m0: - m0: - m0: - - * m1: m0, m8 m1: - m1: m0, m8 - * m2: m1, m8 m2: m0 m2: m0, m1, m8 - * m3: m1 m3: m0, m8 m3: m0, m1, m8 - * m4: m0, m9 m4: - m4: m0, m9 - * m5: m3, m4, m7 m5: m0, m1, m8, m9 m5: m0, m1, m3, m4, m7, m8, m9 - * m6: m2 m6: m0, m1, m8 m6: m0, m1, m2, m8 - * m7: m9 m7: - m7: m9 - * m8: - m8: - m8: - - * m9: - m9: - m9: - - */ - - private val m0 = Module("m0") - private val m1 = Module("m1") - private val m2 = Module("m2") - private val m3 = Module("m3") - private val m4 = Module("m4") - private val m5 = Module("m5") - private val m6 = Module("m6") - private val m7 = Module("m7") - private val m8 = Module("m8") - private val m9 = Module("m9") - private val c1 = Configuration("c1") - private val c2 = Configuration("c2") - private val d10 = Dependency(m1, m0, c1) - private val d18 = Dependency(m1, m8, c2) - private val d21 = Dependency(m2, m1, c1) - private val d28 = Dependency(m2, m8, c2) - private val d31 = Dependency(m3, m1, c1) - private val d40 = Dependency(m4, m0, c1) - private val d49 = Dependency(m4, m9, c2) - private val d53 = Dependency(m5, m3, c1) - private val d54 = Dependency(m5, m4, c1) - private val d57 = Dependency(m5, m7, c2) - private val d62 = Dependency(m6, m2, c2) - private val d79 = Dependency(m7, m9, c2) - - @Test - fun `test get all modules with configuration c1`() { - val service = DependencyRelationServiceImpl(dag()) - - val modules = service.allModules(setOf(c1)) - - assertThat(modules).containsExactlyInAnyOrder(m1, m2, m3, m4, m5) - } - - @Test - fun `test get all modules with configuration c2`() { - val service = DependencyRelationServiceImpl(dag()) - - val modules = service.allModules(setOf(c2)) - - assertThat(modules).containsExactlyInAnyOrder(m1, m2, m4, m5, m6, m7) - } - - @Test - fun `test get all dependencies with configuration c1`() { - val service = DependencyRelationServiceImpl(dag()) - - val dependencies = service.allDependencies(setOf(c1)) - - assertThat(dependencies) - .containsExactlyInAnyOrder(d10, d21, d31, d40, d53, d54) - } - - @Test - fun `test get all dependencies with configuration c2`() { - val service = DependencyRelationServiceImpl(dag()) - - val dependencies = service.allDependencies(setOf(c2)) - - assertThat(dependencies) - .containsExactlyInAnyOrder(d18, d28, d49, d57, d62, d79) - } - - @Test - fun `test get all dependencies with both configurations`() { - val service = DependencyRelationServiceImpl(dag()) - - val dependencies = service.allDependencies(setOf(c1, c2)) - - assertThat(dependencies) - .containsExactlyInAnyOrder(d10, d18, d21, d28, d31, d40, d49, d53, d54, d57, d62, d79) - } - - @Test - fun `test direct dependencies`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.directDependenciesOf(m0)).isEmpty() - assertThat(service.directDependenciesOf(m1)).containsExactlyInAnyOrder(d10, d18) - assertThat(service.directDependenciesOf(m2)).containsExactlyInAnyOrder(d21, d28) - assertThat(service.directDependenciesOf(m3)).contains(d31) - assertThat(service.directDependenciesOf(m4)).containsExactlyInAnyOrder(d40, d49) - assertThat(service.directDependenciesOf(m5)).containsExactlyInAnyOrder(d53, d54, d57) - assertThat(service.directDependenciesOf(m6)).contains(d62) - assertThat(service.directDependenciesOf(m7)).contains(d79) - assertThat(service.directDependenciesOf(m8)).isEmpty() - assertThat(service.directDependenciesOf(m9)).isEmpty() - } - - @Test - fun `test direct dependencies with configuration c1`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.directDependenciesOf(m0, c1)).isEmpty() - assertThat(service.directDependenciesOf(m1, c1)).contains(d10) - assertThat(service.directDependenciesOf(m2, c1)).contains(d21) - assertThat(service.directDependenciesOf(m3, c1)).contains(d31) - assertThat(service.directDependenciesOf(m4, c1)).contains(d40) - assertThat(service.directDependenciesOf(m5, c1)).containsExactlyInAnyOrder(d53, d54) - assertThat(service.directDependenciesOf(m6, c1)).isEmpty() - assertThat(service.directDependenciesOf(m7, c1)).isEmpty() - assertThat(service.directDependenciesOf(m8, c1)).isEmpty() - assertThat(service.directDependenciesOf(m9, c1)).isEmpty() - } - - @Test - fun `test direct dependencies with configuration c2`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.directDependenciesOf(m0, c2)).isEmpty() - assertThat(service.directDependenciesOf(m1, c2)).contains(d18) - assertThat(service.directDependenciesOf(m2, c2)).contains(d28) - assertThat(service.directDependenciesOf(m3, c2)).isEmpty() - assertThat(service.directDependenciesOf(m4, c2)).contains(d49) - assertThat(service.directDependenciesOf(m5, c2)).contains(d57) - assertThat(service.directDependenciesOf(m6, c2)).contains(d62) - assertThat(service.directDependenciesOf(m7, c2)).contains(d79) - assertThat(service.directDependenciesOf(m8, c2)).isEmpty() - assertThat(service.directDependenciesOf(m9, c2)).isEmpty() - } - - @Test - fun `test direct dependencies with both configurations`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.directDependenciesOf(m0, setOf(c2, c1))).isEmpty() - assertThat(service.directDependenciesOf(m1, setOf(c2, c1))) - .containsExactlyInAnyOrder(d10, d18) - assertThat(service.directDependenciesOf(m2, setOf(c2, c1))) - .containsExactlyInAnyOrder(d21, d28) - assertThat(service.directDependenciesOf(m3, setOf(c2, c1))).contains(d31) - assertThat(service.directDependenciesOf(m4, setOf(c2, c1))) - .containsExactlyInAnyOrder(d40, d49) - assertThat(service.directDependenciesOf(m5, setOf(c2, c1))) - .containsExactlyInAnyOrder(d53, d54, d57) - assertThat(service.directDependenciesOf(m6, setOf(c2, c1))).contains(d62) - assertThat(service.directDependenciesOf(m7, setOf(c2, c1))).contains(d79) - assertThat(service.directDependenciesOf(m8, setOf(c2, c1))).isEmpty() - assertThat(service.directDependenciesOf(m9, setOf(c2, c1))).isEmpty() - } - - @Test - fun `test non-direct dependencies`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.nonDirectDependenciesOf(m0)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m1)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m2)).contains(d10) - assertThat(service.nonDirectDependenciesOf(m3)).containsExactlyInAnyOrder(d10, d18) - assertThat(service.nonDirectDependenciesOf(m4)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m5)) - .containsExactlyInAnyOrder(d10, d18, d31, d40, d49, d79) - assertThat(service.nonDirectDependenciesOf(m6)) - .containsExactlyInAnyOrder(d10, d18, d21, d28) - assertThat(service.nonDirectDependenciesOf(m7)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m8)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m9)).isEmpty() - } - - @Test - fun `test non-direct dependencies with configuration c1`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.nonDirectDependenciesOf(m0, c1)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m1, c1)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m2, c1)).contains(d10) - assertThat(service.nonDirectDependenciesOf(m3, c1)).contains(d10) - assertThat(service.nonDirectDependenciesOf(m4, c1)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m5, c1)).containsExactlyInAnyOrder(d10, d31, d40) - assertThat(service.nonDirectDependenciesOf(m6, c1)).containsExactlyInAnyOrder(d10, d21) - assertThat(service.nonDirectDependenciesOf(m7, c1)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m8, c1)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m9, c1)).isEmpty() - } - - @Test - fun `test non-direct dependencies with configuration c2`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.nonDirectDependenciesOf(m0, c2)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m1, c2)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m2, c2)).contains(d18) - assertThat(service.nonDirectDependenciesOf(m3, c2)).contains(d18) - assertThat(service.nonDirectDependenciesOf(m4, c2)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m5, c2)).containsExactlyInAnyOrder(d18, d49, d79) - assertThat(service.nonDirectDependenciesOf(m6, c2)).containsExactlyInAnyOrder(d18, d28) - assertThat(service.nonDirectDependenciesOf(m7, c2)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m8, c2)).isEmpty() - assertThat(service.nonDirectDependenciesOf(m9, c2)).isEmpty() - } - - @Test - fun `test non-direct dependencies with both configurations`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.nonDirectDependenciesOf(m0, setOf(c1, c2))).isEmpty() - assertThat(service.nonDirectDependenciesOf(m1, setOf(c1, c2))).isEmpty() - assertThat(service.nonDirectDependenciesOf(m2, setOf(c1, c2))).contains(d10) - assertThat(service.nonDirectDependenciesOf(m3, setOf(c1, c2))) - .containsExactlyInAnyOrder(d10, d18) - assertThat(service.nonDirectDependenciesOf(m4, setOf(c1, c2))).isEmpty() - assertThat(service.nonDirectDependenciesOf(m5, setOf(c1, c2))) - .containsExactlyInAnyOrder(d10, d18, d31, d40, d49, d79) - assertThat(service.nonDirectDependenciesOf(m6, setOf(c1, c2))) - .containsExactlyInAnyOrder(d10, d18, d21, d28) - assertThat(service.nonDirectDependenciesOf(m7, setOf(c1, c2))).isEmpty() - assertThat(service.nonDirectDependenciesOf(m8, setOf(c1, c2))).isEmpty() - assertThat(service.nonDirectDependenciesOf(m9, setOf(c1, c2))).isEmpty() - } - - @Test - fun `test all dependencies`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.allDependenciesOf(m0)).isEmpty() - assertThat(service.allDependenciesOf(m1)).containsExactlyInAnyOrder(d10, d18) - assertThat(service.allDependenciesOf(m2)).containsExactlyInAnyOrder(d10, d21, d28, d18) - assertThat(service.allDependenciesOf(m3)).containsExactlyInAnyOrder(d10, d31, d18) - assertThat(service.allDependenciesOf(m4)).containsExactlyInAnyOrder(d40, d49) - assertThat(service.allDependenciesOf(m5)) - .containsExactlyInAnyOrder(d10, d31, d40, d53, d54, d18, d49, d79, d57) - assertThat(service.allDependenciesOf(m6)).containsExactlyInAnyOrder(d62, d21, d28, d18, d10) - assertThat(service.allDependenciesOf(m7)).contains(d79) - assertThat(service.allDependenciesOf(m8)).isEmpty() - assertThat(service.allDependenciesOf(m9)).isEmpty() - } - - @Test - fun `test all dependencies with configuration c1`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.allDependenciesOf(m0, c1)).isEmpty() - assertThat(service.allDependenciesOf(m1, c1)).contains(d10) - assertThat(service.allDependenciesOf(m2, c1)).containsExactlyInAnyOrder(d10, d21) - assertThat(service.allDependenciesOf(m3, c1)).containsExactlyInAnyOrder(d10, d31) - assertThat(service.allDependenciesOf(m4, c1)).contains(d40) - assertThat(service.allDependenciesOf(m5, c1)) - .containsExactlyInAnyOrder(d10, d31, d40, d53, d54) - assertThat(service.allDependenciesOf(m6, c1)).containsExactlyInAnyOrder(d21, d10) - assertThat(service.allDependenciesOf(m7, c1)).isEmpty() - assertThat(service.allDependenciesOf(m8, c1)).isEmpty() - assertThat(service.allDependenciesOf(m9, c1)).isEmpty() - } - - @Test - fun `test all dependencies with configuration c2`() { - val service = DependencyRelationServiceImpl(dag()) - - assertThat(service.allDependenciesOf(m0, c2)).isEmpty() - assertThat(service.allDependenciesOf(m1, c2)).containsExactlyInAnyOrder(d18) - assertThat(service.allDependenciesOf(m2, c2)).containsExactlyInAnyOrder(d28, d18) - assertThat(service.allDependenciesOf(m3, c2)).containsExactlyInAnyOrder(d18) - assertThat(service.allDependenciesOf(m4, c2)).containsExactlyInAnyOrder(d49) - assertThat(service.allDependenciesOf(m5, c2)).containsExactlyInAnyOrder(d18, d49, d79, d57) - assertThat(service.allDependenciesOf(m6, c2)).containsExactlyInAnyOrder(d62, d28, d18) - assertThat(service.allDependenciesOf(m7, c2)).contains(d79) - assertThat(service.allDependenciesOf(m8, c2)).isEmpty() - assertThat(service.allDependenciesOf(m9, c2)).isEmpty() - } - - private fun dag(): ModuleDependencyDag { - val moduleRepository = ModuleRepository() - val dependencyRepository = DependencyRepository() - - moduleRepository.addModule(setOf(m3, m2, m1, m0, m3, m5, m4, m7, m6, m8, m9)) - dependencyRepository - .addDependency(setOf(d31, d21, d10, d54, d53, d40, d18, d28, d49, d57, d62, d79)) - - return ModuleDependencyDag(moduleRepository, dependencyRepository) - } -} diff --git a/core/src/test/kotlin/ch/addere/dga/core/service/DependencyRepositoryTest.kt b/core/src/test/kotlin/ch/addere/dga/core/service/DependencyRepositoryImplTest.kt similarity index 86% rename from core/src/test/kotlin/ch/addere/dga/core/service/DependencyRepositoryTest.kt rename to core/src/test/kotlin/ch/addere/dga/core/service/DependencyRepositoryImplTest.kt index fac9958..7a109da 100644 --- a/core/src/test/kotlin/ch/addere/dga/core/service/DependencyRepositoryTest.kt +++ b/core/src/test/kotlin/ch/addere/dga/core/service/DependencyRepositoryImplTest.kt @@ -4,10 +4,10 @@ import assertk.assertThat import assertk.assertions.contains import assertk.assertions.containsExactlyInAnyOrder import assertk.assertions.isEmpty +import ch.addere.dga.core.domain.DependencyRepositoryImpl import ch.addere.dga.core.domain.model.Configuration import ch.addere.dga.core.domain.model.Dependency import ch.addere.dga.core.domain.model.Module -import ch.addere.dga.core.domain.service.DependencyRepository import org.junit.jupiter.api.Test private val M1 = Module("m1") @@ -19,17 +19,17 @@ private val D1 = Dependency(M1, M2, C1) private val D2 = Dependency(M1, M3, C1) private val D3 = Dependency(M2, M3, C2) -class DependencyRepositoryTest { +class DependencyRepositoryImplTest { @Test fun `test empty repo has 0 dependencies`() { - val repository = DependencyRepository() + val repository = DependencyRepositoryImpl() assertThat(repository.getAllDependencies()).isEmpty() } @Test fun `test add and get dependencies`() { - val repository = DependencyRepository() + val repository = DependencyRepositoryImpl() repository.addDependency(D1) @@ -42,7 +42,7 @@ class DependencyRepositoryTest { @Test fun `test add several and get all dependencies`() { - val repository = DependencyRepository() + val repository = DependencyRepositoryImpl() repository.addDependency(setOf(D1, D2, D3)) diff --git a/core/src/test/kotlin/ch/addere/dga/core/service/DependencyServiceImplTest.kt b/core/src/test/kotlin/ch/addere/dga/core/service/DependencyServiceImplTest.kt index 784fb5d..7b68f1a 100644 --- a/core/src/test/kotlin/ch/addere/dga/core/service/DependencyServiceImplTest.kt +++ b/core/src/test/kotlin/ch/addere/dga/core/service/DependencyServiceImplTest.kt @@ -4,12 +4,12 @@ import assertk.assertThat import assertk.assertions.containsAll import assertk.assertions.isEmpty import assertk.assertions.isEqualTo +import ch.addere.dga.core.domain.DependencyRepositoryImpl import ch.addere.dga.core.domain.model.Configuration import ch.addere.dga.core.domain.model.Dependency import ch.addere.dga.core.domain.model.FilteredConfiguration import ch.addere.dga.core.domain.model.FilteredModules import ch.addere.dga.core.domain.model.Module -import ch.addere.dga.core.domain.service.DependencyRepository import ch.addere.dga.core.domain.service.DependencyService import ch.addere.dga.core.domain.service.DependencyServiceImpl import org.junit.jupiter.api.Test @@ -28,7 +28,7 @@ class DependencyServiceImplTest { @Test fun `test empty repo has zero modules`() { - val service = DependencyServiceImpl(DependencyRepository()) + val service = DependencyServiceImpl(DependencyRepositoryImpl()) assertThat(service.nofProjectDependencies()).isEqualTo(0) assertThat(service.nofUniqueConfigurations()).isEqualTo(0) @@ -118,7 +118,7 @@ class DependencyServiceImplTest { } private fun serviceWithModules(): DependencyService { - val dependencyRepository = DependencyRepository() + val dependencyRepository = DependencyRepositoryImpl() dependencyRepository.addDependency(listOf(d1, d2, d3, d4)) return DependencyServiceImpl(dependencyRepository) } diff --git a/importer/src/main/kotlin/ch/addere/dga/importer/domain/service/ModelImporterService.kt b/importer/src/main/kotlin/ch/addere/dga/importer/domain/service/ModelImporterService.kt index 7160ebb..4ca3f4b 100644 --- a/importer/src/main/kotlin/ch/addere/dga/importer/domain/service/ModelImporterService.kt +++ b/importer/src/main/kotlin/ch/addere/dga/importer/domain/service/ModelImporterService.kt @@ -1,9 +1,9 @@ package ch.addere.dga.importer.domain.service +import ch.addere.dga.core.domain.DependencyRepository import ch.addere.dga.core.domain.model.Configuration import ch.addere.dga.core.domain.model.Dependency import ch.addere.dga.core.domain.model.Module -import ch.addere.dga.core.domain.service.DependencyRepository import ch.addere.dga.core.domain.service.ModuleRepository import ch.addere.dga.dependencymodel.DependencyModel @@ -12,20 +12,23 @@ class ModelImporterService( private val dependencyRepository: DependencyRepository ) { fun import(dependencyModel: DependencyModel): String { - val modules = dependencyModel.projectModules - .map { Module(it.projectModule) } - .toSortedSet() + val modules: Set = + dependencyModel.projectModules.map { Module(it.projectModule) }.toSet() moduleRepository.addModule(modules) dependencyModel.projectModuleDependencies - .map { entry -> - val origin = Module(entry.key) - entry.value.map { + .forEach { (moduleName, configurationModelList) -> + val origin = Module(moduleName) + configurationModelList.map { val destination = Module(it.destination.projectModule) val configuration = Configuration(it.configuration) - val dependency = Dependency(origin, destination, configuration) - - dependencyRepository.addDependency(dependency) + dependencyRepository.addDependency( + Dependency( + origin, + destination, + configuration + ) + ) } }