use dcbor::prelude::*;
use dcbor_parse::parse_dcbor_item;
use dcbor_pattern::{Matcher, Pattern};
fn cbor(s: &str) -> CBOR { parse_dcbor_item(s).unwrap() }
#[test]
fn parse_bool_any() {
let src = "bool";
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::any_bool());
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_bool_true() {
let src = "true";
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::bool(true));
assert_eq!(p.to_string(), src);
let parsed_standalone = Pattern::parse("true").unwrap();
assert_eq!(parsed_standalone, Pattern::bool(true));
assert_eq!(parsed_standalone.to_string(), "true");
}
#[test]
fn parse_bool_false() {
let src = "false";
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::bool(false));
assert_eq!(p.to_string(), src);
let parsed_standalone = Pattern::parse("false").unwrap();
assert_eq!(parsed_standalone, Pattern::bool(false));
assert_eq!(parsed_standalone.to_string(), "false");
}
#[test]
fn parse_bool_patterns_round_trip() {
let patterns = vec![
Pattern::any_bool(),
Pattern::bool(true),
Pattern::bool(false),
];
for pattern in patterns {
let string_repr = pattern.to_string();
let parsed = Pattern::parse(&string_repr).unwrap();
assert_eq!(parsed, pattern);
}
}
#[test]
fn parse_null() {
let src = "null";
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::null());
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_null_pattern_round_trip() {
let pattern = Pattern::null();
let string_repr = pattern.to_string();
let parsed = Pattern::parse(&string_repr).unwrap();
assert_eq!(parsed, pattern);
}
#[test]
fn parse_date_any() {
let src = "date";
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::any_date());
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_date_value() {
let src = "date'2023-12-25'";
let p = Pattern::parse(src).unwrap();
let date_cbor = cbor("2023-12-25");
let expected_date = Date::try_from(date_cbor).unwrap();
assert_eq!(p, Pattern::date(expected_date));
assert!(p.to_string().starts_with("date'"));
}
#[test]
fn parse_date_with_time() {
let src = "date'2023-12-25T15:30:45Z'";
let p = Pattern::parse(src).unwrap();
let date_cbor = cbor("2023-12-25T15:30:45Z");
let expected_date = Date::try_from(date_cbor).unwrap();
assert_eq!(p, Pattern::date(expected_date));
assert!(p.to_string().starts_with("date'"));
}
#[test]
fn parse_date_range() {
let src = "date'2023-12-24...2023-12-26'";
let p = Pattern::parse(src).unwrap();
let start_cbor = cbor("2023-12-24");
let end_cbor = cbor("2023-12-26");
let start_date = Date::try_from(start_cbor).unwrap();
let end_date = Date::try_from(end_cbor).unwrap();
assert_eq!(p, Pattern::date_range(start_date..=end_date));
assert!(p.to_string().contains("..."));
}
#[test]
fn parse_date_earliest() {
let src = "date'2023-12-24...'";
let p = Pattern::parse(src).unwrap();
let date_cbor = cbor("2023-12-24");
let expected_date = Date::try_from(date_cbor).unwrap();
assert_eq!(p, Pattern::date_earliest(expected_date));
assert!(p.to_string().ends_with("...'"));
}
#[test]
fn parse_date_latest() {
let src = "date'...2023-12-26'";
let p = Pattern::parse(src).unwrap();
let date_cbor = cbor("2023-12-26");
let expected_date = Date::try_from(date_cbor).unwrap();
assert_eq!(p, Pattern::date_latest(expected_date));
assert!(p.to_string().starts_with("date'..."));
}
#[test]
fn parse_date_regex() {
let src = "date'/2023-.*/'";
let p = Pattern::parse(src).unwrap();
let regex = regex::Regex::new("2023-.*").unwrap();
assert_eq!(p, Pattern::date_regex(regex));
assert_eq!(p.to_string(), "date'/2023-.*/'");
}
#[test]
fn parse_date_patterns_round_trip() {
let date1 = Date::try_from(cbor("2023-05-15")).unwrap();
let date2 = Date::try_from(cbor("2023-12-25")).unwrap();
let patterns = vec![
Pattern::any_date(),
Pattern::date(date1),
Pattern::date_range(date1..=date2),
Pattern::date_earliest(date2),
Pattern::date_latest(date2),
];
for pattern in patterns {
let string_repr = pattern.to_string();
let parsed = Pattern::parse(&string_repr).unwrap();
assert_eq!(parsed, pattern);
}
}
#[test]
fn parse_text_any() {
let src = "text";
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::any_text());
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_text_literal() {
let src = r#""hello""#;
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::text("hello"));
assert_eq!(p.to_string(), src);
let spaced = r#" "hello" "#;
let p_spaced = Pattern::parse(spaced.trim()).unwrap();
assert_eq!(p_spaced, Pattern::text("hello"));
assert_eq!(p_spaced.to_string(), src);
}
#[test]
fn parse_text_literal_with_spaces() {
let src = r#""hello world""#;
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::text("hello world"));
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_text_literal_with_escapes() {
let src = r#""say \"hello\"""#;
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::text(r#"say "hello""#));
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_text_regex() {
let src = r"/h.*o/";
let p = Pattern::parse(src).unwrap();
let regex = regex::Regex::new("h.*o").unwrap();
assert_eq!(p, Pattern::text_regex(regex));
assert_eq!(p.to_string(), src);
let spaced = r" /h.*o/ ";
let p_spaced = Pattern::parse(spaced.trim()).unwrap();
assert_eq!(
p_spaced,
Pattern::text_regex(regex::Regex::new("h.*o").unwrap())
);
assert_eq!(p_spaced.to_string(), src);
}
#[test]
fn parse_text_regex_digits() {
let src = r"/^\d+$/";
let p = Pattern::parse(src).unwrap();
let regex = regex::Regex::new(r"^\d+$").unwrap();
assert_eq!(p, Pattern::text_regex(regex));
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_text_patterns_round_trip() {
let patterns = vec![
Pattern::any_text(),
Pattern::text("hello"),
Pattern::text("hello world"),
Pattern::text(r#"say "hello""#),
Pattern::text_regex(regex::Regex::new(r"^\d+$").unwrap()),
Pattern::text_regex(regex::Regex::new("h.*o").unwrap()),
];
for pattern in patterns {
let string_repr = pattern.to_string();
let parsed = Pattern::parse(&string_repr).unwrap();
assert_eq!(
pattern, parsed,
"Round trip failed for pattern: {}",
string_repr
);
}
}
#[test]
fn parse_text_edge_cases() {
let src = r#""""#;
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::text(""));
assert_eq!(p.to_string(), src);
let src = r#""Hello\nWorld""#;
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::text("Hello\nWorld"));
let src = r"/[a-zA-Z]+/";
let p = Pattern::parse(src).unwrap();
let regex = regex::Regex::new("[a-zA-Z]+").unwrap();
assert_eq!(p, Pattern::text_regex(regex));
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_bytestring_any() {
let src = "bstr";
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::any_byte_string());
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_bytestring_hex() {
let src = r#"h'010203'"#;
let p = Pattern::parse(src).unwrap();
assert_eq!(p, Pattern::byte_string(vec![1, 2, 3]));
assert_eq!(p.to_string(), src);
}
#[test]
fn parse_bytestring_regex() {
let src = r"h'/^[0-9]+$/'";
let p = Pattern::parse(src).unwrap();
let regex = regex::bytes::Regex::new(r"^[0-9]+$").unwrap();
assert_eq!(p, Pattern::byte_string_regex(regex));
assert_eq!(p.to_string(), src);
let pattern = Pattern::parse("h'/abc/'").unwrap();
assert!(pattern.matches(&cbor(r#"h'616263'"#))); assert!(!pattern.matches(&cbor(r#"h'646566'"#))); }
#[test]
fn parse_bytestring_patterns_round_trip() {
let cases = vec![
"bstr",
r#"h'deadbeef'"#,
r#"h''"#,
r"h'/^[a-f0-9]+$/'",
r"h'/test/'",
];
for case in cases {
let p = Pattern::parse(case).unwrap();
let round_trip = Pattern::parse(&p.to_string()).unwrap();
assert_eq!(p, round_trip, "Round trip failed for: {}", case);
}
}