From 6e8f9a8e5e657e83753e1e97f72971843ae0343a Mon Sep 17 00:00:00 2001 From: Chance Date: Tue, 25 Jun 2024 14:48:28 -0400 Subject: [PATCH] adds tests, including adding condition to `test_intersection_issue_44` which is failing --- src/assign.rs | 168 ++++++++++++++++++++++++++++++++++++++++++++----- src/pointer.rs | 81 +++++++++++++++++++++--- 2 files changed, 224 insertions(+), 25 deletions(-) diff --git a/src/assign.rs b/src/assign.rs index b862eb3..5a18159 100644 --- a/src/assign.rs +++ b/src/assign.rs @@ -148,7 +148,7 @@ enum Assigned<'v, V> { #[cfg(feature = "json")] mod json { use super::*; - use crate::{Pointer, Token}; + use crate::{Pointer, PointerBuf, Token}; use core::mem; use serde_json::{map::Entry, Map, Value}; @@ -313,26 +313,160 @@ mod json { use serde_json::{json, Value}; - use crate::{Pointer, PointerBuf}; + use crate::{assign::{json, AssignError}, OutOfBoundsError, Pointer, PointerBuf}; + struct Test { + data: Value, + ptr: &'static str, + value: Value, + expected_data: Value, + expected_result: Result, AssignError>, + } #[test] fn test_assign() { - let mut data = json!({}); - - let ptr = Pointer::from_static("/foo"); - let replaced = ptr.assign(&mut data, json!("bar")).unwrap(); - assert_eq!(replaced, None); - assert_eq!(&data, &json!({"foo": "bar"})); - - // now testing replacement - let replaced = ptr.assign(&mut data, json!("baz")).unwrap(); - assert_eq!(replaced, Some(Value::String("bar".to_string()))); - assert_eq!(&data, &json!({"foo": "baz"})); + let tests = [ + Test { + data: json!({}), + ptr: "/foo", + value: json!("bar"), + expected_data: json!({"foo": "bar"}), + expected_result: Ok(None), + }, + Test { + data: json!({"foo": "bar"}), + ptr: "", + value: json!("baz"), + expected_data: json!("baz"), + expected_result: Ok(Some(json!({"foo": "bar"}))), + }, + Test { + data: json!({"foo": "bar"}), + ptr: "/foo", + value: json!("baz"), + expected_data: json!({"foo": "baz"}), + expected_result: Ok(Some(json!("bar"))), + }, + Test { + data: json!({"foo": "bar"}), + ptr: "/foo/bar", + value: json!("baz"), + expected_data: json!({"foo": {"bar": "baz"}}), + expected_result: Ok(Some(json!("bar"))), + }, + Test { + data: json!({}), + ptr: "/", + value: json!("foo"), + expected_data: json!({"": "foo"}), + expected_result: Ok(None), + }, + Test { + data: json!({}), + ptr: "/-", + value: json!("foo"), + expected_data: json!({"-": "foo"}), + expected_result: Ok(None), + }, + Test { + data: json!(null), + ptr: "/-", + value: json!(34), + expected_data: json!([34]), + expected_result: Ok(Some(json!(null))), + }, + Test { + data: json!({"foo": "bar"}), + ptr: "/foo/-", + value: json!("baz"), + expected_data: json!({"foo": ["baz"]}), + expected_result: Ok(Some(json!("bar"))), + }, + Test { + data: json!({}), + ptr: "/0", + value: json!("foo"), + expected_data: json!({"0": "foo"}), + expected_result: Ok(None), + }, + Test { + data: json!(null), + ptr: "/1", + value: json!("foo"), + expected_data: json!({"1": "foo"}), + expected_result: Ok(Some(json!(null))), + }, + Test { + data: json!([]), + ptr: "/0", + expected_data: json!(["foo"]), + value: json!("foo"), + expected_result: Ok(None), + }, + Test { + data: json!([]), + ptr: "/0", + expected_data: json!(["foo"]), + value: json!("foo"), + expected_result: Ok(None), + }, + Test { + data: json!([]), + ptr: "/-", + value: json!("foo"), + expected_result: Ok(None), + expected_data: json!(["foo"]), + }, + Test { + data: json!([]), + ptr: "/1", + value: json!("foo"), + expected_result: Err(AssignError::OutOfBounds { + offset: 0, + source: OutOfBoundsError{ + index: 1, + length: 0, + }, + }), + expected_data: json!([]), + }, + Test { + data: json!([]), + ptr: "/a", + value: json!("foo"), + expected_result: Err(AssignError::FailedToParseIndex { + offset: 0, + source: json::ParseIndexError { source: usize::from_str("foo").unwrap_err() }, + }), + expected_data: json!([]), + }, + ]; - let tests = [(json!({}), "/foo", json!("bar"))]; - for (mut data, ptr, value) in tests { + for (i,Test { + mut data, + ptr, + value, + expected_data, + expected_result: expected_replaced, + }) in tests.into_iter().enumerate() + { let ptr = PointerBuf::from_str(ptr).unwrap(); - let replaced = ptr.assign(&mut data, value); + let replaced = ptr.assign(&mut data, value.clone()); + assert_eq!( + &expected_data, &data, + "data not as expected.\n\nexpected:\n\n{expected_data}\n\nactual:\n{data}\n" + ); + assert_eq!( + &expected_replaced, + &replaced, + "\nreplaced not as expected for test index {i}:\n\npointer:{ptr}\nvalue:{value}\n\ndata:\n{data}\n\nexpected data:\n{expected_data}\n\nexpected:\n{}\n\nactual:\n{}\n\n", + expected_replaced + .as_ref() + .map_or("None".to_string(), |v| serde_json::to_string_pretty(&v).unwrap()), + replaced + .as_ref() + .map_or("None".to_string(), |v| serde_json::to_string_pretty(&v).unwrap()), + + ); } } @@ -380,7 +514,7 @@ mod json { ]; for (path, val, expected, expected_replaced) in tests { - let ptr = PointerBuf::parse(path).expect(&format!("failed to parse \"{path}\"")); + let ptr = PointerBuf::must_parse(path); let replaced = ptr .assign(&mut data, val.clone()) .expect(&format!("failed to assign \"{path}\"")); diff --git a/src/pointer.rs b/src/pointer.rs index c435ac2..25c4e16 100644 --- a/src/pointer.rs +++ b/src/pointer.rs @@ -99,12 +99,16 @@ const fn is_valid_ptr(value: &str) -> bool { #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Pointer(str); +impl<'a> Default for &'a Pointer { + fn default() -> Self { + unsafe { &*("" as *const str as *const Self) } + } +} impl core::fmt::Display for Pointer { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { self.0.fmt(f) } } - impl Pointer { /// Private constructor for strings that are known to be correctly encoded /// @@ -121,10 +125,21 @@ impl Pointer { /// Attempts to parse a string into a `Pointer`. /// /// If successful, this does not allocate. + /// + /// ## Errors + /// Returns a `ParseError` if the string is not a valid JSON Pointer. pub fn parse + ?Sized>(s: &S) -> Result<&Self, ParseError> { validate(s.as_ref()).map(Self::new) } - + /// Attempts to parse a string into a `Pointer`. + /// + /// If successful, this does not allocate. + /// + /// ## Panics + /// Panics string is not a valid JSON Pointer. + pub fn must_parse + ?Sized>(s: &S) -> &Self { + Self::parse(s).expect("invalid JSON Pointer") + } /// Creates a static `Pointer` from a string. /// /// # Panics @@ -462,6 +477,26 @@ impl PartialEq for PointerBuf { self.0 == other.0 } } +impl PartialEq for String { + fn eq(&self, other: &PointerBuf) -> bool { + self == &other.0 + } +} +impl PartialEq for PointerBuf { + fn eq(&self, other: &String) -> bool { + &self.0 == other + } +} +impl AsRef for Pointer { + fn as_ref(&self) -> &Pointer { + self + } +} +impl AsRef for PointerBuf { + fn as_ref(&self) -> &Pointer { + self + } +} impl PartialEq for &Pointer { fn eq(&self, other: &PointerBuf) -> bool { @@ -534,8 +569,19 @@ impl PointerBuf { } /// Attempts to parse a string into a `PointerBuf`. - pub fn parse(s: &str) -> Result { - Pointer::parse(s).map(Pointer::to_buf) + /// + /// ## Errors + /// Returns a `ParseError` if the string is not a valid JSON Pointer. + pub fn parse + ?Sized>(s: &S) -> Result { + Pointer::parse(&s).map(Pointer::to_buf) + } + /// Attempts to parse a string into a `Pointer`. + /// + /// + /// ## Panics + /// Panics string is not a valid JSON Pointer. + pub fn must_parse + ?Sized>(s: &S) -> Self { + Self::parse(s).expect("invalid JSON Pointer") } /// Creates a new `PointerBuf` from a slice of non-encoded strings. @@ -595,9 +641,13 @@ impl PointerBuf { } /// Merges two `Pointer`s by appending `other` onto `self`. - pub fn append(&mut self, other: &PointerBuf) -> &PointerBuf { + pub fn append>(&mut self, other: P) -> &PointerBuf { + self._append(other.as_ref()) + } + + fn _append(&mut self, other: &Pointer) -> &PointerBuf { if self.is_root() { - self.0.clone_from(&other.0); + self.0 = other.0.to_string(); } else if !other.is_root() { self.0.push_str(&other.0); } @@ -743,6 +793,7 @@ mod tests { use super::*; use quickcheck::TestResult; use quickcheck_macros::quickcheck; + use serde_json::json; #[test] #[should_panic] @@ -1149,6 +1200,9 @@ mod tests { let mut b = base.clone(); b.append(&suffix_1); let isect = a.intersection(&b); + if isect != base { + println!("base: {base:?}\nisect: {isect:?}"); + } TestResult::from_bool(isect == base) } @@ -1157,13 +1211,24 @@ mod tests { let base = PointerBuf::new(); let suffix_0 = Pointer::from_static("/").to_buf(); let suffix_1 = Pointer::from_static("/a/b/c").to_buf(); - println!("suffix_1: {suffix_1:?}"); let mut a = base.clone(); a.append(&suffix_0); let mut b = base.clone(); b.append(&suffix_1); let isect = a.intersection(&b); - // assert_eq!(isect, base); + + let base = PointerBuf::must_parse("/a"); + let suffix_0 = PointerBuf::must_parse("/"); + let suffix_1 = PointerBuf::must_parse("/suffix_1"); + let mut a = base.clone(); + a.append(&suffix_0); + let mut b = base.clone(); + b.append(&suffix_1); + let isect = a.intersection(&b); + assert_eq!( + isect, base, + "intersection failed\n\n expected: \"{base}\"\n actual: \"{isect}\"" + ); } }