diff --git a/ctp-validators/src/main/kotlin/com/commercetools/rmf/validators/DiscriminatedSubtypeRule.kt b/ctp-validators/src/main/kotlin/com/commercetools/rmf/validators/DiscriminatedSubtypeRule.kt new file mode 100644 index 00000000..beade954 --- /dev/null +++ b/ctp-validators/src/main/kotlin/com/commercetools/rmf/validators/DiscriminatedSubtypeRule.kt @@ -0,0 +1,41 @@ +package com.commercetools.rmf.validators + +import io.vrap.rmf.raml.model.types.ObjectType +import org.eclipse.emf.common.util.Diagnostic +import java.util.ArrayList +import java.util.Locale + +@ValidatorSet +class DiscriminatedSubtypeRule(severity: RuleSeverity, options: List? = null) : TypesRule(severity, options) { + + // implement + private val exclude: List = + (options?.filter { ruleOption -> ruleOption.type.lowercase(Locale.getDefault()) == RuleOptionType.EXCLUDE.toString() }?.map { ruleOption -> ruleOption.value }?.plus("") ?: defaultExcludes) + + // implement + override fun caseObjectType(type: ObjectType): List { + val validationResults: MutableList = ArrayList() + + val parent = type.type + if (!type.isInlineType && parent != null && (parent as ObjectType).discriminator != null && type.discriminatorValue == null && exclude.contains(type.name).not()) { + validationResults.add(create(type, + "Discriminator was added to supertype, it should be set to not null for all subtypes. Discriminator is set to null for subtype: {0}, while there is a discriminator for parent type: {1}", + type.name, parent.name)) + } + + return validationResults + } + + companion object : ValidatorFactory { + private val defaultExcludes by lazy { listOf("") } + + @JvmStatic + override fun create(options: List?): DiscriminatedSubtypeRule { + return DiscriminatedSubtypeRule(RuleSeverity.ERROR, options) + } + + @JvmStatic + override fun create(severity: RuleSeverity, options: List?): DiscriminatedSubtypeRule { + return DiscriminatedSubtypeRule(severity, options) + } } +} \ No newline at end of file diff --git a/ctp-validators/src/test/groovy/com/commercetools/rmf/validators/ValidatorRulesTest.groovy b/ctp-validators/src/test/groovy/com/commercetools/rmf/validators/ValidatorRulesTest.groovy index 9e7c78fc..8f25e415 100644 --- a/ctp-validators/src/test/groovy/com/commercetools/rmf/validators/ValidatorRulesTest.groovy +++ b/ctp-validators/src/test/groovy/com/commercetools/rmf/validators/ValidatorRulesTest.groovy @@ -81,6 +81,16 @@ class ValidatorRulesTest extends Specification implements ValidatorFixtures { result.validationResults[0].message == "Discriminator and DiscriminatorValue property defined in the same type: InvalidFooBaz" } + def "discriminator subtype rule"() { + def validators = Arrays.asList(new TypesValidator(Arrays.asList(DiscriminatedSubtypeRule.create(emptyList())))) + def uri = uriFromClasspath("/discriminatorsubtype-rule.raml") + when: + def result = new RamlModelBuilder(validators).buildApi(uri) + then: + result.validationResults.size() == 1 + result.validationResults[0].message == "Discriminator was added to supertype, it should be set to not null for all subtypes. Discriminator is set to null for subtype: InvalidFoo, while there is a discriminator for parent type: Foo" + } + def "filename rule"() { when: def validators = Arrays.asList(new ModulesValidator(Arrays.asList(FilenameRule.create(emptyList())))) diff --git a/ctp-validators/src/test/resources/discriminatorsubtype-rule.raml b/ctp-validators/src/test/resources/discriminatorsubtype-rule.raml new file mode 100644 index 00000000..1dcd3513 --- /dev/null +++ b/ctp-validators/src/test/resources/discriminatorsubtype-rule.raml @@ -0,0 +1,35 @@ +#%RAML 1.0 +title: discriminator parent rule + +types: + Foo: + description: Foo + type: object + discriminator: type + properties: + type: string + FooBar: + description: FooBar + type: Foo + discriminatorValue: foobar + InvalidFoo: + description: FooBar + type: Foo + properties: + type: string + ValidProperty: + type: object + properties: + foo: + type: Foo + description: foo + fooBar: + type: FooBar + description: foobar + +/test: + post: + body: + application/json: + type: Foo + description: foo