diff --git a/core/src/main/kotlin/com/avsystem/justworks/core/parser/SpecValidator.kt b/core/src/main/kotlin/com/avsystem/justworks/core/parser/SpecValidator.kt index ac24363..ecf9030 100644 --- a/core/src/main/kotlin/com/avsystem/justworks/core/parser/SpecValidator.kt +++ b/core/src/main/kotlin/com/avsystem/justworks/core/parser/SpecValidator.kt @@ -38,5 +38,19 @@ object SpecValidator { Issue.Warning("Links are not supported in v1 and will be ignored") } } + + val operations = openApi.paths.orEmpty().flatMap { (path, pathItem) -> + pathItem.readOperationsMap().mapNotNull { (method, op) -> + op.operationId?.let { Triple(it, method.name, path) } + } + } + val operationIds = operations.groupBy { it.first } + + for ((opId, occurrences) in operationIds) { + ensureOrAccumulate(occurrences.size == 1) { + val locations = occurrences.joinToString { "${it.second} ${it.third}" } + Issue.Warning("Duplicate operationId '$opId' found at: $locations") + } + } } } diff --git a/core/src/test/kotlin/com/avsystem/justworks/core/parser/SpecParserTest.kt b/core/src/test/kotlin/com/avsystem/justworks/core/parser/SpecParserTest.kt index ad055d5..3967f2c 100644 --- a/core/src/test/kotlin/com/avsystem/justworks/core/parser/SpecParserTest.kt +++ b/core/src/test/kotlin/com/avsystem/justworks/core/parser/SpecParserTest.kt @@ -243,6 +243,60 @@ class SpecParserTest : SpecParserTestBase() { } } + // -- SPEC-03b: Duplicate operationId warning -- + + @Test + fun `parse spec with duplicate operationId emits warning`() { + val result = SpecParser.parse( + """ + openapi: 3.0.0 + info: + title: Test + version: 1.0.0 + paths: + /pets: + get: + operationId: listPets + tags: [Pets] + responses: + '200': + description: OK + /animals: + get: + operationId: listPets + tags: [Animals] + responses: + '200': + description: OK + """.trimIndent().toTempFile(), + ) + assertIs>(result) + val dupWarnings = result.warnings.filter { + it.message.contains("Duplicate operationId") + } + assertTrue( + dupWarnings.isNotEmpty(), + "Expected warning about duplicate operationId, got: ${result.warnings}", + ) + assertTrue( + dupWarnings.first().message.contains("listPets"), + "Warning should mention the duplicate operationId", + ) + } + + @Test + fun `parse spec with unique operationIds has no duplicate warnings`() { + val result = SpecParser.parse(loadResource("petstore.yaml")) + assertIs>(result) + val dupWarnings = result.warnings.filter { + it.message.contains("Duplicate operationId") + } + assertTrue( + dupWarnings.isEmpty(), + "Petstore should have no duplicate operationId warnings", + ) + } + // -- SPEC-04: Swagger 2.0 auto-conversion -- @Test