1use oxrdf::{
6 BlankNode as OxBlankNode, Literal as OxLiteral, NamedNode as OxNamedNode, Subject as OxSubject,
7 Term as OxTerm, Triple as OxTriple,
8};
9use std::fmt;
10use thiserror::Error;
11
12#[derive(Error, Debug)]
14#[allow(clippy::enum_variant_names)]
15pub enum RdfError {
16 #[error("Invalid IRI: {0}")]
18 InvalidIri(String),
19
20 #[error("Invalid blank node: {0}")]
22 InvalidBlankNode(String),
23
24 #[error("Invalid literal: {0}")]
26 InvalidLiteral(String),
27}
28
29pub type RdfResult<T> = Result<T, RdfError>;
30
31#[derive(Debug, Clone, PartialEq, Eq, Hash)]
33pub struct NamedNode(OxNamedNode);
34
35impl NamedNode {
36 pub fn new(iri: &str) -> RdfResult<Self> {
38 OxNamedNode::new(iri)
39 .map(Self)
40 .map_err(|e| RdfError::InvalidIri(e.to_string()))
41 }
42
43 pub fn as_str(&self) -> &str {
45 self.0.as_str()
46 }
47
48 pub fn inner(&self) -> &OxNamedNode {
50 &self.0
51 }
52}
53
54impl fmt::Display for NamedNode {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 write!(f, "<{}>", self.as_str())
57 }
58}
59
60impl From<OxNamedNode> for NamedNode {
61 fn from(node: OxNamedNode) -> Self {
62 Self(node)
63 }
64}
65
66impl From<NamedNode> for OxNamedNode {
67 fn from(node: NamedNode) -> Self {
68 node.0
69 }
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
74pub struct BlankNode(OxBlankNode);
75
76impl BlankNode {
77 pub fn new() -> Self {
79 Self(OxBlankNode::default())
80 }
81
82 #[allow(clippy::should_implement_trait)]
84 pub fn from_str(s: &str) -> RdfResult<Self> {
85 OxBlankNode::new(s)
86 .map(Self)
87 .map_err(|e| RdfError::InvalidBlankNode(e.to_string()))
88 }
89
90 pub fn as_str(&self) -> &str {
92 self.0.as_str()
93 }
94
95 pub fn inner(&self) -> &OxBlankNode {
97 &self.0
98 }
99}
100
101impl Default for BlankNode {
102 fn default() -> Self {
103 Self::new()
104 }
105}
106
107impl fmt::Display for BlankNode {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 write!(f, "_:{}", self.as_str())
110 }
111}
112
113impl From<OxBlankNode> for BlankNode {
114 fn from(node: OxBlankNode) -> Self {
115 Self(node)
116 }
117}
118
119impl From<BlankNode> for OxBlankNode {
120 fn from(node: BlankNode) -> Self {
121 node.0
122 }
123}
124
125#[derive(Debug, Clone, PartialEq, Eq, Hash)]
127pub struct Literal(OxLiteral);
128
129impl Literal {
130 pub fn new_simple_literal(value: impl Into<String>) -> Self {
132 Self(OxLiteral::new_simple_literal(value))
133 }
134
135 pub fn new_language_tagged_literal(
137 value: impl Into<String>,
138 language: impl Into<String>,
139 ) -> RdfResult<Self> {
140 OxLiteral::new_language_tagged_literal(value, language)
141 .map(Self)
142 .map_err(|e| RdfError::InvalidLiteral(e.to_string()))
143 }
144
145 pub fn new_typed_literal(value: impl Into<String>, datatype: NamedNode) -> Self {
147 Self(OxLiteral::new_typed_literal(value, datatype.0))
148 }
149
150 pub fn value(&self) -> &str {
152 self.0.value()
153 }
154
155 pub fn language(&self) -> Option<&str> {
157 self.0.language()
158 }
159
160 pub fn datatype(&self) -> NamedNode {
162 NamedNode(self.0.datatype().into_owned())
163 }
164
165 pub fn inner(&self) -> &OxLiteral {
167 &self.0
168 }
169}
170
171impl fmt::Display for Literal {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 if let Some(lang) = self.language() {
174 write!(f, "\"{}\"@{}", self.value(), lang)
175 } else {
176 write!(f, "\"{}\"^^{}", self.value(), self.datatype())
177 }
178 }
179}
180
181impl From<OxLiteral> for Literal {
182 fn from(lit: OxLiteral) -> Self {
183 Self(lit)
184 }
185}
186
187impl From<Literal> for OxLiteral {
188 fn from(lit: Literal) -> Self {
189 lit.0
190 }
191}
192
193#[derive(Debug, Clone, PartialEq, Eq, Hash)]
195pub enum RdfSubject {
196 NamedNode(NamedNode),
198 BlankNode(BlankNode),
200}
201
202impl RdfSubject {
203 pub fn is_named_node(&self) -> bool {
205 matches!(self, RdfSubject::NamedNode(_))
206 }
207
208 pub fn is_blank_node(&self) -> bool {
210 matches!(self, RdfSubject::BlankNode(_))
211 }
212}
213
214impl fmt::Display for RdfSubject {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 match self {
217 RdfSubject::NamedNode(n) => write!(f, "{}", n),
218 RdfSubject::BlankNode(b) => write!(f, "{}", b),
219 }
220 }
221}
222
223impl From<NamedNode> for RdfSubject {
224 fn from(node: NamedNode) -> Self {
225 RdfSubject::NamedNode(node)
226 }
227}
228
229impl From<BlankNode> for RdfSubject {
230 fn from(node: BlankNode) -> Self {
231 RdfSubject::BlankNode(node)
232 }
233}
234
235impl From<OxSubject> for RdfSubject {
236 fn from(subject: OxSubject) -> Self {
237 match subject {
238 OxSubject::NamedNode(n) => RdfSubject::NamedNode(n.into()),
239 OxSubject::BlankNode(b) => RdfSubject::BlankNode(b.into()),
240 #[allow(unreachable_patterns)]
241 _ => panic!("RDF-star triples not yet supported"),
242 }
243 }
244}
245
246impl From<RdfSubject> for OxSubject {
247 fn from(subject: RdfSubject) -> Self {
248 match subject {
249 RdfSubject::NamedNode(n) => OxSubject::NamedNode(n.0),
250 RdfSubject::BlankNode(b) => OxSubject::BlankNode(b.0),
251 }
252 }
253}
254
255#[derive(Debug, Clone, PartialEq, Eq, Hash)]
257pub struct RdfPredicate(NamedNode);
258
259impl RdfPredicate {
260 pub fn new(iri: &str) -> RdfResult<Self> {
262 Ok(Self(NamedNode::new(iri)?))
263 }
264
265 pub fn as_named_node(&self) -> &NamedNode {
267 &self.0
268 }
269}
270
271impl fmt::Display for RdfPredicate {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 write!(f, "{}", self.0)
274 }
275}
276
277impl From<NamedNode> for RdfPredicate {
278 fn from(node: NamedNode) -> Self {
279 RdfPredicate(node)
280 }
281}
282
283impl From<RdfPredicate> for NamedNode {
284 fn from(pred: RdfPredicate) -> Self {
285 pred.0
286 }
287}
288
289#[derive(Debug, Clone, PartialEq, Eq, Hash)]
291pub enum RdfObject {
292 NamedNode(NamedNode),
294 BlankNode(BlankNode),
296 Literal(Literal),
298}
299
300impl RdfObject {
301 pub fn is_named_node(&self) -> bool {
303 matches!(self, RdfObject::NamedNode(_))
304 }
305
306 pub fn is_blank_node(&self) -> bool {
308 matches!(self, RdfObject::BlankNode(_))
309 }
310
311 pub fn is_literal(&self) -> bool {
313 matches!(self, RdfObject::Literal(_))
314 }
315}
316
317impl fmt::Display for RdfObject {
318 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
319 match self {
320 RdfObject::NamedNode(n) => write!(f, "{}", n),
321 RdfObject::BlankNode(b) => write!(f, "{}", b),
322 RdfObject::Literal(l) => write!(f, "{}", l),
323 }
324 }
325}
326
327impl From<NamedNode> for RdfObject {
328 fn from(node: NamedNode) -> Self {
329 RdfObject::NamedNode(node)
330 }
331}
332
333impl From<BlankNode> for RdfObject {
334 fn from(node: BlankNode) -> Self {
335 RdfObject::BlankNode(node)
336 }
337}
338
339impl From<Literal> for RdfObject {
340 fn from(lit: Literal) -> Self {
341 RdfObject::Literal(lit)
342 }
343}
344
345impl From<OxTerm> for RdfObject {
346 fn from(term: OxTerm) -> Self {
347 match term {
348 OxTerm::NamedNode(n) => RdfObject::NamedNode(n.into()),
349 OxTerm::BlankNode(b) => RdfObject::BlankNode(b.into()),
350 OxTerm::Literal(l) => RdfObject::Literal(l.into()),
351 #[allow(unreachable_patterns)]
352 _ => panic!("RDF-star triples not yet supported"),
353 }
354 }
355}
356
357impl From<RdfObject> for OxTerm {
358 fn from(object: RdfObject) -> Self {
359 match object {
360 RdfObject::NamedNode(n) => OxTerm::NamedNode(n.0),
361 RdfObject::BlankNode(b) => OxTerm::BlankNode(b.0),
362 RdfObject::Literal(l) => OxTerm::Literal(l.0),
363 }
364 }
365}
366
367#[derive(Debug, Clone, PartialEq, Eq, Hash)]
369pub enum RdfTerm {
370 NamedNode(NamedNode),
372 BlankNode(BlankNode),
374 Literal(Literal),
376}
377
378impl From<RdfSubject> for RdfTerm {
379 fn from(subject: RdfSubject) -> Self {
380 match subject {
381 RdfSubject::NamedNode(n) => RdfTerm::NamedNode(n),
382 RdfSubject::BlankNode(b) => RdfTerm::BlankNode(b),
383 }
384 }
385}
386
387impl From<RdfObject> for RdfTerm {
388 fn from(object: RdfObject) -> Self {
389 match object {
390 RdfObject::NamedNode(n) => RdfTerm::NamedNode(n),
391 RdfObject::BlankNode(b) => RdfTerm::BlankNode(b),
392 RdfObject::Literal(l) => RdfTerm::Literal(l),
393 }
394 }
395}
396
397#[derive(Debug, Clone, PartialEq, Eq, Hash)]
399pub struct Triple {
400 pub subject: RdfSubject,
402 pub predicate: RdfPredicate,
404 pub object: RdfObject,
406}
407
408impl Triple {
409 pub fn new(subject: RdfSubject, predicate: RdfPredicate, object: RdfObject) -> Self {
411 Self {
412 subject,
413 predicate,
414 object,
415 }
416 }
417
418 pub fn to_oxrdf(&self) -> OxTriple {
420 let subject: OxSubject = self.subject.clone().into();
421 let predicate: OxNamedNode = self.predicate.clone().0.into();
422 let object: OxTerm = self.object.clone().into();
423
424 OxTriple::new(subject, predicate, object)
425 }
426}
427
428impl fmt::Display for Triple {
429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430 write!(f, "{} {} {} .", self.subject, self.predicate, self.object)
431 }
432}
433
434impl From<OxTriple> for Triple {
435 fn from(triple: OxTriple) -> Self {
436 Self {
437 subject: triple.subject.into(),
438 predicate: RdfPredicate(triple.predicate.into()),
439 object: triple.object.into(),
440 }
441 }
442}
443
444#[derive(Debug, Clone, PartialEq, Eq, Hash)]
446pub struct Quad {
447 pub subject: RdfSubject,
449 pub predicate: RdfPredicate,
451 pub object: RdfObject,
453 pub graph: Option<NamedNode>,
455}
456
457impl Quad {
458 pub fn new(
460 subject: RdfSubject,
461 predicate: RdfPredicate,
462 object: RdfObject,
463 graph: Option<NamedNode>,
464 ) -> Self {
465 Self {
466 subject,
467 predicate,
468 object,
469 graph,
470 }
471 }
472
473 pub fn from_triple(triple: Triple) -> Self {
475 Self {
476 subject: triple.subject,
477 predicate: triple.predicate,
478 object: triple.object,
479 graph: None,
480 }
481 }
482
483 pub fn as_triple(&self) -> Triple {
485 Triple {
486 subject: self.subject.clone(),
487 predicate: self.predicate.clone(),
488 object: self.object.clone(),
489 }
490 }
491}
492
493impl fmt::Display for Quad {
494 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
495 if let Some(graph) = &self.graph {
496 write!(
497 f,
498 "{} {} {} {} .",
499 self.subject, self.predicate, self.object, graph
500 )
501 } else {
502 write!(f, "{} {} {} .", self.subject, self.predicate, self.object)
503 }
504 }
505}
506
507#[derive(Debug, Clone, PartialEq, Eq)]
509pub struct TriplePattern {
510 pub subject: Option<RdfSubject>,
512 pub predicate: Option<RdfPredicate>,
514 pub object: Option<RdfObject>,
516}
517
518impl TriplePattern {
519 pub fn new(
521 subject: Option<RdfSubject>,
522 predicate: Option<RdfPredicate>,
523 object: Option<RdfObject>,
524 ) -> Self {
525 Self {
526 subject,
527 predicate,
528 object,
529 }
530 }
531
532 pub fn matches(&self, triple: &Triple) -> bool {
534 if let Some(ref s) = self.subject {
535 if s != &triple.subject {
536 return false;
537 }
538 }
539 if let Some(ref p) = self.predicate {
540 if p != &triple.predicate {
541 return false;
542 }
543 }
544 if let Some(ref o) = self.object {
545 if o != &triple.object {
546 return false;
547 }
548 }
549 true
550 }
551}
552
553#[derive(Debug, Clone, PartialEq, Eq)]
555pub struct QuadPattern {
556 pub subject: Option<RdfSubject>,
558 pub predicate: Option<RdfPredicate>,
560 pub object: Option<RdfObject>,
562 pub graph: Option<Option<NamedNode>>,
564}
565
566impl QuadPattern {
567 pub fn matches(&self, quad: &Quad) -> bool {
569 if let Some(ref s) = self.subject {
570 if s != &quad.subject {
571 return false;
572 }
573 }
574 if let Some(ref p) = self.predicate {
575 if p != &quad.predicate {
576 return false;
577 }
578 }
579 if let Some(ref o) = self.object {
580 if o != &quad.object {
581 return false;
582 }
583 }
584 if let Some(ref g) = self.graph {
585 if g != &quad.graph {
586 return false;
587 }
588 }
589 true
590 }
591}
592
593#[cfg(test)]
594mod tests {
595 use super::*;
596
597 #[test]
598 fn test_named_node() {
599 let node = NamedNode::new("http://example.org/alice").unwrap();
600 assert_eq!(node.as_str(), "http://example.org/alice");
601 assert_eq!(node.to_string(), "<http://example.org/alice>");
602 }
603
604 #[test]
605 fn test_blank_node() {
606 let node1 = BlankNode::new();
607 let node2 = BlankNode::new();
608 assert_ne!(node1, node2); }
610
611 #[test]
612 fn test_literal() {
613 let lit = Literal::new_simple_literal("Alice");
615 assert_eq!(lit.value(), "Alice");
616
617 let lit = Literal::new_language_tagged_literal("Alice", "en").unwrap();
619 assert_eq!(lit.value(), "Alice");
620 assert_eq!(lit.language(), Some("en"));
621 }
622
623 #[test]
624 fn test_triple() {
625 let subject = NamedNode::new("http://example.org/alice").unwrap();
626 let predicate = RdfPredicate::new("http://xmlns.com/foaf/0.1/name").unwrap();
627 let object = Literal::new_simple_literal("Alice");
628
629 let triple = Triple::new(subject.into(), predicate, object.into());
630
631 assert!(triple.subject.is_named_node());
632 assert!(triple.object.is_literal());
633 }
634
635 #[test]
636 fn test_triple_pattern_matching() {
637 let subject = NamedNode::new("http://example.org/alice").unwrap();
638 let predicate = RdfPredicate::new("http://xmlns.com/foaf/0.1/name").unwrap();
639 let object = Literal::new_simple_literal("Alice");
640
641 let triple = Triple::new(subject.clone().into(), predicate.clone(), object.into());
642
643 let pattern = TriplePattern::new(Some(subject.into()), None, None);
645 assert!(pattern.matches(&triple));
646
647 let wrong_subject = NamedNode::new("http://example.org/bob").unwrap();
649 let pattern = TriplePattern::new(Some(wrong_subject.into()), None, None);
650 assert!(!pattern.matches(&triple));
651
652 let pattern = TriplePattern::new(None, None, None);
654 assert!(pattern.matches(&triple));
655 }
656
657 #[test]
658 fn test_quad() {
659 let subject = NamedNode::new("http://example.org/alice").unwrap();
660 let predicate = RdfPredicate::new("http://xmlns.com/foaf/0.1/name").unwrap();
661 let object = Literal::new_simple_literal("Alice");
662 let graph = NamedNode::new("http://example.org/graph/social").unwrap();
663
664 let quad = Quad::new(subject.into(), predicate, object.into(), Some(graph));
665
666 assert!(quad.graph.is_some());
667
668 let triple = quad.as_triple();
669 assert!(triple.subject.is_named_node());
670 }
671
672 #[test]
675 fn test_named_node_inner() {
676 let node = NamedNode::new("http://example.org/foo").unwrap();
677 let inner = node.inner();
678 assert_eq!(inner.as_str(), "http://example.org/foo");
679 }
680
681 #[test]
682 fn test_blank_node_from_str() {
683 let bn = BlankNode::from_str("b1").unwrap();
684 assert_eq!(bn.as_str(), "b1");
685 let inner = bn.inner();
686 assert_eq!(inner.as_str(), "b1");
687 }
688
689 #[test]
690 fn test_literal_language_tagged() {
691 let lit = Literal::new_language_tagged_literal("hello", "en").unwrap();
692 assert_eq!(lit.value(), "hello");
693 assert_eq!(lit.language(), Some("en"));
694 }
695
696 #[test]
697 fn test_literal_typed() {
698 let dt = NamedNode::new("http://www.w3.org/2001/XMLSchema#integer").unwrap();
699 let lit = Literal::new_typed_literal("42", dt.clone());
700 assert_eq!(lit.value(), "42");
701 let dt2 = lit.datatype();
702 assert_eq!(dt2.as_str(), dt.as_str());
703 }
704
705 #[test]
706 fn test_literal_inner() {
707 let lit = Literal::new_simple_literal("test");
708 let inner = lit.inner();
709 assert_eq!(inner.value(), "test");
710 }
711
712 #[test]
713 fn test_rdf_subject_type_checks() {
714 let named = NamedNode::new("http://example.org/s").unwrap();
715 let subj = RdfSubject::from(named);
716 assert!(subj.is_named_node());
717 assert!(!subj.is_blank_node());
718
719 let blank = BlankNode::new();
720 let subj2 = RdfSubject::from(blank);
721 assert!(!subj2.is_named_node());
722 assert!(subj2.is_blank_node());
723 }
724
725 #[test]
726 fn test_rdf_predicate() {
727 let pred = RdfPredicate::new("http://example.org/p").unwrap();
728 let nn = pred.as_named_node();
729 assert_eq!(nn.as_str(), "http://example.org/p");
730 }
731
732 #[test]
733 fn test_rdf_object_type_checks() {
734 let named = NamedNode::new("http://example.org/o").unwrap();
735 let obj = RdfObject::from(named);
736 assert!(obj.is_named_node());
737 assert!(!obj.is_blank_node());
738 assert!(!obj.is_literal());
739
740 let lit = Literal::new_simple_literal("text");
741 let obj2 = RdfObject::from(lit);
742 assert!(!obj2.is_named_node());
743 assert!(!obj2.is_blank_node());
744 assert!(obj2.is_literal());
745
746 let blank = BlankNode::new();
747 let obj3 = RdfObject::from(blank);
748 assert!(!obj3.is_named_node());
749 assert!(obj3.is_blank_node());
750 assert!(!obj3.is_literal());
751 }
752
753 #[test]
754 fn test_triple_to_oxrdf() {
755 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
756 let pred = RdfPredicate::new("http://example.org/p").unwrap();
757 let obj = RdfObject::from(Literal::new_simple_literal("value"));
758 let triple = Triple::new(subj, pred, obj);
759
760 let ox = triple.to_oxrdf();
761 assert_eq!(ox.subject.to_string(), "<http://example.org/s>");
762 }
763
764 #[test]
765 fn test_quad_from_triple() {
766 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
767 let pred = RdfPredicate::new("http://example.org/p").unwrap();
768 let obj = RdfObject::from(Literal::new_simple_literal("value"));
769 let triple = Triple::new(subj, pred, obj);
770
771 let quad = Quad::from_triple(triple.clone());
772 assert!(quad.graph.is_none());
773 let back = quad.as_triple();
774 assert!(back.subject.is_named_node());
775 }
776
777 #[test]
778 fn test_triple_pattern_new() {
779 let subj = Some(RdfSubject::from(
780 NamedNode::new("http://example.org/s").unwrap(),
781 ));
782 let pattern = TriplePattern::new(subj, None, None);
783 assert!(pattern.subject.is_some());
784 assert!(pattern.predicate.is_none());
785 assert!(pattern.object.is_none());
786 }
787
788 #[test]
789 fn test_quad_pattern_matches() {
790 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
791 let pred = RdfPredicate::new("http://example.org/p").unwrap();
792 let obj = RdfObject::from(Literal::new_simple_literal("value"));
793 let triple = Triple::new(subj.clone(), pred.clone(), obj.clone());
794 let quad = Quad::from_triple(triple);
795
796 let pattern = QuadPattern {
798 subject: None,
799 predicate: None,
800 object: None,
801 graph: None,
802 };
803 assert!(pattern.matches(&quad));
804
805 let pattern2 = QuadPattern {
807 subject: Some(subj),
808 predicate: None,
809 object: None,
810 graph: None,
811 };
812 assert!(pattern2.matches(&quad));
813 }
814
815 #[test]
816 fn test_triple_display() {
817 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
818 let pred = RdfPredicate::new("http://example.org/p").unwrap();
819 let obj = RdfObject::from(Literal::new_simple_literal("hello"));
820 let triple = Triple::new(subj, pred, obj);
821
822 let display = format!("{}", triple);
823 assert!(display.contains("http://example.org/s"));
824 assert!(display.contains("http://example.org/p"));
825 }
826
827 #[test]
830 fn test_named_node_from_ox() {
831 let ox_node = OxNamedNode::new("http://example.org/test").unwrap();
832 let node: NamedNode = ox_node.into();
833 assert_eq!(node.as_str(), "http://example.org/test");
834 }
835
836 #[test]
837 fn test_named_node_into_ox() {
838 let node = NamedNode::new("http://example.org/test").unwrap();
839 let ox_node: OxNamedNode = node.into();
840 assert_eq!(ox_node.as_str(), "http://example.org/test");
841 }
842
843 #[test]
844 fn test_blank_node_default() {
845 let bn = BlankNode::default();
846 assert!(!bn.as_str().is_empty());
847 }
848
849 #[test]
850 fn test_blank_node_display() {
851 let bn = BlankNode::from_str("b42").unwrap();
852 let display = format!("{}", bn);
853 assert!(display.starts_with("_:"));
854 assert!(display.contains("b42"));
855 }
856
857 #[test]
858 fn test_blank_node_from_ox() {
859 let ox_bn = OxBlankNode::default();
860 let bn: BlankNode = ox_bn.into();
861 assert!(!bn.as_str().is_empty());
862 }
863
864 #[test]
865 fn test_blank_node_into_ox() {
866 let bn = BlankNode::from_str("b1").unwrap();
867 let ox_bn: OxBlankNode = bn.into();
868 assert_eq!(ox_bn.as_str(), "b1");
869 }
870
871 #[test]
872 fn test_literal_display_simple() {
873 let lit = Literal::new_simple_literal("hello");
874 let display = format!("{}", lit);
875 assert!(display.contains("hello"));
876 }
877
878 #[test]
879 fn test_literal_display_language_tagged() {
880 let lit = Literal::new_language_tagged_literal("hello", "en").unwrap();
881 let display = format!("{}", lit);
882 assert!(display.contains("hello"));
883 assert!(display.contains("@en"));
884 }
885
886 #[test]
887 fn test_literal_display_typed() {
888 let dt = NamedNode::new("http://www.w3.org/2001/XMLSchema#integer").unwrap();
889 let lit = Literal::new_typed_literal("42", dt);
890 let display = format!("{}", lit);
891 assert!(display.contains("42"));
892 }
893
894 #[test]
895 fn test_literal_from_ox() {
896 let ox_lit = OxLiteral::new_simple_literal("test");
897 let lit: Literal = ox_lit.into();
898 assert_eq!(lit.value(), "test");
899 }
900
901 #[test]
902 fn test_literal_into_ox() {
903 let lit = Literal::new_simple_literal("test");
904 let ox_lit: OxLiteral = lit.into();
905 assert_eq!(ox_lit.value(), "test");
906 }
907
908 #[test]
909 fn test_rdf_subject_display() {
910 let named = NamedNode::new("http://example.org/s").unwrap();
911 let subj = RdfSubject::from(named);
912 let display = format!("{}", subj);
913 assert!(display.contains("http://example.org/s"));
914
915 let blank = BlankNode::from_str("b1").unwrap();
916 let subj2 = RdfSubject::from(blank);
917 let display2 = format!("{}", subj2);
918 assert!(display2.starts_with("_:"));
919 }
920
921 #[test]
922 fn test_rdf_subject_from_ox() {
923 let ox_nn = OxNamedNode::new("http://example.org/s").unwrap();
924 let ox_subj = OxSubject::NamedNode(ox_nn);
925 let subj: RdfSubject = ox_subj.into();
926 assert!(subj.is_named_node());
927
928 let ox_bn = OxBlankNode::default();
929 let ox_subj2 = OxSubject::BlankNode(ox_bn);
930 let subj2: RdfSubject = ox_subj2.into();
931 assert!(subj2.is_blank_node());
932 }
933
934 #[test]
935 fn test_rdf_predicate_from_named_node() {
936 let nn = NamedNode::new("http://example.org/p").unwrap();
937 let pred: RdfPredicate = nn.into();
938 assert_eq!(pred.as_named_node().as_str(), "http://example.org/p");
939 }
940
941 #[test]
942 fn test_rdf_predicate_into_named_node() {
943 let pred = RdfPredicate::new("http://example.org/p").unwrap();
944 let nn: NamedNode = pred.into();
945 assert_eq!(nn.as_str(), "http://example.org/p");
946 }
947
948 #[test]
949 fn test_rdf_predicate_display() {
950 let pred = RdfPredicate::new("http://example.org/p").unwrap();
951 let display = format!("{}", pred);
952 assert!(display.contains("http://example.org/p"));
953 }
954
955 #[test]
956 fn test_rdf_object_display() {
957 let named = NamedNode::new("http://example.org/o").unwrap();
958 let obj = RdfObject::from(named);
959 let display = format!("{}", obj);
960 assert!(display.contains("http://example.org/o"));
961
962 let blank = BlankNode::from_str("b2").unwrap();
963 let obj2 = RdfObject::from(blank);
964 let display2 = format!("{}", obj2);
965 assert!(display2.starts_with("_:"));
966
967 let lit = Literal::new_simple_literal("value");
968 let obj3 = RdfObject::from(lit);
969 let display3 = format!("{}", obj3);
970 assert!(display3.contains("value"));
971 }
972
973 #[test]
974 fn test_rdf_object_from_ox_term() {
975 let ox_nn = OxNamedNode::new("http://example.org/o").unwrap();
976 let term = OxTerm::NamedNode(ox_nn);
977 let obj: RdfObject = term.into();
978 assert!(obj.is_named_node());
979
980 let ox_bn = OxBlankNode::default();
981 let term2 = OxTerm::BlankNode(ox_bn);
982 let obj2: RdfObject = term2.into();
983 assert!(obj2.is_blank_node());
984
985 let ox_lit = OxLiteral::new_simple_literal("test");
986 let term3 = OxTerm::Literal(ox_lit);
987 let obj3: RdfObject = term3.into();
988 assert!(obj3.is_literal());
989 }
990
991 #[test]
992 fn test_rdf_error_display() {
993 let e1 = RdfError::InvalidIri("bad iri".to_string());
994 let s1 = format!("{}", e1);
995 assert!(s1.contains("Invalid IRI"));
996
997 let e2 = RdfError::InvalidBlankNode("bad bn".to_string());
998 let s2 = format!("{}", e2);
999 assert!(s2.contains("Invalid blank node"));
1000
1001 let e3 = RdfError::InvalidLiteral("bad lit".to_string());
1002 let s3 = format!("{}", e3);
1003 assert!(s3.contains("Invalid literal"));
1004 }
1005
1006 #[test]
1007 fn test_named_node_invalid_iri() {
1008 let result = NamedNode::new("not a valid iri");
1009 assert!(result.is_err());
1010 }
1011
1012 #[test]
1015 fn test_blank_node_invalid_str() {
1016 let result = BlankNode::from_str("invalid blank node id!");
1018 assert!(result.is_err());
1019 }
1020
1021 #[test]
1022 fn test_literal_language_tag_invalid() {
1023 let result = Literal::new_language_tagged_literal("hello", "invalid tag with spaces");
1025 assert!(result.is_err());
1026 }
1027
1028 #[test]
1029 fn test_literal_simple_no_language() {
1030 let lit = Literal::new_simple_literal("test value");
1031 assert_eq!(lit.value(), "test value");
1032 assert!(lit.language().is_none());
1033 }
1034
1035 #[test]
1036 fn test_literal_datatype_for_simple() {
1037 let lit = Literal::new_simple_literal("hello");
1038 let dt = lit.datatype();
1039 assert!(dt.as_str().contains("string"));
1041 }
1042
1043 #[test]
1044 fn test_rdf_subject_into_ox_named() {
1045 let nn = NamedNode::new("http://example.org/s").unwrap();
1046 let subj = RdfSubject::NamedNode(nn);
1047 let ox_subj: OxSubject = subj.into();
1048 match ox_subj {
1049 OxSubject::NamedNode(n) => assert_eq!(n.as_str(), "http://example.org/s"),
1050 _ => panic!("Expected NamedNode"),
1051 }
1052 }
1053
1054 #[test]
1055 fn test_rdf_subject_into_ox_blank() {
1056 let bn = BlankNode::from_str("b99").unwrap();
1057 let subj = RdfSubject::BlankNode(bn);
1058 let ox_subj: OxSubject = subj.into();
1059 match ox_subj {
1060 OxSubject::BlankNode(b) => assert_eq!(b.as_str(), "b99"),
1061 _ => panic!("Expected BlankNode"),
1062 }
1063 }
1064
1065 #[test]
1066 fn test_rdf_object_into_ox_term_named() {
1067 let nn = NamedNode::new("http://example.org/o").unwrap();
1068 let obj = RdfObject::NamedNode(nn);
1069 let term: OxTerm = obj.into();
1070 match term {
1071 OxTerm::NamedNode(n) => assert_eq!(n.as_str(), "http://example.org/o"),
1072 _ => panic!("Expected NamedNode"),
1073 }
1074 }
1075
1076 #[test]
1077 fn test_rdf_object_into_ox_term_blank() {
1078 let bn = BlankNode::from_str("b1").unwrap();
1079 let obj = RdfObject::BlankNode(bn);
1080 let term: OxTerm = obj.into();
1081 match term {
1082 OxTerm::BlankNode(b) => assert_eq!(b.as_str(), "b1"),
1083 _ => panic!("Expected BlankNode"),
1084 }
1085 }
1086
1087 #[test]
1088 fn test_rdf_object_into_ox_term_literal() {
1089 let lit = Literal::new_simple_literal("val");
1090 let obj = RdfObject::Literal(lit);
1091 let term: OxTerm = obj.into();
1092 match term {
1093 OxTerm::Literal(l) => assert_eq!(l.value(), "val"),
1094 _ => panic!("Expected Literal"),
1095 }
1096 }
1097
1098 #[test]
1099 fn test_rdf_term_from_subject_named() {
1100 let nn = NamedNode::new("http://example.org/t").unwrap();
1101 let subj = RdfSubject::NamedNode(nn);
1102 let term: RdfTerm = subj.into();
1103 assert!(matches!(term, RdfTerm::NamedNode(_)));
1104 }
1105
1106 #[test]
1107 fn test_rdf_term_from_subject_blank() {
1108 let bn = BlankNode::new();
1109 let subj = RdfSubject::BlankNode(bn);
1110 let term: RdfTerm = subj.into();
1111 assert!(matches!(term, RdfTerm::BlankNode(_)));
1112 }
1113
1114 #[test]
1115 fn test_rdf_term_from_object_named() {
1116 let nn = NamedNode::new("http://example.org/t2").unwrap();
1117 let obj = RdfObject::NamedNode(nn);
1118 let term: RdfTerm = obj.into();
1119 assert!(matches!(term, RdfTerm::NamedNode(_)));
1120 }
1121
1122 #[test]
1123 fn test_rdf_term_from_object_blank() {
1124 let bn = BlankNode::new();
1125 let obj = RdfObject::BlankNode(bn);
1126 let term: RdfTerm = obj.into();
1127 assert!(matches!(term, RdfTerm::BlankNode(_)));
1128 }
1129
1130 #[test]
1131 fn test_rdf_term_from_object_literal() {
1132 let lit = Literal::new_simple_literal("val");
1133 let obj = RdfObject::Literal(lit);
1134 let term: RdfTerm = obj.into();
1135 assert!(matches!(term, RdfTerm::Literal(_)));
1136 }
1137
1138 #[test]
1139 fn test_triple_from_ox_triple() {
1140 let ox_subj = OxSubject::NamedNode(OxNamedNode::new("http://example.org/s").unwrap());
1141 let ox_pred = OxNamedNode::new("http://example.org/p").unwrap();
1142 let ox_obj = OxTerm::Literal(OxLiteral::new_simple_literal("value"));
1143 let ox_triple = OxTriple::new(ox_subj, ox_pred, ox_obj);
1144
1145 let triple: Triple = ox_triple.into();
1146 assert!(triple.subject.is_named_node());
1147 assert!(triple.object.is_literal());
1148 }
1149
1150 #[test]
1151 fn test_triple_display_full() {
1152 let subj = RdfSubject::from(NamedNode::new("http://example.org/alice").unwrap());
1153 let pred = RdfPredicate::new("http://xmlns.com/foaf/0.1/name").unwrap();
1154 let obj = RdfObject::from(Literal::new_simple_literal("Alice"));
1155 let triple = Triple::new(subj, pred, obj);
1156 let display = format!("{}", triple);
1157 assert!(display.contains("<http://example.org/alice>"));
1158 assert!(display.contains("<http://xmlns.com/foaf/0.1/name>"));
1159 assert!(display.contains("Alice"));
1160 assert!(display.ends_with("."));
1161 }
1162
1163 #[test]
1164 fn test_quad_display_with_graph() {
1165 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
1166 let pred = RdfPredicate::new("http://example.org/p").unwrap();
1167 let obj = RdfObject::from(Literal::new_simple_literal("v"));
1168 let graph = NamedNode::new("http://example.org/g").unwrap();
1169 let quad = Quad::new(subj, pred, obj, Some(graph));
1170 let display = format!("{}", quad);
1171 assert!(display.contains("<http://example.org/g>"));
1172 assert!(display.ends_with("."));
1173 }
1174
1175 #[test]
1176 fn test_quad_display_default_graph() {
1177 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
1178 let pred = RdfPredicate::new("http://example.org/p").unwrap();
1179 let obj = RdfObject::from(Literal::new_simple_literal("v"));
1180 let quad = Quad::new(subj, pred, obj, None);
1181 let display = format!("{}", quad);
1182 assert!(display.ends_with("."));
1183 assert!(!display.contains("graph"));
1184 }
1185
1186 #[test]
1187 fn test_triple_pattern_predicate_match() {
1188 let subj = NamedNode::new("http://example.org/s").unwrap();
1189 let pred = RdfPredicate::new("http://example.org/p1").unwrap();
1190 let obj = Literal::new_simple_literal("val");
1191 let triple = Triple::new(subj.into(), pred.clone(), obj.into());
1192
1193 let pattern = TriplePattern::new(None, Some(pred), None);
1195 assert!(pattern.matches(&triple));
1196
1197 let other_pred = RdfPredicate::new("http://example.org/p2").unwrap();
1199 let pattern2 = TriplePattern::new(None, Some(other_pred), None);
1200 assert!(!pattern2.matches(&triple));
1201 }
1202
1203 #[test]
1204 fn test_triple_pattern_object_match() {
1205 let subj = NamedNode::new("http://example.org/s").unwrap();
1206 let pred = RdfPredicate::new("http://example.org/p").unwrap();
1207 let obj = Literal::new_simple_literal("target_value");
1208 let triple = Triple::new(subj.into(), pred, obj.clone().into());
1209
1210 let pattern = TriplePattern::new(None, None, Some(obj.into()));
1212 assert!(pattern.matches(&triple));
1213
1214 let other_obj = RdfObject::from(Literal::new_simple_literal("other_value"));
1216 let pattern2 = TriplePattern::new(None, None, Some(other_obj));
1217 assert!(!pattern2.matches(&triple));
1218 }
1219
1220 #[test]
1221 fn test_quad_pattern_graph_match() {
1222 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
1223 let pred = RdfPredicate::new("http://example.org/p").unwrap();
1224 let obj = RdfObject::from(Literal::new_simple_literal("v"));
1225 let graph = NamedNode::new("http://example.org/g").unwrap();
1226 let quad = Quad::new(subj, pred, obj, Some(graph.clone()));
1227
1228 let pattern = QuadPattern {
1230 subject: None,
1231 predicate: None,
1232 object: None,
1233 graph: Some(Some(graph)),
1234 };
1235 assert!(pattern.matches(&quad));
1236
1237 let pattern_default = QuadPattern {
1239 subject: None,
1240 predicate: None,
1241 object: None,
1242 graph: Some(None),
1243 };
1244 assert!(!pattern_default.matches(&quad));
1245 }
1246
1247 #[test]
1248 fn test_quad_pattern_predicate_mismatch() {
1249 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
1250 let pred = RdfPredicate::new("http://example.org/p1").unwrap();
1251 let obj = RdfObject::from(Literal::new_simple_literal("v"));
1252 let quad = Quad::from_triple(Triple::new(subj, pred, obj));
1253
1254 let other_pred = RdfPredicate::new("http://example.org/p2").unwrap();
1255 let pattern = QuadPattern {
1256 subject: None,
1257 predicate: Some(other_pred),
1258 object: None,
1259 graph: None,
1260 };
1261 assert!(!pattern.matches(&quad));
1262 }
1263
1264 #[test]
1265 fn test_quad_pattern_object_mismatch() {
1266 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
1267 let pred = RdfPredicate::new("http://example.org/p").unwrap();
1268 let obj = RdfObject::from(Literal::new_simple_literal("val1"));
1269 let quad = Quad::from_triple(Triple::new(subj, pred, obj));
1270
1271 let other_obj = RdfObject::from(Literal::new_simple_literal("val2"));
1272 let pattern = QuadPattern {
1273 subject: None,
1274 predicate: None,
1275 object: Some(other_obj),
1276 graph: None,
1277 };
1278 assert!(!pattern.matches(&quad));
1279 }
1280
1281 #[test]
1282 fn test_named_node_equality() {
1283 let n1 = NamedNode::new("http://example.org/same").unwrap();
1284 let n2 = NamedNode::new("http://example.org/same").unwrap();
1285 let n3 = NamedNode::new("http://example.org/different").unwrap();
1286 assert_eq!(n1, n2);
1287 assert_ne!(n1, n3);
1288 }
1289
1290 #[test]
1291 fn test_blank_node_clone_and_hash() {
1292 let bn = BlankNode::from_str("b1").unwrap();
1293 let bn_clone = bn.clone();
1294 assert_eq!(bn, bn_clone);
1295
1296 use std::collections::HashSet;
1298 let mut set = HashSet::new();
1299 set.insert(bn.clone());
1300 assert!(set.contains(&bn_clone));
1301 }
1302
1303 #[test]
1304 fn test_literal_clone_and_eq() {
1305 let lit1 = Literal::new_simple_literal("same");
1306 let lit2 = lit1.clone();
1307 assert_eq!(lit1, lit2);
1308 }
1309
1310 #[test]
1311 fn test_quad_as_triple_preserves_content() {
1312 let subj = RdfSubject::from(NamedNode::new("http://example.org/s").unwrap());
1313 let pred = RdfPredicate::new("http://example.org/p").unwrap();
1314 let obj = RdfObject::from(Literal::new_simple_literal("val"));
1315 let graph = NamedNode::new("http://example.org/graph").unwrap();
1316 let quad = Quad::new(subj.clone(), pred.clone(), obj.clone(), Some(graph));
1317
1318 let triple = quad.as_triple();
1319 assert_eq!(triple.subject, subj);
1320 assert_eq!(triple.predicate, pred);
1321 assert_eq!(triple.object, obj);
1322 }
1323}