From 50bde7d46ca35bbd51450b89240570032bbaef37 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 14 Aug 2024 14:48:13 -0500 Subject: [PATCH 1/4] refactor(filter): Flatten some logic --- crates/snapbox/src/filter/pattern.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/crates/snapbox/src/filter/pattern.rs b/crates/snapbox/src/filter/pattern.rs index 54aae274..906feee5 100644 --- a/crates/snapbox/src/filter/pattern.rs +++ b/crates/snapbox/src/filter/pattern.rs @@ -494,25 +494,24 @@ fn normalize_str_to_redactions(input: &str, pattern: &str, redactions: &Redactio let mut pattern_lines = crate::utils::LinesWithTerminator::new(pattern).peekable(); 'outer: while let Some(pattern_line) = pattern_lines.next() { if is_line_elide(pattern_line) { - if let Some(next_pattern_line) = pattern_lines.peek() { - for (index_offset, next_input_line) in - input_lines[input_index..].iter().copied().enumerate() - { - if line_matches(next_input_line, next_pattern_line, redactions) { - normalized.push(pattern_line); - input_index += index_offset; - continue 'outer; - } - } - // Give up doing further normalization - break; - } else { + let Some(next_pattern_line) = pattern_lines.peek() else { // Give up doing further normalization normalized.push(pattern_line); // captured rest so don't copy remaining lines over input_index = input_lines.len(); break; + }; + for (index_offset, next_input_line) in + input_lines[input_index..].iter().copied().enumerate() + { + if line_matches(next_input_line, next_pattern_line, redactions) { + normalized.push(pattern_line); + input_index += index_offset; + continue 'outer; + } } + // Give up doing further normalization + break; } else { let Some(input_line) = input_lines.get(input_index) else { // Give up doing further normalization From 140a6a425c1b4bad3446904548c1e6c7a750caf2 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 14 Aug 2024 14:54:21 -0500 Subject: [PATCH 2/4] refactor(filter): Flatten some logic --- crates/snapbox/src/filter/pattern.rs | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/crates/snapbox/src/filter/pattern.rs b/crates/snapbox/src/filter/pattern.rs index 906feee5..d31e5f19 100644 --- a/crates/snapbox/src/filter/pattern.rs +++ b/crates/snapbox/src/filter/pattern.rs @@ -492,29 +492,29 @@ fn normalize_str_to_redactions(input: &str, pattern: &str, redactions: &Redactio let mut input_index = 0; let input_lines: Vec<_> = crate::utils::LinesWithTerminator::new(input).collect(); let mut pattern_lines = crate::utils::LinesWithTerminator::new(pattern).peekable(); - 'outer: while let Some(pattern_line) = pattern_lines.next() { + while let Some(pattern_line) = pattern_lines.next() { if is_line_elide(pattern_line) { let Some(next_pattern_line) = pattern_lines.peek() else { - // Give up doing further normalization + // Stop as elide consumes to end normalized.push(pattern_line); - // captured rest so don't copy remaining lines over input_index = input_lines.len(); break; }; - for (index_offset, next_input_line) in - input_lines[input_index..].iter().copied().enumerate() - { - if line_matches(next_input_line, next_pattern_line, redactions) { - normalized.push(pattern_line); - input_index += index_offset; - continue 'outer; - } - } - // Give up doing further normalization - break; + let Some(index_offset) = + input_lines[input_index..] + .iter() + .position(|next_input_line| { + line_matches(next_input_line, next_pattern_line, redactions) + }) + else { + // Give up as we can't find where the elide ends + break; + }; + normalized.push(pattern_line); + input_index += index_offset; } else { let Some(input_line) = input_lines.get(input_index) else { - // Give up doing further normalization + // Give up as we have no more content to check break; }; From b71f8d051bbb85bb4db78349743c5f32bca1cad6 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 14 Aug 2024 15:23:43 -0500 Subject: [PATCH 3/4] refactor(filter): Rewrite Array normalization to match str --- crates/snapbox/src/filter/pattern.rs | 80 +++++++++++++++++----------- 1 file changed, 48 insertions(+), 32 deletions(-) diff --git a/crates/snapbox/src/filter/pattern.rs b/crates/snapbox/src/filter/pattern.rs index d31e5f19..5c3637fe 100644 --- a/crates/snapbox/src/filter/pattern.rs +++ b/crates/snapbox/src/filter/pattern.rs @@ -431,38 +431,7 @@ fn normalize_value_to_redactions( *act = normalize_str_to_redactions(act, exp, substitutions); } (Array(act), Array(exp)) => { - let mut sections = exp.split(|e| e == VALUE_WILDCARD).peekable(); - let mut processed = 0; - while let Some(expected_subset) = sections.next() { - // Process all values in the current section - if !expected_subset.is_empty() { - let actual_subset = &mut act[processed..processed + expected_subset.len()]; - for (a, e) in actual_subset.iter_mut().zip(expected_subset) { - normalize_value_to_redactions(a, e, substitutions); - } - processed += expected_subset.len(); - } - - if let Some(next_section) = sections.peek() { - // If the next section has nothing in it, replace from processed to end with - // a single "{...}" - if next_section.is_empty() { - act.splice(processed.., vec![String(VALUE_WILDCARD.to_owned())]); - processed += 1; - } else { - let first = next_section.first().unwrap(); - // Replace everything up until the value we are looking for with - // a single "{...}". - if let Some(index) = act.iter().position(|v| v == first) { - act.splice(processed..index, vec![String(VALUE_WILDCARD.to_owned())]); - processed += 1; - } else { - // If we cannot find the value we are looking for return early - break; - } - } - } - } + *act = normalize_array_to_redactions(act, exp, substitutions); } (Object(act), Object(exp)) => { let has_key_wildcard = @@ -483,6 +452,53 @@ fn normalize_value_to_redactions( } } +#[cfg(feature = "structured-data")] +fn normalize_array_to_redactions( + input: &[serde_json::Value], + pattern: &[serde_json::Value], + redactions: &Redactions, +) -> Vec { + if input == pattern { + return input.to_vec(); + } + + let mut normalized: Vec = Vec::new(); + let mut input_index = 0; + let mut pattern = pattern.iter().peekable(); + while let Some(pattern_elem) = pattern.next() { + if pattern_elem == VALUE_WILDCARD { + let Some(next_pattern_elem) = pattern.peek() else { + // Stop as elide consumes to end + normalized.push(pattern_elem.clone()); + input_index = input.len(); + break; + }; + let Some(index_offset) = input[input_index..] + .iter() + .position(|next_input_elem| next_input_elem == *next_pattern_elem) + else { + // Give up as we can't find where the elide ends + break; + }; + normalized.push(pattern_elem.clone()); + input_index += index_offset; + } else { + let Some(input_elem) = input.get(input_index) else { + // Give up as we have no more content to check + break; + }; + + input_index += 1; + let mut normalized_elem = input_elem.clone(); + normalize_value_to_redactions(&mut normalized_elem, pattern_elem, redactions); + normalized.push(normalized_elem); + } + } + + normalized.extend(input[input_index..].iter().cloned()); + normalized +} + fn normalize_str_to_redactions(input: &str, pattern: &str, redactions: &Redactions) -> String { if input == pattern { return input.to_owned(); From 9344f207c90caaab31fb49f7018a0f1b9c3ff3b0 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Wed, 14 Aug 2024 15:25:58 -0500 Subject: [PATCH 4/4] fix(filter): Take redactions into account for Array elides Fixes #352 --- crates/snapbox/src/filter/pattern.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/snapbox/src/filter/pattern.rs b/crates/snapbox/src/filter/pattern.rs index 5c3637fe..ead3b9e1 100644 --- a/crates/snapbox/src/filter/pattern.rs +++ b/crates/snapbox/src/filter/pattern.rs @@ -473,10 +473,11 @@ fn normalize_array_to_redactions( input_index = input.len(); break; }; - let Some(index_offset) = input[input_index..] - .iter() - .position(|next_input_elem| next_input_elem == *next_pattern_elem) - else { + let Some(index_offset) = input[input_index..].iter().position(|next_input_elem| { + let mut next_input_elem = next_input_elem.clone(); + normalize_value_to_redactions(&mut next_input_elem, next_pattern_elem, redactions); + next_input_elem == **next_pattern_elem + }) else { // Give up as we can't find where the elide ends break; };