From 27625f52d539e6ae47a23592acc5b1ecad00a6a5 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Thu, 21 Sep 2023 21:01:48 -0500 Subject: [PATCH 1/7] propagate nullability from subschemas where appropriate. --- .../OpenAPIKit/Schema Object/JSONSchema.swift | 51 ++++++++- .../Schema Object/JSONSchemaTests.swift | 103 ++++++++++++++++++ 2 files changed, 150 insertions(+), 4 deletions(-) diff --git a/Sources/OpenAPIKit/Schema Object/JSONSchema.swift b/Sources/OpenAPIKit/Schema Object/JSONSchema.swift index 0498ba1bb..23003eee5 100644 --- a/Sources/OpenAPIKit/Schema Object/JSONSchema.swift +++ b/Sources/OpenAPIKit/Schema Object/JSONSchema.swift @@ -389,6 +389,29 @@ extension JSONSchema { } return context } + + /// Get subschemas if this schema is an anyOf, allOf, etc. + /// Returns an empty array for any schema that does not have + /// subschemas. + /// + /// - IMPORTANT: An object's properties are NOT considered + /// subschemas. + public var subschemas: [JSONSchema] { + switch self.value { + case .not(let schema, core: _): + return [schema] + case .array(_, let arrayContext): + return arrayContext.items.map { [$0] } ?? [] + case .all(of: let schemas, core: _): + return schemas + case .any(of: let schemas, core: _): + return schemas + case .one(of: let schemas, core: _): + return schemas + default: + return [] + } + } } // MARK: - Vendor Extensions @@ -1778,34 +1801,54 @@ extension JSONSchema: Decodable { let container = try decoder.container(keyedBy: SubschemaCodingKeys.self) if container.contains(.allOf) { - self = .all( + var schema: JSONSchema = .all( of: try container.decode([JSONSchema].self, forKey: .allOf), core: try CoreContext(from: decoder) ) + if schema.subschemas.contains(where: { $0.nullable }) { + schema = schema.nullableSchemaObject() + } + + self = schema return } if container.contains(.anyOf) { - self = .any( + var schema: JSONSchema = .any( of: try container.decode([JSONSchema].self, forKey: .anyOf), core: try CoreContext(from: decoder) ) + if schema.subschemas.contains(where: { $0.nullable }) { + schema = schema.nullableSchemaObject() + } + + self = schema return } if container.contains(.oneOf) { - self = .one( + var schema: JSONSchema = .one( of: try container.decode([JSONSchema].self, forKey: .oneOf), core: try CoreContext(from: decoder) ) + if schema.subschemas.contains(where: { $0.nullable }) { + schema = schema.nullableSchemaObject() + } + + self = schema return } if container.contains(.not) { - self = .not( + var schema: JSONSchema = .not( try container.decode(JSONSchema.self, forKey: .not), core: try CoreContext(from: decoder) ) + if schema.subschemas.contains(where: { $0.nullable }) { + schema = schema.requiredSchemaObject() + } + + self = schema return } diff --git a/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift index c1d7af681..e03207cbc 100644 --- a/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift @@ -917,6 +917,38 @@ final class SchemaObjectTests: XCTestCase { XCTAssertNil(null.stringContext) } + func test_subschemasAccessor() { + let null = JSONSchema.null() + let boolean = JSONSchema.boolean(.init(format: .unspecified, required: true)) + let object = JSONSchema.object(.init(format: .unspecified, required: true), .init(properties: [:])) + let array = JSONSchema.array(.init(format: .unspecified, required: true), .init(items: .boolean)) + let number = JSONSchema.number(.init(format: .unspecified, required: true), .init()) + let integer = JSONSchema.integer(.init(format: .unspecified, required: true), .init()) + let string = JSONSchema.string(.init(format: .unspecified, required: true), .init(maxLength: 5)) + + let allOf = JSONSchema.all(of: [.string(.init(), .init())]) + let anyOf = JSONSchema.any(of: [boolean]) + let oneOf = JSONSchema.one(of: [boolean]) + let not = JSONSchema.not(boolean) + let reference = JSONSchema.reference(.external(URL(string: "hello/world.json#/hello")!)) + let fragment = JSONSchema.fragment(.init(description: "hello world")) + + XCTAssertEqual(boolean.subschemas, []) + XCTAssertEqual(object.subschemas, []) + XCTAssertEqual(array.subschemas, [.boolean]) + XCTAssertEqual(number.subschemas, []) + XCTAssertEqual(integer.subschemas, []) + XCTAssertEqual(string.subschemas, []) + + XCTAssertEqual(allOf.subschemas, [.string]) + XCTAssertEqual(anyOf.subschemas, [.boolean]) + XCTAssertEqual(oneOf.subschemas, [.boolean]) + XCTAssertEqual(not.subschemas, [.boolean]) + XCTAssertEqual(reference.subschemas, []) + XCTAssertEqual(fragment.subschemas, []) + XCTAssertEqual(null.subschemas, []) + } + func test_numericContextFromIntegerContext() { let i1 = JSONSchema.IntegerContext(multipleOf: 2) let i2 = JSONSchema.IntegerContext(maximum: (10, exclusive: false)) @@ -5209,6 +5241,15 @@ extension SchemaObjectTests { } """.data(using: .utf8)! + let allWithNullableSchemaData = """ + { + "allOf": [ + { "type": "string" }, + { "type": "null" } + ] + } + """.data(using: .utf8)! + let nestedOptionalAllData = """ { "type": "object", @@ -5228,6 +5269,7 @@ extension SchemaObjectTests { let allWithDiscriminator = try orderUnstableDecode(JSONSchema.self, from: allWithDiscriminatorData) let allWithReference = try orderUnstableDecode(JSONSchema.self, from: allWithReferenceData) let allWithReferenceAndDescription = try orderUnstableDecode(JSONSchema.self, from: allWithReferenceAndDescriptionData) + let allWithNullableSchema = try orderUnstableDecode(JSONSchema.self, from: allWithNullableSchemaData) let nestedOptionalAll = try orderUnstableDecode(JSONSchema.self, from: nestedOptionalAllData) XCTAssertEqual( @@ -5282,6 +5324,17 @@ extension SchemaObjectTests { ) ) + XCTAssertEqual( + allWithNullableSchema, + JSONSchema.all( + of: [ + .string(), + .null() + ], + core: .init(nullable: true) + ) + ) + XCTAssertEqual( nestedOptionalAll, JSONSchema.object( @@ -5453,10 +5506,20 @@ extension SchemaObjectTests { } """.data(using: .utf8)! + let oneWithNullableSchemaData = """ + { + "allOf": [ + { "type": "string" }, + { "type": "null" } + ] + } + """.data(using: .utf8)! + let one = try orderUnstableDecode(JSONSchema.self, from: oneData) let oneWithTitle = try orderUnstableDecode(JSONSchema.self, from: oneWithTitleData) let oneWithDiscriminator = try orderUnstableDecode(JSONSchema.self, from: oneWithDiscriminatorData) let oneWithReference = try orderUnstableDecode(JSONSchema.self, from: oneWithReferenceData) + let oneWithNullableSchema = try orderUnstableDecode(JSONSchema.self, from: oneWithNullableSchemaData) XCTAssertEqual( one, @@ -5499,6 +5562,17 @@ extension SchemaObjectTests { ] ) ) + + XCTAssertEqual( + oneWithNullableSchema, + JSONSchema.one( + of: [ + .string(), + .null() + ], + core: .init(nullable: true) + ) + ) } func test_encodeAny() { @@ -5659,10 +5733,20 @@ extension SchemaObjectTests { } """.data(using: .utf8)! + let anyWithNullableSchemaData = """ + { + "anyOf": [ + { "type": "string" }, + { "type": "null" } + ] + } + """.data(using: .utf8)! + let any = try orderUnstableDecode(JSONSchema.self, from: anyData) let anyWithTitle = try orderUnstableDecode(JSONSchema.self, from: anyWithTitleData) let anyWithDiscriminator = try orderUnstableDecode(JSONSchema.self, from: anyWithDiscriminatorData) let anyWithReference = try orderUnstableDecode(JSONSchema.self, from: anyWithReferenceData) + let anyWithNullableSchema = try orderUnstableDecode(JSONSchema.self, from: anyWithNullableSchemaData) XCTAssertEqual( any, @@ -5705,6 +5789,17 @@ extension SchemaObjectTests { ] ) ) + + XCTAssertEqual( + anyWithNullableSchema, + JSONSchema.any( + of: [ + .string(), + .null() + ], + core: .init(nullable: true) + ) + ) } func test_encodeNot() { @@ -5765,11 +5860,19 @@ extension SchemaObjectTests { } """.data(using: .utf8)! + let notWithNullableSchemaData = """ + { + "not": { "type": [ "string", "null" ] } + } + """.data(using: .utf8)! + let not = try orderUnstableDecode(JSONSchema.self, from: notData) let notWithTitle = try orderUnstableDecode(JSONSchema.self, from: notWithTitleData) + let notWithNullableSchema = try orderUnstableDecode(JSONSchema.self, from: notWithNullableSchemaData) XCTAssertEqual(not, JSONSchema.not(.boolean(.init(format: .generic)))) XCTAssertEqual(notWithTitle, JSONSchema.not(.boolean(.init(format: .generic)), core: .init(title: "hello"))) + XCTAssertEqual(notWithNullableSchema, JSONSchema.not(.string(nullable: true), core: .init(nullable: false))) } func test_encodeFileReference() { From 8889552233ad944511b3c6dd1287dbdc7ae3ffc5 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Thu, 21 Sep 2023 21:14:48 -0500 Subject: [PATCH 2/7] propagate nullable from child schemas for openapikit30 module --- .../Schema Object/JSONSchema.swift | 51 ++++++++- .../Schema Object/JSONSchemaTests.swift | 101 ++++++++++++++++++ 2 files changed, 148 insertions(+), 4 deletions(-) diff --git a/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift b/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift index 6281f273e..dd791c998 100644 --- a/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift +++ b/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift @@ -425,6 +425,29 @@ extension JSONSchema { } return context } + + /// Get subschemas if this schema is an anyOf, allOf, etc. + /// Returns an empty array for any schema that does not have + /// subschemas. + /// + /// - IMPORTANT: An object's properties are NOT considered + /// subschemas. + public var subschemas: [JSONSchema] { + switch self.value { + case .not(let schema, core: _): + return [schema] + case .array(_, let arrayContext): + return arrayContext.items.map { [$0] } ?? [] + case .all(of: let schemas, core: _): + return schemas + case .any(of: let schemas, core: _): + return schemas + case .one(of: let schemas, core: _): + return schemas + default: + return [] + } + } } // MARK: - Transformations @@ -1725,34 +1748,54 @@ extension JSONSchema: Decodable { let container = try decoder.container(keyedBy: SubschemaCodingKeys.self) if container.contains(.allOf) { - self = .all( + var schema: JSONSchema = .all( of: try container.decode([JSONSchema].self, forKey: .allOf), core: try CoreContext(from: decoder) ) + if schema.subschemas.contains(where: { $0.nullable }) { + schema = schema.nullableSchemaObject() + } + + self = schema return } if container.contains(.anyOf) { - self = .any( + var schema: JSONSchema = .any( of: try container.decode([JSONSchema].self, forKey: .anyOf), core: try CoreContext(from: decoder) ) + if schema.subschemas.contains(where: { $0.nullable }) { + schema = schema.nullableSchemaObject() + } + + self = schema return } if container.contains(.oneOf) { - self = .one( + var schema: JSONSchema = .one( of: try container.decode([JSONSchema].self, forKey: .oneOf), core: try CoreContext(from: decoder) ) + if schema.subschemas.contains(where: { $0.nullable }) { + schema = schema.nullableSchemaObject() + } + + self = schema return } if container.contains(.not) { - self = .not( + var schema: JSONSchema = .not( try container.decode(JSONSchema.self, forKey: .not), core: try CoreContext(from: decoder) ) + if schema.subschemas.contains(where: { $0.nullable }) { + schema = schema.nullableSchemaObject() + } + + self = schema return } diff --git a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift index e655d95df..9eaf8e064 100644 --- a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift @@ -858,6 +858,36 @@ final class SchemaObjectTests: XCTestCase { XCTAssertNil(fragment.stringContext) } + func test_subschemasAccessor() { + let boolean = JSONSchema.boolean(.init(format: .unspecified, required: true)) + let object = JSONSchema.object(.init(format: .unspecified, required: true), .init(properties: [:])) + let array = JSONSchema.array(.init(format: .unspecified, required: true), .init(items: .boolean)) + let number = JSONSchema.number(.init(format: .unspecified, required: true), .init()) + let integer = JSONSchema.integer(.init(format: .unspecified, required: true), .init()) + let string = JSONSchema.string(.init(format: .unspecified, required: true), .init(maxLength: 5)) + + let allOf = JSONSchema.all(of: [.string(.init(), .init())]) + let anyOf = JSONSchema.any(of: [boolean]) + let oneOf = JSONSchema.one(of: [boolean]) + let not = JSONSchema.not(boolean) + let reference = JSONSchema.reference(.external(URL(string: "hello/world.json#/hello")!)) + let fragment = JSONSchema.fragment(.init(description: "hello world")) + + XCTAssertEqual(boolean.subschemas, []) + XCTAssertEqual(object.subschemas, []) + XCTAssertEqual(array.subschemas, [.boolean]) + XCTAssertEqual(number.subschemas, []) + XCTAssertEqual(integer.subschemas, []) + XCTAssertEqual(string.subschemas, []) + + XCTAssertEqual(allOf.subschemas, [.string]) + XCTAssertEqual(anyOf.subschemas, [.boolean]) + XCTAssertEqual(oneOf.subschemas, [.boolean]) + XCTAssertEqual(not.subschemas, [.boolean]) + XCTAssertEqual(reference.subschemas, []) + XCTAssertEqual(fragment.subschemas, []) + } + func test_numericContextFromIntegerContext() { let i1 = JSONSchema.IntegerContext(multipleOf: 2) let i2 = JSONSchema.IntegerContext(maximum: (10, exclusive: false)) @@ -4812,6 +4842,15 @@ extension SchemaObjectTests { } """.data(using: .utf8)! + let allWithNullableSchemaData = """ + { + "allOf": [ + { "type": "string" }, + { "type": "number", "nullable": true } + ] + } + """.data(using: .utf8)! + let nestedOptionalAllData = """ { "type": "object", @@ -4831,6 +4870,7 @@ extension SchemaObjectTests { let allWithDiscriminator = try orderUnstableDecode(JSONSchema.self, from: allWithDiscriminatorData) let allWithReference = try orderUnstableDecode(JSONSchema.self, from: allWithReferenceData) let allWithReferenceAndDescription = try orderUnstableDecode(JSONSchema.self, from: allWithReferenceAndDescriptionData) + let allWithNullableSchema = try orderUnstableDecode(JSONSchema.self, from: allWithNullableSchemaData) let nestedOptionalAll = try orderUnstableDecode(JSONSchema.self, from: nestedOptionalAllData) XCTAssertEqual( @@ -4885,6 +4925,17 @@ extension SchemaObjectTests { ) ) + XCTAssertEqual( + allWithNullableSchema, + JSONSchema.all( + of: [ + .string(), + .integer(nullable: true) + ], + core: .init(nullable: true) + ) + ) + XCTAssertEqual( nestedOptionalAll, JSONSchema.object( @@ -5056,10 +5107,20 @@ extension SchemaObjectTests { } """.data(using: .utf8)! + let oneWithNullableSchemaData = """ + { + "allOf": [ + { "type": "string" }, + { "type": "number", "nullable": true } + ] + } + """.data(using: .utf8)! + let one = try orderUnstableDecode(JSONSchema.self, from: oneData) let oneWithTitle = try orderUnstableDecode(JSONSchema.self, from: oneWithTitleData) let oneWithDiscriminator = try orderUnstableDecode(JSONSchema.self, from: oneWithDiscriminatorData) let oneWithReference = try orderUnstableDecode(JSONSchema.self, from: oneWithReferenceData) + let oneWithNullableSchema = try orderUnstableDecode(JSONSchema.self, from: oneWithNullableSchemaData) XCTAssertEqual( one, @@ -5102,6 +5163,17 @@ extension SchemaObjectTests { ] ) ) + + XCTAssertEqual( + oneWithNullableSchema, + JSONSchema.one( + of: [ + .string(), + .number(nullable: true) + ], + core: .init(nullable: true) + ) + ) } func test_encodeAny() { @@ -5262,10 +5334,20 @@ extension SchemaObjectTests { } """.data(using: .utf8)! + let anyWithNullableSchemaData = """ + { + "anyOf": [ + { "type": "string" }, + { "type": "number", "nullable": true } + ] + } + """.data(using: .utf8)! + let any = try orderUnstableDecode(JSONSchema.self, from: anyData) let anyWithTitle = try orderUnstableDecode(JSONSchema.self, from: anyWithTitleData) let anyWithDiscriminator = try orderUnstableDecode(JSONSchema.self, from: anyWithDiscriminatorData) let anyWithReference = try orderUnstableDecode(JSONSchema.self, from: anyWithReferenceData) + let anyWithNullableSchema = try orderUnstableDecode(JSONSchema.self, from: anyWithNullableSchemaData) XCTAssertEqual( any, @@ -5308,6 +5390,17 @@ extension SchemaObjectTests { ] ) ) + + XCTAssertEqual( + anyWithNullableSchema, + JSONSchema.any( + of: [ + .string(), + .number(nullable: true) + ], + core: .init(nullable: true) + ) + ) } func test_encodeNot() { @@ -5368,11 +5461,19 @@ extension SchemaObjectTests { } """.data(using: .utf8)! + let notWithNullableSchemaData = """ + { + "not": { "type": "string", "nullable": true } + } + """.data(using: .utf8)! + let not = try orderUnstableDecode(JSONSchema.self, from: notData) let notWithTitle = try orderUnstableDecode(JSONSchema.self, from: notWithTitleData) + let notWithNullableSchema = try orderUnstableDecode(JSONSchema.self, from: notWithNullableSchemaData) XCTAssertEqual(not, JSONSchema.not(.boolean(.init(format: .generic)))) XCTAssertEqual(notWithTitle, JSONSchema.not(.boolean(.init(format: .generic)), core: .init(title: "hello"))) + XCTAssertEqual(notWithNullableSchema, JSONSchema.not(.string(nullable: true), core: .init(nullable: false))) } func test_encodeFileReference() { From 5c6defb0acd073b7a6f86f3eba9206715974d7cd Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Thu, 21 Sep 2023 21:34:49 -0500 Subject: [PATCH 3/7] work with out of order decoding --- .../Schema Object/JSONSchemaTests.swift | 12 ++++-- .../Schema Object/JSONSchemaTests.swift | 38 ++++++++++++++----- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift index 9eaf8e064..aae7e5ac7 100644 --- a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift @@ -5164,15 +5164,21 @@ extension SchemaObjectTests { ) ) - XCTAssertEqual( - oneWithNullableSchema, - JSONSchema.one( + XCTAssertTrue( + oneWithNullableSchema == JSONSchema.one( of: [ .string(), .number(nullable: true) ], core: .init(nullable: true) ) + || oneWithNullableSchema == JSONSchema.one( + of: [ + .number(nullable: true), + .string() + ], + core: .init(nullable: true) + ) ) } diff --git a/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift index e03207cbc..1091836e0 100644 --- a/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift @@ -5324,15 +5324,21 @@ extension SchemaObjectTests { ) ) - XCTAssertEqual( - allWithNullableSchema, - JSONSchema.all( + XCTAssertTrue( + allWithNullableSchema == JSONSchema.all( of: [ .string(), .null() ], core: .init(nullable: true) ) + || allWithNullableSchema == JSONSchema.all( + of: [ + .null(), + .string() + ], + core: .init(nullable: true) + ) ) XCTAssertEqual( @@ -5508,7 +5514,7 @@ extension SchemaObjectTests { let oneWithNullableSchemaData = """ { - "allOf": [ + "oneOf": [ { "type": "string" }, { "type": "null" } ] @@ -5563,15 +5569,21 @@ extension SchemaObjectTests { ) ) - XCTAssertEqual( - oneWithNullableSchema, - JSONSchema.one( + XCTAssertTrue( + oneWithNullableSchema == JSONSchema.one( of: [ .string(), .null() ], core: .init(nullable: true) ) + || oneWithNullableSchema == JSONSchema.one( + of: [ + .null(), + .string() + ], + core: .init(nullable: true) + ) ) } @@ -5790,15 +5802,21 @@ extension SchemaObjectTests { ) ) - XCTAssertEqual( - anyWithNullableSchema, - JSONSchema.any( + XCTAssertTrue( + anyWithNullableSchema == JSONSchema.any( of: [ .string(), .null() ], core: .init(nullable: true) ) + || anyWithNullableSchema == JSONSchema.any( + of: [ + .null(), + .string() + ], + core: .init(nullable: true) + ) ) } From 311c586db5bfc21261133280773b4b945367ba99 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Thu, 21 Sep 2023 21:40:45 -0500 Subject: [PATCH 4/7] fix two typos --- Sources/OpenAPIKit30/Schema Object/JSONSchema.swift | 2 +- Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift b/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift index dd791c998..8568794a8 100644 --- a/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift +++ b/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift @@ -1792,7 +1792,7 @@ extension JSONSchema: Decodable { core: try CoreContext(from: decoder) ) if schema.subschemas.contains(where: { $0.nullable }) { - schema = schema.nullableSchemaObject() + schema = schema.requiredSchemaObject() } self = schema diff --git a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift index aae7e5ac7..d16d44f9b 100644 --- a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift @@ -5109,7 +5109,7 @@ extension SchemaObjectTests { let oneWithNullableSchemaData = """ { - "allOf": [ + "oneOf": [ { "type": "string" }, { "type": "number", "nullable": true } ] From 02cb7d908f0a1073b9d47da596ef59e3d05fd37d Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Thu, 21 Sep 2023 21:49:19 -0500 Subject: [PATCH 5/7] realize mistake that I was conflating required with nonnullable for not schemas. --- .../OpenAPIKit/Schema Object/JSONSchema.swift | 5 +---- .../OpenAPIKit30/Schema Object/JSONSchema.swift | 5 +---- .../Schema Object/JSONSchemaTests.swift | 16 +++++++++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Sources/OpenAPIKit/Schema Object/JSONSchema.swift b/Sources/OpenAPIKit/Schema Object/JSONSchema.swift index 23003eee5..f49fe06f8 100644 --- a/Sources/OpenAPIKit/Schema Object/JSONSchema.swift +++ b/Sources/OpenAPIKit/Schema Object/JSONSchema.swift @@ -1840,13 +1840,10 @@ extension JSONSchema: Decodable { } if container.contains(.not) { - var schema: JSONSchema = .not( + let schema: JSONSchema = .not( try container.decode(JSONSchema.self, forKey: .not), core: try CoreContext(from: decoder) ) - if schema.subschemas.contains(where: { $0.nullable }) { - schema = schema.requiredSchemaObject() - } self = schema return diff --git a/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift b/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift index 8568794a8..25cdece8b 100644 --- a/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift +++ b/Sources/OpenAPIKit30/Schema Object/JSONSchema.swift @@ -1787,13 +1787,10 @@ extension JSONSchema: Decodable { } if container.contains(.not) { - var schema: JSONSchema = .not( + let schema: JSONSchema = .not( try container.decode(JSONSchema.self, forKey: .not), core: try CoreContext(from: decoder) ) - if schema.subschemas.contains(where: { $0.nullable }) { - schema = schema.requiredSchemaObject() - } self = schema return diff --git a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift index d16d44f9b..dd168a89a 100644 --- a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift @@ -4925,12 +4925,18 @@ extension SchemaObjectTests { ) ) - XCTAssertEqual( - allWithNullableSchema, - JSONSchema.all( + XCTAssertTrue( + allWithNullableSchema == JSONSchema.all( of: [ .string(), - .integer(nullable: true) + .number(nullable: true) + ], + core: .init(nullable: true) + ) + || allWithNullableSchema == JSONSchema.all( + of: [ + .number(nullable: true), + .string() ], core: .init(nullable: true) ) @@ -5479,7 +5485,7 @@ extension SchemaObjectTests { XCTAssertEqual(not, JSONSchema.not(.boolean(.init(format: .generic)))) XCTAssertEqual(notWithTitle, JSONSchema.not(.boolean(.init(format: .generic)), core: .init(title: "hello"))) - XCTAssertEqual(notWithNullableSchema, JSONSchema.not(.string(nullable: true), core: .init(nullable: false))) + XCTAssertEqual(notWithNullableSchema, JSONSchema.not(.string(nullable: true), core: .init())) } func test_encodeFileReference() { From 29b829b5d404dde46d4fce5b3a9589f1b9431234 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Thu, 21 Sep 2023 21:53:21 -0500 Subject: [PATCH 6/7] one more order-independant test --- .../Schema Object/JSONSchemaTests.swift | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift index dd168a89a..074ca02a1 100644 --- a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift @@ -5403,15 +5403,21 @@ extension SchemaObjectTests { ) ) - XCTAssertEqual( - anyWithNullableSchema, - JSONSchema.any( + XCTAssertTrue( + anyWithNullableSchema == JSONSchema.any( of: [ .string(), .number(nullable: true) ], core: .init(nullable: true) ) + || anyWithNullableSchema == JSONSchema.any( + of: [ + .number(nullable: true), + .string() + ], + core: .init(nullable: true) + ) ) } From 2606f62ecfc575de26edfec1fbbb8744c5e81257 Mon Sep 17 00:00:00 2001 From: Mathew Polzin Date: Fri, 22 Sep 2023 08:26:58 -0500 Subject: [PATCH 7/7] undo workaround. ordering was not the issue. --- .../Schema Object/JSONSchemaTests.swift | 36 +++++-------------- .../Schema Object/JSONSchemaTests.swift | 36 +++++-------------- 2 files changed, 18 insertions(+), 54 deletions(-) diff --git a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift index 074ca02a1..401ca78fb 100644 --- a/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKit30Tests/Schema Object/JSONSchemaTests.swift @@ -4925,21 +4925,15 @@ extension SchemaObjectTests { ) ) - XCTAssertTrue( - allWithNullableSchema == JSONSchema.all( + XCTAssertEqual( + allWithNullableSchema, + JSONSchema.all( of: [ .string(), .number(nullable: true) ], core: .init(nullable: true) ) - || allWithNullableSchema == JSONSchema.all( - of: [ - .number(nullable: true), - .string() - ], - core: .init(nullable: true) - ) ) XCTAssertEqual( @@ -5170,21 +5164,15 @@ extension SchemaObjectTests { ) ) - XCTAssertTrue( - oneWithNullableSchema == JSONSchema.one( + XCTAssertEqual( + oneWithNullableSchema, + JSONSchema.one( of: [ .string(), .number(nullable: true) ], core: .init(nullable: true) ) - || oneWithNullableSchema == JSONSchema.one( - of: [ - .number(nullable: true), - .string() - ], - core: .init(nullable: true) - ) ) } @@ -5403,21 +5391,15 @@ extension SchemaObjectTests { ) ) - XCTAssertTrue( - anyWithNullableSchema == JSONSchema.any( + XCTAssertEqual( + anyWithNullableSchema, + JSONSchema.any( of: [ .string(), .number(nullable: true) ], core: .init(nullable: true) ) - || anyWithNullableSchema == JSONSchema.any( - of: [ - .number(nullable: true), - .string() - ], - core: .init(nullable: true) - ) ) } diff --git a/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift b/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift index 1091836e0..99b130641 100644 --- a/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift +++ b/Tests/OpenAPIKitTests/Schema Object/JSONSchemaTests.swift @@ -5324,21 +5324,15 @@ extension SchemaObjectTests { ) ) - XCTAssertTrue( - allWithNullableSchema == JSONSchema.all( + XCTAssertEqual( + allWithNullableSchema, + JSONSchema.all( of: [ .string(), .null() ], core: .init(nullable: true) ) - || allWithNullableSchema == JSONSchema.all( - of: [ - .null(), - .string() - ], - core: .init(nullable: true) - ) ) XCTAssertEqual( @@ -5569,21 +5563,15 @@ extension SchemaObjectTests { ) ) - XCTAssertTrue( - oneWithNullableSchema == JSONSchema.one( + XCTAssertEqual( + oneWithNullableSchema, + JSONSchema.one( of: [ .string(), .null() ], core: .init(nullable: true) ) - || oneWithNullableSchema == JSONSchema.one( - of: [ - .null(), - .string() - ], - core: .init(nullable: true) - ) ) } @@ -5802,21 +5790,15 @@ extension SchemaObjectTests { ) ) - XCTAssertTrue( - anyWithNullableSchema == JSONSchema.any( + XCTAssertEqual( + anyWithNullableSchema, + JSONSchema.any( of: [ .string(), .null() ], core: .init(nullable: true) ) - || anyWithNullableSchema == JSONSchema.any( - of: [ - .null(), - .string() - ], - core: .init(nullable: true) - ) ) }