diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 33d5ae1..529ece3 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -6,3 +6,6 @@ # Scala Steward: Reformat with scalafmt 3.7.14 ece31cc91dfbb7f55e1dd9080ef914e3a00ce20a + +# Scala Steward: Reformat with scalafmt 3.9.1 +1c32f8c9a3f5e6fe1c4e61a9e029dfae28a9e75e diff --git a/.scalafmt.conf b/.scalafmt.conf index e1fd888..4654121 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,3 +1,3 @@ runner.dialect = scala3 -version = 3.7.17 +version = 3.9.1 maxColumn = 120 \ No newline at end of file diff --git a/apispec-model/src/test/scala/sttp/apispec/SchemaTest.scala b/apispec-model/src/test/scala/sttp/apispec/SchemaTest.scala index 6ac0205..4fe4f52 100644 --- a/apispec-model/src/test/scala/sttp/apispec/SchemaTest.scala +++ b/apispec-model/src/test/scala/sttp/apispec/SchemaTest.scala @@ -22,20 +22,25 @@ class SchemaTest extends AnyFunSuite { } test("nullable enum") { - val schema = Schema(`type` = Some(List(SchemaType.String)), `enum` = Some(List("a", "b").map(ExampleSingleValue(_)))) - assert(schema.nullable == Schema( - `type` = Some(List(SchemaType.String, SchemaType.Null)), - `enum` = Some(List("a", "b", "null").map(ExampleSingleValue(_))) - )) + val schema = + Schema(`type` = Some(List(SchemaType.String)), `enum` = Some(List("a", "b").map(ExampleSingleValue(_)))) + assert( + schema.nullable == Schema( + `type` = Some(List(SchemaType.String, SchemaType.Null)), + `enum` = Some(List("a", "b", "null").map(ExampleSingleValue(_))) + ) + ) assert(schema.nullable.nullable == schema.nullable) // idempotency } test("nullable const") { val schema = Schema(`type` = Some(List(SchemaType.String)), `const` = Some(ExampleSingleValue("a"))) - assert(schema.nullable == Schema( - `type` = Some(List(SchemaType.String, SchemaType.Null)), - `enum` = Some(List("a", "null").map(ExampleSingleValue(_))) - )) + assert( + schema.nullable == Schema( + `type` = Some(List(SchemaType.String, SchemaType.Null)), + `enum` = Some(List("a", "null").map(ExampleSingleValue(_))) + ) + ) assert(schema.nullable.nullable == schema.nullable) } } diff --git a/apispec-model/src/test/scala/sttp/apispec/validation/BoundsTest.scala b/apispec-model/src/test/scala/sttp/apispec/validation/BoundsTest.scala index 6cd3170..2ed6048 100644 --- a/apispec-model/src/test/scala/sttp/apispec/validation/BoundsTest.scala +++ b/apispec-model/src/test/scala/sttp/apispec/validation/BoundsTest.scala @@ -94,5 +94,3 @@ class BoundsTest extends AnyFunSuite { assert(!b.contains(Bounds(Some(Bound.exclusive(-1)), Some(Bound.exclusive(11))))) } } - - diff --git a/apispec-model/src/test/scala/sttp/apispec/validation/SchemaComparatorTest.scala b/apispec-model/src/test/scala/sttp/apispec/validation/SchemaComparatorTest.scala index 932d2fc..1153d50 100644 --- a/apispec-model/src/test/scala/sttp/apispec/validation/SchemaComparatorTest.scala +++ b/apispec-model/src/test/scala/sttp/apispec/validation/SchemaComparatorTest.scala @@ -54,7 +54,7 @@ abstract class SchemaComparatorTest(referencePrefix: String) extends AnyFunSuite private val opaqueSchema = Schema( allOf = List( stringSchema.copy(pattern = Some(Pattern("[a-z]+"))), - stringSchema.copy(pattern = Some(Pattern("aaa"))), + stringSchema.copy(pattern = Some(Pattern("aaa"))) ) ) @@ -86,7 +86,7 @@ abstract class SchemaComparatorTest(referencePrefix: String) extends AnyFunSuite private val sharedSchemas = Map( "String" -> stringSchema, "Integer" -> integerSchema, - "Number" -> numberSchema, + "Number" -> numberSchema ) private val writerSchemas = sharedSchemas ++ Map( @@ -115,10 +115,12 @@ abstract class SchemaComparatorTest(referencePrefix: String) extends AnyFunSuite .compare(writerSchema, readerSchema) test("ignoring annotations") { - assert(compare( - stringSchema.copy(title = Some("SomeTitle")), - stringSchema.copy(title = Some("OtherTitle")) - ) == Nil) + assert( + compare( + stringSchema.copy(title = Some("SomeTitle")), + stringSchema.copy(title = Some("OtherTitle")) + ) == Nil + ) } test("comparing with empty schema") { @@ -126,9 +128,11 @@ abstract class SchemaComparatorTest(referencePrefix: String) extends AnyFunSuite assert(compare(Schema.Empty, Schema.Empty) == Nil) assert(compare(stringSchema, Schema.Empty) == Nil) assert(compare(opaqueSchema, Schema.Empty) == Nil) - assert(compare(Schema.Empty, stringSchema) == List( - TypeMismatch(SchemaType.Values.filter(_ != SchemaType.String), List(SchemaType.String)) - )) + assert( + compare(Schema.Empty, stringSchema) == List( + TypeMismatch(SchemaType.Values.filter(_ != SchemaType.String), List(SchemaType.String)) + ) + ) } test("comparing with Nothing schema") { @@ -142,32 +146,44 @@ abstract class SchemaComparatorTest(referencePrefix: String) extends AnyFunSuite test("type checking") { assert(compare(integerSchema, numberSchema) == Nil) - assert(compare(stringSchema, integerSchema) == List( - TypeMismatch(List(SchemaType.String), List(SchemaType.Integer)) - )) - assert(compare(Schema(SchemaType.String, SchemaType.Integer), integerSchema) == List( - TypeMismatch(List(SchemaType.String), List(SchemaType.Integer)) - )) - assert(compare( - Schema(SchemaType.String, SchemaType.Integer), - Schema(SchemaType.Boolean, SchemaType.Integer), - ) == List( - TypeMismatch(List(SchemaType.String), List(SchemaType.Boolean, SchemaType.Integer)) - )) - assert(compare( - Schema(SchemaType.String, SchemaType.Integer), - Schema(SchemaType.Boolean, SchemaType.Integer, SchemaType.String), - ) == Nil) + assert( + compare(stringSchema, integerSchema) == List( + TypeMismatch(List(SchemaType.String), List(SchemaType.Integer)) + ) + ) + assert( + compare(Schema(SchemaType.String, SchemaType.Integer), integerSchema) == List( + TypeMismatch(List(SchemaType.String), List(SchemaType.Integer)) + ) + ) + assert( + compare( + Schema(SchemaType.String, SchemaType.Integer), + Schema(SchemaType.Boolean, SchemaType.Integer) + ) == List( + TypeMismatch(List(SchemaType.String), List(SchemaType.Boolean, SchemaType.Integer)) + ) + ) + assert( + compare( + Schema(SchemaType.String, SchemaType.Integer), + Schema(SchemaType.Boolean, SchemaType.Integer, SchemaType.String) + ) == Nil + ) } test("reference resolution") { assert(compare(ref("String"), ref("String")) == Nil) - assert(compare(ref("String"), ref("Integer")) == List( - TypeMismatch(List(SchemaType.String), List(SchemaType.Integer)) - )) - assert(compare(ref("Something"), ref("Something")) == List( - TypeMismatch(List(SchemaType.String), List(SchemaType.Integer)) - )) + assert( + compare(ref("String"), ref("Integer")) == List( + TypeMismatch(List(SchemaType.String), List(SchemaType.Integer)) + ) + ) + assert( + compare(ref("Something"), ref("Something")) == List( + TypeMismatch(List(SchemaType.String), List(SchemaType.Integer)) + ) + ) assert(compare(ref("Integer"), ref("Something")) == Nil) assert(compare(ref("Something"), ref("String")) == Nil) } @@ -176,25 +192,31 @@ abstract class SchemaComparatorTest(referencePrefix: String) extends AnyFunSuite // `allOf` is currently not understood by SchemaComparator, // so the schemas are opaque and are compared for pure structural equality val schema = Schema(allOf = List(ref("Something"), ref("String"))) - assert(compare(schema, schema) == List( - GeneralSchemaMismatch(schema, schema) - )) + assert( + compare(schema, schema) == List( + GeneralSchemaMismatch(schema, schema) + ) + ) } test("opaque schemas with different references to identical schemas") { // `allOf` is currently not understood by SchemaComparator, // so the schemas are opaque and are compared for pure structural equality - assert(compare( - Schema(allOf = List(ref("Something"), ref("Integer"))), - Schema(allOf = List(ref("String"), ref("Integer"))) - ) == Nil) + assert( + compare( + Schema(allOf = List(ref("Something"), ref("Integer"))), + Schema(allOf = List(ref("String"), ref("Integer"))) + ) == Nil + ) } test("comparing recursive schemas") { assert(compare(writerTreeSchema, readerTreeSchema) == Nil) - assert(compare(writerTreeSchema, strictReaderTreeSchema) == List( - MissingRequiredProperties(Set("value")) - )) + assert( + compare(writerTreeSchema, strictReaderTreeSchema) == List( + MissingRequiredProperties(Set("value")) + ) + ) } test("compatible nullable schemas") { @@ -205,15 +227,21 @@ abstract class SchemaComparatorTest(referencePrefix: String) extends AnyFunSuite } test("incompatible nullable schemas") { - assert(compare(stringSchema.nullable, stringSchema) == List( - TypeMismatch(List(SchemaType.Null), List(SchemaType.String)) - )) - assert(compare(opaqueSchema.nullable, opaqueSchema) == List( - IncompatibleUnionVariant(1, List(GeneralSchemaMismatch(Schema.Null, opaqueSchema))) - )) - assert(compare(ref("String").nullable, ref("String")) == List( - IncompatibleUnionVariant(1, List(TypeMismatch(List(SchemaType.Null), List(SchemaType.String)))) - )) + assert( + compare(stringSchema.nullable, stringSchema) == List( + TypeMismatch(List(SchemaType.Null), List(SchemaType.String)) + ) + ) + assert( + compare(opaqueSchema.nullable, opaqueSchema) == List( + IncompatibleUnionVariant(1, List(GeneralSchemaMismatch(Schema.Null, opaqueSchema))) + ) + ) + assert( + compare(ref("String").nullable, ref("String")) == List( + IncompatibleUnionVariant(1, List(TypeMismatch(List(SchemaType.Null), List(SchemaType.String)))) + ) + ) } private def enums(values: Any*): List[ExampleSingleValue] = @@ -221,7 +249,7 @@ abstract class SchemaComparatorTest(referencePrefix: String) extends AnyFunSuite private def enumSchema(values: String*): Schema = values.toList match { case single :: Nil => stringSchema.copy(`enum` = Some(List(single).map(ExampleSingleValue(_)))) - case multiple => stringSchema.copy(`enum` = Some(multiple.map(ExampleSingleValue(_)))) + case multiple => stringSchema.copy(`enum` = Some(multiple.map(ExampleSingleValue(_)))) } test("compatible enum & const") { @@ -232,442 +260,543 @@ abstract class SchemaComparatorTest(referencePrefix: String) extends AnyFunSuite } test("incompatible enum & const") { - assert(compare(stringSchema, enumSchema("a", "b")) == List( - EnumMismatch(None, enums("a", "b")) - )) - assert(compare(enumSchema("a"), enumSchema("b")) == List( - EnumMismatch(Some(enums("a")), enums("b")) - )) - assert(compare(enumSchema("a"), enumSchema("b", "c")) == List( - EnumMismatch(Some(enums("a")), enums("b", "c")) - )) - assert(compare(enumSchema("a", "b"), enumSchema("c")) == List( - EnumMismatch(Some(enums("a", "b")), enums("c")) - )) - assert(compare(enumSchema("a", "b"), enumSchema("b", "c")) == List( - EnumMismatch(Some(enums("a")), enums("b", "c")) - )) + assert( + compare(stringSchema, enumSchema("a", "b")) == List( + EnumMismatch(None, enums("a", "b")) + ) + ) + assert( + compare(enumSchema("a"), enumSchema("b")) == List( + EnumMismatch(Some(enums("a")), enums("b")) + ) + ) + assert( + compare(enumSchema("a"), enumSchema("b", "c")) == List( + EnumMismatch(Some(enums("a")), enums("b", "c")) + ) + ) + assert( + compare(enumSchema("a", "b"), enumSchema("c")) == List( + EnumMismatch(Some(enums("a", "b")), enums("c")) + ) + ) + assert( + compare(enumSchema("a", "b"), enumSchema("b", "c")) == List( + EnumMismatch(Some(enums("a")), enums("b", "c")) + ) + ) } test("compatible formats") { - assert(compare( - stringSchema.copy(format = Some(SchemaFormat.Date)), - stringSchema, - ) == Nil) + assert( + compare( + stringSchema.copy(format = Some(SchemaFormat.Date)), + stringSchema + ) == Nil + ) - assert(compare( - integerSchema.copy(format = Some(SchemaFormat.Int32)), - integerSchema.copy(format = Some(SchemaFormat.Int64)), - ) == Nil) + assert( + compare( + integerSchema.copy(format = Some(SchemaFormat.Int32)), + integerSchema.copy(format = Some(SchemaFormat.Int64)) + ) == Nil + ) - assert(compare( - numberSchema.copy(format = Some(SchemaFormat.Float)), - numberSchema.copy(format = Some(SchemaFormat.Double)), - ) == Nil) + assert( + compare( + numberSchema.copy(format = Some(SchemaFormat.Float)), + numberSchema.copy(format = Some(SchemaFormat.Double)) + ) == Nil + ) } test("incompatible formats") { - assert(compare( - stringSchema, - stringSchema.copy(format = Some(SchemaFormat.Date)), - ) == List( - FormatMismatch(None, SchemaFormat.Date) - )) - - assert(compare( - stringSchema.copy(format = Some(SchemaFormat.Binary)), - stringSchema.copy(format = Some(SchemaFormat.Date)), - ) == List( - FormatMismatch(Some(SchemaFormat.Binary), SchemaFormat.Date) - )) - - assert(compare( - integerSchema.copy(format = Some(SchemaFormat.Int64)), - integerSchema.copy(format = Some(SchemaFormat.Int32)), - ) == List( - FormatMismatch(Some(SchemaFormat.Int64), SchemaFormat.Int32) - )) + assert( + compare( + stringSchema, + stringSchema.copy(format = Some(SchemaFormat.Date)) + ) == List( + FormatMismatch(None, SchemaFormat.Date) + ) + ) + + assert( + compare( + stringSchema.copy(format = Some(SchemaFormat.Binary)), + stringSchema.copy(format = Some(SchemaFormat.Date)) + ) == List( + FormatMismatch(Some(SchemaFormat.Binary), SchemaFormat.Date) + ) + ) + + assert( + compare( + integerSchema.copy(format = Some(SchemaFormat.Int64)), + integerSchema.copy(format = Some(SchemaFormat.Int32)) + ) == List( + FormatMismatch(Some(SchemaFormat.Int64), SchemaFormat.Int32) + ) + ) } test("compatible numerical assertions") { - assert(compare( - integerSchema.copy( - multipleOf = Some(BigDecimal(2)), - minimum = Some(BigDecimal(1)), - maximum = Some(BigDecimal(10)), - ), - integerSchema, - ) == Nil) - - assert(compare( - integerSchema.copy( - multipleOf = Some(BigDecimal(4)), - minimum = Some(BigDecimal(2)), - maximum = Some(BigDecimal(9)), - ), - integerSchema.copy( - multipleOf = Some(BigDecimal(2)), - minimum = Some(BigDecimal(1)), - maximum = Some(BigDecimal(10)), - ), - ) == Nil) + assert( + compare( + integerSchema.copy( + multipleOf = Some(BigDecimal(2)), + minimum = Some(BigDecimal(1)), + maximum = Some(BigDecimal(10)) + ), + integerSchema + ) == Nil + ) + + assert( + compare( + integerSchema.copy( + multipleOf = Some(BigDecimal(4)), + minimum = Some(BigDecimal(2)), + maximum = Some(BigDecimal(9)) + ), + integerSchema.copy( + multipleOf = Some(BigDecimal(2)), + minimum = Some(BigDecimal(1)), + maximum = Some(BigDecimal(10)) + ) + ) == Nil + ) } test("incompatible numerical assertions") { - assert(compare( - integerSchema, - integerSchema.copy( - multipleOf = Some(BigDecimal(2)), - minimum = Some(BigDecimal(1)), - maximum = Some(BigDecimal(10)), - ) - ) == List( - MultipleOfMismatch(None, BigDecimal(2)), - NumericBoundsMismatch(Bounds(None, None), Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(10)))) - )) - - assert(compare( - integerSchema.copy( - multipleOf = Some(BigDecimal(3)), - minimum = Some(BigDecimal(1)), - maximum = Some(BigDecimal(10)), - ), - integerSchema.copy( - multipleOf = Some(BigDecimal(2)), - exclusiveMinimum = Some(BigDecimal(1)), - maximum = Some(BigDecimal(10)), - ) - ) == List( - MultipleOfMismatch(Some(BigDecimal(3)), BigDecimal(2)), - NumericBoundsMismatch( - Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(10))), - Bounds(Some(Bound.exclusive(1)), Some(Bound.inclusive(10))) - ) - )) + assert( + compare( + integerSchema, + integerSchema.copy( + multipleOf = Some(BigDecimal(2)), + minimum = Some(BigDecimal(1)), + maximum = Some(BigDecimal(10)) + ) + ) == List( + MultipleOfMismatch(None, BigDecimal(2)), + NumericBoundsMismatch(Bounds(None, None), Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(10)))) + ) + ) + + assert( + compare( + integerSchema.copy( + multipleOf = Some(BigDecimal(3)), + minimum = Some(BigDecimal(1)), + maximum = Some(BigDecimal(10)) + ), + integerSchema.copy( + multipleOf = Some(BigDecimal(2)), + exclusiveMinimum = Some(BigDecimal(1)), + maximum = Some(BigDecimal(10)) + ) + ) == List( + MultipleOfMismatch(Some(BigDecimal(3)), BigDecimal(2)), + NumericBoundsMismatch( + Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(10))), + Bounds(Some(Bound.exclusive(1)), Some(Bound.inclusive(10))) + ) + ) + ) } test("compatible string assertions") { - assert(compare( - stringSchema.copy( - maxLength = Some(10), - minLength = Some(1), - pattern = Some(Pattern("[a-z]+")), - ), - stringSchema, - ) == Nil) - - assert(compare( - stringSchema.copy( - maxLength = Some(8), - minLength = Some(3), - pattern = Some(Pattern("[a-z]+")), - ), - stringSchema.copy( - maxLength = Some(10), - minLength = Some(1), - ), - ) == Nil) + assert( + compare( + stringSchema.copy( + maxLength = Some(10), + minLength = Some(1), + pattern = Some(Pattern("[a-z]+")) + ), + stringSchema + ) == Nil + ) + + assert( + compare( + stringSchema.copy( + maxLength = Some(8), + minLength = Some(3), + pattern = Some(Pattern("[a-z]+")) + ), + stringSchema.copy( + maxLength = Some(10), + minLength = Some(1) + ) + ) == Nil + ) } test("incompatible string assertions") { - assert(compare( - stringSchema, - stringSchema.copy( - maxLength = Some(10), - minLength = Some(1), - pattern = Some(Pattern("[a-z]+")), - ), - ) == List( - StringLengthBoundsMismatch( - Bounds(Some(Bound.inclusive(0)), None), - Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(10)))), - PatternMismatch(None, Pattern("[a-z]+")) - )) - - assert(compare( - stringSchema.copy( - maxLength = Some(10), - minLength = Some(1), - pattern = Some(Pattern("[a-z]+")), - ), - stringSchema.copy( - maxLength = Some(10), - minLength = Some(2), - pattern = Some(Pattern("[A-Z]+")), - ), - ) == List( - StringLengthBoundsMismatch( - Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(10))), - Bounds(Some(Bound.inclusive(2)), Some(Bound.inclusive(10)))), - PatternMismatch(Some(Pattern("[a-z]+")), Pattern("[A-Z]+")) - )) + assert( + compare( + stringSchema, + stringSchema.copy( + maxLength = Some(10), + minLength = Some(1), + pattern = Some(Pattern("[a-z]+")) + ) + ) == List( + StringLengthBoundsMismatch( + Bounds(Some(Bound.inclusive(0)), None), + Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(10))) + ), + PatternMismatch(None, Pattern("[a-z]+")) + ) + ) + + assert( + compare( + stringSchema.copy( + maxLength = Some(10), + minLength = Some(1), + pattern = Some(Pattern("[a-z]+")) + ), + stringSchema.copy( + maxLength = Some(10), + minLength = Some(2), + pattern = Some(Pattern("[A-Z]+")) + ) + ) == List( + StringLengthBoundsMismatch( + Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(10))), + Bounds(Some(Bound.inclusive(2)), Some(Bound.inclusive(10))) + ), + PatternMismatch(Some(Pattern("[a-z]+")), Pattern("[A-Z]+")) + ) + ) } test("comparing product schemas") { - assert(compare( - objectSchema.copy( - properties = ListMap( - "a" -> stringSchema, - "b" -> integerSchema, - "c" -> booleanSchema, - "d" -> stringSchema, + assert( + compare( + objectSchema.copy( + properties = ListMap( + "a" -> stringSchema, + "b" -> integerSchema, + "c" -> booleanSchema, + "d" -> stringSchema + ), + required = List("a", "b", "d") ), - required = List("a", "b", "d") - ), - objectSchema.copy( - properties = ListMap( - "a" -> stringSchema, - "b" -> numberSchema, - "c" -> stringSchema, - "e" -> stringSchema, - "f" -> stringSchema, - ), - required = List("a", "b", "e"), - dependentRequired = ListMap("c" -> List("f")) - ), - ) == List( - MissingRequiredProperties(Set("e")), - MissingDependentRequiredProperties("c", Set("f")), - IncompatibleProperty("c", List( - TypeMismatch(List(SchemaType.Boolean), List(SchemaType.String)) - )), - )) + objectSchema.copy( + properties = ListMap( + "a" -> stringSchema, + "b" -> numberSchema, + "c" -> stringSchema, + "e" -> stringSchema, + "f" -> stringSchema + ), + required = List("a", "b", "e"), + dependentRequired = ListMap("c" -> List("f")) + ) + ) == List( + MissingRequiredProperties(Set("e")), + MissingDependentRequiredProperties("c", Set("f")), + IncompatibleProperty( + "c", + List( + TypeMismatch(List(SchemaType.Boolean), List(SchemaType.String)) + ) + ) + ) + ) } test("compatible coproduct schemas") { - assert(compare( - Schema( - oneOf = List(ref("Foo"), ref("Bar")), - discriminator = Some(Discriminator("type", None)) - ), - Schema( - oneOf = List(ref("Foo"), ref("Bar"), ref("Baz")), - discriminator = Some(Discriminator("type", None)) - ), - ) == Nil) + assert( + compare( + Schema( + oneOf = List(ref("Foo"), ref("Bar")), + discriminator = Some(Discriminator("type", None)) + ), + Schema( + oneOf = List(ref("Foo"), ref("Bar"), ref("Baz")), + discriminator = Some(Discriminator("type", None)) + ) + ) == Nil + ) } test("incompatible coproduct schemas") { - assert(compare( - Schema( - oneOf = List(ref("Foo"), ref("Bar"), ref("Baz")), - discriminator = Some(Discriminator("type", None)) - ), - Schema( - oneOf = List(ref("Foo"), ref("Bar")), - discriminator = Some(Discriminator("type", None)) - ), - ) == List( - UnsupportedDiscriminatorValues(List("Baz")) - )) + assert( + compare( + Schema( + oneOf = List(ref("Foo"), ref("Bar"), ref("Baz")), + discriminator = Some(Discriminator("type", None)) + ), + Schema( + oneOf = List(ref("Foo"), ref("Bar")), + discriminator = Some(Discriminator("type", None)) + ) + ) == List( + UnsupportedDiscriminatorValues(List("Baz")) + ) + ) } test("discriminator property mismatch") { - assert(compare( - Schema( - oneOf = List(ref("Foo"), ref("Bar")), - discriminator = Some(Discriminator("kind", None)) - ), - Schema( - oneOf = List(ref("Foo"), ref("Bar"), ref("Baz")), - discriminator = Some(Discriminator("type", None)) - ), - ) == List( - DiscriminatorPropertyMismatch("kind", "type") - )) + assert( + compare( + Schema( + oneOf = List(ref("Foo"), ref("Bar")), + discriminator = Some(Discriminator("kind", None)) + ), + Schema( + oneOf = List(ref("Foo"), ref("Bar"), ref("Baz")), + discriminator = Some(Discriminator("type", None)) + ) + ) == List( + DiscriminatorPropertyMismatch("kind", "type") + ) + ) } test("unsupported discriminator values") { - assert(compare( - Schema( - oneOf = List(ref("Foo"), ref("Bar")), - discriminator = Some(Discriminator("type", Some(ListMap("WFoo" -> s"${referencePrefix}Foo")))) - ), - Schema( - oneOf = List(ref("Foo"), ref("Bar"), ref("Baz")), - discriminator = Some(Discriminator("type", Some(ListMap("RBar" -> s"${referencePrefix}Bar")))) - ), - ) == List( - UnsupportedDiscriminatorValues(List("WFoo", "Bar")) - )) + assert( + compare( + Schema( + oneOf = List(ref("Foo"), ref("Bar")), + discriminator = Some(Discriminator("type", Some(ListMap("WFoo" -> s"${referencePrefix}Foo")))) + ), + Schema( + oneOf = List(ref("Foo"), ref("Bar"), ref("Baz")), + discriminator = Some(Discriminator("type", Some(ListMap("RBar" -> s"${referencePrefix}Bar")))) + ) + ) == List( + UnsupportedDiscriminatorValues(List("WFoo", "Bar")) + ) + ) } test("incompatible coproduct case schema") { - assert(compare( - Schema( - oneOf = List(ref("Foo"), ref("Bar")), - discriminator = Some(Discriminator("type", Some(ListMap("Baz" -> s"${referencePrefix}Bar")))) - ), - Schema( - oneOf = List(ref("Foo"), ref("Baz")), - discriminator = Some(Discriminator("type", None)) - ), - ) == List( - IncompatibleDiscriminatorCase("Baz", compare(barSchema, bazSchema)) - )) + assert( + compare( + Schema( + oneOf = List(ref("Foo"), ref("Bar")), + discriminator = Some(Discriminator("type", Some(ListMap("Baz" -> s"${referencePrefix}Bar")))) + ), + Schema( + oneOf = List(ref("Foo"), ref("Baz")), + discriminator = Some(Discriminator("type", None)) + ) + ) == List( + IncompatibleDiscriminatorCase("Baz", compare(barSchema, bazSchema)) + ) + ) } test("compatible collection schemas") { - assert(compare( - arraySchema.copy( - items = Some(integerSchema), - minItems = Some(1), - maxItems = Some(5), - uniqueItems = Some(true), - ), - arraySchema.copy( - items = Some(numberSchema) - ), - ) == Nil) - - assert(compare( - arraySchema.copy( - items = Some(integerSchema), - minItems = Some(1), - maxItems = Some(5), - uniqueItems = Some(true), - ), - arraySchema.copy( - items = Some(numberSchema), - minItems = Some(1), - maxItems = Some(10), - uniqueItems = Some(true), - ), - ) == Nil) + assert( + compare( + arraySchema.copy( + items = Some(integerSchema), + minItems = Some(1), + maxItems = Some(5), + uniqueItems = Some(true) + ), + arraySchema.copy( + items = Some(numberSchema) + ) + ) == Nil + ) + + assert( + compare( + arraySchema.copy( + items = Some(integerSchema), + minItems = Some(1), + maxItems = Some(5), + uniqueItems = Some(true) + ), + arraySchema.copy( + items = Some(numberSchema), + minItems = Some(1), + maxItems = Some(10), + uniqueItems = Some(true) + ) + ) == Nil + ) } test("incompatible collection schemas") { - assert(compare( - arraySchema.copy( - items = Some(integerSchema), - minItems = Some(1), - maxItems = Some(5), - ), - arraySchema.copy( - items = Some(stringSchema), - minItems = Some(2), - maxItems = Some(4), - uniqueItems = Some(true), - ), - ) == List( - ArrayLengthBoundsMismatch( - Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(5))), - Bounds(Some(Bound.inclusive(2)), Some(Bound.inclusive(4))) - ), - UniqueItemsRequired, - IncompatibleItems(List( - TypeMismatch(List(SchemaType.Integer), List(SchemaType.String)) - )) - )) + assert( + compare( + arraySchema.copy( + items = Some(integerSchema), + minItems = Some(1), + maxItems = Some(5) + ), + arraySchema.copy( + items = Some(stringSchema), + minItems = Some(2), + maxItems = Some(4), + uniqueItems = Some(true) + ) + ) == List( + ArrayLengthBoundsMismatch( + Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(5))), + Bounds(Some(Bound.inclusive(2)), Some(Bound.inclusive(4))) + ), + UniqueItemsRequired, + IncompatibleItems( + List( + TypeMismatch(List(SchemaType.Integer), List(SchemaType.String)) + ) + ) + ) + ) } test("compatible tuple schemas") { - assert(compare( - arraySchema.copy( - prefixItems = Some(List(integerSchema, stringSchema, booleanSchema)), - ), - arraySchema.copy( - prefixItems = Some(List(numberSchema, stringSchema)), - ), - ) == Nil) + assert( + compare( + arraySchema.copy( + prefixItems = Some(List(integerSchema, stringSchema, booleanSchema)) + ), + arraySchema.copy( + prefixItems = Some(List(numberSchema, stringSchema)) + ) + ) == Nil + ) } test("incompatible tuple schemas") { - assert(compare( - arraySchema.copy( - prefixItems = Some(List(integerSchema, stringSchema)), - ), - arraySchema.copy( - prefixItems = Some(List(numberSchema, booleanSchema, stringSchema)), - ), - ) == List( - IncompatiblePrefixItem(1, List( - TypeMismatch(List(SchemaType.String), List(SchemaType.Boolean)) - )), - IncompatiblePrefixItem(2, List( - TypeMismatch(SchemaType.Values.filter(_ != SchemaType.String), List(SchemaType.String)) - )) - )) + assert( + compare( + arraySchema.copy( + prefixItems = Some(List(integerSchema, stringSchema)) + ), + arraySchema.copy( + prefixItems = Some(List(numberSchema, booleanSchema, stringSchema)) + ) + ) == List( + IncompatiblePrefixItem( + 1, + List( + TypeMismatch(List(SchemaType.String), List(SchemaType.Boolean)) + ) + ), + IncompatiblePrefixItem( + 2, + List( + TypeMismatch(SchemaType.Values.filter(_ != SchemaType.String), List(SchemaType.String)) + ) + ) + ) + ) } test("compatible map schemas") { - assert(compare( - objectSchema.copy( - additionalProperties = Some(integerSchema), - propertyNames = Some(stringSchema.copy(maxLength = Some(8))), - minProperties = Some(1), - maxProperties = Some(10), - ), - objectSchema.copy( - additionalProperties = Some(numberSchema), - ), - ) == Nil) - - assert(compare( - objectSchema.copy( - additionalProperties = Some(integerSchema), - propertyNames = Some(stringSchema.copy(maxLength = Some(8))), - minProperties = Some(2), - maxProperties = Some(10), - ), - objectSchema.copy( - additionalProperties = Some(numberSchema), - propertyNames = Some(stringSchema.copy(maxLength = Some(10))), - minProperties = Some(1), - maxProperties = Some(12), - ), - ) == Nil) + assert( + compare( + objectSchema.copy( + additionalProperties = Some(integerSchema), + propertyNames = Some(stringSchema.copy(maxLength = Some(8))), + minProperties = Some(1), + maxProperties = Some(10) + ), + objectSchema.copy( + additionalProperties = Some(numberSchema) + ) + ) == Nil + ) + + assert( + compare( + objectSchema.copy( + additionalProperties = Some(integerSchema), + propertyNames = Some(stringSchema.copy(maxLength = Some(8))), + minProperties = Some(2), + maxProperties = Some(10) + ), + objectSchema.copy( + additionalProperties = Some(numberSchema), + propertyNames = Some(stringSchema.copy(maxLength = Some(10))), + minProperties = Some(1), + maxProperties = Some(12) + ) + ) == Nil + ) } test("incompatible map schemas") { - assert(compare( - objectSchema.copy( - additionalProperties = Some(stringSchema), - ), - objectSchema.copy( - additionalProperties = Some(numberSchema), - propertyNames = Some(stringSchema.copy(maxLength = Some(10))), - minProperties = Some(1), - maxProperties = Some(12), - ), - ) == List( - IncompatibleAdditionalProperties(List( - TypeMismatch(List(SchemaType.String), List(SchemaType.Number)) - )), - IncompatiblePropertyNames(List( - StringLengthBoundsMismatch( + assert( + compare( + objectSchema.copy( + additionalProperties = Some(stringSchema) + ), + objectSchema.copy( + additionalProperties = Some(numberSchema), + propertyNames = Some(stringSchema.copy(maxLength = Some(10))), + minProperties = Some(1), + maxProperties = Some(12) + ) + ) == List( + IncompatibleAdditionalProperties( + List( + TypeMismatch(List(SchemaType.String), List(SchemaType.Number)) + ) + ), + IncompatiblePropertyNames( + List( + StringLengthBoundsMismatch( + Bounds(Some(Bound.inclusive(0)), None), + Bounds(Some(Bound.inclusive(0)), Some(Bound.inclusive(10))) + ) + ) + ), + ObjectSizeBoundsMismatch( Bounds(Some(Bound.inclusive(0)), None), - Bounds(Some(Bound.inclusive(0)), Some(Bound.inclusive(10))) + Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(12))) ) - )), - ObjectSizeBoundsMismatch( - Bounds(Some(Bound.inclusive(0)), None), - Bounds(Some(Bound.inclusive(1)), Some(Bound.inclusive(12))) - )) + ) ) } test("compatible untagged union schemas") { - assert(compare( - Schema(anyOf = List(stringSchema, integerSchema)), - Schema(anyOf = List(stringSchema, numberSchema, booleanSchema)), - ) == Nil) + assert( + compare( + Schema(anyOf = List(stringSchema, integerSchema)), + Schema(anyOf = List(stringSchema, numberSchema, booleanSchema)) + ) == Nil + ) } test("incompatible untagged union schemas") { - assert(compare( - Schema(anyOf = List(stringSchema, numberSchema, booleanSchema)), - Schema(anyOf = List(stringSchema, integerSchema)), - ) == List( - IncompatibleUnionVariant(1, List(AlternativeIssues(List( - List(TypeMismatch(List(SchemaType.Number), List(SchemaType.String))), - List(TypeMismatch(List(SchemaType.Number), List(SchemaType.Integer))) - )))), - IncompatibleUnionVariant(2, List(AlternativeIssues(List( - List(TypeMismatch(List(SchemaType.Boolean), List(SchemaType.String))), - List(TypeMismatch(List(SchemaType.Boolean), List(SchemaType.Integer))) - )))) - )) + assert( + compare( + Schema(anyOf = List(stringSchema, numberSchema, booleanSchema)), + Schema(anyOf = List(stringSchema, integerSchema)) + ) == List( + IncompatibleUnionVariant( + 1, + List( + AlternativeIssues( + List( + List(TypeMismatch(List(SchemaType.Number), List(SchemaType.String))), + List(TypeMismatch(List(SchemaType.Number), List(SchemaType.Integer))) + ) + ) + ) + ), + IncompatibleUnionVariant( + 2, + List( + AlternativeIssues( + List( + List(TypeMismatch(List(SchemaType.Boolean), List(SchemaType.String))), + List(TypeMismatch(List(SchemaType.Boolean), List(SchemaType.Integer))) + ) + ) + ) + ) + ) + ) } } diff --git a/asyncapi-circe/src/test/scala/sttp/apispec/asyncapi/circe/EncoderTest.scala b/asyncapi-circe/src/test/scala/sttp/apispec/asyncapi/circe/EncoderTest.scala index 264b3c1..9a982a8 100644 --- a/asyncapi-circe/src/test/scala/sttp/apispec/asyncapi/circe/EncoderTest.scala +++ b/asyncapi-circe/src/test/scala/sttp/apispec/asyncapi/circe/EncoderTest.scala @@ -176,7 +176,8 @@ class EncoderTest extends AnyFunSuite { contentType = Some("text/plain"), examples = List( MessageExample(None, Some(ExampleSingleValue("abc")), Some("lowercase"), Some("Lowercase letters example")), - MessageExample(None, Some(ExampleSingleValue("ABC")), Some("uppercase"), Some("Uppercase letters example"))) + MessageExample(None, Some(ExampleSingleValue("ABC")), Some("uppercase"), Some("Uppercase letters example")) + ) ) val comp = Components(messages = ListMap("string" -> Right(message))) @@ -201,13 +202,12 @@ class EncoderTest extends AnyFunSuite { val schema = Schema.oneOf( List(Schema.referenceTo("", "Dog"), Schema.referenceTo("", "Cat")), - Some(Discriminator("pet", Some(ListMap("Dog" -> "Dog", "Cat" -> "Cat"))))) + Some(Discriminator("pet", Some(ListMap("Dog" -> "Dog", "Cat" -> "Cat")))) + ) val message = SingleMessage(payload = Some(Right(schema))) assert(expected === message.asJson.deepDropNullValues) } - - def parse(s: String): Json = io.circe.parser.parse(s).fold(throw _, identity) } diff --git a/build.sbt b/build.sbt index aea9e74..2ded3e7 100644 --- a/build.sbt +++ b/build.sbt @@ -88,9 +88,9 @@ lazy val projectAggregates: Seq[ProjectReference] = if (sys.env.isDefinedAt("STT val compileAndTest = "compile->compile;test->test" lazy val rootProject = (project in file(".")) - .settings(commonSettings*) + .settings(commonSettings *) .settings(publish / skip := true, name := "sttp-apispec", scalaVersion := scala2_13) - .aggregate(projectAggregates*) + .aggregate(projectAggregates *) lazy val circeTestUtils: ProjectMatrix = (projectMatrix in file("circe-testutils")) .settings(commonSettings) @@ -282,4 +282,4 @@ lazy val openapiComparatorTests: ProjectMatrix = (projectMatrix in file("openapi scalaVersions = scalaNativeVersions, settings = commonNativeSettings ) - .dependsOn(openapiModel, openapiCirce, circeTestUtils % Test) \ No newline at end of file + .dependsOn(openapiModel, openapiCirce, circeTestUtils % Test) diff --git a/openapi-circe/src/test/scala/sttp/apispec/openapi/circe/threeone/EncoderTest.scala b/openapi-circe/src/test/scala/sttp/apispec/openapi/circe/threeone/EncoderTest.scala index 85c3a72..dd0bfed 100644 --- a/openapi-circe/src/test/scala/sttp/apispec/openapi/circe/threeone/EncoderTest.scala +++ b/openapi-circe/src/test/scala/sttp/apispec/openapi/circe/threeone/EncoderTest.scala @@ -50,25 +50,33 @@ class EncoderTest extends AnyFunSuite with ResourcePlatform { Operation( operationId = Some("getPets"), description = Some("Gets all pets") - ).addResponse(200, Response( - description = "Success", - content = ListMap("application/json" -> - MediaType(schema = Some(arrayOf(ref("#/components/schemas/Pet")))) + ).addResponse( + 200, + Response( + description = "Success", + content = ListMap( + "application/json" -> + MediaType(schema = Some(arrayOf(ref("#/components/schemas/Pet")))) + ) ) - )) + ) ) ) ) val petSchema = Schema( `type` = Some(List(SchemaType.Object)), - properties = - ListMap("id" -> Schema(`type` = Some(List(SchemaType.Integer)), format = Some("int32")), - "name" -> Schema(`type` = Some(List(SchemaType.String))) + properties = ListMap( + "id" -> Schema(`type` = Some(List(SchemaType.Integer)), format = Some("int32")), + "name" -> Schema(`type` = Some(List(SchemaType.String))) + ) + ) + val withComponents = withPathItem.components( + Components(schemas = + ListMap( + "Pet" -> petSchema ) + ) ) - val withComponents = withPathItem.components(Components(schemas = ListMap( - "Pet" -> petSchema - ))) val server = Server(url = "http://petstore.swagger.io/v1") val withServer = withComponents.servers(List(server)) val serialized = withServer.asJson @@ -87,23 +95,33 @@ class EncoderTest extends AnyFunSuite with ResourcePlatform { schemaComponent("nullable string")(Schema(SchemaType.String, SchemaType.Null)), schemaComponent("nullable reference")(Schema.referenceTo("#/components/schemas/", "Foo").nullable), schemaComponent("nullable enum")(Schema(`enum` = Some(List("a", "b", null).map(ExampleSingleValue(_))))), - schemaComponent("single example")(Schema(SchemaType.String) - .copy(examples = Some(List(ExampleSingleValue("exampleValue"))))), - schemaComponent("multi valued example")(Schema(SchemaType.Array) - .copy(examples = Some(List(ExampleMultipleValue(List("ex1", "ex1")))))), - schemaComponent("object with example")(Schema(SchemaType.Object) - .copy(examples = Some(List(ExampleSingleValue("""{"a": 1, "b": null}"""))))), - schemaComponent("min/max")(Schema( - minimum = Some(BigDecimal(10)), - maximum = Some(BigDecimal(20)), - )), - schemaComponent("exclusive min/max")(Schema( - exclusiveMinimum = Some(BigDecimal(10)), - exclusiveMaximum = Some(BigDecimal(20)), - )), + schemaComponent("single example")( + Schema(SchemaType.String) + .copy(examples = Some(List(ExampleSingleValue("exampleValue")))) + ), + schemaComponent("multi valued example")( + Schema(SchemaType.Array) + .copy(examples = Some(List(ExampleMultipleValue(List("ex1", "ex1"))))) + ), + schemaComponent("object with example")( + Schema(SchemaType.Object) + .copy(examples = Some(List(ExampleSingleValue("""{"a": 1, "b": null}""")))) + ), + schemaComponent("min/max")( + Schema( + minimum = Some(BigDecimal(10)), + maximum = Some(BigDecimal(20)) + ) + ), + schemaComponent("exclusive min/max")( + Schema( + exclusiveMinimum = Some(BigDecimal(10)), + exclusiveMaximum = Some(BigDecimal(20)) + ) + ), schemaComponent("exclusiveMinimum false")(Schema(minimum = Some(BigDecimal(10)))), schemaComponent("array")(Schema(SchemaType.Array).copy(items = Some(Schema(SchemaType.String)))), - schemaComponent("array with unique items")(Schema(SchemaType.Array).copy(uniqueItems = Some(true))), + schemaComponent("array with unique items")(Schema(SchemaType.Array).copy(uniqueItems = Some(true))) ) ) @@ -117,13 +135,17 @@ class EncoderTest extends AnyFunSuite with ResourcePlatform { import sttp.apispec.openapi.circe._ val schemas31 = ListMap( - schemaComponent("multiple examples")(Schema(SchemaType.String) - .copy(examples = Some(List("ex1", "ex2").map(ExampleSingleValue(_))))), + schemaComponent("multiple examples")( + Schema(SchemaType.String) + .copy(examples = Some(List("ex1", "ex2").map(ExampleSingleValue(_)))) + ) ) - val openApiJson = fullSchemaOpenApi.copy( - components = fullSchemaOpenApi.components.map(c => c.copy(schemas = c.schemas ++ schemas31)) - ).asJson + val openApiJson = fullSchemaOpenApi + .copy( + components = fullSchemaOpenApi.components.map(c => c.copy(schemas = c.schemas ++ schemas31)) + ) + .asJson val Right(json) = readJson("/spec/3.1/schema.json"): @unchecked assert(openApiJson.spaces2SortKeys == json.spaces2SortKeys) @@ -150,10 +172,9 @@ class EncoderTest extends AnyFunSuite with ResourcePlatform { ) ) ) - ), + ) ) - test("encode security scheme with empty scopes") { import sttp.apispec.openapi.circe._