Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/diff_walker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,39 @@ impl<F: FnMut(Change)> DiffWalker<F> {
}
}

fn diff_enum(&mut self, json_path: &str, lhs: &mut SchemaObject, rhs: &mut SchemaObject) {
let lhs_enum = lhs.enum_values.as_deref().unwrap_or(&[]);
let rhs_enum = rhs.enum_values.as_deref().unwrap_or(&[]);
let lhs_has_no_enum = lhs.enum_values.is_none();
let rhs_has_no_enum = rhs.enum_values.is_none();

// Find removed enum values (in lhs but not in rhs)
for lhs_value in lhs_enum {
if !rhs_enum.contains(lhs_value) {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::EnumRemove {
removed: lhs_value.clone(),
rhs_has_no_enum,
},
});
}
}

// Find added enum values (in rhs but not in lhs)
for rhs_value in rhs_enum {
if !lhs_enum.contains(rhs_value) {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::EnumAdd {
added: rhs_value.clone(),
lhs_has_no_enum,
},
});
}
}
}

fn resolve_references(
&self,
lhs: &mut SchemaObject,
Expand Down Expand Up @@ -496,6 +529,7 @@ impl<F: FnMut(Change)> DiffWalker<F> {
}
self.diff_const(json_path, lhs, rhs);
self.diff_format(json_path, lhs, rhs);
self.diff_enum(json_path, lhs, rhs);
// If we split the types, we don't want to compare type-specific properties
// because they are already compared in the `Self::diff_any_of`
if !is_lhs_split && !is_rhs_split {
Expand Down
22 changes: 22 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,22 @@ pub enum ChangeKind {
/// The new format value.
new_format: String,
},
/// An enum value has been added to the allowed values.
EnumAdd {
/// The value that was added to the enum.
added: serde_json::Value,
/// Whether the enum constraint was added (lhs had no enum).
/// If true, this is breaking as it adds a new constraint.
lhs_has_no_enum: bool,
},
/// An enum value has been removed from the allowed values.
EnumRemove {
/// The value that was removed from the enum.
removed: serde_json::Value,
/// Whether the entire enum constraint was removed (rhs has no enum).
/// If true, this is non-breaking as it relaxes the constraint.
rhs_has_no_enum: bool,
},
}

impl ChangeKind {
Expand Down Expand Up @@ -170,6 +186,12 @@ impl ChangeKind {
Self::FormatAdd { .. } => true,
Self::FormatRemove { .. } => false,
Self::FormatChange { .. } => true,
// EnumAdd is breaking only if it adds a new enum constraint (lhs had no enum).
// Adding values to an existing enum is non-breaking (accepts more data).
Self::EnumAdd { lhs_has_no_enum, .. } => *lhs_has_no_enum,
// EnumRemove is breaking if removing values from a surviving enum constraint.
// Removing the entire enum constraint is non-breaking (accepts more data).
Self::EnumRemove { rhs_has_no_enum, .. } => !rhs_has_no_enum,
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions tests/fixtures/enum/add.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"lhs": {
"type": "string",
"enum": ["error", "warning", "info"]
},
"rhs": {
"type": "string",
"enum": ["error", "warning", "info", "debug"]
}
}
10 changes: 10 additions & 0 deletions tests/fixtures/enum/add_and_remove.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"lhs": {
"type": "string",
"enum": ["error", "warning", "debug"]
},
"rhs": {
"type": "string",
"enum": ["error", "info", "debug"]
}
}
9 changes: 9 additions & 0 deletions tests/fixtures/enum/add_constraint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"lhs": {
"type": "string"
},
"rhs": {
"type": "string",
"enum": ["error", "warning", "info"]
}
}
8 changes: 8 additions & 0 deletions tests/fixtures/enum/mixed_types.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"lhs": {
"enum": ["error", 1, null, true]
},
"rhs": {
"enum": ["error", 1, null, true, "warning"]
}
}
10 changes: 10 additions & 0 deletions tests/fixtures/enum/number_values.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"lhs": {
"type": "integer",
"enum": [1, 2, 3]
},
"rhs": {
"type": "integer",
"enum": [1, 2, 3, 4]
}
}
10 changes: 10 additions & 0 deletions tests/fixtures/enum/real_world_event_type.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"lhs": {
"type": "string",
"enum": ["expectct", "expectstaple", "transaction", "default"]
},
"rhs": {
"type": "string",
"enum": ["expectct", "expectstaple", "transaction", "default", "generic"]
}
}
10 changes: 10 additions & 0 deletions tests/fixtures/enum/remove.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"lhs": {
"type": "string",
"enum": ["error", "warning", "info", "debug"]
},
"rhs": {
"type": "string",
"enum": ["error", "warning", "info"]
}
}
9 changes: 9 additions & 0 deletions tests/fixtures/enum/remove_constraint.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"lhs": {
"type": "string",
"enum": ["error", "warning", "info"]
},
"rhs": {
"type": "string"
}
}
10 changes: 10 additions & 0 deletions tests/fixtures/enum/unchanged.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"lhs": {
"type": "string",
"enum": ["error", "warning", "info"]
},
"rhs": {
"type": "string",
"enum": ["error", "warning", "info"]
}
}
29 changes: 29 additions & 0 deletions tests/snapshots/test__from_fixtures@enum__add.json.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
enum:
- error
- warning
- info
type: string
rhs:
enum:
- error
- warning
- info
- debug
type: string
input_file: tests/fixtures/enum/add.json
---
[
Change {
path: "",
change: EnumAdd {
added: String("debug"),
lhs_has_no_enum: false,
},
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
enum:
- error
- warning
- debug
type: string
rhs:
enum:
- error
- info
- debug
type: string
input_file: tests/fixtures/enum/add_and_remove.json
---
[
Change {
path: "",
change: EnumRemove {
removed: String("warning"),
rhs_has_no_enum: false,
},
},
Change {
path: "",
change: EnumAdd {
added: String("info"),
lhs_has_no_enum: false,
},
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
type: string
rhs:
enum:
- error
- warning
- info
type: string
input_file: tests/fixtures/enum/add_constraint.json
---
[
Change {
path: "",
change: EnumAdd {
added: String("error"),
lhs_has_no_enum: true,
},
},
Change {
path: "",
change: EnumAdd {
added: String("warning"),
lhs_has_no_enum: true,
},
},
Change {
path: "",
change: EnumAdd {
added: String("info"),
lhs_has_no_enum: true,
},
},
]
29 changes: 29 additions & 0 deletions tests/snapshots/test__from_fixtures@enum__mixed_types.json.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
enum:
- error
- 1
- ~
- true
rhs:
enum:
- error
- 1
- ~
- true
- warning
input_file: tests/fixtures/enum/mixed_types.json
---
[
Change {
path: "",
change: EnumAdd {
added: String("warning"),
lhs_has_no_enum: false,
},
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
enum:
- 1
- 2
- 3
type: integer
rhs:
enum:
- 1
- 2
- 3
- 4
type: integer
input_file: tests/fixtures/enum/number_values.json
---
[
Change {
path: "",
change: EnumAdd {
added: Number(4),
lhs_has_no_enum: false,
},
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
enum:
- expectct
- expectstaple
- transaction
- default
type: string
rhs:
enum:
- expectct
- expectstaple
- transaction
- default
- generic
type: string
input_file: tests/fixtures/enum/real_world_event_type.json
---
[
Change {
path: "",
change: EnumAdd {
added: String("generic"),
lhs_has_no_enum: false,
},
},
]
Loading