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
111 changes: 111 additions & 0 deletions src/diff_walker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,114 @@ impl<F: FnMut(Change)> DiffWalker<F> {
}
}

fn diff_pattern(&mut self, json_path: &str, lhs: &mut SchemaObject, rhs: &mut SchemaObject) {
let lhs_pattern = &lhs.string().pattern;
let rhs_pattern = &rhs.string().pattern;

match (lhs_pattern, rhs_pattern) {
(Some(lhs_pat), Some(rhs_pat)) if lhs_pat != rhs_pat => {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::PatternChange {
old_pattern: lhs_pat.clone(),
new_pattern: rhs_pat.clone(),
},
});
}
(Some(removed_pat), None) => {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::PatternRemove {
removed: removed_pat.clone(),
},
});
}
(None, Some(added_pat)) => {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::PatternAdd {
added: added_pat.clone(),
},
});
}
_ => {} // No change or both None
}
}

fn diff_min_length(
&mut self,
json_path: &str,
lhs: &mut SchemaObject,
rhs: &mut SchemaObject,
) {
let lhs_min = lhs.string().min_length;
let rhs_min = rhs.string().min_length;

match (lhs_min, rhs_min) {
(Some(lhs_val), Some(rhs_val)) if lhs_val != rhs_val => {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::MinLengthChange {
old_value: lhs_val,
new_value: rhs_val,
},
});
}
(Some(removed_val), None) => {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::MinLengthRemove {
removed: removed_val,
},
});
}
(None, Some(added_val)) => {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::MinLengthAdd { added: added_val },
});
}
_ => {} // No change or both None
}
}

fn diff_max_length(
&mut self,
json_path: &str,
lhs: &mut SchemaObject,
rhs: &mut SchemaObject,
) {
let lhs_max = lhs.string().max_length;
let rhs_max = rhs.string().max_length;

match (lhs_max, rhs_max) {
(Some(lhs_val), Some(rhs_val)) if lhs_val != rhs_val => {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::MaxLengthChange {
old_value: lhs_val,
new_value: rhs_val,
},
});
}
(Some(removed_val), None) => {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::MaxLengthRemove {
removed: removed_val,
},
});
}
(None, Some(added_val)) => {
(self.cb)(Change {
path: json_path.to_owned(),
change: ChangeKind::MaxLengthAdd { added: added_val },
});
}
_ => {} // No change or both None
}
}

