Skip to content

Commit

Permalink
adds tests, including adding condition to `test_intersection_issue_44…
Browse files Browse the repository at this point in the history
…` which is failing
  • Loading branch information
chanced committed Jun 25, 2024
1 parent b2f585c commit 6e8f9a8
Show file tree
Hide file tree
Showing 2 changed files with 224 additions and 25 deletions.
168 changes: 151 additions & 17 deletions src/assign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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<Option<Value>, 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()),

);
}
}

Expand Down Expand Up @@ -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}\""));
Expand Down
81 changes: 73 additions & 8 deletions src/pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
///
Expand All @@ -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<S: AsRef<str> + ?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<S: AsRef<str> + ?Sized>(s: &S) -> &Self {
Self::parse(s).expect("invalid JSON Pointer")
}
/// Creates a static `Pointer` from a string.
///
/// # Panics
Expand Down Expand Up @@ -462,6 +477,26 @@ impl PartialEq<Pointer> for PointerBuf {
self.0 == other.0
}
}
impl PartialEq<PointerBuf> for String {
fn eq(&self, other: &PointerBuf) -> bool {
self == &other.0
}
}
impl PartialEq<String> for PointerBuf {
fn eq(&self, other: &String) -> bool {
&self.0 == other
}
}
impl AsRef<Pointer> for Pointer {
fn as_ref(&self) -> &Pointer {
self
}
}
impl AsRef<Pointer> for PointerBuf {
fn as_ref(&self) -> &Pointer {
self
}
}

impl PartialEq<PointerBuf> for &Pointer {
fn eq(&self, other: &PointerBuf) -> bool {
Expand Down Expand Up @@ -534,8 +569,19 @@ impl PointerBuf {
}

/// Attempts to parse a string into a `PointerBuf`.
pub fn parse(s: &str) -> Result<Self, ParseError> {
Pointer::parse(s).map(Pointer::to_buf)
///
/// ## Errors
/// Returns a `ParseError` if the string is not a valid JSON Pointer.
pub fn parse<S: AsRef<str> + ?Sized>(s: &S) -> Result<Self, ParseError> {
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<S: AsRef<str> + ?Sized>(s: &S) -> Self {
Self::parse(s).expect("invalid JSON Pointer")
}

/// Creates a new `PointerBuf` from a slice of non-encoded strings.
Expand Down Expand Up @@ -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<P: AsRef<Pointer>>(&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);
}
Expand Down Expand Up @@ -743,6 +793,7 @@ mod tests {
use super::*;
use quickcheck::TestResult;
use quickcheck_macros::quickcheck;
use serde_json::json;

#[test]
#[should_panic]
Expand Down Expand Up @@ -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)
}

Expand All @@ -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}\""
);
}
}

0 comments on commit 6e8f9a8

Please sign in to comment.