#[cfg(test)]
mod tests {
use crate::jsonld::expansion_algorithm::JsonLdExpansionConverter;
use crate::jsonld::expansion_context::JsonLdEvent;
use crate::jsonld::profile::JsonLdProcessingMode;
use json_event_parser::JsonEvent;
use std::borrow::Cow;
#[test]
fn test_expansion_converter_new_default() {
let converter =
JsonLdExpansionConverter::new(None, false, false, JsonLdProcessingMode::JsonLd1_1);
assert!(!converter.is_end());
assert!(!converter.streaming);
assert!(!converter.lenient);
assert!(converter.base_url.is_none());
}
#[test]
fn test_expansion_converter_streaming_mode() {
let converter =
JsonLdExpansionConverter::new(None, true, false, JsonLdProcessingMode::JsonLd1_1);
assert!(converter.streaming);
}
#[test]
fn test_expansion_converter_lenient_mode() {
let converter =
JsonLdExpansionConverter::new(None, false, true, JsonLdProcessingMode::JsonLd1_1);
assert!(converter.lenient);
}
#[test]
fn test_expansion_converter_context_stack_non_empty() {
let converter =
JsonLdExpansionConverter::new(None, false, false, JsonLdProcessingMode::JsonLd1_1);
let _ctx = converter.context();
}
#[test]
fn test_expansion_converter_state_stack_non_empty() {
let converter =
JsonLdExpansionConverter::new(None, false, false, JsonLdProcessingMode::JsonLd1_1);
assert!(!converter.state.is_empty());
}
fn expand_events(events: &[JsonEvent<'_>]) -> Vec<JsonLdEvent> {
let mut conv =
JsonLdExpansionConverter::new(None, false, false, JsonLdProcessingMode::JsonLd1_1);
let mut results = Vec::new();
let mut errors = Vec::new();
for event in events {
conv.convert_event(event.clone(), &mut results, &mut errors);
}
results
}
fn expand_events_streaming(events: &[JsonEvent<'_>]) -> Vec<JsonLdEvent> {
let mut conv =
JsonLdExpansionConverter::new(None, true, false, JsonLdProcessingMode::JsonLd1_1);
let mut results = Vec::new();
let mut errors = Vec::new();
for event in events {
conv.convert_event(event.clone(), &mut results, &mut errors);
}
results
}
fn index_values(events: &[JsonLdEvent]) -> Vec<&str> {
events
.iter()
.filter_map(|e| {
if let JsonLdEvent::IndexValue(v) = e {
Some(v.as_str())
} else {
None
}
})
.collect()
}
#[test]
fn test_index_container_emits_index_value_non_streaming() {
let s = |v: &'static str| JsonEvent::String(Cow::Borrowed(v));
let key = |k: &'static str| JsonEvent::ObjectKey(Cow::Borrowed(k));
let events = vec![
JsonEvent::StartObject,
key("@context"),
JsonEvent::StartObject,
key("data"),
JsonEvent::StartObject,
key("@id"),
s("http://example.org/data"),
key("@container"),
s("@index"),
JsonEvent::EndObject,
JsonEvent::EndObject,
key("data"),
JsonEvent::StartObject,
key("key1"),
JsonEvent::StartObject,
key("@id"),
s("http://example.org/node1"),
JsonEvent::EndObject,
key("key2"),
JsonEvent::StartObject,
key("@id"),
s("http://example.org/node2"),
JsonEvent::EndObject,
JsonEvent::EndObject,
JsonEvent::EndObject,
JsonEvent::Eof,
];
let results = expand_events(&events);
let idx = index_values(&results);
assert!(
idx.contains(&"key1"),
"Expected IndexValue('key1') in results, got: {idx:?}"
);
assert!(
idx.contains(&"key2"),
"Expected IndexValue('key2') in results, got: {idx:?}"
);
assert_eq!(
idx.len(),
2,
"Expected exactly 2 IndexValue events, got: {idx:?}"
);
}
#[test]
fn test_index_container_emits_index_value_streaming() {
let s = |v: &'static str| JsonEvent::String(Cow::Borrowed(v));
let key = |k: &'static str| JsonEvent::ObjectKey(Cow::Borrowed(k));
let events = vec![
JsonEvent::StartObject,
key("@context"),
JsonEvent::StartObject,
key("data"),
JsonEvent::StartObject,
key("@id"),
s("http://example.org/data"),
key("@container"),
s("@index"),
JsonEvent::EndObject,
JsonEvent::EndObject,
key("data"),
JsonEvent::StartObject,
key("alpha"),
JsonEvent::StartObject,
key("@id"),
s("http://example.org/alpha"),
JsonEvent::EndObject,
key("beta"),
JsonEvent::StartObject,
key("@id"),
s("http://example.org/beta"),
JsonEvent::EndObject,
JsonEvent::EndObject,
JsonEvent::EndObject,
JsonEvent::Eof,
];
let results = expand_events_streaming(&events);
let idx = index_values(&results);
assert!(
idx.contains(&"alpha"),
"Expected IndexValue('alpha') in streaming results, got: {idx:?}"
);
assert!(
idx.contains(&"beta"),
"Expected IndexValue('beta') in streaming results, got: {idx:?}"
);
assert_eq!(
idx.len(),
2,
"Expected exactly 2 IndexValue events in streaming mode, got: {idx:?}"
);
}
#[test]
fn test_index_value_position_inside_object() {
let s = |v: &'static str| JsonEvent::String(Cow::Borrowed(v));
let key = |k: &'static str| JsonEvent::ObjectKey(Cow::Borrowed(k));
let events = vec![
JsonEvent::StartObject,
key("@context"),
JsonEvent::StartObject,
key("items"),
JsonEvent::StartObject,
key("@id"),
s("http://example.org/items"),
key("@container"),
s("@index"),
JsonEvent::EndObject,
JsonEvent::EndObject,
key("items"),
JsonEvent::StartObject,
key("mykey"),
JsonEvent::StartObject,
key("@id"),
s("http://example.org/x"),
JsonEvent::EndObject,
JsonEvent::EndObject,
JsonEvent::EndObject,
JsonEvent::Eof,
];
let results = expand_events(&events);
let start_pos = results
.iter()
.position(|e| matches!(e, JsonLdEvent::StartObject { .. }));
let idx_pos = results
.iter()
.position(|e| matches!(e, JsonLdEvent::IndexValue(_)));
let end_pos = results
.iter()
.position(|e| matches!(e, JsonLdEvent::EndObject));
assert!(start_pos.is_some(), "StartObject expected in results");
assert!(idx_pos.is_some(), "IndexValue expected in results");
assert!(end_pos.is_some(), "EndObject expected in results");
if let (Some(s), Some(i), Some(e)) = (start_pos, idx_pos, end_pos) {
assert!(
s < i,
"StartObject must come before IndexValue (s={s}, i={i})"
);
assert!(
i < e,
"IndexValue must come before EndObject (i={i}, e={e})"
);
}
}
#[test]
fn test_inline_at_index_emits_index_value() {
let s = |v: &'static str| JsonEvent::String(Cow::Borrowed(v));
let key = |k: &'static str| JsonEvent::ObjectKey(Cow::Borrowed(k));
let events = vec![
JsonEvent::StartObject,
key("@type"),
s("http://example.org/Thing"),
key("@index"),
s("myAnnotation"),
JsonEvent::EndObject,
JsonEvent::Eof,
];
let results = expand_events(&events);
let idx = index_values(&results);
assert!(
idx.contains(&"myAnnotation"),
"Expected IndexValue('myAnnotation') for inline @index, got: {idx:?}"
);
}
}