fn resolve_references(
&self,
lhs: &mut SchemaObject,
Expand Down Expand Up @@ -496,6 +604,9 @@ impl<F: FnMut(Change)> DiffWalker<F> {
}
self.diff_const(json_path, lhs, rhs);
self.diff_format(json_path, lhs, rhs);
self.diff_pattern(json_path, lhs, rhs);
self.diff_min_length(json_path, lhs, rhs);
self.diff_max_length(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
70 changes: 70 additions & 0 deletions src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,57 @@ pub enum ChangeKind {
/// The new format value.
new_format: String,
},
/// A pattern constraint has been added.
PatternAdd {
/// The pattern that was added.
added: String,
},
/// A pattern constraint has been removed.
PatternRemove {
/// The pattern that was removed.
removed: String,
},
/// A pattern constraint has been changed.
PatternChange {
/// The old pattern value.
old_pattern: String,
/// The new pattern value.
new_pattern: String,
},
/// A minLength constraint has been added.
MinLengthAdd {
/// The minLength value that was added.
added: u32,
},
/// A minLength constraint has been removed.
MinLengthRemove {
/// The minLength value that was removed.
removed: u32,
},
/// A minLength constraint has been changed.
MinLengthChange {
/// The old minLength value.
old_value: u32,
/// The new minLength value.
new_value: u32,
},
/// A maxLength constraint has been added.
MaxLengthAdd {
/// The maxLength value that was added.
added: u32,
},
/// A maxLength constraint has been removed.
MaxLengthRemove {
/// The maxLength value that was removed.
removed: u32,
},
/// A maxLength constraint has been changed.
MaxLengthChange {
/// The old maxLength value.
old_value: u32,
/// The new maxLength value.
new_value: u32,
},
}

impl ChangeKind {
Expand Down Expand Up @@ -170,6 +221,25 @@ impl ChangeKind {
Self::FormatAdd { .. } => true,
Self::FormatRemove { .. } => false,
Self::FormatChange { .. } => true,
// Pattern changes are conservatively treated as breaking.
// Determining if one regex is a subset of another requires complex analysis.
Self::PatternAdd { .. } => true,
Self::PatternRemove { .. } => false,
Self::PatternChange { .. } => true,
// MinLength: increasing restricts (breaking), decreasing relaxes (non-breaking)
Self::MinLengthAdd { .. } => true,
Self::MinLengthRemove { .. } => false,
Self::MinLengthChange {
old_value,
new_value,
} => new_value > old_value,
// MaxLength: decreasing restricts (breaking), increasing relaxes (non-breaking)
Self::MaxLengthAdd { .. } => true,
Self::MaxLengthRemove { .. } => false,
Self::MaxLengthChange {
old_value,
new_value,
} => new_value < old_value,
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/max_length/max_length_add.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string" },
"rhs": { "type": "string", "maxLength": 10 }
}
4 changes: 4 additions & 0 deletions tests/fixtures/max_length/max_length_decrease.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "maxLength": 10 },
"rhs": { "type": "string", "maxLength": 5 }
}
4 changes: 4 additions & 0 deletions tests/fixtures/max_length/max_length_increase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "maxLength": 5 },
"rhs": { "type": "string", "maxLength": 10 }
}
4 changes: 4 additions & 0 deletions tests/fixtures/max_length/max_length_remove.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "maxLength": 10 },
"rhs": { "type": "string" }
}
4 changes: 4 additions & 0 deletions tests/fixtures/max_length/max_length_unchanged.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "maxLength": 10 },
"rhs": { "type": "string", "maxLength": 10 }
}
4 changes: 4 additions & 0 deletions tests/fixtures/min_length/min_length_add.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string" },
"rhs": { "type": "string", "minLength": 5 }
}
4 changes: 4 additions & 0 deletions tests/fixtures/min_length/min_length_decrease.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "minLength": 5 },
"rhs": { "type": "string", "minLength": 3 }
}
4 changes: 4 additions & 0 deletions tests/fixtures/min_length/min_length_increase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "minLength": 3 },
"rhs": { "type": "string", "minLength": 5 }
}
4 changes: 4 additions & 0 deletions tests/fixtures/min_length/min_length_remove.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "minLength": 5 },
"rhs": { "type": "string" }
}
4 changes: 4 additions & 0 deletions tests/fixtures/min_length/min_length_unchanged.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "minLength": 5 },
"rhs": { "type": "string", "minLength": 5 }
}
4 changes: 4 additions & 0 deletions tests/fixtures/pattern/pattern_add.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string" },
"rhs": { "type": "string", "pattern": "^[a-z]+$" }
}
4 changes: 4 additions & 0 deletions tests/fixtures/pattern/pattern_change.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "pattern": "^[a-z]+$" },
"rhs": { "type": "string", "pattern": "^[A-Z]+$" }
}
4 changes: 4 additions & 0 deletions tests/fixtures/pattern/pattern_remove.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "pattern": "^[a-z]+$" },
"rhs": { "type": "string" }
}
4 changes: 4 additions & 0 deletions tests/fixtures/pattern/pattern_unchanged.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"lhs": { "type": "string", "pattern": "^[a-z]+$" },
"rhs": { "type": "string", "pattern": "^[a-z]+$" }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
type: string
rhs:
maxLength: 10
type: string
input_file: tests/fixtures/max_length/max_length_add.json
---
[
Change {
path: "",
change: MaxLengthAdd {
added: 10,
},
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
maxLength: 10
type: string
rhs:
maxLength: 5
type: string
input_file: tests/fixtures/max_length/max_length_decrease.json
---
[
Change {
path: "",
change: MaxLengthChange {
old_value: 10,
new_value: 5,
},
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
maxLength: 5
type: string
rhs:
maxLength: 10
type: string
input_file: tests/fixtures/max_length/max_length_increase.json
---
[
Change {
path: "",
change: MaxLengthChange {
old_value: 5,
new_value: 10,
},
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
maxLength: 10
type: string
rhs:
type: string
input_file: tests/fixtures/max_length/max_length_remove.json
---
[
Change {
path: "",
change: MaxLengthRemove {
removed: 10,
},
},
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
source: tests/test.rs
assertion_line: 12
expression: diff
info:
lhs:
maxLength: 10
type: string
rhs:
maxLength: 10
type: string
input_file: tests/fixtures/max_length/max_length_unchanged.json
---
[]
Loading