diff --git a/src/change.rs b/src/change.rs index e29b3cf..c1526d3 100644 --- a/src/change.rs +++ b/src/change.rs @@ -55,10 +55,31 @@ pub enum ChangeComparison { #[derive(Debug)] pub enum ChangeClass { + /// This change is backward incompatible. A client on the old version may + /// not be able to communicate with a server on the new version. + /// + /// This represents an input type becoming more restricted (so an old client + /// can send request data that a new server will reject), or an output type + /// becoming less restricted (so a new server can send response data that an + /// old client will reject). BackwardIncompatible, + /// This change is forward incompatible. A server on the old version may + /// not be able to communicate with a client on the new version. + /// + /// This represents an input type becoming less restricted (so a new client + /// can send request data that an old server will reject), or an output type + /// becoming more restricted (so an old server can send response data that a + /// new client will reject). ForwardIncompatible, + /// This change is bidirectionally incompatible. A server on the old version + /// may not be able to communicate with a client on the new version, and + /// vice versa. Incompatible, + /// This change is trivial (e.g., metadata changed). Servers and clients + /// across versions will not be affected. Trivial, + /// This change is not handled by `drift` yet, and it should be assumed to + /// be bidirectionally incompatible. Unhandled, } diff --git a/src/schema.rs b/src/schema.rs index 133c978..044943f 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -17,6 +17,21 @@ pub(crate) enum SchemaComparison { Output, } +/// Controls whether effective nullability should be checked at this point. +/// +/// Effective nullability is a property of the entire schema ref chain +/// (wrapper.nullable || inner.effective_nullable). We check it once at +/// comparison entry points (response schemas, request bodies, properties, etc.) +/// but not when traversing through wrapper structures. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum EffectiveNullableCheck { + /// This is a comparison entry point; check effective nullability. + Entry, + /// We're traversing through a wrapper; effective nullability was already + /// checked at the entry point. + WrapperTraversal, +} + impl From for ChangeComparison { fn from(value: SchemaComparison) -> Self { match value { @@ -37,6 +52,11 @@ impl Compare { Ok(()) } + /// Compare two schema references. This is the main entry point for schema + /// comparison, used for response schemas, request bodies, properties, array + /// items, etc. + /// + /// Always checks effective nullability at this level. fn compare_schema_ref_helper( &mut self, dry_run: bool, @@ -44,6 +64,32 @@ impl Compare { old_schema: Contextual<'_, &ReferenceOr>, new_schema: Contextual<'_, &ReferenceOr>, ) -> anyhow::Result { + self.compare_schema_ref_inner( + dry_run, + comparison, + EffectiveNullableCheck::Entry, + old_schema, + new_schema, + ) + } + + /// Inner implementation of schema ref comparison with explicit nullable + /// check control. + fn compare_schema_ref_inner( + &mut self, + dry_run: bool, + comparison: SchemaComparison, + nullable_check: EffectiveNullableCheck, + old_schema: Contextual<'_, &ReferenceOr>, + new_schema: Contextual<'_, &ReferenceOr>, + ) -> anyhow::Result { + // At entry points, check effective nullability before any structural + // comparison. This handles nullable changes through wrapper chains. + if nullable_check == EffectiveNullableCheck::Entry { + let _ = + self.compare_effective_nullable(dry_run, comparison, &old_schema, &new_schema)?; + } + // Handle single-element wrappers: allOf/anyOf/oneOf with one item. // These are semantically equivalent to their inner type. // @@ -55,11 +101,11 @@ impl Compare { Ok(result) } else { // General path: resolve and compare. - let (old_schema, old_context) = old_schema.contextual_resolve()?; - let (new_schema, new_context) = new_schema.contextual_resolve()?; + let (old_resolved, old_context) = old_schema.contextual_resolve()?; + let (new_resolved, new_context) = new_schema.contextual_resolve()?; - let old_schema = Contextual::new(old_context, old_schema.as_ref()); - let new_schema = Contextual::new(new_context, new_schema.as_ref()); + let old_schema = Contextual::new(old_context, old_resolved.as_ref()); + let new_schema = Contextual::new(new_context, new_resolved.as_ref()); self.compare_schema(comparison, dry_run, old_schema, new_schema) } @@ -93,7 +139,8 @@ impl Compare { }, ) => { // Both old and new are single-element wrappers. - if old_meta != new_meta { + // Effective nullability is checked at the entry point, not here. + if has_non_nullable_metadata_diff(old_meta, new_meta) { self.push_change( "schema metadata changed", old_schema, @@ -105,8 +152,12 @@ impl Compare { } let old_inner = old_schema.append_deref(old_inner, "0"); let new_inner = new_schema.append_deref(new_inner, "0"); - Ok(Some(self.compare_schema_ref_helper( - dry_run, comparison, old_inner, new_inner, + Ok(Some(self.compare_schema_ref_inner( + dry_run, + comparison, + EffectiveNullableCheck::WrapperTraversal, + old_inner, + new_inner, )?)) } ( @@ -117,11 +168,8 @@ impl Compare { BareRef | InlineType, ) => { // Old is a single-element wrapper, new is a bare ref or inline - // type. - // - // A bare ref or inline type does not have metadata, so if the - // old metadata is non-default, report a trivial change. - if has_meaningful_metadata(old_meta) { + // type. Effective nullability is checked at the entry point. + if has_meaningful_non_nullable_metadata(old_meta) { self.push_change( "schema metadata removed", old_schema, @@ -132,9 +180,10 @@ impl Compare { ); } let old_inner = old_schema.append_deref(old_inner, "0"); - Ok(Some(self.compare_schema_ref_helper( + Ok(Some(self.compare_schema_ref_inner( dry_run, comparison, + EffectiveNullableCheck::WrapperTraversal, old_inner, new_schema.clone(), )?)) @@ -147,11 +196,8 @@ impl Compare { }, ) => { // Old is a bare ref or inline type, new is a single-element - // wrapper. - // - // A bare ref or inline type does not have metadata, so if the - // new metadata is non-default, report a trivial change. - if has_meaningful_metadata(new_meta) { + // wrapper. Effective nullability is checked at the entry point. + if has_meaningful_non_nullable_metadata(new_meta) { self.push_change( "schema metadata added", old_schema, @@ -162,9 +208,10 @@ impl Compare { ); } let new_inner = new_schema.append_deref(new_inner, "0"); - Ok(Some(self.compare_schema_ref_helper( + Ok(Some(self.compare_schema_ref_inner( dry_run, comparison, + EffectiveNullableCheck::WrapperTraversal, old_schema.clone(), new_inner, )?)) @@ -179,6 +226,62 @@ impl Compare { } } + /// Compare effective nullability of two schema references. + /// + /// Effective nullability is `wrapper.nullable || inner.effective_nullable` + /// for single-element wrappers, or just `schema.nullable` for terminal + /// schemas. + /// + /// This is called at comparison entry points (response schemas, request + /// bodies, properties, etc.) to detect nullable changes through wrapper + /// chains. + fn compare_effective_nullable( + &mut self, + dry_run: bool, + comparison: SchemaComparison, + old_schema: &Contextual<'_, &ReferenceOr>, + new_schema: &Contextual<'_, &ReferenceOr>, + ) -> anyhow::Result { + use EffectiveNullability::*; + + let old_nullable = get_effective_nullable(old_schema)?; + let new_nullable = get_effective_nullable(new_schema)?; + + let (message, class, details) = match (old_nullable, new_nullable) { + (NotNullable, NotNullable) | (Nullable(_), Nullable(_)) => { + return Ok(true); + } + (NotNullable, Nullable(kind)) => { + // non-nullable → nullable + let message = match kind { + NullabilityKind::Wrapper => "nullable added at wrapper", + NullabilityKind::Direct => "schema became nullable", + }; + let class = match comparison { + SchemaComparison::Input => ChangeClass::ForwardIncompatible, + SchemaComparison::Output => ChangeClass::BackwardIncompatible, + }; + (message, class, ChangeDetails::LessStrict) + } + (Nullable(kind), NotNullable) => { + // nullable → non-nullable + let message = match kind { + NullabilityKind::Wrapper => "nullable removed from wrapper", + NullabilityKind::Direct => "schema became non-nullable", + }; + let class = match comparison { + SchemaComparison::Input => ChangeClass::BackwardIncompatible, + SchemaComparison::Output => ChangeClass::ForwardIncompatible, + }; + (message, class, ChangeDetails::MoreStrict) + } + }; + + self.schema_push_change( + dry_run, message, old_schema, new_schema, comparison, class, details, + ) + } + fn compare_schema( &mut self, comparison: SchemaComparison, @@ -206,54 +309,18 @@ impl Compare { return Ok(*equal); } - // We expand structures to ensure we don't accidentally fail to examine - // a field. let Schema { - schema_data: - SchemaData { - nullable: old_nullable, - read_only: old_read_only, - write_only: old_write_only, - deprecated: old_deprecated, - external_docs: old_external_docs, - example: old_example, - title: old_title, - description: old_description, - discriminator: old_discriminator, - default: old_default, - extensions: old_extensions, - }, + schema_data: old_schema_data, schema_kind: old_schema_kind, } = old_schema.as_ref(); let Schema { - schema_data: - SchemaData { - nullable: new_nullable, - read_only: new_read_only, - write_only: new_write_only, - deprecated: new_deprecated, - external_docs: new_external_docs, - example: new_example, - title: new_title, - description: new_description, - discriminator: new_discriminator, - default: new_default, - extensions: new_extensions, - }, + schema_data: new_schema_data, schema_kind: new_schema_kind, } = new_schema.as_ref(); // Examine properties that don't affect the serialized form. - let metadata_equal = old_read_only == new_read_only - && old_write_only == new_write_only - && old_deprecated == new_deprecated - && old_external_docs == new_external_docs - && old_example == new_example - && old_title == new_title - && old_description == new_description - && old_discriminator == new_discriminator - && old_default == new_default - && old_extensions == new_extensions; + // Nullability is checked at entry points via compare_effective_nullable. + let metadata_equal = !has_non_nullable_metadata_diff(old_schema_data, new_schema_data); if !metadata_equal { let _ = self.schema_push_change( @@ -267,7 +334,13 @@ impl Compare { ); } - let nullable_equal = old_nullable == new_nullable; + // Note: we do not report nullability changes here. They're instead + // reported in compare_schema_ref_inner (which knows how to perform + // recursion). But we use nullable_equal in the self.visited set. (To be + // honest, this seems a bit dubious. But does self.visited.insert even + // need to carry information about whether schemas are equal?) + let nullable_equal = old_schema_data.nullable == new_schema_data.nullable; + let schema_equal = self.compare_schema_kind( comparison, dry_run, @@ -866,8 +939,174 @@ fn classify_schema_ref(schema_ref: &ReferenceOr) -> SchemaRefKind<'_> { } } -/// Check if schema_data has any non-default values that would constitute -/// metadata worth preserving. -fn has_meaningful_metadata(data: &SchemaData) -> bool { - *data != SchemaData::default() +/// Result of computing effective nullability. +/// +/// For single-element wrappers, effective nullability is +/// `wrapper.nullable || inner.effective_nullable`. For terminal schemas, +/// it's just `schema.nullable`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum EffectiveNullability { + /// The schema is not effectively nullable. + NotNullable, + /// The schema is effectively nullable, with the source indicating where + /// the nullability comes from (outermost source if multiple). + Nullable(NullabilityKind), +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +enum NullabilityKind { + /// Direct schema has `nullable: true` (e.g., `{ "type": "string", "nullable": true }`). + Direct, + /// Single-element wrapper has `nullable: true` in its metadata. + Wrapper, +} + +/// Compute the effective nullability of a schema reference. +fn get_effective_nullable( + schema_ref: &Contextual<'_, &ReferenceOr>, +) -> anyhow::Result { + match schema_ref.as_ref() { + ReferenceOr::Reference { .. } => { + // Bare ref: resolve and delegate to the schema handler. + let (resolved, context) = schema_ref.contextual_resolve()?; + let schema = Contextual::new(context, resolved.as_ref()); + get_effective_nullable_for_schema(&schema) + } + ReferenceOr::Item(schema) => { + // Inline schema: delegate to the schema handler. + let schema = schema_ref.subcomponent(schema); + get_effective_nullable_for_schema(&schema) + } + } +} + +/// Compute effective nullability for a resolved Schema. +/// +/// Handles recursion through single-element wrappers. +fn get_effective_nullable_for_schema( + schema: &Contextual<'_, &Schema>, +) -> anyhow::Result { + // Check for the single-element wrapper pattern. + let inner = match &schema.schema_kind { + openapiv3::SchemaKind::AllOf { all_of } if all_of.len() == 1 => { + Some(all_of.first().expect("checked length is 1")) + } + openapiv3::SchemaKind::AnyOf { any_of } if any_of.len() == 1 => { + Some(any_of.first().expect("checked length is 1")) + } + openapiv3::SchemaKind::OneOf { one_of } if one_of.len() == 1 => { + Some(one_of.first().expect("checked length is 1")) + } + _ => { + // This is either a multi-element wrapper or a non-wrapper schema. + // We do not handle the former case in too much depth (we treat any + // kind of difference as non-identical). For a non-wrapper schema, + // we have nowhere to recurse to. In both cases, None is fine. + None + } + }; + + // If this schema is nullable, return immediately. This check must come + // before the cycle check so that nullable schemas in a cycle are detected. + if schema.schema_data.nullable { + let kind = if inner.is_some() { + NullabilityKind::Wrapper + } else { + NullabilityKind::Direct + }; + return Ok(EffectiveNullability::Nullable(kind)); + } + + // Guard against cycles (e.g., allOf: [$ref: self]). + // + // We only reach this point if the current schema is non-nullable. We only + // recurse (below) for non-nullable wrappers. Therefore, every schema in a + // cycle path is non-nullable, and returning NotNullable is correct. + if schema.context().stack().contains_cycle() { + return Ok(EffectiveNullability::NotNullable); + } + + // If it's a wrapper, recurse into the inner schema. + match inner { + Some(inner) => { + let inner_ctx = Contextual::new(schema.context().clone(), inner); + get_effective_nullable(&inner_ctx) + } + None => Ok(EffectiveNullability::NotNullable), + } +} + +/// Check if schema_data has any non-default values other than nullable. +/// +/// Nullable is a semantic property, not metadata, so it should be compared +/// separately with proper compatibility classification. +fn has_meaningful_non_nullable_metadata(data: &SchemaData) -> bool { + let SchemaData { + // Nullable is semantic, not metadata. + nullable: _, + read_only, + write_only, + deprecated, + external_docs, + example, + title, + description, + discriminator, + default, + extensions, + } = data; + + *read_only + || *write_only + || *deprecated + || external_docs.is_some() + || example.is_some() + || title.is_some() + || description.is_some() + || discriminator.is_some() + || default.is_some() + || !extensions.is_empty() +} + +/// Check if two schema_data values differ in any field other than nullable. +fn has_non_nullable_metadata_diff(old: &SchemaData, new: &SchemaData) -> bool { + let SchemaData { + // Nullable is semantic, not metadata. + nullable: _, + read_only: old_read_only, + write_only: old_write_only, + deprecated: old_deprecated, + external_docs: old_external_docs, + example: old_example, + title: old_title, + description: old_description, + discriminator: old_discriminator, + default: old_default, + extensions: old_extensions, + } = old; + + let SchemaData { + nullable: _, + read_only: new_read_only, + write_only: new_write_only, + deprecated: new_deprecated, + external_docs: new_external_docs, + example: new_example, + title: new_title, + description: new_description, + discriminator: new_discriminator, + default: new_default, + extensions: new_extensions, + } = new; + + old_read_only != new_read_only + || old_write_only != new_write_only + || old_deprecated != new_deprecated + || old_external_docs != new_external_docs + || old_example != new_example + || old_title != new_title + || old_description != new_description + || old_discriminator != new_discriminator + || old_default != new_default + || old_extensions != new_extensions } diff --git a/tests/cases/simple/base.json b/tests/cases/simple/base.json index 9b0c33a..9579752 100644 --- a/tests/cases/simple/base.json +++ b/tests/cases/simple/base.json @@ -26,6 +26,16 @@ }, "description": "Language for the greeting", "required": false + }, + { + "name": "format", + "in": "query", + "schema": { + "type": "string", + "nullable": true + }, + "description": "Output format (nullable for testing)", + "required": false } ], "responses": { @@ -307,6 +317,116 @@ } } } + }, + "/shared": { + "post": { + "operationId": "use_shared", + "summary": "Uses SharedType in both request and response", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SharedType" + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SharedType" + } + } + } + } + } + } + }, + "/nested-wrapper": { + "get": { + "operationId": "get_nested_wrapper", + "summary": "Get nested wrapper via inline allOf (tests nullable through ref chain)", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "description": "Inline wrapper around nested chain.", + "allOf": [ + { + "$ref": "#/components/schemas/NestedWrapperA" + } + ] + } + } + } + } + } + } + }, + "/nested-wrapper-bare-ref": { + "get": { + "operationId": "get_nested_wrapper_bare_ref", + "summary": "Get nested wrapper via bare ref (tests nullable through ref chain)", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NestedWrapperA" + } + } + } + } + } + } + }, + "/nested-nullable-wrapper": { + "get": { + "operationId": "get_nested_nullable_wrapper", + "summary": "Get nested nullable wrapper via inline allOf (tests nullable removal through ref chain)", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "description": "Inline wrapper around nullable nested chain.", + "allOf": [ + { + "$ref": "#/components/schemas/NestedNullableWrapperA" + } + ] + } + } + } + } + } + } + }, + "/nested-nullable-wrapper-bare-ref": { + "get": { + "operationId": "get_nested_nullable_wrapper_bare_ref", + "summary": "Get nested nullable wrapper via bare ref (tests nullable removal through ref chain)", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NestedNullableWrapperA" + } + } + } + } + } + } } }, "components": { @@ -331,6 +451,7 @@ }, "via_anyof": { "description": "Via anyOf.", + "nullable": true, "anyOf": [ { "$ref": "#/components/schemas/SubType" @@ -345,10 +466,35 @@ } ] }, + "redundant_nullable_wrapper": { + "description": "Nullable wrapper around already-nullable type.", + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/NullableSubType" + } + ] + }, + "nullable_via_ref": { + "$ref": "#/components/schemas/NullableSubType" + }, + "non_nullable_wrapper_of_nullable": { + "description": "Non-nullable wrapper around nullable type.", + "allOf": [ + { + "$ref": "#/components/schemas/NullableSubType" + } + ] + }, "not_a_number": { "not": { "type": "number" } + }, + "optional_field": { + "type": "string", + "description": "An optional nullable field", + "nullable": true } }, "required": [ @@ -363,8 +509,18 @@ } } }, + "NullableSubType": { + "type": "object", + "nullable": true, + "properties": { + "value": { + "type": "string" + } + } + }, "Tree": { "type": "object", + "nullable": true, "properties": { "children": { "type": "array", @@ -379,12 +535,32 @@ "properties": { "name": { "type": "string" + }, + "description": { + "type": "string", + "nullable": true + }, + "metadata_ref": { + "allOf": [ + { + "$ref": "#/components/schemas/SubType" + } + ] + }, + "metadata_nullable": { + "nullable": true, + "anyOf": [ + { + "$ref": "#/components/schemas/SubType" + } + ] } }, "required": ["name"] }, "UpdateItem": { "type": "object", + "nullable": true, "properties": { "name": { "type": "string" @@ -479,6 +655,71 @@ }, "RefChainB": { "$ref": "#/components/schemas/SubType" + }, + "SharedType": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "data": { + "type": "string" + }, + "optional_data": { + "type": "string", + "nullable": true + } + }, + "required": ["id"] + }, + "NestedWrapperA": { + "description": "Outer wrapper (non-nullable).", + "allOf": [ + { + "$ref": "#/components/schemas/NestedWrapperB" + } + ] + }, + "NestedWrapperB": { + "description": "Middle wrapper (non-nullable).", + "allOf": [ + { + "$ref": "#/components/schemas/NestedWrapperC" + } + ] + }, + "NestedWrapperC": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + } + }, + "NestedNullableWrapperA": { + "description": "Outer wrapper for nullable chain.", + "allOf": [ + { + "$ref": "#/components/schemas/NestedNullableWrapperB" + } + ] + }, + "NestedNullableWrapperB": { + "description": "Middle wrapper for nullable chain.", + "allOf": [ + { + "$ref": "#/components/schemas/NestedNullableWrapperC" + } + ] + }, + "NestedNullableWrapperC": { + "type": "object", + "nullable": true, + "properties": { + "value": { + "type": "string" + } + } } } } diff --git a/tests/cases/simple/output/add-cookie-parameter.out b/tests/cases/simple/output/add-cookie-parameter.out index 805b882..9221d21 100644 --- a/tests/cases/simple/output/add-cookie-parameter.out +++ b/tests/cases/simple/output/add-cookie-parameter.out @@ -1,6 +1,6 @@ --- add-cookie-parameter.json +++ patched -@@ -365,6 +365,16 @@ +@@ -580,6 +580,16 @@ "get": { "description": "A simple ping endpoint that does nothing.", "operationId": "ping", diff --git a/tests/cases/simple/output/add-default-response.out b/tests/cases/simple/output/add-default-response.out index 712492a..22734d2 100644 --- a/tests/cases/simple/output/add-default-response.out +++ b/tests/cases/simple/output/add-default-response.out @@ -1,6 +1,6 @@ --- add-default-response.json +++ patched -@@ -368,6 +368,16 @@ +@@ -583,6 +583,16 @@ "responses": { "200": { "description": "Ping successful" diff --git a/tests/cases/simple/output/add-header-parameter.out b/tests/cases/simple/output/add-header-parameter.out index 006a63b..c990f6c 100644 --- a/tests/cases/simple/output/add-header-parameter.out +++ b/tests/cases/simple/output/add-header-parameter.out @@ -1,6 +1,6 @@ --- add-header-parameter.json +++ patched -@@ -365,6 +365,16 @@ +@@ -580,6 +580,16 @@ "get": { "description": "A simple ping endpoint that does nothing.", "operationId": "ping", diff --git a/tests/cases/simple/output/add-operation-with-id.out b/tests/cases/simple/output/add-operation-with-id.out index 7b51342..78a263a 100644 --- a/tests/cases/simple/output/add-operation-with-id.out +++ b/tests/cases/simple/output/add-operation-with-id.out @@ -1,7 +1,7 @@ --- add-operation-with-id.json +++ patched -@@ -314,6 +314,17 @@ - "summary": "Update an item" +@@ -529,6 +529,17 @@ + "summary": "Get nested wrapper via bare ref (tests nullable through ref chain)" } }, + "/new-endpoint": { diff --git a/tests/cases/simple/output/add-operation.out b/tests/cases/simple/output/add-operation.out index f938e86..b6a3103 100644 --- a/tests/cases/simple/output/add-operation.out +++ b/tests/cases/simple/output/add-operation.out @@ -1,6 +1,6 @@ --- add-operation.json +++ patched -@@ -238,6 +238,16 @@ +@@ -361,6 +361,16 @@ "summary": "Get arrays" } }, diff --git a/tests/cases/simple/output/add-optional-body.out b/tests/cases/simple/output/add-optional-body.out index 75fe676..d18ce08 100644 --- a/tests/cases/simple/output/add-optional-body.out +++ b/tests/cases/simple/output/add-optional-body.out @@ -1,6 +1,6 @@ --- add-optional-body.json +++ patched -@@ -317,6 +317,21 @@ +@@ -532,6 +532,21 @@ "/no-body": { "post": { "operationId": "no_body", diff --git a/tests/cases/simple/output/add-optional-parameter.out b/tests/cases/simple/output/add-optional-parameter.out index 34b0217..96213d9 100644 --- a/tests/cases/simple/output/add-optional-parameter.out +++ b/tests/cases/simple/output/add-optional-parameter.out @@ -1,7 +1,7 @@ --- add-optional-parameter.json +++ patched -@@ -257,6 +257,15 @@ - "schema": { +@@ -390,6 +390,15 @@ + "nullable": true, "type": "string" } + }, @@ -26,7 +26,7 @@ Result for patch: "#/paths/~1hello~1{name}/get", ], new_path: [ - "#/paths/~1hello~1{name}/get/parameters/2", + "#/paths/~1hello~1{name}/get/parameters/3", ], comparison: Input, class: ForwardIncompatible, diff --git a/tests/cases/simple/output/add-required-body.out b/tests/cases/simple/output/add-required-body.out index 47d7d4e..4e623a9 100644 --- a/tests/cases/simple/output/add-required-body.out +++ b/tests/cases/simple/output/add-required-body.out @@ -1,6 +1,6 @@ --- add-required-body.json +++ patched -@@ -317,6 +317,21 @@ +@@ -532,6 +532,21 @@ "/no-body": { "post": { "operationId": "no_body", diff --git a/tests/cases/simple/output/add-required-parameter.out b/tests/cases/simple/output/add-required-parameter.out index b2e82b0..45dcb34 100644 --- a/tests/cases/simple/output/add-required-parameter.out +++ b/tests/cases/simple/output/add-required-parameter.out @@ -1,7 +1,7 @@ --- add-required-parameter.json +++ patched -@@ -257,6 +257,15 @@ - "schema": { +@@ -390,6 +390,15 @@ + "nullable": true, "type": "string" } + }, @@ -21,15 +21,27 @@ Result for patch: [ Change { - message: "A new, required parameter 'format' was added", + message: "The parameter 'format' was optional and is now required", old_path: [ - "#/paths/~1hello~1{name}/get", + "#/paths/~1hello~1{name}/get/parameters/2", ], new_path: [ - "#/paths/~1hello~1{name}/get/parameters/2", + "#/paths/~1hello~1{name}/get/parameters/3", + ], + comparison: Input, + class: BackwardIncompatible, + details: MoreStrict, + }, + Change { + message: "schema became non-nullable", + old_path: [ + "#/paths/~1hello~1{name}/get/parameters/2/schema", + ], + new_path: [ + "#/paths/~1hello~1{name}/get/parameters/3/schema", ], comparison: Input, class: BackwardIncompatible, - details: AddedRequired, + details: MoreStrict, }, ] diff --git a/tests/cases/simple/output/add-response-code.out b/tests/cases/simple/output/add-response-code.out index 4d98490..b70cfb1 100644 --- a/tests/cases/simple/output/add-response-code.out +++ b/tests/cases/simple/output/add-response-code.out @@ -1,6 +1,6 @@ --- add-response-code.json +++ patched -@@ -368,6 +368,9 @@ +@@ -583,6 +583,9 @@ "responses": { "200": { "description": "Ping successful" diff --git a/tests/cases/simple/output/add-type-extension.out b/tests/cases/simple/output/add-type-extension.out index 2b9722c..10c4388 100644 --- a/tests/cases/simple/output/add-type-extension.out +++ b/tests/cases/simple/output/add-type-extension.out @@ -1,6 +1,6 @@ --- add-type-extension.json +++ patched -@@ -88,7 +88,10 @@ +@@ -133,7 +133,10 @@ "required": [ "message" ], diff --git a/tests/cases/simple/output/additional-props-non-nullable-to-nullable.out b/tests/cases/simple/output/additional-props-non-nullable-to-nullable.out new file mode 100644 index 0000000..18b2067 --- /dev/null +++ b/tests/cases/simple/output/additional-props-non-nullable-to-nullable.out @@ -0,0 +1,29 @@ +--- additional-props-non-nullable-to-nullable.json ++++ patched +@@ -225,6 +225,7 @@ + }, + "ObjectWithConstraints": { + "additionalProperties": { ++ "nullable": true, + "type": "string" + }, + "maxProperties": 5, + + +Result for patch: +[ + Change { + message: "schema became nullable", + old_path: [ + "#/components/schemas/ObjectWithConstraints/additionalProperties", + "#/paths/~1objects/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/ObjectWithConstraints/additionalProperties", + "#/paths/~1objects/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/allof-to-anyof.out b/tests/cases/simple/output/allof-to-anyof.out index c65c7a9..52ee699 100644 --- a/tests/cases/simple/output/allof-to-anyof.out +++ b/tests/cases/simple/output/allof-to-anyof.out @@ -1,7 +1,7 @@ --- allof-to-anyof.json +++ patched -@@ -58,12 +58,12 @@ - } +@@ -102,12 +102,12 @@ + "nullable": true }, "via_allof": { - "allOf": [ diff --git a/tests/cases/simple/output/allof-to-oneof-with-type-change.out b/tests/cases/simple/output/allof-to-oneof-with-type-change.out index 2712e0a..dc2daab 100644 --- a/tests/cases/simple/output/allof-to-oneof-with-type-change.out +++ b/tests/cases/simple/output/allof-to-oneof-with-type-change.out @@ -1,7 +1,7 @@ --- allof-to-oneof-with-type-change.json +++ patched -@@ -58,12 +58,12 @@ - } +@@ -102,12 +102,12 @@ + "nullable": true }, "via_allof": { - "allOf": [ @@ -16,7 +16,7 @@ }, "via_anyof": { "anyOf": [ -@@ -137,7 +137,7 @@ +@@ -258,7 +258,7 @@ "SubType": { "properties": { "value": { @@ -59,4 +59,20 @@ Result for patch: class: Incompatible, details: UnknownDifference, }, + Change { + message: "schema types changed", + old_path: [ + "#/components/schemas/SubType/properties/value", + "#/components/schemas/CreateItem/properties/metadata_nullable/0/$ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/SubType/properties/value", + "#/components/schemas/CreateItem/properties/metadata_nullable/0/$ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: Incompatible, + details: UnknownDifference, + }, ] diff --git a/tests/cases/simple/output/allof-to-oneof.out b/tests/cases/simple/output/allof-to-oneof.out index 14f9d00..cd6edad 100644 --- a/tests/cases/simple/output/allof-to-oneof.out +++ b/tests/cases/simple/output/allof-to-oneof.out @@ -1,7 +1,7 @@ --- allof-to-oneof.json +++ patched -@@ -58,12 +58,12 @@ - } +@@ -102,12 +102,12 @@ + "nullable": true }, "via_allof": { - "allOf": [ diff --git a/tests/cases/simple/output/allof-to-ref-with-type-change.out b/tests/cases/simple/output/allof-to-ref-with-type-change.out index f4d9b89..1ff13e7 100644 --- a/tests/cases/simple/output/allof-to-ref-with-type-change.out +++ b/tests/cases/simple/output/allof-to-ref-with-type-change.out @@ -1,7 +1,7 @@ --- allof-to-ref-with-type-change.json +++ patched -@@ -58,12 +58,7 @@ - } +@@ -102,12 +102,7 @@ + "nullable": true }, "via_allof": { - "allOf": [ @@ -14,7 +14,7 @@ }, "via_anyof": { "anyOf": [ -@@ -136,6 +131,9 @@ +@@ -257,6 +252,9 @@ }, "SubType": { "properties": { @@ -58,4 +58,20 @@ Result for patch: class: Unhandled, details: UnknownDifference, }, + Change { + message: "object properties changed", + old_path: [ + "#/components/schemas/SubType", + "#/components/schemas/CreateItem/properties/metadata_nullable/0/$ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/SubType", + "#/components/schemas/CreateItem/properties/metadata_nullable/0/$ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: Unhandled, + details: UnknownDifference, + }, ] diff --git a/tests/cases/simple/output/allof-to-ref.out b/tests/cases/simple/output/allof-to-ref.out index 7f3de13..1f87971 100644 --- a/tests/cases/simple/output/allof-to-ref.out +++ b/tests/cases/simple/output/allof-to-ref.out @@ -1,7 +1,7 @@ --- allof-to-ref.json +++ patched -@@ -58,12 +58,7 @@ - } +@@ -102,12 +102,7 @@ + "nullable": true }, "via_allof": { - "allOf": [ diff --git a/tests/cases/simple/output/any-schema-change.out b/tests/cases/simple/output/any-schema-change.out index 35a3e91..1af1eb7 100644 --- a/tests/cases/simple/output/any-schema-change.out +++ b/tests/cases/simple/output/any-schema-change.out @@ -1,6 +1,6 @@ --- any-schema-change.json +++ patched -@@ -48,6 +48,7 @@ +@@ -67,6 +67,7 @@ }, "GreetingResponse": { "properties": { diff --git a/tests/cases/simple/output/anyof-to-allof.out b/tests/cases/simple/output/anyof-to-allof.out index ced8976..ef16749 100644 --- a/tests/cases/simple/output/anyof-to-allof.out +++ b/tests/cases/simple/output/anyof-to-allof.out @@ -1,6 +1,6 @@ --- anyof-to-allof.json +++ patched -@@ -66,12 +66,12 @@ +@@ -110,13 +110,12 @@ "description": "Via allOf." }, "via_anyof": { @@ -10,7 +10,8 @@ "$ref": "#/components/schemas/SubType" } ], -- "description": "Via anyOf." +- "description": "Via anyOf.", +- "nullable": true + "description": "Via allOf." }, "via_oneof": { @@ -19,6 +20,20 @@ Result for patch: [ + Change { + message: "nullable removed from wrapper", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, Change { message: "schema metadata changed", old_path: [ diff --git a/tests/cases/simple/output/anyof-to-oneof.out b/tests/cases/simple/output/anyof-to-oneof.out index 0e1f38d..0067ce6 100644 --- a/tests/cases/simple/output/anyof-to-oneof.out +++ b/tests/cases/simple/output/anyof-to-oneof.out @@ -1,6 +1,6 @@ --- anyof-to-oneof.json +++ patched -@@ -66,12 +66,12 @@ +@@ -110,13 +110,12 @@ "description": "Via allOf." }, "via_anyof": { @@ -11,7 +11,8 @@ "$ref": "#/components/schemas/SubType" } - ], -- "description": "Via anyOf." +- "description": "Via anyOf.", +- "nullable": true + ] }, "via_oneof": { @@ -20,6 +21,20 @@ Result for patch: [ + Change { + message: "nullable removed from wrapper", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, Change { message: "schema metadata changed", old_path: [ diff --git a/tests/cases/simple/output/anyof-to-ref.out b/tests/cases/simple/output/anyof-to-ref.out index 2e1d099..848cb6d 100644 --- a/tests/cases/simple/output/anyof-to-ref.out +++ b/tests/cases/simple/output/anyof-to-ref.out @@ -1,6 +1,6 @@ --- anyof-to-ref.json +++ patched -@@ -66,12 +66,7 @@ +@@ -110,13 +110,7 @@ "description": "Via allOf." }, "via_anyof": { @@ -9,7 +9,8 @@ - "$ref": "#/components/schemas/SubType" - } - ], -- "description": "Via anyOf." +- "description": "Via anyOf.", +- "nullable": true + "$ref": "#/components/schemas/SubType" }, "via_oneof": { @@ -18,6 +19,20 @@ Result for patch: [ + Change { + message: "nullable removed from wrapper", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, Change { message: "schema metadata removed", old_path: [ diff --git a/tests/cases/simple/output/array-items-non-nullable-to-nullable.out b/tests/cases/simple/output/array-items-non-nullable-to-nullable.out new file mode 100644 index 0000000..f3a45fa --- /dev/null +++ b/tests/cases/simple/output/array-items-non-nullable-to-nullable.out @@ -0,0 +1,29 @@ +--- array-items-non-nullable-to-nullable.json ++++ patched +@@ -13,6 +13,7 @@ + }, + "ArrayWithConstraints": { + "items": { ++ "nullable": true, + "type": "string" + }, + "maxItems": 10, + + +Result for patch: +[ + Change { + message: "schema became nullable", + old_path: [ + "#/components/schemas/ArrayWithConstraints/items", + "#/paths/~1arrays/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/ArrayWithConstraints/items", + "#/paths/~1arrays/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/array-items-remove.out b/tests/cases/simple/output/array-items-remove.out index 426e982..097a94c 100644 --- a/tests/cases/simple/output/array-items-remove.out +++ b/tests/cases/simple/output/array-items-remove.out @@ -1,10 +1,11 @@ --- array-items-remove.json +++ patched -@@ -146,7 +146,7 @@ +@@ -268,7 +268,8 @@ "properties": { "children": { "items": { - "$ref": "#/components/schemas/Tree" ++ "nullable": true, + "type": "string" }, "type": "array" diff --git a/tests/cases/simple/output/body-description-change.out b/tests/cases/simple/output/body-description-change.out index 3e2eb01..cdd8d9c 100644 --- a/tests/cases/simple/output/body-description-change.out +++ b/tests/cases/simple/output/body-description-change.out @@ -1,6 +1,6 @@ --- body-description-change.json +++ patched -@@ -285,6 +285,7 @@ +@@ -418,6 +418,7 @@ } } }, diff --git a/tests/cases/simple/output/body-extension-change.out b/tests/cases/simple/output/body-extension-change.out index 06cbc81..427c709 100644 --- a/tests/cases/simple/output/body-extension-change.out +++ b/tests/cases/simple/output/body-extension-change.out @@ -1,6 +1,6 @@ --- body-extension-change.json +++ patched -@@ -285,7 +285,8 @@ +@@ -418,7 +418,8 @@ } } }, diff --git a/tests/cases/simple/output/body-optional-to-required.out b/tests/cases/simple/output/body-optional-to-required.out index b09a68f..881e6e8 100644 --- a/tests/cases/simple/output/body-optional-to-required.out +++ b/tests/cases/simple/output/body-optional-to-required.out @@ -1,6 +1,6 @@ --- body-optional-to-required.json +++ patched -@@ -304,7 +304,7 @@ +@@ -437,7 +437,7 @@ } } }, diff --git a/tests/cases/simple/output/body-required-to-optional.out b/tests/cases/simple/output/body-required-to-optional.out index a41b06d..fabd1bc 100644 --- a/tests/cases/simple/output/body-required-to-optional.out +++ b/tests/cases/simple/output/body-required-to-optional.out @@ -1,6 +1,6 @@ --- body-required-to-optional.json +++ patched -@@ -285,7 +285,7 @@ +@@ -418,7 +418,7 @@ } } }, diff --git a/tests/cases/simple/output/boolean-change.out b/tests/cases/simple/output/boolean-change.out index 6fc74f3..3a7dd5e 100644 --- a/tests/cases/simple/output/boolean-change.out +++ b/tests/cases/simple/output/boolean-change.out @@ -1,6 +1,6 @@ --- boolean-change.json +++ patched -@@ -159,6 +159,7 @@ +@@ -281,6 +281,7 @@ "type": "integer" }, "enabled": { diff --git a/tests/cases/simple/output/boolean-enum-change.out b/tests/cases/simple/output/boolean-enum-change.out index 670c172..154f21a 100644 --- a/tests/cases/simple/output/boolean-enum-change.out +++ b/tests/cases/simple/output/boolean-enum-change.out @@ -1,6 +1,6 @@ --- boolean-enum-change.json +++ patched -@@ -159,6 +159,9 @@ +@@ -281,6 +281,9 @@ "type": "integer" }, "enabled": { diff --git a/tests/cases/simple/output/change-default-response.out b/tests/cases/simple/output/change-default-response.out index 51a21da..04583bc 100644 --- a/tests/cases/simple/output/change-default-response.out +++ b/tests/cases/simple/output/change-default-response.out @@ -1,6 +1,6 @@ --- change-default-response.json +++ patched -@@ -451,7 +451,7 @@ +@@ -694,7 +694,7 @@ } } }, diff --git a/tests/cases/simple/output/change-header-parameter.out b/tests/cases/simple/output/change-header-parameter.out index 8b8fec2..41dcaa9 100644 --- a/tests/cases/simple/output/change-header-parameter.out +++ b/tests/cases/simple/output/change-header-parameter.out @@ -1,6 +1,6 @@ --- change-header-parameter.json +++ patched -@@ -466,7 +466,7 @@ +@@ -709,7 +709,7 @@ "name": "X-Request-Id", "required": true, "schema": { diff --git a/tests/cases/simple/output/change-operation-parameter-requirement.out b/tests/cases/simple/output/change-operation-parameter-requirement.out index dccb0ce..1739f62 100644 --- a/tests/cases/simple/output/change-operation-parameter-requirement.out +++ b/tests/cases/simple/output/change-operation-parameter-requirement.out @@ -1,6 +1,6 @@ --- change-operation-parameter-requirement.json +++ patched -@@ -253,7 +253,7 @@ +@@ -376,7 +376,7 @@ "description": "Language for the greeting", "in": "query", "name": "language", diff --git a/tests/cases/simple/output/change-operation-parameter-type.out b/tests/cases/simple/output/change-operation-parameter-type.out index 1a21afd..cd8f68b 100644 --- a/tests/cases/simple/output/change-operation-parameter-type.out +++ b/tests/cases/simple/output/change-operation-parameter-type.out @@ -1,14 +1,14 @@ --- change-operation-parameter-type.json +++ patched -@@ -255,7 +255,7 @@ +@@ -378,7 +378,7 @@ "name": "language", "required": false, "schema": { - "type": "string" + "type": "integer" } - } - ], + }, + { Result for patch: diff --git a/tests/cases/simple/output/change-property-type.out b/tests/cases/simple/output/change-property-type.out index 59b6235..206167b 100644 --- a/tests/cases/simple/output/change-property-type.out +++ b/tests/cases/simple/output/change-property-type.out @@ -1,14 +1,14 @@ --- change-property-type.json +++ patched -@@ -50,7 +50,7 @@ +@@ -69,7 +69,7 @@ "properties": { "message": { "description": "The greeting message", - "type": "string" + "type": "integer" }, - "not_a_number": { - "not": { + "non_nullable_wrapper_of_nullable": { + "allOf": [ Result for patch: diff --git a/tests/cases/simple/output/inline-to-allof.out b/tests/cases/simple/output/inline-to-allof.out index 5173ba2..dfdf9b2 100644 --- a/tests/cases/simple/output/inline-to-allof.out +++ b/tests/cases/simple/output/inline-to-allof.out @@ -1,6 +1,6 @@ --- inline-to-allof.json +++ patched -@@ -246,7 +246,12 @@ +@@ -369,7 +369,12 @@ "in": "path", "name": "name", "schema": { diff --git a/tests/cases/simple/output/inline-to-wrapper-nullable-added.out b/tests/cases/simple/output/inline-to-wrapper-nullable-added.out new file mode 100644 index 0000000..83c2e2e --- /dev/null +++ b/tests/cases/simple/output/inline-to-wrapper-nullable-added.out @@ -0,0 +1,64 @@ +--- inline-to-wrapper-nullable-added.json ++++ patched +@@ -68,8 +68,13 @@ + "GreetingResponse": { + "properties": { + "message": { ++ "allOf": [ ++ { ++ "type": "string" ++ } ++ ], + "description": "The greeting message", +- "type": "string" ++ "nullable": true + }, + "non_nullable_wrapper_of_nullable": { + "allOf": [ + + +Result for patch: +[ + Change { + message: "nullable added at wrapper", + old_path: [ + "#/components/schemas/GreetingResponse/properties/message", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/message", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, + Change { + message: "schema metadata added", + old_path: [ + "#/components/schemas/GreetingResponse/properties/message", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/message", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: Trivial, + details: Metadata, + }, + Change { + message: "schema metadata changed", + old_path: [ + "#/components/schemas/GreetingResponse/properties/message", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/message/0", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: Trivial, + details: Metadata, + }, +] diff --git a/tests/cases/simple/output/input-non-nullable-to-nullable.out b/tests/cases/simple/output/input-non-nullable-to-nullable.out new file mode 100644 index 0000000..8321e87 --- /dev/null +++ b/tests/cases/simple/output/input-non-nullable-to-nullable.out @@ -0,0 +1,29 @@ +--- input-non-nullable-to-nullable.json ++++ patched +@@ -42,6 +42,7 @@ + ] + }, + "name": { ++ "nullable": true, + "type": "string" + } + }, + + +Result for patch: +[ + Change { + message: "schema became nullable", + old_path: [ + "#/components/schemas/CreateItem/properties/name", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/CreateItem/properties/name", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: ForwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/input-nullable-to-non-nullable.out b/tests/cases/simple/output/input-nullable-to-non-nullable.out new file mode 100644 index 0000000..8a640fd --- /dev/null +++ b/tests/cases/simple/output/input-nullable-to-non-nullable.out @@ -0,0 +1,29 @@ +--- input-nullable-to-non-nullable.json ++++ patched +@@ -23,7 +23,6 @@ + "CreateItem": { + "properties": { + "description": { +- "nullable": true, + "type": "string" + }, + "metadata_nullable": { + + +Result for patch: +[ + Change { + message: "schema became non-nullable", + old_path: [ + "#/components/schemas/CreateItem/properties/description", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/CreateItem/properties/description", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: BackwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/input-ref-to-wrapper-nullable-added.out b/tests/cases/simple/output/input-ref-to-wrapper-nullable-added.out new file mode 100644 index 0000000..a8ad526 --- /dev/null +++ b/tests/cases/simple/output/input-ref-to-wrapper-nullable-added.out @@ -0,0 +1,35 @@ +--- input-ref-to-wrapper-nullable-added.json ++++ patched +@@ -42,7 +42,12 @@ + ] + }, + "name": { +- "type": "string" ++ "allOf": [ ++ { ++ "type": "string" ++ } ++ ], ++ "nullable": true + } + }, + "required": [ + + +Result for patch: +[ + Change { + message: "nullable added at wrapper", + old_path: [ + "#/components/schemas/CreateItem/properties/name", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/CreateItem/properties/name", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: ForwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/input-root-non-nullable-to-nullable.out b/tests/cases/simple/output/input-root-non-nullable-to-nullable.out new file mode 100644 index 0000000..950b475 --- /dev/null +++ b/tests/cases/simple/output/input-root-non-nullable-to-nullable.out @@ -0,0 +1,27 @@ +--- input-root-non-nullable-to-nullable.json ++++ patched +@@ -21,6 +21,7 @@ + "uniqueItems": false + }, + "CreateItem": { ++ "nullable": true, + "properties": { + "description": { + "nullable": true, + + +Result for patch: +[ + Change { + message: "schema became nullable", + old_path: [ + "#/paths/~1items/post/request_body/content/application~1json/schema", + ], + new_path: [ + "#/paths/~1items/post/request_body/content/application~1json/schema", + ], + comparison: Input, + class: ForwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/input-root-nullable-to-non-nullable.out b/tests/cases/simple/output/input-root-nullable-to-non-nullable.out new file mode 100644 index 0000000..b14a91c --- /dev/null +++ b/tests/cases/simple/output/input-root-nullable-to-non-nullable.out @@ -0,0 +1,27 @@ +--- input-root-nullable-to-non-nullable.json ++++ patched +@@ -290,7 +290,6 @@ + "type": "object" + }, + "UpdateItem": { +- "nullable": true, + "properties": { + "name": { + "type": "string" + + +Result for patch: +[ + Change { + message: "schema became non-nullable", + old_path: [ + "#/paths/~1items/put/request_body/content/application~1json/schema", + ], + new_path: [ + "#/paths/~1items/put/request_body/content/application~1json/schema", + ], + comparison: Input, + class: BackwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/input-wrapper-non-nullable-to-nullable.out b/tests/cases/simple/output/input-wrapper-non-nullable-to-nullable.out new file mode 100644 index 0000000..1741b62 --- /dev/null +++ b/tests/cases/simple/output/input-wrapper-non-nullable-to-nullable.out @@ -0,0 +1,31 @@ +--- input-wrapper-non-nullable-to-nullable.json ++++ patched +@@ -39,7 +39,8 @@ + { + "$ref": "#/components/schemas/SubType" + } +- ] ++ ], ++ "nullable": true + }, + "name": { + "type": "string" + + +Result for patch: +[ + Change { + message: "nullable added at wrapper", + old_path: [ + "#/components/schemas/CreateItem/properties/metadata_ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/CreateItem/properties/metadata_ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: ForwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/input-wrapper-nullable-to-non-nullable.out b/tests/cases/simple/output/input-wrapper-nullable-to-non-nullable.out new file mode 100644 index 0000000..e6b8fef --- /dev/null +++ b/tests/cases/simple/output/input-wrapper-nullable-to-non-nullable.out @@ -0,0 +1,31 @@ +--- input-wrapper-nullable-to-non-nullable.json ++++ patched +@@ -31,8 +31,7 @@ + { + "$ref": "#/components/schemas/SubType" + } +- ], +- "nullable": true ++ ] + }, + "metadata_ref": { + "allOf": [ + + +Result for patch: +[ + Change { + message: "nullable removed from wrapper", + old_path: [ + "#/components/schemas/CreateItem/properties/metadata_nullable", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/CreateItem/properties/metadata_nullable", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: BackwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/input-wrapper-to-ref-nullable-removed.out b/tests/cases/simple/output/input-wrapper-to-ref-nullable-removed.out new file mode 100644 index 0000000..d6631b1 --- /dev/null +++ b/tests/cases/simple/output/input-wrapper-to-ref-nullable-removed.out @@ -0,0 +1,35 @@ +--- input-wrapper-to-ref-nullable-removed.json ++++ patched +@@ -27,12 +27,7 @@ + "type": "string" + }, + "metadata_nullable": { +- "anyOf": [ +- { +- "$ref": "#/components/schemas/SubType" +- } +- ], +- "nullable": true ++ "$ref": "#/components/schemas/SubType" + }, + "metadata_ref": { + "allOf": [ + + +Result for patch: +[ + Change { + message: "nullable removed from wrapper", + old_path: [ + "#/components/schemas/CreateItem/properties/metadata_nullable", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/CreateItem/properties/metadata_nullable", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: BackwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/integer-format-change.out b/tests/cases/simple/output/integer-format-change.out index f97a7a4..fe5f8fc 100644 --- a/tests/cases/simple/output/integer-format-change.out +++ b/tests/cases/simple/output/integer-format-change.out @@ -1,6 +1,6 @@ --- integer-format-change.json +++ patched -@@ -156,6 +156,7 @@ +@@ -278,6 +278,7 @@ "TypedProperties": { "properties": { "count": { diff --git a/tests/cases/simple/output/modify-cycle-type.out b/tests/cases/simple/output/modify-cycle-type.out index 4dd795b..a42b4b3 100644 --- a/tests/cases/simple/output/modify-cycle-type.out +++ b/tests/cases/simple/output/modify-cycle-type.out @@ -1,7 +1,7 @@ --- modify-cycle-type.json +++ patched -@@ -145,10 +145,7 @@ - "Tree": { +@@ -267,10 +267,7 @@ + "nullable": true, "properties": { "children": { - "items": { @@ -16,6 +16,20 @@ Result for patch: [ + Change { + message: "schema became nullable", + old_path: [ + "#/components/schemas/Tree/properties/children", + "#/paths/~1tree/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/Tree/properties/children", + "#/paths/~1tree/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, Change { message: "schema types changed", old_path: [ diff --git a/tests/cases/simple/output/multi-allof-variant-change.out b/tests/cases/simple/output/multi-allof-variant-change.out index b2c82ec..e8bf201 100644 --- a/tests/cases/simple/output/multi-allof-variant-change.out +++ b/tests/cases/simple/output/multi-allof-variant-change.out @@ -1,6 +1,6 @@ --- multi-allof-variant-change.json +++ patched -@@ -95,7 +95,7 @@ +@@ -140,7 +140,7 @@ { "properties": { "id": { diff --git a/tests/cases/simple/output/multi-oneof-count-change.out b/tests/cases/simple/output/multi-oneof-count-change.out index 8d054d6..6189abe 100644 --- a/tests/cases/simple/output/multi-oneof-count-change.out +++ b/tests/cases/simple/output/multi-oneof-count-change.out @@ -1,6 +1,6 @@ --- multi-oneof-count-change.json +++ patched -@@ -117,6 +117,9 @@ +@@ -162,6 +162,9 @@ }, { "type": "integer" diff --git a/tests/cases/simple/output/multi-oneof-variant-change.out b/tests/cases/simple/output/multi-oneof-variant-change.out index 9e67399..2d5506b 100644 --- a/tests/cases/simple/output/multi-oneof-variant-change.out +++ b/tests/cases/simple/output/multi-oneof-variant-change.out @@ -1,6 +1,6 @@ --- multi-oneof-variant-change.json +++ patched -@@ -113,7 +113,7 @@ +@@ -158,7 +158,7 @@ "MultiOneOf": { "oneOf": [ { diff --git a/tests/cases/simple/output/nested-wrapper-non-nullable-to-nullable.out b/tests/cases/simple/output/nested-wrapper-non-nullable-to-nullable.out new file mode 100644 index 0000000..00ef186 --- /dev/null +++ b/tests/cases/simple/output/nested-wrapper-non-nullable-to-nullable.out @@ -0,0 +1,39 @@ +--- nested-wrapper-non-nullable-to-nullable.json ++++ patched +@@ -207,6 +207,7 @@ + "description": "Middle wrapper (non-nullable)." + }, + "NestedWrapperC": { ++ "nullable": true, + "properties": { + "value": { + "type": "string" + + +Result for patch: +[ + Change { + message: "schema became nullable", + old_path: [ + "#/paths/~1nested-wrapper/get/responses/200/content/application~1json/schema", + ], + new_path: [ + "#/paths/~1nested-wrapper/get/responses/200/content/application~1json/schema", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, + Change { + message: "schema became nullable", + old_path: [ + "#/paths/~1nested-wrapper-bare-ref/get/responses/200/content/application~1json/schema", + ], + new_path: [ + "#/paths/~1nested-wrapper-bare-ref/get/responses/200/content/application~1json/schema", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/nested-wrapper-nullable-to-non-nullable.out b/tests/cases/simple/output/nested-wrapper-nullable-to-non-nullable.out new file mode 100644 index 0000000..d228bfd --- /dev/null +++ b/tests/cases/simple/output/nested-wrapper-nullable-to-non-nullable.out @@ -0,0 +1,39 @@ +--- nested-wrapper-nullable-to-non-nullable.json ++++ patched +@@ -182,7 +182,6 @@ + "description": "Middle wrapper for nullable chain." + }, + "NestedNullableWrapperC": { +- "nullable": true, + "properties": { + "value": { + "type": "string" + + +Result for patch: +[ + Change { + message: "schema became non-nullable", + old_path: [ + "#/paths/~1nested-nullable-wrapper/get/responses/200/content/application~1json/schema", + ], + new_path: [ + "#/paths/~1nested-nullable-wrapper/get/responses/200/content/application~1json/schema", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, + Change { + message: "schema became non-nullable", + old_path: [ + "#/paths/~1nested-nullable-wrapper-bare-ref/get/responses/200/content/application~1json/schema", + ], + new_path: [ + "#/paths/~1nested-nullable-wrapper-bare-ref/get/responses/200/content/application~1json/schema", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/non-nullable-to-nullable.out b/tests/cases/simple/output/non-nullable-to-nullable.out new file mode 100644 index 0000000..9f35399 --- /dev/null +++ b/tests/cases/simple/output/non-nullable-to-nullable.out @@ -0,0 +1,29 @@ +--- non-nullable-to-nullable.json ++++ patched +@@ -69,6 +69,7 @@ + "properties": { + "message": { + "description": "The greeting message", ++ "nullable": true, + "type": "string" + }, + "non_nullable_wrapper_of_nullable": { + + +Result for patch: +[ + Change { + message: "schema became nullable", + old_path: [ + "#/components/schemas/GreetingResponse/properties/message", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/message", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/not-inner-to-allof.out b/tests/cases/simple/output/not-inner-to-allof.out index c3c4808..8f6d42a 100644 --- a/tests/cases/simple/output/not-inner-to-allof.out +++ b/tests/cases/simple/output/not-inner-to-allof.out @@ -1,6 +1,6 @@ --- not-inner-to-allof.json +++ patched -@@ -54,7 +54,12 @@ +@@ -81,7 +81,12 @@ }, "not_a_number": { "not": { @@ -13,7 +13,7 @@ + "description": "A number type" } }, - "via_allof": { + "nullable_via_ref": { Result for patch: diff --git a/tests/cases/simple/output/not-to-allof.out b/tests/cases/simple/output/not-to-allof.out index b3ef213..07ecc11 100644 --- a/tests/cases/simple/output/not-to-allof.out +++ b/tests/cases/simple/output/not-to-allof.out @@ -1,7 +1,7 @@ --- not-to-allof.json +++ patched -@@ -53,9 +53,14 @@ - "type": "string" +@@ -80,9 +80,14 @@ + "description": "Non-nullable wrapper around nullable type." }, "not_a_number": { - "not": { @@ -16,8 +16,8 @@ + ], + "description": "Not a number, wrapped in allOf" }, - "via_allof": { - "allOf": [ + "nullable_via_ref": { + "$ref": "#/components/schemas/NullableSubType" Result for patch: diff --git a/tests/cases/simple/output/nullable-to-non-nullable.out b/tests/cases/simple/output/nullable-to-non-nullable.out new file mode 100644 index 0000000..51ff898 --- /dev/null +++ b/tests/cases/simple/output/nullable-to-non-nullable.out @@ -0,0 +1,29 @@ +--- nullable-to-non-nullable.json ++++ patched +@@ -89,7 +89,6 @@ + }, + "optional_field": { + "description": "An optional nullable field", +- "nullable": true, + "type": "string" + }, + "redundant_nullable_wrapper": { + + +Result for patch: +[ + Change { + message: "schema became non-nullable", + old_path: [ + "#/components/schemas/GreetingResponse/properties/optional_field", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/optional_field", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/number-constraints-change.out b/tests/cases/simple/output/number-constraints-change.out index 241849d..46579f2 100644 --- a/tests/cases/simple/output/number-constraints-change.out +++ b/tests/cases/simple/output/number-constraints-change.out @@ -1,6 +1,6 @@ --- number-constraints-change.json +++ patched -@@ -162,6 +162,7 @@ +@@ -284,6 +284,7 @@ "type": "boolean" }, "ratio": { diff --git a/tests/cases/simple/output/object-additional-props-false.out b/tests/cases/simple/output/object-additional-props-false.out index 7eb6590..c0859f1 100644 --- a/tests/cases/simple/output/object-additional-props-false.out +++ b/tests/cases/simple/output/object-additional-props-false.out @@ -1,7 +1,7 @@ --- object-additional-props-false.json +++ patched -@@ -121,9 +121,7 @@ - ] +@@ -224,9 +224,7 @@ + "type": "object" }, "ObjectWithConstraints": { - "additionalProperties": { diff --git a/tests/cases/simple/output/object-additional-props-schema-change.out b/tests/cases/simple/output/object-additional-props-schema-change.out index e702620..e956d14 100644 --- a/tests/cases/simple/output/object-additional-props-schema-change.out +++ b/tests/cases/simple/output/object-additional-props-schema-change.out @@ -1,6 +1,6 @@ --- object-additional-props-schema-change.json +++ patched -@@ -122,7 +122,7 @@ +@@ -225,7 +225,7 @@ }, "ObjectWithConstraints": { "additionalProperties": { diff --git a/tests/cases/simple/output/object-additional-props-type-change.out b/tests/cases/simple/output/object-additional-props-type-change.out index dd355d5..91fdf65 100644 --- a/tests/cases/simple/output/object-additional-props-type-change.out +++ b/tests/cases/simple/output/object-additional-props-type-change.out @@ -1,7 +1,7 @@ --- object-additional-props-type-change.json +++ patched -@@ -121,9 +121,7 @@ - ] +@@ -224,9 +224,7 @@ + "type": "object" }, "ObjectWithConstraints": { - "additionalProperties": { diff --git a/tests/cases/simple/output/object-max-properties-change.out b/tests/cases/simple/output/object-max-properties-change.out index c519851..f77067f 100644 --- a/tests/cases/simple/output/object-max-properties-change.out +++ b/tests/cases/simple/output/object-max-properties-change.out @@ -1,6 +1,6 @@ --- object-max-properties-change.json +++ patched -@@ -124,7 +124,7 @@ +@@ -227,7 +227,7 @@ "additionalProperties": { "type": "string" }, diff --git a/tests/cases/simple/output/object-min-properties-change.out b/tests/cases/simple/output/object-min-properties-change.out index cc5eca9..b97583f 100644 --- a/tests/cases/simple/output/object-min-properties-change.out +++ b/tests/cases/simple/output/object-min-properties-change.out @@ -1,6 +1,6 @@ --- object-min-properties-change.json +++ patched -@@ -125,7 +125,7 @@ +@@ -228,7 +228,7 @@ "type": "string" }, "maxProperties": 5, diff --git a/tests/cases/simple/output/oneof-to-allof.out b/tests/cases/simple/output/oneof-to-allof.out index 78d37b8..6e4b649 100644 --- a/tests/cases/simple/output/oneof-to-allof.out +++ b/tests/cases/simple/output/oneof-to-allof.out @@ -1,7 +1,7 @@ --- oneof-to-allof.json +++ patched -@@ -74,12 +74,12 @@ - "description": "Via anyOf." +@@ -119,12 +119,12 @@ + "nullable": true }, "via_oneof": { - "description": "Via oneOf.", diff --git a/tests/cases/simple/output/oneof-to-anyof.out b/tests/cases/simple/output/oneof-to-anyof.out index c643d8b..89d4909 100644 --- a/tests/cases/simple/output/oneof-to-anyof.out +++ b/tests/cases/simple/output/oneof-to-anyof.out @@ -1,7 +1,7 @@ --- oneof-to-anyof.json +++ patched -@@ -74,12 +74,12 @@ - "description": "Via anyOf." +@@ -119,12 +119,12 @@ + "nullable": true }, "via_oneof": { - "description": "Via oneOf.", diff --git a/tests/cases/simple/output/oneof-to-ref.out b/tests/cases/simple/output/oneof-to-ref.out index 0ec92a5..97ec3c3 100644 --- a/tests/cases/simple/output/oneof-to-ref.out +++ b/tests/cases/simple/output/oneof-to-ref.out @@ -1,7 +1,7 @@ --- oneof-to-ref.json +++ patched -@@ -74,12 +74,7 @@ - "description": "Via anyOf." +@@ -119,12 +119,7 @@ + "nullable": true }, "via_oneof": { - "description": "Via oneOf.", diff --git a/tests/cases/simple/output/output-root-non-nullable-to-nullable.out b/tests/cases/simple/output/output-root-non-nullable-to-nullable.out new file mode 100644 index 0000000..5ae81d7 --- /dev/null +++ b/tests/cases/simple/output/output-root-non-nullable-to-nullable.out @@ -0,0 +1,27 @@ +--- output-root-non-nullable-to-nullable.json ++++ patched +@@ -66,6 +66,7 @@ + "type": "object" + }, + "GreetingResponse": { ++ "nullable": true, + "properties": { + "message": { + "description": "The greeting message", + + +Result for patch: +[ + Change { + message: "schema became nullable", + old_path: [ + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema", + ], + new_path: [ + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/output-root-nullable-to-non-nullable.out b/tests/cases/simple/output/output-root-nullable-to-non-nullable.out new file mode 100644 index 0000000..64fa183 --- /dev/null +++ b/tests/cases/simple/output/output-root-nullable-to-non-nullable.out @@ -0,0 +1,41 @@ +--- output-root-nullable-to-non-nullable.json ++++ patched +@@ -264,7 +264,6 @@ + "type": "object" + }, + "Tree": { +- "nullable": true, + "properties": { + "children": { + "items": { + + +Result for patch: +[ + Change { + message: "schema became non-nullable", + old_path: [ + "#/paths/~1tree/get/responses/200/content/application~1json/schema", + ], + new_path: [ + "#/paths/~1tree/get/responses/200/content/application~1json/schema", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, + Change { + message: "schema became non-nullable", + old_path: [ + "#/components/schemas/Tree/properties/children/items", + "#/paths/~1tree/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/Tree/properties/children/items", + "#/paths/~1tree/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/param-non-nullable-to-nullable.out b/tests/cases/simple/output/param-non-nullable-to-nullable.out new file mode 100644 index 0000000..ab33b93 --- /dev/null +++ b/tests/cases/simple/output/param-non-nullable-to-nullable.out @@ -0,0 +1,27 @@ +--- param-non-nullable-to-nullable.json ++++ patched +@@ -378,6 +378,7 @@ + "name": "language", + "required": false, + "schema": { ++ "nullable": true, + "type": "string" + } + }, + + +Result for patch: +[ + Change { + message: "schema became nullable", + old_path: [ + "#/paths/~1hello~1{name}/get/parameters/1/schema", + ], + new_path: [ + "#/paths/~1hello~1{name}/get/parameters/1/schema", + ], + comparison: Input, + class: ForwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/param-nullable-to-non-nullable.out b/tests/cases/simple/output/param-nullable-to-non-nullable.out new file mode 100644 index 0000000..c1177e3 --- /dev/null +++ b/tests/cases/simple/output/param-nullable-to-non-nullable.out @@ -0,0 +1,27 @@ +--- param-nullable-to-non-nullable.json ++++ patched +@@ -387,7 +387,6 @@ + "name": "format", + "required": false, + "schema": { +- "nullable": true, + "type": "string" + } + } + + +Result for patch: +[ + Change { + message: "schema became non-nullable", + old_path: [ + "#/paths/~1hello~1{name}/get/parameters/2/schema", + ], + new_path: [ + "#/paths/~1hello~1{name}/get/parameters/2/schema", + ], + comparison: Input, + class: BackwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/param-required-to-optional.out b/tests/cases/simple/output/param-required-to-optional.out index c955a3c..a79a050 100644 --- a/tests/cases/simple/output/param-required-to-optional.out +++ b/tests/cases/simple/output/param-required-to-optional.out @@ -1,6 +1,6 @@ --- param-required-to-optional.json +++ patched -@@ -464,7 +464,7 @@ +@@ -707,7 +707,7 @@ { "in": "header", "name": "X-Request-Id", diff --git a/tests/cases/simple/output/param-schema-to-content.out b/tests/cases/simple/output/param-schema-to-content.out index b9f44c6..715122d 100644 --- a/tests/cases/simple/output/param-schema-to-content.out +++ b/tests/cases/simple/output/param-schema-to-content.out @@ -1,6 +1,6 @@ --- param-schema-to-content.json +++ patched -@@ -250,13 +250,17 @@ +@@ -373,13 +373,17 @@ } }, { @@ -19,9 +19,9 @@ - "type": "string" - } + "required": false - } - ], - "responses": { + }, + { + "description": "Output format (nullable for testing)", Result for patch: diff --git a/tests/cases/simple/output/redundant-wrapper-nullable-added.out b/tests/cases/simple/output/redundant-wrapper-nullable-added.out new file mode 100644 index 0000000..9bba164 --- /dev/null +++ b/tests/cases/simple/output/redundant-wrapper-nullable-added.out @@ -0,0 +1,16 @@ +--- redundant-wrapper-nullable-added.json ++++ patched +@@ -77,7 +77,8 @@ + "$ref": "#/components/schemas/NullableSubType" + } + ], +- "description": "Non-nullable wrapper around nullable type." ++ "description": "Non-nullable wrapper around nullable type.", ++ "nullable": true + }, + "not_a_number": { + "not": { + + +Result for patch: +[] diff --git a/tests/cases/simple/output/redundant-wrapper-nullable-removed.out b/tests/cases/simple/output/redundant-wrapper-nullable-removed.out new file mode 100644 index 0000000..90c8099 --- /dev/null +++ b/tests/cases/simple/output/redundant-wrapper-nullable-removed.out @@ -0,0 +1,16 @@ +--- redundant-wrapper-nullable-removed.json ++++ patched +@@ -98,8 +98,7 @@ + "$ref": "#/components/schemas/NullableSubType" + } + ], +- "description": "Nullable wrapper around already-nullable type.", +- "nullable": true ++ "description": "Nullable wrapper around already-nullable type." + }, + "via_allof": { + "allOf": [ + + +Result for patch: +[] diff --git a/tests/cases/simple/output/redundant-wrapper-to-ref.out b/tests/cases/simple/output/redundant-wrapper-to-ref.out new file mode 100644 index 0000000..68012ad --- /dev/null +++ b/tests/cases/simple/output/redundant-wrapper-to-ref.out @@ -0,0 +1,36 @@ +--- redundant-wrapper-to-ref.json ++++ patched +@@ -93,13 +93,7 @@ + "type": "string" + }, + "redundant_nullable_wrapper": { +- "allOf": [ +- { +- "$ref": "#/components/schemas/NullableSubType" +- } +- ], +- "description": "Nullable wrapper around already-nullable type.", +- "nullable": true ++ "$ref": "#/components/schemas/NullableSubType" + }, + "via_allof": { + "allOf": [ + + +Result for patch: +[ + Change { + message: "schema metadata removed", + old_path: [ + "#/components/schemas/GreetingResponse/properties/redundant_nullable_wrapper", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/redundant_nullable_wrapper", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: Trivial, + details: Metadata, + }, +] diff --git a/tests/cases/simple/output/ref-chain-change.out b/tests/cases/simple/output/ref-chain-change.out index 9d3bca3..b561fae 100644 --- a/tests/cases/simple/output/ref-chain-change.out +++ b/tests/cases/simple/output/ref-chain-change.out @@ -1,13 +1,13 @@ --- ref-chain-change.json +++ patched -@@ -132,7 +132,7 @@ +@@ -235,7 +235,7 @@ "$ref": "#/components/schemas/RefChainB" }, "RefChainB": { - "$ref": "#/components/schemas/SubType" + "$ref": "#/components/schemas/ErrorResponse" }, - "SubType": { + "SharedType": { "properties": { diff --git a/tests/cases/simple/output/ref-to-allof.out b/tests/cases/simple/output/ref-to-allof.out index 0ffecab..dddebb5 100644 --- a/tests/cases/simple/output/ref-to-allof.out +++ b/tests/cases/simple/output/ref-to-allof.out @@ -1,6 +1,6 @@ --- ref-to-allof.json +++ patched -@@ -82,7 +82,12 @@ +@@ -127,7 +127,12 @@ ] }, "via_ref": { diff --git a/tests/cases/simple/output/ref-to-anyof.out b/tests/cases/simple/output/ref-to-anyof.out index f764670..b2e51f0 100644 --- a/tests/cases/simple/output/ref-to-anyof.out +++ b/tests/cases/simple/output/ref-to-anyof.out @@ -1,6 +1,6 @@ --- ref-to-anyof.json +++ patched -@@ -82,7 +82,12 @@ +@@ -127,7 +127,12 @@ ] }, "via_ref": { diff --git a/tests/cases/simple/output/ref-to-inline-allof.out b/tests/cases/simple/output/ref-to-inline-allof.out index 41f89a9..625a3ab 100644 --- a/tests/cases/simple/output/ref-to-inline-allof.out +++ b/tests/cases/simple/output/ref-to-inline-allof.out @@ -1,6 +1,6 @@ --- ref-to-inline-allof.json +++ patched -@@ -82,7 +82,18 @@ +@@ -127,7 +127,18 @@ ] }, "via_ref": { diff --git a/tests/cases/simple/output/ref-to-oneof.out b/tests/cases/simple/output/ref-to-oneof.out index 4f95563..ef12459 100644 --- a/tests/cases/simple/output/ref-to-oneof.out +++ b/tests/cases/simple/output/ref-to-oneof.out @@ -1,6 +1,6 @@ --- ref-to-oneof.json +++ patched -@@ -82,7 +82,12 @@ +@@ -127,7 +127,12 @@ ] }, "via_ref": { diff --git a/tests/cases/simple/output/ref-to-redundant-wrapper.out b/tests/cases/simple/output/ref-to-redundant-wrapper.out new file mode 100644 index 0000000..e068a3a --- /dev/null +++ b/tests/cases/simple/output/ref-to-redundant-wrapper.out @@ -0,0 +1,36 @@ +--- ref-to-redundant-wrapper.json ++++ patched +@@ -85,7 +85,13 @@ + } + }, + "nullable_via_ref": { +- "$ref": "#/components/schemas/NullableSubType" ++ "allOf": [ ++ { ++ "$ref": "#/components/schemas/NullableSubType" ++ } ++ ], ++ "description": "Wrapped with redundant nullable.", ++ "nullable": true + }, + "optional_field": { + "description": "An optional nullable field", + + +Result for patch: +[ + Change { + message: "schema metadata added", + old_path: [ + "#/components/schemas/GreetingResponse/properties/nullable_via_ref", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/nullable_via_ref", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: Trivial, + details: Metadata, + }, +] diff --git a/tests/cases/simple/output/ref-to-wrapper-nullable-added.out b/tests/cases/simple/output/ref-to-wrapper-nullable-added.out new file mode 100644 index 0000000..e26ba2d --- /dev/null +++ b/tests/cases/simple/output/ref-to-wrapper-nullable-added.out @@ -0,0 +1,35 @@ +--- ref-to-wrapper-nullable-added.json ++++ patched +@@ -127,7 +127,12 @@ + ] + }, + "via_ref": { +- "$ref": "#/components/schemas/SubType" ++ "allOf": [ ++ { ++ "$ref": "#/components/schemas/SubType" ++ } ++ ], ++ "nullable": true + } + }, + "required": [ + + +Result for patch: +[ + Change { + message: "nullable added at wrapper", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_ref", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_ref", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/remove-default-response.out b/tests/cases/simple/output/remove-default-response.out index 615e057..2400966 100644 --- a/tests/cases/simple/output/remove-default-response.out +++ b/tests/cases/simple/output/remove-default-response.out @@ -1,6 +1,6 @@ --- remove-default-response.json +++ patched -@@ -442,16 +442,6 @@ +@@ -685,16 +685,6 @@ "responses": { "200": { "description": "Success" diff --git a/tests/cases/simple/output/remove-header-parameter.out b/tests/cases/simple/output/remove-header-parameter.out index 3f5b122..516a2af 100644 --- a/tests/cases/simple/output/remove-header-parameter.out +++ b/tests/cases/simple/output/remove-header-parameter.out @@ -1,6 +1,6 @@ --- remove-header-parameter.json +++ patched -@@ -462,14 +462,6 @@ +@@ -705,14 +705,6 @@ "operationId": "with_header", "parameters": [ { diff --git a/tests/cases/simple/output/remove-operation-parameter.out b/tests/cases/simple/output/remove-operation-parameter.out index 7fc3327..e1c2fe1 100644 --- a/tests/cases/simple/output/remove-operation-parameter.out +++ b/tests/cases/simple/output/remove-operation-parameter.out @@ -1,11 +1,9 @@ --- remove-operation-parameter.json +++ patched -@@ -248,15 +248,6 @@ - "schema": { - "type": "string" +@@ -373,15 +373,6 @@ } -- }, -- { + }, + { - "description": "Language for the greeting", - "in": "query", - "name": "language", @@ -13,9 +11,11 @@ - "schema": { - "type": "string" - } - } - ], - "responses": { +- }, +- { + "description": "Output format (nullable for testing)", + "in": "query", + "name": "format", Result for patch: diff --git a/tests/cases/simple/output/remove-operation.out b/tests/cases/simple/output/remove-operation.out index 04ed3a9..fc389eb 100644 --- a/tests/cases/simple/output/remove-operation.out +++ b/tests/cases/simple/output/remove-operation.out @@ -1,6 +1,6 @@ --- remove-operation.json +++ patched -@@ -361,18 +361,7 @@ +@@ -576,18 +576,7 @@ "summary": "Get oneOf schema" } }, diff --git a/tests/cases/simple/output/remove-optional-body.out b/tests/cases/simple/output/remove-optional-body.out index 4a7a983..6887e87 100644 --- a/tests/cases/simple/output/remove-optional-body.out +++ b/tests/cases/simple/output/remove-optional-body.out @@ -1,6 +1,6 @@ --- remove-optional-body.json +++ patched -@@ -296,16 +296,6 @@ +@@ -429,16 +429,6 @@ }, "put": { "operationId": "update_item", diff --git a/tests/cases/simple/output/remove-required-body.out b/tests/cases/simple/output/remove-required-body.out index 8cb5edc..76be9c1 100644 --- a/tests/cases/simple/output/remove-required-body.out +++ b/tests/cases/simple/output/remove-required-body.out @@ -1,6 +1,6 @@ --- remove-required-body.json +++ patched -@@ -277,16 +277,6 @@ +@@ -410,16 +410,6 @@ "/items": { "post": { "operationId": "create_item", diff --git a/tests/cases/simple/output/remove-response-code.out b/tests/cases/simple/output/remove-response-code.out index 6decf76..3dbf0d6 100644 --- a/tests/cases/simple/output/remove-response-code.out +++ b/tests/cases/simple/output/remove-response-code.out @@ -1,6 +1,6 @@ --- remove-response-code.json +++ patched -@@ -440,9 +440,6 @@ +@@ -683,9 +683,6 @@ "get": { "operationId": "with_default", "responses": { diff --git a/tests/cases/simple/output/remove-unnamed-operation.out b/tests/cases/simple/output/remove-unnamed-operation.out index a895a32..a9cedb4 100644 --- a/tests/cases/simple/output/remove-unnamed-operation.out +++ b/tests/cases/simple/output/remove-unnamed-operation.out @@ -1,6 +1,6 @@ --- remove-unnamed-operation.json +++ patched -@@ -426,16 +426,6 @@ +@@ -669,16 +669,6 @@ "summary": "Get typed properties" } }, diff --git a/tests/cases/simple/output/schema-kind-type-to-oneof.out b/tests/cases/simple/output/schema-kind-type-to-oneof.out index f6591ab..8993af5 100644 --- a/tests/cases/simple/output/schema-kind-type-to-oneof.out +++ b/tests/cases/simple/output/schema-kind-type-to-oneof.out @@ -1,7 +1,7 @@ --- schema-kind-type-to-oneof.json +++ patched -@@ -135,12 +135,14 @@ - "$ref": "#/components/schemas/SubType" +@@ -256,12 +256,14 @@ + "type": "object" }, "SubType": { - "properties": { @@ -18,7 +18,7 @@ + ] }, "Tree": { - "properties": { + "nullable": true, Result for patch: @@ -39,4 +39,20 @@ Result for patch: class: Incompatible, details: Datatype, }, + Change { + message: "schema kind changed from regular type to oneOf", + old_path: [ + "#/components/schemas/SubType", + "#/components/schemas/CreateItem/properties/metadata_nullable/0/$ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/SubType", + "#/components/schemas/CreateItem/properties/metadata_nullable/0/$ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: Incompatible, + details: Datatype, + }, ] diff --git a/tests/cases/simple/output/shared-non-nullable-to-nullable.out b/tests/cases/simple/output/shared-non-nullable-to-nullable.out new file mode 100644 index 0000000..f15fbaa --- /dev/null +++ b/tests/cases/simple/output/shared-non-nullable-to-nullable.out @@ -0,0 +1,43 @@ +--- shared-non-nullable-to-nullable.json ++++ patched +@@ -240,6 +240,7 @@ + "SharedType": { + "properties": { + "data": { ++ "nullable": true, + "type": "string" + }, + "id": { + + +Result for patch: +[ + Change { + message: "schema became nullable", + old_path: [ + "#/components/schemas/SharedType/properties/data", + "#/paths/~1shared/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/SharedType/properties/data", + "#/paths/~1shared/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: ForwardIncompatible, + details: LessStrict, + }, + Change { + message: "schema became nullable", + old_path: [ + "#/components/schemas/SharedType/properties/data", + "#/paths/~1shared/post/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/SharedType/properties/data", + "#/paths/~1shared/post/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/shared-nullable-to-non-nullable.out b/tests/cases/simple/output/shared-nullable-to-non-nullable.out new file mode 100644 index 0000000..4432bde --- /dev/null +++ b/tests/cases/simple/output/shared-nullable-to-non-nullable.out @@ -0,0 +1,43 @@ +--- shared-nullable-to-non-nullable.json ++++ patched +@@ -246,7 +246,6 @@ + "type": "string" + }, + "optional_data": { +- "nullable": true, + "type": "string" + } + }, + + +Result for patch: +[ + Change { + message: "schema became non-nullable", + old_path: [ + "#/components/schemas/SharedType/properties/optional_data", + "#/paths/~1shared/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/SharedType/properties/optional_data", + "#/paths/~1shared/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: BackwardIncompatible, + details: MoreStrict, + }, + Change { + message: "schema became non-nullable", + old_path: [ + "#/components/schemas/SharedType/properties/optional_data", + "#/paths/~1shared/post/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/SharedType/properties/optional_data", + "#/paths/~1shared/post/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/string-format-change.out b/tests/cases/simple/output/string-format-change.out index 1f8edf0..48f6a89 100644 --- a/tests/cases/simple/output/string-format-change.out +++ b/tests/cases/simple/output/string-format-change.out @@ -1,13 +1,13 @@ --- string-format-change.json +++ patched -@@ -50,6 +50,7 @@ +@@ -69,6 +69,7 @@ "properties": { "message": { "description": "The greeting message", + "format": "uuid", "type": "string" }, - "not_a_number": { + "non_nullable_wrapper_of_nullable": { Result for patch: diff --git a/tests/cases/simple/output/type-indirection.out b/tests/cases/simple/output/type-indirection.out index 910cf39..a338a10 100644 --- a/tests/cases/simple/output/type-indirection.out +++ b/tests/cases/simple/output/type-indirection.out @@ -1,6 +1,6 @@ --- type-indirection.json +++ patched -@@ -49,8 +49,7 @@ +@@ -68,8 +68,7 @@ "GreetingResponse": { "properties": { "message": { @@ -8,9 +8,9 @@ - "type": "string" + "$ref": "#/components/schemas/GreetingResponseMessage" }, - "not_a_number": { - "not": { -@@ -90,6 +89,13 @@ + "non_nullable_wrapper_of_nullable": { + "allOf": [ +@@ -135,6 +134,13 @@ ], "type": "object" }, diff --git a/tests/cases/simple/output/type-rename.out b/tests/cases/simple/output/type-rename.out index bac28a3..b068a6f 100644 --- a/tests/cases/simple/output/type-rename.out +++ b/tests/cases/simple/output/type-rename.out @@ -1,6 +1,6 @@ --- type-rename.json +++ patched -@@ -46,7 +46,7 @@ +@@ -65,7 +65,7 @@ ], "type": "object" }, @@ -9,7 +9,7 @@ "properties": { "message": { "description": "The greeting message", -@@ -264,7 +264,7 @@ +@@ -397,7 +397,7 @@ "content": { "application/json": { "schema": { diff --git a/tests/cases/simple/output/unhandled-add-prop.out b/tests/cases/simple/output/unhandled-add-prop.out index 37193a0..a0c94c8 100644 --- a/tests/cases/simple/output/unhandled-add-prop.out +++ b/tests/cases/simple/output/unhandled-add-prop.out @@ -1,8 +1,8 @@ --- unhandled-add-prop.json +++ patched -@@ -57,6 +57,10 @@ - "type": "number" - } +@@ -101,6 +101,10 @@ + "description": "Nullable wrapper around already-nullable type.", + "nullable": true }, + "source": { + "description": "Where the greeting originated", @@ -11,7 +11,7 @@ "via_allof": { "allOf": [ { -@@ -86,7 +90,8 @@ +@@ -131,7 +135,8 @@ } }, "required": [ diff --git a/tests/cases/simple/output/wrapper-non-nullable-to-nullable.out b/tests/cases/simple/output/wrapper-non-nullable-to-nullable.out new file mode 100644 index 0000000..80b1793 --- /dev/null +++ b/tests/cases/simple/output/wrapper-non-nullable-to-nullable.out @@ -0,0 +1,31 @@ +--- wrapper-non-nullable-to-nullable.json ++++ patched +@@ -107,7 +107,8 @@ + "$ref": "#/components/schemas/SubType" + } + ], +- "description": "Via allOf." ++ "description": "Via allOf.", ++ "nullable": true + }, + "via_anyof": { + "anyOf": [ + + +Result for patch: +[ + Change { + message: "nullable added at wrapper", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_allof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_allof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: BackwardIncompatible, + details: LessStrict, + }, +] diff --git a/tests/cases/simple/output/wrapper-nullable-to-non-nullable.out b/tests/cases/simple/output/wrapper-nullable-to-non-nullable.out new file mode 100644 index 0000000..dd42fa8 --- /dev/null +++ b/tests/cases/simple/output/wrapper-nullable-to-non-nullable.out @@ -0,0 +1,31 @@ +--- wrapper-nullable-to-non-nullable.json ++++ patched +@@ -115,8 +115,7 @@ + "$ref": "#/components/schemas/SubType" + } + ], +- "description": "Via anyOf.", +- "nullable": true ++ "description": "Via anyOf." + }, + "via_oneof": { + "description": "Via oneOf.", + + +Result for patch: +[ + Change { + message: "nullable removed from wrapper", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, +] diff --git a/tests/cases/simple/output/wrapper-to-inline-nullable-removed.out b/tests/cases/simple/output/wrapper-to-inline-nullable-removed.out new file mode 100644 index 0000000..e40dd73 --- /dev/null +++ b/tests/cases/simple/output/wrapper-to-inline-nullable-removed.out @@ -0,0 +1,54 @@ +--- wrapper-to-inline-nullable-removed.json ++++ patched +@@ -110,13 +110,12 @@ + "description": "Via allOf." + }, + "via_anyof": { +- "anyOf": [ +- { +- "$ref": "#/components/schemas/SubType" ++ "properties": { ++ "value": { ++ "type": "string" + } +- ], +- "description": "Via anyOf.", +- "nullable": true ++ }, ++ "type": "object" + }, + "via_oneof": { + "description": "Via oneOf.", + + +Result for patch: +[ + Change { + message: "nullable removed from wrapper", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, + Change { + message: "schema metadata removed", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: Trivial, + details: Metadata, + }, +] diff --git a/tests/cases/simple/output/wrapper-to-ref-nullable-removed.out b/tests/cases/simple/output/wrapper-to-ref-nullable-removed.out new file mode 100644 index 0000000..554c26b --- /dev/null +++ b/tests/cases/simple/output/wrapper-to-ref-nullable-removed.out @@ -0,0 +1,50 @@ +--- wrapper-to-ref-nullable-removed.json ++++ patched +@@ -110,13 +110,7 @@ + "description": "Via allOf." + }, + "via_anyof": { +- "anyOf": [ +- { +- "$ref": "#/components/schemas/SubType" +- } +- ], +- "description": "Via anyOf.", +- "nullable": true ++ "$ref": "#/components/schemas/SubType" + }, + "via_oneof": { + "description": "Via oneOf.", + + +Result for patch: +[ + Change { + message: "nullable removed from wrapper", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: ForwardIncompatible, + details: MoreStrict, + }, + Change { + message: "schema metadata removed", + old_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/GreetingResponse/properties/via_anyof", + "#/paths/~1hello~1{name}/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: Trivial, + details: Metadata, + }, +] diff --git a/tests/cases/simple/output/wrapper-unchanged-with-type-change.out b/tests/cases/simple/output/wrapper-unchanged-with-type-change.out index 7b96447..c27e159 100644 --- a/tests/cases/simple/output/wrapper-unchanged-with-type-change.out +++ b/tests/cases/simple/output/wrapper-unchanged-with-type-change.out @@ -1,6 +1,6 @@ --- wrapper-unchanged-with-type-change.json +++ patched -@@ -137,7 +137,7 @@ +@@ -258,7 +258,7 @@ "SubType": { "properties": { "value": { @@ -29,4 +29,20 @@ Result for patch: class: Incompatible, details: UnknownDifference, }, + Change { + message: "schema types changed", + old_path: [ + "#/components/schemas/SubType/properties/value", + "#/components/schemas/CreateItem/properties/metadata_nullable/0/$ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/SubType/properties/value", + "#/components/schemas/CreateItem/properties/metadata_nullable/0/$ref", + "#/paths/~1items/post/request_body/content/application~1json/schema/$ref", + ], + comparison: Input, + class: Incompatible, + details: UnknownDifference, + }, ] diff --git a/tests/cases/simple/patch/additional-props-non-nullable-to-nullable.json b/tests/cases/simple/patch/additional-props-non-nullable-to-nullable.json new file mode 100644 index 0000000..b23fe9b --- /dev/null +++ b/tests/cases/simple/patch/additional-props-non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/ObjectWithConstraints/additionalProperties/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/array-items-non-nullable-to-nullable.json b/tests/cases/simple/patch/array-items-non-nullable-to-nullable.json new file mode 100644 index 0000000..05e83ce --- /dev/null +++ b/tests/cases/simple/patch/array-items-non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/ArrayWithConstraints/items/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/array-items-remove.json b/tests/cases/simple/patch/array-items-remove.json index 18f0cf9..03f7bf6 100644 --- a/tests/cases/simple/patch/array-items-remove.json +++ b/tests/cases/simple/patch/array-items-remove.json @@ -3,7 +3,8 @@ "op": "add", "path": "/components/schemas/Tree/properties/children/items", "value": { - "type": "string" + "type": "string", + "nullable": true } } ] diff --git a/tests/cases/simple/patch/boolean-enum-change.json b/tests/cases/simple/patch/boolean-enum-change.json index ea478de..b776c97 100644 --- a/tests/cases/simple/patch/boolean-enum-change.json +++ b/tests/cases/simple/patch/boolean-enum-change.json @@ -2,6 +2,8 @@ { "op": "add", "path": "/components/schemas/TypedProperties/properties/enabled/enum", - "value": [true] + "value": [ + true + ] } ] diff --git a/tests/cases/simple/patch/change-operation-parameter-requirement.json b/tests/cases/simple/patch/change-operation-parameter-requirement.json index cf46c17..ece6f73 100644 --- a/tests/cases/simple/patch/change-operation-parameter-requirement.json +++ b/tests/cases/simple/patch/change-operation-parameter-requirement.json @@ -1,12 +1,12 @@ [ - { - "op": "test", - "path": "/paths/~1hello~1{name}/get/parameters/1/name", - "value": "language" - }, - { - "op": "replace", - "path": "/paths/~1hello~1{name}/get/parameters/1/required", - "value": true - } + { + "op": "test", + "path": "/paths/~1hello~1{name}/get/parameters/1/name", + "value": "language" + }, + { + "op": "replace", + "path": "/paths/~1hello~1{name}/get/parameters/1/required", + "value": true + } ] diff --git a/tests/cases/simple/patch/change-operation-parameter-type.json b/tests/cases/simple/patch/change-operation-parameter-type.json index 76ea4cf..17bdbd2 100644 --- a/tests/cases/simple/patch/change-operation-parameter-type.json +++ b/tests/cases/simple/patch/change-operation-parameter-type.json @@ -1,12 +1,12 @@ [ - { - "op": "test", - "path": "/paths/~1hello~1{name}/get/parameters/1/name", - "value": "language" - }, - { - "op": "replace", - "path": "/paths/~1hello~1{name}/get/parameters/1/schema/type", - "value": "integer" - } + { + "op": "test", + "path": "/paths/~1hello~1{name}/get/parameters/1/name", + "value": "language" + }, + { + "op": "replace", + "path": "/paths/~1hello~1{name}/get/parameters/1/schema/type", + "value": "integer" + } ] diff --git a/tests/cases/simple/patch/change-property-type.json b/tests/cases/simple/patch/change-property-type.json index e91d4fb..7307e9d 100644 --- a/tests/cases/simple/patch/change-property-type.json +++ b/tests/cases/simple/patch/change-property-type.json @@ -1,7 +1,7 @@ [ - { - "op": "replace", - "path": "/components/schemas/GreetingResponse/properties/message/type", - "value": "integer" - } + { + "op": "replace", + "path": "/components/schemas/GreetingResponse/properties/message/type", + "value": "integer" + } ] diff --git a/tests/cases/simple/patch/inline-to-wrapper-nullable-added.json b/tests/cases/simple/patch/inline-to-wrapper-nullable-added.json new file mode 100644 index 0000000..a7ab545 --- /dev/null +++ b/tests/cases/simple/patch/inline-to-wrapper-nullable-added.json @@ -0,0 +1,15 @@ +[ + { + "op": "replace", + "path": "/components/schemas/GreetingResponse/properties/message", + "value": { + "nullable": true, + "description": "The greeting message", + "allOf": [ + { + "type": "string" + } + ] + } + } +] diff --git a/tests/cases/simple/patch/input-non-nullable-to-nullable.json b/tests/cases/simple/patch/input-non-nullable-to-nullable.json new file mode 100644 index 0000000..bd8929f --- /dev/null +++ b/tests/cases/simple/patch/input-non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/CreateItem/properties/name/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/input-nullable-to-non-nullable.json b/tests/cases/simple/patch/input-nullable-to-non-nullable.json new file mode 100644 index 0000000..c4c8f12 --- /dev/null +++ b/tests/cases/simple/patch/input-nullable-to-non-nullable.json @@ -0,0 +1,6 @@ +[ + { + "op": "remove", + "path": "/components/schemas/CreateItem/properties/description/nullable" + } +] diff --git a/tests/cases/simple/patch/input-ref-to-wrapper-nullable-added.json b/tests/cases/simple/patch/input-ref-to-wrapper-nullable-added.json new file mode 100644 index 0000000..a4ca909 --- /dev/null +++ b/tests/cases/simple/patch/input-ref-to-wrapper-nullable-added.json @@ -0,0 +1,14 @@ +[ + { + "op": "replace", + "path": "/components/schemas/CreateItem/properties/name", + "value": { + "nullable": true, + "allOf": [ + { + "type": "string" + } + ] + } + } +] diff --git a/tests/cases/simple/patch/input-root-non-nullable-to-nullable.json b/tests/cases/simple/patch/input-root-non-nullable-to-nullable.json new file mode 100644 index 0000000..a97cea1 --- /dev/null +++ b/tests/cases/simple/patch/input-root-non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/CreateItem/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/input-root-nullable-to-non-nullable.json b/tests/cases/simple/patch/input-root-nullable-to-non-nullable.json new file mode 100644 index 0000000..c877cb9 --- /dev/null +++ b/tests/cases/simple/patch/input-root-nullable-to-non-nullable.json @@ -0,0 +1,6 @@ +[ + { + "op": "remove", + "path": "/components/schemas/UpdateItem/nullable" + } +] diff --git a/tests/cases/simple/patch/input-wrapper-non-nullable-to-nullable.json b/tests/cases/simple/patch/input-wrapper-non-nullable-to-nullable.json new file mode 100644 index 0000000..ec0d68a --- /dev/null +++ b/tests/cases/simple/patch/input-wrapper-non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/CreateItem/properties/metadata_ref/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/input-wrapper-nullable-to-non-nullable.json b/tests/cases/simple/patch/input-wrapper-nullable-to-non-nullable.json new file mode 100644 index 0000000..370e915 --- /dev/null +++ b/tests/cases/simple/patch/input-wrapper-nullable-to-non-nullable.json @@ -0,0 +1,6 @@ +[ + { + "op": "remove", + "path": "/components/schemas/CreateItem/properties/metadata_nullable/nullable" + } +] diff --git a/tests/cases/simple/patch/input-wrapper-to-ref-nullable-removed.json b/tests/cases/simple/patch/input-wrapper-to-ref-nullable-removed.json new file mode 100644 index 0000000..017467b --- /dev/null +++ b/tests/cases/simple/patch/input-wrapper-to-ref-nullable-removed.json @@ -0,0 +1,9 @@ +[ + { + "op": "replace", + "path": "/components/schemas/CreateItem/properties/metadata_nullable", + "value": { + "$ref": "#/components/schemas/SubType" + } + } +] diff --git a/tests/cases/simple/patch/nested-wrapper-non-nullable-to-nullable.json b/tests/cases/simple/patch/nested-wrapper-non-nullable-to-nullable.json new file mode 100644 index 0000000..44bc6ea --- /dev/null +++ b/tests/cases/simple/patch/nested-wrapper-non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/NestedWrapperC/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/nested-wrapper-nullable-to-non-nullable.json b/tests/cases/simple/patch/nested-wrapper-nullable-to-non-nullable.json new file mode 100644 index 0000000..482f8e4 --- /dev/null +++ b/tests/cases/simple/patch/nested-wrapper-nullable-to-non-nullable.json @@ -0,0 +1,6 @@ +[ + { + "op": "remove", + "path": "/components/schemas/NestedNullableWrapperC/nullable" + } +] diff --git a/tests/cases/simple/patch/non-nullable-to-nullable.json b/tests/cases/simple/patch/non-nullable-to-nullable.json new file mode 100644 index 0000000..89951c6 --- /dev/null +++ b/tests/cases/simple/patch/non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/GreetingResponse/properties/message/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/nullable-to-non-nullable.json b/tests/cases/simple/patch/nullable-to-non-nullable.json new file mode 100644 index 0000000..efcc0df --- /dev/null +++ b/tests/cases/simple/patch/nullable-to-non-nullable.json @@ -0,0 +1,6 @@ +[ + { + "op": "remove", + "path": "/components/schemas/GreetingResponse/properties/optional_field/nullable" + } +] diff --git a/tests/cases/simple/patch/output-root-non-nullable-to-nullable.json b/tests/cases/simple/patch/output-root-non-nullable-to-nullable.json new file mode 100644 index 0000000..1921546 --- /dev/null +++ b/tests/cases/simple/patch/output-root-non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/GreetingResponse/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/output-root-nullable-to-non-nullable.json b/tests/cases/simple/patch/output-root-nullable-to-non-nullable.json new file mode 100644 index 0000000..3b631e2 --- /dev/null +++ b/tests/cases/simple/patch/output-root-nullable-to-non-nullable.json @@ -0,0 +1,6 @@ +[ + { + "op": "remove", + "path": "/components/schemas/Tree/nullable" + } +] diff --git a/tests/cases/simple/patch/param-non-nullable-to-nullable.json b/tests/cases/simple/patch/param-non-nullable-to-nullable.json new file mode 100644 index 0000000..e3ec2fb --- /dev/null +++ b/tests/cases/simple/patch/param-non-nullable-to-nullable.json @@ -0,0 +1,12 @@ +[ + { + "op": "test", + "path": "/paths/~1hello~1{name}/get/parameters/1/name", + "value": "language" + }, + { + "op": "add", + "path": "/paths/~1hello~1{name}/get/parameters/1/schema/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/param-nullable-to-non-nullable.json b/tests/cases/simple/patch/param-nullable-to-non-nullable.json new file mode 100644 index 0000000..8278722 --- /dev/null +++ b/tests/cases/simple/patch/param-nullable-to-non-nullable.json @@ -0,0 +1,11 @@ +[ + { + "op": "test", + "path": "/paths/~1hello~1{name}/get/parameters/2/name", + "value": "format" + }, + { + "op": "remove", + "path": "/paths/~1hello~1{name}/get/parameters/2/schema/nullable" + } +] diff --git a/tests/cases/simple/patch/redundant-wrapper-nullable-added.json b/tests/cases/simple/patch/redundant-wrapper-nullable-added.json new file mode 100644 index 0000000..e8cd80a --- /dev/null +++ b/tests/cases/simple/patch/redundant-wrapper-nullable-added.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/GreetingResponse/properties/non_nullable_wrapper_of_nullable/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/redundant-wrapper-nullable-removed.json b/tests/cases/simple/patch/redundant-wrapper-nullable-removed.json new file mode 100644 index 0000000..62ded33 --- /dev/null +++ b/tests/cases/simple/patch/redundant-wrapper-nullable-removed.json @@ -0,0 +1,6 @@ +[ + { + "op": "remove", + "path": "/components/schemas/GreetingResponse/properties/redundant_nullable_wrapper/nullable" + } +] diff --git a/tests/cases/simple/patch/redundant-wrapper-to-ref.json b/tests/cases/simple/patch/redundant-wrapper-to-ref.json new file mode 100644 index 0000000..548973e --- /dev/null +++ b/tests/cases/simple/patch/redundant-wrapper-to-ref.json @@ -0,0 +1,9 @@ +[ + { + "op": "replace", + "path": "/components/schemas/GreetingResponse/properties/redundant_nullable_wrapper", + "value": { + "$ref": "#/components/schemas/NullableSubType" + } + } +] diff --git a/tests/cases/simple/patch/ref-to-redundant-wrapper.json b/tests/cases/simple/patch/ref-to-redundant-wrapper.json new file mode 100644 index 0000000..191fbd2 --- /dev/null +++ b/tests/cases/simple/patch/ref-to-redundant-wrapper.json @@ -0,0 +1,15 @@ +[ + { + "op": "replace", + "path": "/components/schemas/GreetingResponse/properties/nullable_via_ref", + "value": { + "nullable": true, + "description": "Wrapped with redundant nullable.", + "allOf": [ + { + "$ref": "#/components/schemas/NullableSubType" + } + ] + } + } +] diff --git a/tests/cases/simple/patch/ref-to-wrapper-nullable-added.json b/tests/cases/simple/patch/ref-to-wrapper-nullable-added.json new file mode 100644 index 0000000..7e17eb0 --- /dev/null +++ b/tests/cases/simple/patch/ref-to-wrapper-nullable-added.json @@ -0,0 +1,14 @@ +[ + { + "op": "replace", + "path": "/components/schemas/GreetingResponse/properties/via_ref", + "value": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/SubType" + } + ] + } + } +] diff --git a/tests/cases/simple/patch/remove-operation-parameter.json b/tests/cases/simple/patch/remove-operation-parameter.json index 32fb971..c45f2ae 100644 --- a/tests/cases/simple/patch/remove-operation-parameter.json +++ b/tests/cases/simple/patch/remove-operation-parameter.json @@ -1,6 +1,6 @@ [ - { - "op": "remove", - "path": "/paths/~1hello~1{name}/get/parameters/1" - } + { + "op": "remove", + "path": "/paths/~1hello~1{name}/get/parameters/1" + } ] diff --git a/tests/cases/simple/patch/shared-non-nullable-to-nullable.json b/tests/cases/simple/patch/shared-non-nullable-to-nullable.json new file mode 100644 index 0000000..4435690 --- /dev/null +++ b/tests/cases/simple/patch/shared-non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/SharedType/properties/data/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/shared-nullable-to-non-nullable.json b/tests/cases/simple/patch/shared-nullable-to-non-nullable.json new file mode 100644 index 0000000..f591e4f --- /dev/null +++ b/tests/cases/simple/patch/shared-nullable-to-non-nullable.json @@ -0,0 +1,6 @@ +[ + { + "op": "remove", + "path": "/components/schemas/SharedType/properties/optional_data/nullable" + } +] diff --git a/tests/cases/simple/patch/unhandled-add-prop.json b/tests/cases/simple/patch/unhandled-add-prop.json index ad68b05..d62e1f9 100644 --- a/tests/cases/simple/patch/unhandled-add-prop.json +++ b/tests/cases/simple/patch/unhandled-add-prop.json @@ -1,15 +1,15 @@ [ - { - "op": "add", - "path": "/components/schemas/GreetingResponse/properties/source", - "value": { - "type": "string", - "description": "Where the greeting originated" - } - }, - { - "op": "add", - "path": "/components/schemas/GreetingResponse/required/-", - "value": "source" - } + { + "op": "add", + "path": "/components/schemas/GreetingResponse/properties/source", + "value": { + "type": "string", + "description": "Where the greeting originated" + } + }, + { + "op": "add", + "path": "/components/schemas/GreetingResponse/required/-", + "value": "source" + } ] diff --git a/tests/cases/simple/patch/wrapper-non-nullable-to-nullable.json b/tests/cases/simple/patch/wrapper-non-nullable-to-nullable.json new file mode 100644 index 0000000..fc3b039 --- /dev/null +++ b/tests/cases/simple/patch/wrapper-non-nullable-to-nullable.json @@ -0,0 +1,7 @@ +[ + { + "op": "add", + "path": "/components/schemas/GreetingResponse/properties/via_allof/nullable", + "value": true + } +] diff --git a/tests/cases/simple/patch/wrapper-nullable-to-non-nullable.json b/tests/cases/simple/patch/wrapper-nullable-to-non-nullable.json new file mode 100644 index 0000000..d783701 --- /dev/null +++ b/tests/cases/simple/patch/wrapper-nullable-to-non-nullable.json @@ -0,0 +1,6 @@ +[ + { + "op": "remove", + "path": "/components/schemas/GreetingResponse/properties/via_anyof/nullable" + } +] diff --git a/tests/cases/simple/patch/wrapper-to-inline-nullable-removed.json b/tests/cases/simple/patch/wrapper-to-inline-nullable-removed.json new file mode 100644 index 0000000..da43834 --- /dev/null +++ b/tests/cases/simple/patch/wrapper-to-inline-nullable-removed.json @@ -0,0 +1,14 @@ +[ + { + "op": "replace", + "path": "/components/schemas/GreetingResponse/properties/via_anyof", + "value": { + "type": "object", + "properties": { + "value": { + "type": "string" + } + } + } + } +] diff --git a/tests/cases/simple/patch/wrapper-to-ref-nullable-removed.json b/tests/cases/simple/patch/wrapper-to-ref-nullable-removed.json new file mode 100644 index 0000000..20c364b --- /dev/null +++ b/tests/cases/simple/patch/wrapper-to-ref-nullable-removed.json @@ -0,0 +1,9 @@ +[ + { + "op": "replace", + "path": "/components/schemas/GreetingResponse/properties/via_anyof", + "value": { + "$ref": "#/components/schemas/SubType" + } + } +]