Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(server): migrate kebab case in path segments rule to use context…
… object to support OpenAPI 3 (#714)
- Loading branch information
1 parent
9643b42
commit 7a0e718
Showing
5 changed files
with
47 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
25 changes: 13 additions & 12 deletions
25
server/src/main/java/de/zalando/zally/rule/zalando/KebabCaseInPathSegmentsRule.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,28 +1,29 @@ | ||
package de.zalando.zally.rule.zalando | ||
|
||
import de.zalando.zally.rule.api.Check | ||
import de.zalando.zally.rule.api.Context | ||
import de.zalando.zally.rule.api.Rule | ||
import de.zalando.zally.rule.api.Severity | ||
import de.zalando.zally.rule.api.Violation | ||
import de.zalando.zally.util.PatternUtil | ||
import io.swagger.models.Swagger | ||
|
||
@Rule( | ||
ruleSet = ZalandoRuleSet::class, | ||
id = "129", | ||
severity = Severity.MUST, | ||
title = "Lowercase words with hyphens" | ||
ruleSet = ZalandoRuleSet::class, | ||
id = "129", | ||
severity = Severity.MUST, | ||
title = "Lowercase words with hyphens" | ||
) | ||
class KebabCaseInPathSegmentsRule { | ||
|
||
private val description = "Use lowercase separate words with hyphens for path segments" | ||
internal val lowerCaseHyphenSeparatedRegex = """^[a-z-]+$""".toRegex() | ||
|
||
@Check(severity = Severity.MUST) | ||
fun validate(swagger: Swagger): Violation? { | ||
val paths = swagger.paths.orEmpty().keys.filterNot { | ||
val pathSegments = it.split("/").filter { it.isNotEmpty() } | ||
pathSegments.filter { !PatternUtil.isPathVariable(it) && !PatternUtil.isLowerCaseAndHyphens(it) }.isEmpty() | ||
} | ||
return if (paths.isNotEmpty()) Violation(description, paths) else null | ||
} | ||
fun checkKebabCaseInPathSegments(context: Context): List<Violation> = | ||
context.api.paths.orEmpty().entries | ||
.filter { (path, _) -> | ||
path.split("/").filterNot { it.isEmpty() } | ||
.any { segment -> !PatternUtil.isPathVariable(segment) && !segment.matches(lowerCaseHyphenSeparatedRegex) } | ||
} | ||
.map { (_, pathEntry) -> context.violation(description, pathEntry) } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
62 changes: 33 additions & 29 deletions
62
server/src/test/java/de/zalando/zally/rule/zalando/KebabCaseInPathSegmentsRuleTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,48 +1,52 @@ | ||
package de.zalando.zally.rule.zalando | ||
|
||
import de.zalando.zally.swaggerWithPaths | ||
import io.swagger.models.Swagger | ||
import de.zalando.zally.getOpenApiContextFromContent | ||
import org.assertj.core.api.Assertions.assertThat | ||
import org.intellij.lang.annotations.Language | ||
import org.junit.Test | ||
|
||
class KebabCaseInPathSegmentsRuleTest { | ||
|
||
private val testPath1 = "/shipment-order/{shipment_order_id}" | ||
private val testPath2 = "/partner-order/{partner_order_id}" | ||
private val testPath3 = "/partner-order/{partner_order_id}/partner-order/{partner_order_id}" | ||
private val wrongTestPath1 = "/shipment_order/{shipment_order_id}" | ||
private val wrongTestPath2 = "/partner-order/{partner_order_id}/partner-order1/{partner_order_id}" | ||
|
||
private val rule = KebabCaseInPathSegmentsRule() | ||
|
||
@Test | ||
fun emptySwagger() { | ||
assertThat(rule.validate(Swagger())).isNull() | ||
} | ||
|
||
@Test | ||
fun validateNormalPath() { | ||
val swagger = swaggerWithPaths(testPath1) | ||
assertThat(rule.validate(swagger)).isNull() | ||
fun `checkKebabCaseInPathSegments should return violation for path segments which are not lowercase separate words with hyphens`() { | ||
@Language("YAML") | ||
val spec = """ | ||
openapi: 3.0.1 | ||
paths: | ||
/partnerOrders: {} | ||
""".trimIndent() | ||
val context = getOpenApiContextFromContent(spec) | ||
|
||
val violations = rule.checkKebabCaseInPathSegments(context) | ||
|
||
assertThat(violations).isNotEmpty | ||
assertThat(violations[0].description).contains("Use lowercase separate words with hyphens") | ||
assertThat(violations[0].pointer.toString()).isEqualTo("/paths/~1partnerOrders") | ||
} | ||
|
||
@Test | ||
fun validateMultipleNormalPaths() { | ||
val swagger = swaggerWithPaths(testPath1, testPath2, testPath3) | ||
assertThat(rule.validate(swagger)).isNull() | ||
fun `checkKebabCaseInPathSegments should return no violation if all segments are lowercase separated words with hyphens`() { | ||
@Language("YAML") | ||
val spec = """ | ||
openapi: 3.0.1 | ||
paths: | ||
/partner-orders: {} | ||
""".trimIndent() | ||
val context = getOpenApiContextFromContent(spec) | ||
|
||
val violations = rule.checkKebabCaseInPathSegments(context) | ||
|
||
assertThat(violations).isEmpty() | ||
} | ||
|
||
@Test | ||
fun validateFalsePath() { | ||
val swagger = swaggerWithPaths(wrongTestPath1) | ||
val result = rule.validate(swagger)!! | ||
assertThat(result.paths).hasSameElementsAs(listOf(wrongTestPath1)) | ||
} | ||
fun `lowerCaseHyphenSeparatedRegex should match lowercase, with hyphen separated words`() { | ||
assertThat("articles".matches(rule.lowerCaseHyphenSeparatedRegex)).isTrue() | ||
assertThat("partner-articles".matches(rule.lowerCaseHyphenSeparatedRegex)).isTrue() | ||
|
||
@Test | ||
fun validateMultipleFalsePaths() { | ||
val swagger = swaggerWithPaths(wrongTestPath1, testPath2, wrongTestPath2) | ||
val result = rule.validate(swagger)!! | ||
assertThat(result.paths).hasSameElementsAs(listOf(wrongTestPath1, wrongTestPath2)) | ||
assertThat("COOL-ARTICLES".matches(rule.lowerCaseHyphenSeparatedRegex)).isFalse() | ||
assertThat("wEirDARtiCles".matches(rule.lowerCaseHyphenSeparatedRegex)).isFalse() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters