#![cfg(test)]
use super::to_rdf::JsonLdParser;
use super::to_rdf_converter::{canonicalize_json_number, RdfJsonNumber};
use crate::model::RdfTerm;
use crate::vocab::rdf;
#[test]
fn test_canonicalize_json_number() {
assert_eq!(
canonicalize_json_number("12", false),
Some(RdfJsonNumber::Integer("12".into()))
);
assert_eq!(
canonicalize_json_number("-12", false),
Some(RdfJsonNumber::Integer("-12".into()))
);
assert_eq!(
canonicalize_json_number("1", true),
Some(RdfJsonNumber::Double("1.0E0".into()))
);
assert_eq!(
canonicalize_json_number("1", true),
Some(RdfJsonNumber::Double("1.0E0".into()))
);
assert_eq!(
canonicalize_json_number("+1", true),
Some(RdfJsonNumber::Double("1.0E0".into()))
);
assert_eq!(
canonicalize_json_number("-1", true),
Some(RdfJsonNumber::Double("-1.0E0".into()))
);
assert_eq!(
canonicalize_json_number("12", true),
Some(RdfJsonNumber::Double("1.2E1".into()))
);
assert_eq!(
canonicalize_json_number("-12", true),
Some(RdfJsonNumber::Double("-1.2E1".into()))
);
assert_eq!(
canonicalize_json_number("12.3456E3", false),
Some(RdfJsonNumber::Double("1.23456E4".into()))
);
assert_eq!(
canonicalize_json_number("12.3456e3", false),
Some(RdfJsonNumber::Double("1.23456E4".into()))
);
assert_eq!(
canonicalize_json_number("-12.3456E3", false),
Some(RdfJsonNumber::Double("-1.23456E4".into()))
);
assert_eq!(
canonicalize_json_number("12.34E-3", false),
Some(RdfJsonNumber::Double("1.234E-2".into()))
);
assert_eq!(
canonicalize_json_number("12.340E-3", false),
Some(RdfJsonNumber::Double("1.234E-2".into()))
);
assert_eq!(
canonicalize_json_number("0.01234E-1", false),
Some(RdfJsonNumber::Double("1.234E-3".into()))
);
assert_eq!(
canonicalize_json_number("1.0", false),
Some(RdfJsonNumber::Integer("1".into()))
);
assert_eq!(
canonicalize_json_number("1.0E0", false),
Some(RdfJsonNumber::Integer("1".into()))
);
assert_eq!(
canonicalize_json_number("0.01E2", false),
Some(RdfJsonNumber::Integer("1".into()))
);
assert_eq!(
canonicalize_json_number("1E2", false),
Some(RdfJsonNumber::Integer("100".into()))
);
assert_eq!(
canonicalize_json_number("1E21", false),
Some(RdfJsonNumber::Double("1.0E21".into()))
);
assert_eq!(
canonicalize_json_number("0", false),
Some(RdfJsonNumber::Integer("0".into()))
);
assert_eq!(
canonicalize_json_number("0", true),
Some(RdfJsonNumber::Double("0.0E0".into()))
);
assert_eq!(
canonicalize_json_number("-0", true),
Some(RdfJsonNumber::Double("-0.0E0".into()))
);
assert_eq!(
canonicalize_json_number("0E-10", true),
Some(RdfJsonNumber::Double("0.0E0".into()))
);
}
fn parse_jsonld(jsonld: &str) -> Vec<crate::model::Quad> {
JsonLdParser::new()
.for_slice(jsonld.as_bytes())
.collect::<Result<Vec<_>, _>>()
.expect("JSON-LD parse must succeed")
}
#[test]
fn test_set_container_emits_flat_triples_not_list() {
let jsonld = r#"[{
"@id": "http://example.org/s",
"http://example.org/p": {
"@set": [
{"@value": "a"},
{"@value": "b"},
{"@value": "c"}
]
}
}]"#;
let quads = parse_jsonld(jsonld);
assert_eq!(
quads.len(),
3,
"Expected 3 flat quads for @set with 3 members, got {}: {quads:#?}",
quads.len()
);
let rdf_list_predicates = [rdf::FIRST.as_str(), rdf::REST.as_str(), rdf::NIL.as_str()];
for quad in &quads {
let pred = quad.predicate().as_str();
assert!(
!rdf_list_predicates.contains(&pred),
"@set must not produce list predicates but found '{pred}' in {quad}"
);
}
}
#[test]
fn test_set_container_shared_subject_and_predicate() {
let jsonld = r#"[{
"@id": "http://example.org/subject",
"http://example.org/knows": {
"@set": [
{"@id": "http://example.org/alice"},
{"@id": "http://example.org/bob"}
]
}
}]"#;
let quads = parse_jsonld(jsonld);
assert_eq!(
quads.len(),
2,
"Expected 2 quads for @set with 2 object IRIs, got {}: {quads:#?}",
quads.len()
);
for quad in &quads {
assert_eq!(
quad.subject().as_str(),
"http://example.org/subject",
"All @set quads must share subject"
);
assert_eq!(
quad.predicate().as_str(),
"http://example.org/knows",
"All @set quads must share predicate"
);
}
let objects: Vec<&str> = quads.iter().map(|q| q.object().as_str()).collect();
assert!(
objects.contains(&"http://example.org/alice"),
"alice must appear in objects"
);
assert!(
objects.contains(&"http://example.org/bob"),
"bob must appear in objects"
);
}
#[test]
fn test_set_container_empty_produces_no_quads() {
let jsonld = r#"[{
"@id": "http://example.org/s",
"http://example.org/p": {
"@set": []
}
}]"#;
let quads = parse_jsonld(jsonld);
assert!(
quads.is_empty(),
"Empty @set must produce zero quads, got: {quads:#?}"
);
}
#[test]
fn test_list_container_still_uses_rdf_list_structure() {
let jsonld = r#"[{
"@id": "http://example.org/s",
"http://example.org/p": {
"@list": [
{"@value": "x"},
{"@value": "y"}
]
}
}]"#;
let quads = parse_jsonld(jsonld);
assert_eq!(
quads.len(),
5,
"Expected 5 quads for @list with 2 elements (rdf:List structure), got {}: {quads:#?}",
quads.len()
);
let predicates: Vec<&str> = quads.iter().map(|q| q.predicate().as_str()).collect();
assert!(
predicates.contains(&rdf::FIRST.as_str()),
"rdf:first must appear in @list quads"
);
assert!(
predicates.contains(&rdf::REST.as_str()),
"rdf:rest must appear in @list quads"
);
}