From 23982f973ec55c7374b2621d6ed6a1d147340c5f Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 6 Feb 2026 02:37:49 +0000 Subject: [PATCH 1/4] [spr] changes to main this commit is based on Created using spr 1.3.6-beta.1 [skip ci] --- src/compare.rs | 7 +++-- src/operations.rs | 2 +- .../simple/output/add-cookie-parameter.out | 2 +- .../simple/output/add-default-response.out | 2 +- .../simple/output/add-header-parameter.out | 2 +- .../simple/output/add-operation-with-id.out | 2 +- tests/cases/simple/output/add-operation.out | 2 +- .../cases/simple/output/add-optional-body.out | 2 +- .../simple/output/add-optional-parameter.out | 2 +- .../cases/simple/output/add-required-body.out | 2 +- .../simple/output/add-required-parameter.out | 2 +- .../cases/simple/output/add-response-code.out | 2 +- .../simple/output/add-type-extension.out | 2 +- tests/cases/simple/output/allof-to-anyof.out | 2 +- .../allof-to-oneof-with-type-change.out | 4 +-- tests/cases/simple/output/allof-to-oneof.out | 2 +- .../output/allof-to-ref-with-type-change.out | 4 +-- tests/cases/simple/output/allof-to-ref.out | 2 +- .../cases/simple/output/any-schema-change.out | 2 +- tests/cases/simple/output/anyof-to-allof.out | 2 +- tests/cases/simple/output/anyof-to-oneof.out | 2 +- tests/cases/simple/output/anyof-to-ref.out | 2 +- tests/cases/simple/output/array-items-add.out | 2 +- .../simple/output/array-items-remove.out | 2 +- .../simple/output/array-max-items-change.out | 2 +- .../simple/output/array-min-items-change.out | 2 +- .../output/array-unique-items-change.out | 2 +- .../simple/output/body-description-change.out | 2 +- .../simple/output/body-extension-change.out | 2 +- .../output/body-optional-to-required.out | 2 +- .../output/body-required-to-optional.out | 2 +- tests/cases/simple/output/boolean-change.out | 2 +- .../simple/output/boolean-enum-change.out | 2 +- .../simple/output/change-default-response.out | 2 +- .../simple/output/change-header-parameter.out | 2 +- ...change-operation-parameter-requirement.out | 2 +- .../change-operation-parameter-type.out | 2 +- .../simple/output/change-property-type.out | 2 +- tests/cases/simple/output/inline-to-allof.out | 2 +- .../simple/output/integer-format-change.out | 2 +- .../cases/simple/output/modify-cycle-type.out | 2 +- .../output/multi-allof-variant-change.out | 2 +- .../output/multi-anyof-variant-change.out | 2 +- .../output/multi-oneof-count-change.out | 2 +- .../output/multi-oneof-variant-change.out | 2 +- .../simple/output/not-inner-to-allof.out | 2 +- tests/cases/simple/output/not-to-allof.out | 2 +- .../output/number-constraints-change.out | 2 +- .../output/object-additional-props-false.out | 2 +- .../object-additional-props-schema-change.out | 2 +- .../object-additional-props-type-change.out | 2 +- .../output/object-max-properties-change.out | 2 +- .../output/object-min-properties-change.out | 2 +- tests/cases/simple/output/oneof-to-allof.out | 2 +- tests/cases/simple/output/oneof-to-anyof.out | 2 +- tests/cases/simple/output/oneof-to-ref.out | 2 +- .../output/param-required-to-optional.out | 2 +- .../simple/output/param-schema-to-content.out | 2 +- .../cases/simple/output/ref-chain-change.out | 2 +- tests/cases/simple/output/ref-to-allof.out | 2 +- tests/cases/simple/output/ref-to-anyof.out | 2 +- .../simple/output/ref-to-inline-allof.out | 2 +- tests/cases/simple/output/ref-to-oneof.out | 2 +- .../simple/output/remove-default-response.out | 2 +- .../simple/output/remove-header-parameter.out | 2 +- .../output/remove-operation-parameter.out | 2 +- .../cases/simple/output/remove-operation.out | 2 +- .../simple/output/remove-optional-body.out | 2 +- .../simple/output/remove-required-body.out | 2 +- .../simple/output/remove-response-code.out | 2 +- .../output/remove-unnamed-operation.out | 2 +- .../output/schema-kind-type-to-oneof.out | 2 +- .../simple/output/string-format-change.out | 2 +- .../cases/simple/output/type-indirection.out | 4 +-- tests/cases/simple/output/type-rename.out | 4 +-- .../simple/output/unhandled-add-prop.out | 4 +-- .../wrapper-unchanged-with-type-change.out | 2 +- tests/test_changes.rs | 30 ++++++++++++++----- 78 files changed, 108 insertions(+), 91 deletions(-) diff --git a/src/compare.rs b/src/compare.rs index eb77743..039cc7d 100644 --- a/src/compare.rs +++ b/src/compare.rs @@ -2,6 +2,7 @@ use std::collections::BTreeMap; +use anyhow::Context as _; use indexmap::IndexMap; use openapiv3::{ MediaType, Operation, Parameter, ParameterSchemaOrContent, ReferenceOr, RequestBody, @@ -35,10 +36,12 @@ pub(crate) struct Compare { impl Compare { pub fn compare(&mut self, old: &Value, new: &Value) -> anyhow::Result<()> { let old_context = Context::new(old); - let old_operations = operations(&old_context)?; + let old_operations = + operations(&old_context).context("error deserializing old OpenAPI document")?; let new_context = Context::new(new); - let new_operations = operations(&new_context)?; + let new_operations = + operations(&new_context).context("error deserializing new OpenAPI document")?; let SetCompare { a_unique, diff --git a/src/operations.rs b/src/operations.rs index 700cd44..d21af01 100644 --- a/src/operations.rs +++ b/src/operations.rs @@ -41,7 +41,7 @@ pub struct OperationInfo<'a> { pub fn operations<'a>( context: &Context<'a>, ) -> anyhow::Result)>> { - let api = OpenAPI::deserialize(context.raw_openapi).unwrap(); + let api = OpenAPI::deserialize(context.raw_openapi)?; let mut out = Vec::new(); diff --git a/tests/cases/simple/output/add-cookie-parameter.out b/tests/cases/simple/output/add-cookie-parameter.out index 805b882..51fbbfa 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 @@ +@@ "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..f363a44 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 @@ +@@ "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..9fea299 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 @@ +@@ "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..18d243d 100644 --- a/tests/cases/simple/output/add-operation-with-id.out +++ b/tests/cases/simple/output/add-operation-with-id.out @@ -1,6 +1,6 @@ --- add-operation-with-id.json +++ patched -@@ -314,6 +314,17 @@ +@@ "summary": "Update an item" } }, diff --git a/tests/cases/simple/output/add-operation.out b/tests/cases/simple/output/add-operation.out index f938e86..c7803ea 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 @@ +@@ "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..aa34604 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 @@ +@@ "/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..480f70b 100644 --- a/tests/cases/simple/output/add-optional-parameter.out +++ b/tests/cases/simple/output/add-optional-parameter.out @@ -1,6 +1,6 @@ --- add-optional-parameter.json +++ patched -@@ -257,6 +257,15 @@ +@@ "schema": { "type": "string" } diff --git a/tests/cases/simple/output/add-required-body.out b/tests/cases/simple/output/add-required-body.out index 47d7d4e..0d43efc 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 @@ +@@ "/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..df7a466 100644 --- a/tests/cases/simple/output/add-required-parameter.out +++ b/tests/cases/simple/output/add-required-parameter.out @@ -1,6 +1,6 @@ --- add-required-parameter.json +++ patched -@@ -257,6 +257,15 @@ +@@ "schema": { "type": "string" } diff --git a/tests/cases/simple/output/add-response-code.out b/tests/cases/simple/output/add-response-code.out index 4d98490..181b8d6 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 @@ +@@ "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..306f21f 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 @@ +@@ "required": [ "message" ], diff --git a/tests/cases/simple/output/allof-to-anyof.out b/tests/cases/simple/output/allof-to-anyof.out index c65c7a9..a1f68b0 100644 --- a/tests/cases/simple/output/allof-to-anyof.out +++ b/tests/cases/simple/output/allof-to-anyof.out @@ -1,6 +1,6 @@ --- allof-to-anyof.json +++ patched -@@ -58,12 +58,12 @@ +@@ } }, "via_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..60c4216 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,6 +1,6 @@ --- allof-to-oneof-with-type-change.json +++ patched -@@ -58,12 +58,12 @@ +@@ } }, "via_allof": { @@ -16,7 +16,7 @@ }, "via_anyof": { "anyOf": [ -@@ -137,7 +137,7 @@ +@@ "SubType": { "properties": { "value": { diff --git a/tests/cases/simple/output/allof-to-oneof.out b/tests/cases/simple/output/allof-to-oneof.out index 14f9d00..c800e11 100644 --- a/tests/cases/simple/output/allof-to-oneof.out +++ b/tests/cases/simple/output/allof-to-oneof.out @@ -1,6 +1,6 @@ --- allof-to-oneof.json +++ patched -@@ -58,12 +58,12 @@ +@@ } }, "via_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..154d75b 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,6 +1,6 @@ --- allof-to-ref-with-type-change.json +++ patched -@@ -58,12 +58,7 @@ +@@ } }, "via_allof": { @@ -14,7 +14,7 @@ }, "via_anyof": { "anyOf": [ -@@ -136,6 +131,9 @@ +@@ }, "SubType": { "properties": { diff --git a/tests/cases/simple/output/allof-to-ref.out b/tests/cases/simple/output/allof-to-ref.out index 7f3de13..cc05304 100644 --- a/tests/cases/simple/output/allof-to-ref.out +++ b/tests/cases/simple/output/allof-to-ref.out @@ -1,6 +1,6 @@ --- allof-to-ref.json +++ patched -@@ -58,12 +58,7 @@ +@@ } }, "via_allof": { diff --git a/tests/cases/simple/output/any-schema-change.out b/tests/cases/simple/output/any-schema-change.out index 35a3e91..dc506c4 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 @@ +@@ }, "GreetingResponse": { "properties": { diff --git a/tests/cases/simple/output/anyof-to-allof.out b/tests/cases/simple/output/anyof-to-allof.out index ced8976..7a6b7f9 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 @@ +@@ "description": "Via allOf." }, "via_anyof": { diff --git a/tests/cases/simple/output/anyof-to-oneof.out b/tests/cases/simple/output/anyof-to-oneof.out index 0e1f38d..6081cb5 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 @@ +@@ "description": "Via allOf." }, "via_anyof": { diff --git a/tests/cases/simple/output/anyof-to-ref.out b/tests/cases/simple/output/anyof-to-ref.out index 2e1d099..76839b1 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 @@ +@@ "description": "Via allOf." }, "via_anyof": { diff --git a/tests/cases/simple/output/array-items-add.out b/tests/cases/simple/output/array-items-add.out index f197b94..61ccbdb 100644 --- a/tests/cases/simple/output/array-items-add.out +++ b/tests/cases/simple/output/array-items-add.out @@ -1,6 +1,6 @@ --- array-items-add.json +++ patched -@@ -12,9 +12,6 @@ +@@ ] }, "ArrayWithConstraints": { diff --git a/tests/cases/simple/output/array-items-remove.out b/tests/cases/simple/output/array-items-remove.out index 426e982..f30ddee 100644 --- a/tests/cases/simple/output/array-items-remove.out +++ b/tests/cases/simple/output/array-items-remove.out @@ -1,6 +1,6 @@ --- array-items-remove.json +++ patched -@@ -146,7 +146,7 @@ +@@ "properties": { "children": { "items": { diff --git a/tests/cases/simple/output/array-max-items-change.out b/tests/cases/simple/output/array-max-items-change.out index b00e190..ca1389e 100644 --- a/tests/cases/simple/output/array-max-items-change.out +++ b/tests/cases/simple/output/array-max-items-change.out @@ -1,6 +1,6 @@ --- array-max-items-change.json +++ patched -@@ -15,7 +15,7 @@ +@@ "items": { "type": "string" }, diff --git a/tests/cases/simple/output/array-min-items-change.out b/tests/cases/simple/output/array-min-items-change.out index df42d55..44b8d48 100644 --- a/tests/cases/simple/output/array-min-items-change.out +++ b/tests/cases/simple/output/array-min-items-change.out @@ -1,6 +1,6 @@ --- array-min-items-change.json +++ patched -@@ -16,7 +16,7 @@ +@@ "type": "string" }, "maxItems": 10, diff --git a/tests/cases/simple/output/array-unique-items-change.out b/tests/cases/simple/output/array-unique-items-change.out index 34e50e4..b45d105 100644 --- a/tests/cases/simple/output/array-unique-items-change.out +++ b/tests/cases/simple/output/array-unique-items-change.out @@ -1,6 +1,6 @@ --- array-unique-items-change.json +++ patched -@@ -18,7 +18,7 @@ +@@ "maxItems": 10, "minItems": 1, "type": "array", diff --git a/tests/cases/simple/output/body-description-change.out b/tests/cases/simple/output/body-description-change.out index 3e2eb01..80af1ac 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 @@ +@@ } } }, diff --git a/tests/cases/simple/output/body-extension-change.out b/tests/cases/simple/output/body-extension-change.out index 06cbc81..927d8d6 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 @@ +@@ } } }, diff --git a/tests/cases/simple/output/body-optional-to-required.out b/tests/cases/simple/output/body-optional-to-required.out index b09a68f..841a6e9 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 @@ +@@ } } }, diff --git a/tests/cases/simple/output/body-required-to-optional.out b/tests/cases/simple/output/body-required-to-optional.out index a41b06d..9784dc9 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 @@ +@@ } } }, diff --git a/tests/cases/simple/output/boolean-change.out b/tests/cases/simple/output/boolean-change.out index 6fc74f3..246caec 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 @@ +@@ "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..ee70159 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 @@ +@@ "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..c72f9ca 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 @@ +@@ } } }, diff --git a/tests/cases/simple/output/change-header-parameter.out b/tests/cases/simple/output/change-header-parameter.out index 8b8fec2..90e9fd9 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 @@ +@@ "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..e4d4853 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 @@ +@@ "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..53863f9 100644 --- a/tests/cases/simple/output/change-operation-parameter-type.out +++ b/tests/cases/simple/output/change-operation-parameter-type.out @@ -1,6 +1,6 @@ --- change-operation-parameter-type.json +++ patched -@@ -255,7 +255,7 @@ +@@ "name": "language", "required": false, "schema": { diff --git a/tests/cases/simple/output/change-property-type.out b/tests/cases/simple/output/change-property-type.out index 59b6235..57f6eee 100644 --- a/tests/cases/simple/output/change-property-type.out +++ b/tests/cases/simple/output/change-property-type.out @@ -1,6 +1,6 @@ --- change-property-type.json +++ patched -@@ -50,7 +50,7 @@ +@@ "properties": { "message": { "description": "The greeting message", diff --git a/tests/cases/simple/output/inline-to-allof.out b/tests/cases/simple/output/inline-to-allof.out index 5173ba2..8c43487 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 @@ +@@ "in": "path", "name": "name", "schema": { diff --git a/tests/cases/simple/output/integer-format-change.out b/tests/cases/simple/output/integer-format-change.out index f97a7a4..621e470 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 @@ +@@ "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..19df865 100644 --- a/tests/cases/simple/output/modify-cycle-type.out +++ b/tests/cases/simple/output/modify-cycle-type.out @@ -1,6 +1,6 @@ --- modify-cycle-type.json +++ patched -@@ -145,10 +145,7 @@ +@@ "Tree": { "properties": { "children": { diff --git a/tests/cases/simple/output/multi-allof-variant-change.out b/tests/cases/simple/output/multi-allof-variant-change.out index b2c82ec..ebb7f6e 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 @@ +@@ { "properties": { "id": { diff --git a/tests/cases/simple/output/multi-anyof-variant-change.out b/tests/cases/simple/output/multi-anyof-variant-change.out index fc70f50..1ead364 100644 --- a/tests/cases/simple/output/multi-anyof-variant-change.out +++ b/tests/cases/simple/output/multi-anyof-variant-change.out @@ -1,6 +1,6 @@ --- multi-anyof-variant-change.json +++ patched -@@ -4,7 +4,7 @@ +@@ "AnyOfExample": { "anyOf": [ { diff --git a/tests/cases/simple/output/multi-oneof-count-change.out b/tests/cases/simple/output/multi-oneof-count-change.out index 8d054d6..2e4ab21 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 @@ +@@ }, { "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..ca20ee2 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 @@ +@@ "MultiOneOf": { "oneOf": [ { diff --git a/tests/cases/simple/output/not-inner-to-allof.out b/tests/cases/simple/output/not-inner-to-allof.out index c3c4808..c5e70e0 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 @@ +@@ }, "not_a_number": { "not": { diff --git a/tests/cases/simple/output/not-to-allof.out b/tests/cases/simple/output/not-to-allof.out index b3ef213..a31c5f5 100644 --- a/tests/cases/simple/output/not-to-allof.out +++ b/tests/cases/simple/output/not-to-allof.out @@ -1,6 +1,6 @@ --- not-to-allof.json +++ patched -@@ -53,9 +53,14 @@ +@@ "type": "string" }, "not_a_number": { diff --git a/tests/cases/simple/output/number-constraints-change.out b/tests/cases/simple/output/number-constraints-change.out index 241849d..a7088cc 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 @@ +@@ "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..2fda705 100644 --- a/tests/cases/simple/output/object-additional-props-false.out +++ b/tests/cases/simple/output/object-additional-props-false.out @@ -1,6 +1,6 @@ --- object-additional-props-false.json +++ patched -@@ -121,9 +121,7 @@ +@@ ] }, "ObjectWithConstraints": { 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..b2218fb 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 @@ +@@ }, "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..d90217c 100644 --- a/tests/cases/simple/output/object-additional-props-type-change.out +++ b/tests/cases/simple/output/object-additional-props-type-change.out @@ -1,6 +1,6 @@ --- object-additional-props-type-change.json +++ patched -@@ -121,9 +121,7 @@ +@@ ] }, "ObjectWithConstraints": { diff --git a/tests/cases/simple/output/object-max-properties-change.out b/tests/cases/simple/output/object-max-properties-change.out index c519851..a7bf74c 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 @@ +@@ "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..0d8fdea 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 @@ +@@ "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..5f3e337 100644 --- a/tests/cases/simple/output/oneof-to-allof.out +++ b/tests/cases/simple/output/oneof-to-allof.out @@ -1,6 +1,6 @@ --- oneof-to-allof.json +++ patched -@@ -74,12 +74,12 @@ +@@ "description": "Via anyOf." }, "via_oneof": { diff --git a/tests/cases/simple/output/oneof-to-anyof.out b/tests/cases/simple/output/oneof-to-anyof.out index c643d8b..16f2fb8 100644 --- a/tests/cases/simple/output/oneof-to-anyof.out +++ b/tests/cases/simple/output/oneof-to-anyof.out @@ -1,6 +1,6 @@ --- oneof-to-anyof.json +++ patched -@@ -74,12 +74,12 @@ +@@ "description": "Via anyOf." }, "via_oneof": { diff --git a/tests/cases/simple/output/oneof-to-ref.out b/tests/cases/simple/output/oneof-to-ref.out index 0ec92a5..b859544 100644 --- a/tests/cases/simple/output/oneof-to-ref.out +++ b/tests/cases/simple/output/oneof-to-ref.out @@ -1,6 +1,6 @@ --- oneof-to-ref.json +++ patched -@@ -74,12 +74,7 @@ +@@ "description": "Via anyOf." }, "via_oneof": { diff --git a/tests/cases/simple/output/param-required-to-optional.out b/tests/cases/simple/output/param-required-to-optional.out index c955a3c..1614909 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 @@ +@@ { "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..afa9481 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 @@ +@@ } }, { diff --git a/tests/cases/simple/output/ref-chain-change.out b/tests/cases/simple/output/ref-chain-change.out index 9d3bca3..e0a3a54 100644 --- a/tests/cases/simple/output/ref-chain-change.out +++ b/tests/cases/simple/output/ref-chain-change.out @@ -1,6 +1,6 @@ --- ref-chain-change.json +++ patched -@@ -132,7 +132,7 @@ +@@ "$ref": "#/components/schemas/RefChainB" }, "RefChainB": { diff --git a/tests/cases/simple/output/ref-to-allof.out b/tests/cases/simple/output/ref-to-allof.out index 0ffecab..381c173 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 @@ +@@ ] }, "via_ref": { diff --git a/tests/cases/simple/output/ref-to-anyof.out b/tests/cases/simple/output/ref-to-anyof.out index f764670..ac48522 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 @@ +@@ ] }, "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..107fd1f 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 @@ +@@ ] }, "via_ref": { diff --git a/tests/cases/simple/output/ref-to-oneof.out b/tests/cases/simple/output/ref-to-oneof.out index 4f95563..cccb7a3 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 @@ +@@ ] }, "via_ref": { diff --git a/tests/cases/simple/output/remove-default-response.out b/tests/cases/simple/output/remove-default-response.out index 615e057..c714100 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 @@ +@@ "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..8cc1104 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 @@ +@@ "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..1076bfe 100644 --- a/tests/cases/simple/output/remove-operation-parameter.out +++ b/tests/cases/simple/output/remove-operation-parameter.out @@ -1,6 +1,6 @@ --- remove-operation-parameter.json +++ patched -@@ -248,15 +248,6 @@ +@@ "schema": { "type": "string" } diff --git a/tests/cases/simple/output/remove-operation.out b/tests/cases/simple/output/remove-operation.out index 04ed3a9..59c4268 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 @@ +@@ "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..02239b2 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 @@ +@@ }, "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..ff420d0 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 @@ +@@ "/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..fad59bf 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 @@ +@@ "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..b246f75 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 @@ +@@ "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..da0321f 100644 --- a/tests/cases/simple/output/schema-kind-type-to-oneof.out +++ b/tests/cases/simple/output/schema-kind-type-to-oneof.out @@ -1,6 +1,6 @@ --- schema-kind-type-to-oneof.json +++ patched -@@ -135,12 +135,14 @@ +@@ "$ref": "#/components/schemas/SubType" }, "SubType": { diff --git a/tests/cases/simple/output/string-format-change.out b/tests/cases/simple/output/string-format-change.out index 1f8edf0..1ece512 100644 --- a/tests/cases/simple/output/string-format-change.out +++ b/tests/cases/simple/output/string-format-change.out @@ -1,6 +1,6 @@ --- string-format-change.json +++ patched -@@ -50,6 +50,7 @@ +@@ "properties": { "message": { "description": "The greeting message", diff --git a/tests/cases/simple/output/type-indirection.out b/tests/cases/simple/output/type-indirection.out index 910cf39..48bdd43 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 @@ +@@ "GreetingResponse": { "properties": { "message": { @@ -10,7 +10,7 @@ }, "not_a_number": { "not": { -@@ -90,6 +89,13 @@ +@@ ], "type": "object" }, diff --git a/tests/cases/simple/output/type-rename.out b/tests/cases/simple/output/type-rename.out index bac28a3..b767464 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 @@ +@@ ], "type": "object" }, @@ -9,7 +9,7 @@ "properties": { "message": { "description": "The greeting message", -@@ -264,7 +264,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..0525b81 100644 --- a/tests/cases/simple/output/unhandled-add-prop.out +++ b/tests/cases/simple/output/unhandled-add-prop.out @@ -1,6 +1,6 @@ --- unhandled-add-prop.json +++ patched -@@ -57,6 +57,10 @@ +@@ "type": "number" } }, @@ -11,7 +11,7 @@ "via_allof": { "allOf": [ { -@@ -86,7 +90,8 @@ +@@ } }, "required": [ 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..18e3fe6 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 @@ +@@ "SubType": { "properties": { "value": { diff --git a/tests/test_changes.rs b/tests/test_changes.rs index 05ad940..0c21d93 100644 --- a/tests/test_changes.rs +++ b/tests/test_changes.rs @@ -1,5 +1,7 @@ // Copyright 2025 Oxide Computer Company +use std::fmt::Write; + use drift::compare; use similar::TextDiff; @@ -39,19 +41,31 @@ fn test_change() { json_patch::patch(&mut patched, &patch_value).unwrap(); let udiff = { - // Suppress the observation regarding the lack of a - // terminating newline. let mut base_pretty = serde_json::to_string_pretty(&base_value).unwrap(); base_pretty.push('\n'); let mut patched_pretty = serde_json::to_string_pretty(&patched).unwrap(); patched_pretty.push('\n'); let diff = TextDiff::from_lines(&base_pretty, &patched_pretty); - diff.unified_diff() - .header( - patch_entry.file_name().to_string_lossy().as_ref(), - "patched", - ) - .to_string() + let patch_name = patch_entry.file_name(); + + // Format the unified diff manually, replacing `@@ -N,M + // +N,M @@` hunk headers with bare `@@` to avoid churn + // when base.json changes shift line positions. + let mut out = String::new(); + let mut first = true; + for hunk in diff.unified_diff().iter_hunks() { + if first { + writeln!(out, "--- {}", patch_name.to_string_lossy()).unwrap(); + writeln!(out, "+++ patched").unwrap(); + first = false; + } + writeln!(out, "@@").unwrap(); + for change in hunk.iter_changes() { + write!(out, "{}{}", change.tag(), change.to_string_lossy()) + .unwrap(); + } + } + out }; let result = From 2c96ca473224c1cdce7240f406b0ce41ea404008 Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 6 Feb 2026 02:56:41 +0000 Subject: [PATCH 2/4] clippy Created using spr 1.3.6-beta.1 --- src/path.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/path.rs b/src/path.rs index 61991e2..6df11a5 100644 --- a/src/path.rs +++ b/src/path.rs @@ -341,7 +341,7 @@ fn is_path_ancestor_of(ancestor: &str, path: &str) -> bool { && path .as_bytes() .get(ancestor.len()) - .map_or(true, |&b| b == b'/') + .is_none_or(|&b| b == b'/') } #[cfg(test)] From 96dab89326abbfb6af2fb5619280a7e3129249d9 Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 6 Feb 2026 03:01:54 +0000 Subject: [PATCH 3/4] [spr] changes introduced through rebase Created using spr 1.3.6-beta.1 [skip ci] --- src/compare.rs | 2 +- tests/test_changes.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compare.rs b/src/compare.rs index 039cc7d..f32fff3 100644 --- a/src/compare.rs +++ b/src/compare.rs @@ -1,4 +1,4 @@ -// Copyright 2025 Oxide Computer Company +// Copyright 2026 Oxide Computer Company use std::collections::BTreeMap; diff --git a/tests/test_changes.rs b/tests/test_changes.rs index 0c21d93..c222a9f 100644 --- a/tests/test_changes.rs +++ b/tests/test_changes.rs @@ -1,4 +1,4 @@ -// Copyright 2025 Oxide Computer Company +// Copyright 2026 Oxide Computer Company use std::fmt::Write; From e778ec10abcb593d2f4c5ee0311b32910873bd38 Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 8 May 2026 16:41:31 -0700 Subject: [PATCH 4/4] [spr] changes introduced through rebase Created using spr 1.3.6-beta.1 [skip ci] --- src/schema.rs | 4 -- tests/cases/cycle-detection/base.json | 35 ++++++++++++++ .../output/swap-alternating-cycle-entry.out | 46 +++++++++++++++++++ .../patch/swap-alternating-cycle-entry.json | 7 +++ 4 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 tests/cases/cycle-detection/output/swap-alternating-cycle-entry.out create mode 100644 tests/cases/cycle-detection/patch/swap-alternating-cycle-entry.json diff --git a/src/schema.rs b/src/schema.rs index e6d68c8..699ffca 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -189,10 +189,6 @@ impl Compare { old_schema: Contextual<'_, &Schema>, new_schema: Contextual<'_, &Schema>, ) -> anyhow::Result { - // We wait for both new and old to contain a cycle; this ensures that - // we consider "unrolled" cycles properly. There is a possibility of - // getting stuck in an A->B->A / B->A->B cycle... we can address that - // should that construction arise. if old_schema.context().stack().contains_cycle() && new_schema.context().stack().contains_cycle() { diff --git a/tests/cases/cycle-detection/base.json b/tests/cases/cycle-detection/base.json index 0e5255a..1670d76 100644 --- a/tests/cases/cycle-detection/base.json +++ b/tests/cases/cycle-detection/base.json @@ -124,6 +124,23 @@ } } } + }, + "/alternating-cycle": { + "get": { + "operationId": "get_alternating_cycle", + "responses": { + "200": { + "description": "Mutual cycle AltX <-> AltY. Swapping the entry from AltX to AltY makes old-side traversal walk AltX -> AltY -> AltX -> ... while new-side walks AltY -> AltX -> AltY -> ..., exercising the alternating (A,B)/(B,A) pair-keyed traversal.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AltX" + } + } + } + } + } + } } }, "components": { @@ -280,6 +297,24 @@ "$ref": "#/components/schemas/SelfCycleB" } } + }, + "AltX": { + "description": "Mutual cycle pair, side X. Structurally identical to AltY (object whose `next` refers to the partner); distinguishable only by name and this description.", + "type": "object", + "properties": { + "next": { + "$ref": "#/components/schemas/AltY" + } + } + }, + "AltY": { + "description": "Mutual cycle pair, side Y. Structurally identical to AltX (object whose `next` refers to the partner); distinguishable only by name and this description.", + "type": "object", + "properties": { + "next": { + "$ref": "#/components/schemas/AltX" + } + } } } } diff --git a/tests/cases/cycle-detection/output/swap-alternating-cycle-entry.out b/tests/cases/cycle-detection/output/swap-alternating-cycle-entry.out new file mode 100644 index 0000000..118982b --- /dev/null +++ b/tests/cases/cycle-detection/output/swap-alternating-cycle-entry.out @@ -0,0 +1,46 @@ +--- swap-alternating-cycle-entry.json ++++ patched +@@ + "content": { + "application/json": { + "schema": { +- "$ref": "#/components/schemas/AltX" ++ "$ref": "#/components/schemas/AltY" + } + } + }, + + +Result for patch: +[ + Change { + message: "schema metadata changed", + old_path: [ + "#/components/schemas/AltX", + "#/paths/~1alternating-cycle/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/AltY", + "#/paths/~1alternating-cycle/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: Trivial, + details: Metadata, + }, + Change { + message: "schema metadata changed", + old_path: [ + "#/components/schemas/AltY", + "#/components/schemas/AltX/properties/next/$ref", + "#/paths/~1alternating-cycle/get/responses/200/content/application~1json/schema/$ref", + ], + new_path: [ + "#/components/schemas/AltX", + "#/components/schemas/AltY/properties/next/$ref", + "#/paths/~1alternating-cycle/get/responses/200/content/application~1json/schema/$ref", + ], + comparison: Output, + class: Trivial, + details: Metadata, + }, +] diff --git a/tests/cases/cycle-detection/patch/swap-alternating-cycle-entry.json b/tests/cases/cycle-detection/patch/swap-alternating-cycle-entry.json new file mode 100644 index 0000000..6842d48 --- /dev/null +++ b/tests/cases/cycle-detection/patch/swap-alternating-cycle-entry.json @@ -0,0 +1,7 @@ +[ + { + "op": "replace", + "path": "/paths/~1alternating-cycle/get/responses/200/content/application~1json/schema/$ref", + "value": "#/components/schemas/AltY" + } +]