1. RDF Messages Interoperability Tests
This document proposes interoperability tests for implementations that support RDF Message Logs and RDF Message live streams for different serializations.
Implementations of parsers, serializers, and live stream adapters MUST provide conformance tests that verify message-level behavior.
An RDF Message Log parser MUST expose a message-level interface that emits one RDF Dataset per completed message.
A message is completed when a message delimiter or the end of the input is encountered. Empty messages MUST be preserved when they occur before the first triple or quad, or between two delimiters. A trailing delimiter after a non-empty message MUST finalize that message and MUST not by itself create an additional empty trailing message.
Blank node identifiers in RDF Message Logs MUST be scoped to the message in which they occur. Therefore, if the same blank node label appears in two different messages in the same input stream, the parser MUST produce two distinct blank nodes. This requirement applies even when the entire RDF Message Log is parsed from one continuous input string or stream by one parser instance.
Message delimiters are message-level syntax. They MUST only occur where the underlying RDF syntax permits directives or top-level statements, and MUST not occur inside an open graph block. A delimiter encountered inside a graph block MUST be a parse error.
Serializers should produce RDF Message Logs that round-trip to the same message sequence and the same quads per message. Conformance tests should not require a serializer to choose a specific delimiter spelling when more than one delimiter spelling is supported by the target syntax.
1.1. Parsing Tests for Turtle, TriG, N-Triples, and N-Quads
1.1.1. Single Message Without Delimiter
Input:
VERSION"1.2-messages" <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .
1.1.2. Two Messages With MESSAGE
Input:
VERSION"1.2-messages" <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . MESSAGE<http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . Message 2: <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
1.1.3. Two Messages With @message .
Input:
@version"1.2-messages" . @prefix ex: <http://example.org/> . ex : s1 ex : p ex : o1 . @message. ex : s2 ex : p ex : o2 .
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . Message 2: <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
1.1.4. Empty First Message
Input:
VERSION"1.2-messages" MESSAGE<http://example.org/s1> <http://example.org/p> <http://example.org/o1> .
Expected messages:
Message 1: empty Message 2: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .
1.1.5. Empty Message Between Non-Empty Messages
Input:
VERSION"1.2-messages" <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . MESSAGE MESSAGE<http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . Message 2: empty Message 3: <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
1.1.6. Final Delimiter Does Not Create Extra Empty Message
Input:
VERSION"1.2-messages" <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . MESSAGE
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> .
1.1.7. N-Quads Messages Preserve Graph Names
Input:
VERSION "1.2-messages" <http://example.org/s1> <http://example.org/p> <http://example.org/o1> <http://example.org/g1> . MESSAGE <http://example.org/s2> <http://example.org/p> <http://example.org/o2> <http://example.org/g2> .
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> <http://example.org/g1> . Message 2: <http://example.org/s2> <http://example.org/p> <http://example.org/o2> <http://example.org/g2> .
1.1.8. Message With Default Graph And Named Graph Quads
Input:
VERSION"1.2-messages" PREFIX ex: <http://example.org/> ex : s1 ex : p ex : o1 . ex : g { ex : s2 ex : p ex : o2 . ex : s3 ex : p ex : o3 . } MESSAGEex : s4 ex : p ex : o4 .
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . <http://example.org/s2> <http://example.org/p> <http://example.org/o2> <http://example.org/g> . <http://example.org/s3> <http://example.org/p> <http://example.org/o3> <http://example.org/g> . Message 2: <http://example.org/s4> <http://example.org/p> <http://example.org/o4> .
1.1.9. Blank Node Labels Are Scoped Per Message
Input:
VERSION"1.2-messages" _ : b0 <http://example.org/p> <http://example.org/o1> . MESSAGE_ : b0 <http://example.org/p> <http://example.org/o2> .
Expected result:
Message 1 contains one quad whose subject is a blank node. Message 2 contains one quad whose subject is a blank node. The two blank nodes must not be the same RDF term.
This test must be performed on one continuous input string or stream, not by creating two independent parser instances.
1.1.10. Repeated Prefixes Across Messages
Input:
VERSION"1.2-messages" PREFIX ex: <http://example.org/one/> ex : s ex : p ex : o . MESSAGEPREFIX ex: <http://example.org/two/> ex : s ex : p ex : o .
Expected messages:
Message 1: <http://example.org/one/s> <http://example.org/one/p> <http://example.org/one/o> . Message 2: <http://example.org/two/s> <http://example.org/two/p> <http://example.org/two/o> .
1.1.11. Message Boundary After A Graph Block
Input:
VERSION"1.2-messages" <http://example.org/g> { <http://example.org/a> <http://example.org/b> <http://example.org/c> . } MESSAGE<http://example.org/d> <http://example.org/e> <http://example.org/f> .
Expected messages:
Message 1: <http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/g> . Message 2: <http://example.org/d> <http://example.org/e> <http://example.org/f> .
1.2. Parsing Tests for NDJSON-LD
In these tests, each input line is one JSON object. Context messages update parser state but do not emit RDF messages. A parser maintains an active context that is updated by context messages.
1.2.1. Context Message Followed By Data Message
Input:
{ "@context" : "https://schema.org/" } { "@type" : "Product" , "name" : "Hairdryer DRY 2000" , "color" : "red" }
Expected messages:
Message 1: RDF dataset obtained by interpreting the second JSON object with @context = "https://schema.org/".
1.2.2. Empty Message Does Not Change Active Context
Input:
{ "@context" : "https://schema.org/" } {} { "@type" : "Product" , "name" : "27-inch 4K Monitor 2700P" , "color" : "black" }
Expected messages:
Message 1: empty Message 2: RDF dataset obtained by interpreting the third JSON object with @context = "https://schema.org/".
1.2.3. Context Switch Applies To Subsequent Data Messages
Input:
{ "@context" : "https://schema.org/" } { "@type" : "Product" , "name" : "Hairdryer DRY 2000" , "color" : "red" } { "@context" : "https://example.org/other-vocab/" } { "@type" : "OtherType" , "name" : "Piotr" }
Expected messages:
Message 1: RDF dataset obtained by interpreting the second JSON object with @context = "https://schema.org/". Message 2: RDF dataset obtained by interpreting the fourth JSON object with @context = "https://example.org/other-vocab/".
1.2.4. Data Message With Local @context Is Wrapped With Active Context
Input:
{ "@context" : { "ex" : "https://example.org/base/" , "name" : "ex:baseName" }} { "@context" : { "label" : "ex:label" }, "@type" : "ex:Thing" , "name" : "Alice" , "label" : "A" } { "@type" : "ex:Thing" , "name" : "Bob" }
Expected messages:
Message 1:
RDF dataset obtained by processing the effective JSON-LD document:
{"@context": {"ex": "https://example.org/base/", "name": "ex:baseName"}, "@graph": {"@context": {"label": "ex:label"}, "@type": "ex:Thing", "name": "Alice", "label": "A"}}
Message 2:
RDF dataset obtained by processing the effective JSON-LD document:
{"@context": {"ex": "https://example.org/base/", "name": "ex:baseName"}, "@graph": {"@type": "ex:Thing", "name": "Bob"}}
The local @context from line 2 does not change the active context C for subsequent messages.
1.2.5. Data Message Without Prior Context Is Allowed
Input:
{ "@id" : "https://example.org/p1" , "@type" : "https://example.org/Product" }
Expected messages:
Message 1: RDF dataset obtained by interpreting the JSON object as regular JSON-LD, without a stream-level active context.
1.3. Parsing Tests for RDF/XML
These tests apply to parsers of RDF Message Logs in the RDF/XML serialization. In all tests, the rdfm prefix refers to https://w3c-cg.github.io/rsp/spec/messages#.
1.3.1. Two Messages
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" > <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s1" > <ex:p rdf:resource= "http://example.org/o1" /> </rdf:Description> </rdf:RDF> <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s2" > <ex:p rdf:resource= "http://example.org/o2" /> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . Message 2: <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
1.3.2. Empty Log
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" />
Expected result:
No messages.
1.3.3. Empty Message Between Non-Empty Messages
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" > <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s1" > <ex:p rdf:resource= "http://example.org/o1" /> </rdf:Description> </rdf:RDF> <rdf:RDF/> <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s2" > <ex:p rdf:resource= "http://example.org/o2" /> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . Message 2: (empty) Message 3: <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
1.3.4. Blank Node Identifiers Are Scoped Per Message
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" > <rdf:RDF> <rdf:Description rdf:nodeID= "b0" > <ex:p rdf:resource= "http://example.org/o1" /> </rdf:Description> </rdf:RDF> <rdf:RDF> <rdf:Description rdf:nodeID= "b0" > <ex:p rdf:resource= "http://example.org/o2" /> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected result:
Message 1 contains one quad whose subject is a blank node. Message 2 contains one quad whose subject is a blank node. The two blank nodes must not be the same RDF term.
This test must be performed on one continuous input string or stream, not by splitting the input and creating two independent parser instances.
1.3.5. Blank Node Identifier Reused Within One Message
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" > <rdf:RDF> <rdf:Description rdf:nodeID= "b0" > <ex:p rdf:resource= "http://example.org/o1" /> </rdf:Description> <rdf:Description rdf:nodeID= "b0" > <ex:p rdf:resource= "http://example.org/o2" /> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected result:
Message 1 contains two quads whose subjects are blank nodes. The two blank nodes must be the same RDF term.
1.3.6. Namespaces Declared On The Log Element
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/one/" > <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s" > <ex:p rdf:resource= "http://example.org/o" /> </rdf:Description> </rdf:RDF> <rdf:RDF xmlns:ex= "http://example.org/two/" > <rdf:Description rdf:about= "http://example.org/s" > <ex:p rdf:resource= "http://example.org/o" /> </rdf:Description> </rdf:RDF> <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s" > <ex:p rdf:resource= "http://example.org/o" /> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected messages:
Message 1: <http://example.org/s> <http://example.org/one/p> <http://example.org/o> . Message 2: <http://example.org/s> <http://example.org/two/p> <http://example.org/o> . Message 3: <http://example.org/s> <http://example.org/one/p> <http://example.org/o> .
The namespace declared on the second <rdf:RDF> element applies only to that message.
1.3.7. Base IRI Declared On The Log Element
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" xml:base= "http://example.org/one/" > <rdf:RDF> <rdf:Description rdf:about= "s" > <ex:p rdf:resource= "o" /> </rdf:Description> </rdf:RDF> <rdf:RDF xml:base= "http://example.org/two/" > <rdf:Description rdf:about= "s" > <ex:p rdf:resource= "o" /> </rdf:Description> </rdf:RDF> <rdf:RDF> <rdf:Description rdf:about= "s" > <ex:p rdf:resource= "o" /> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected messages:
Message 1: <http://example.org/one/s> <http://example.org/p> <http://example.org/one/o> . Message 2: <http://example.org/two/s> <http://example.org/p> <http://example.org/two/o> . Message 3: <http://example.org/one/s> <http://example.org/p> <http://example.org/one/o> .
1.3.8. Language Tag Declared On The Log Element
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" xml:lang= "en" > <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s" > <ex:p> hello</ex:p> </rdf:Description> </rdf:RDF> <rdf:RDF xml:lang= "pl" > <rdf:Description rdf:about= "http://example.org/s" > <ex:p> czesc</ex:p> </rdf:Description> </rdf:RDF> <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s" > <ex:p> bye</ex:p> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected messages:
Message 1: <http://example.org/s> <http://example.org/p> "hello"@en . Message 2: <http://example.org/s> <http://example.org/p> "czesc"@pl . Message 3: <http://example.org/s> <http://example.org/p> "bye"@en .
1.3.9. Comments And Processing Instructions Between Messages Are Ignored
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" > <!-- first message --> <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s1" > <ex:p rdf:resource= "http://example.org/o1" /> </rdf:Description> </rdf:RDF> <?example-pi some data?> <!-- second message --> <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s2" > <ex:p rdf:resource= "http://example.org/o2" /> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . Message 2: <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
1.3.10. Multiline Literal
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" > <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s" > <ex:p> line one line two</ex:p> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected messages:
Message 1: <http://example.org/s> <http://example.org/p> "line one\nline two" .
1.4. Serialization Tests for Turtle, TriG, N-Triples, and N-Quads
Given a sequence of RDF Messages, a serializer should write a document that can be parsed back into the same sequence of messages and quads.
Serializers may choose the concrete message delimiter supported by their syntax. These tests should not assert whether @message . or MESSAGE was used.
Round-trip input messages:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . Message 2: empty Message 3: <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
Expected result after serializing and parsing the output:
Message 1: <http://example.org/s1> <http://example.org/p> <http://example.org/o1> . Message 2: empty Message 3: <http://example.org/s2> <http://example.org/p> <http://example.org/o2> .
Round-trip input messages with named graph quads:
Message 1: <http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/g> . Message 2: <http://example.org/d> <http://example.org/e> <http://example.org/f> <http://example.org/g> .
Expected result after serializing and parsing the output:
Message 1: <http://example.org/a> <http://example.org/b> <http://example.org/c> <http://example.org/g> . Message 2: <http://example.org/d> <http://example.org/e> <http://example.org/f> <http://example.org/g> .
1.5. Error Tests
1.5.1. Message Delimiter Without Message Support
If a parser is not in RDF Messages mode and encounters a message delimiter, it must reject the document.
Input:
<http://example.org/s> <http://example.org/p> <http://example.org/o> . MESSAGE
Expected result:
Parse error.
1.5.2. @message Without Trailing Dot
Input:
VERSION"1.2-messages" <http://example.org/s> <http://example.org/p> <http://example.org/o> . @message<http://example.org/invalid>
Expected result:
Parse error.
1.5.3. Message Delimiter Inside An Open Graph Block
A message delimiter must not be accepted inside an open graph block. It must be rejected instead of being interpreted as splitting the graph block across two messages.
Input:
VERSION"1.2-messages" <http://example.org/g> { <http://example.org/a> <http://example.org/b> <http://example.org/c> . MESSAGE<http://example.org/d> <http://example.org/e> <http://example.org/f> . }
Expected result:
Parse error.
1.5.4. RDF/XML Root Element Is Not rdfm:MessageLog
If a parser is reading an RDF/XML RDF Message Log, it must reject a document whose root element is not <rdfm:MessageLog>.
Input:
<?xml version="1.0" encoding="utf-8"?> <rdf:RDF xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:ex= "http://example.org/" > <rdf:Description rdf:about= "http://example.org/s" > <ex:p rdf:resource= "http://example.org/o" /> </rdf:Description> </rdf:RDF>
Expected result:
Parse error.
1.5.5. RDF/XML Node Element Directly Inside rdfm:MessageLog
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" > <rdf:Description rdf:about= "http://example.org/s" > <ex:p rdf:resource= "http://example.org/o" /> </rdf:Description> </rdfm:MessageLog>
Expected result:
Parse error.
1.5.6. RDF/XML Text Between Messages
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" > <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s1" > <ex:p rdf:resource= "http://example.org/o1" /> </rdf:Description> </rdf:RDF> some text<rdf:RDF> <rdf:Description rdf:about= "http://example.org/s2" > <ex:p rdf:resource= "http://example.org/o2" /> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected result:
Parse error.
1.5.7. RDF/XML Log Read By A Parser Without Message Support
If a parser is not in RDF Messages mode and reads an RDF/XML RDF Message Log as a plain RDF/XML document, it must reject the document, because rdf:RDF is not allowed as a property element name.
Input:
<?xml version="1.0" encoding="utf-8"?> <rdfm:MessageLog xmlns:rdf= "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfm= "https://w3c-cg.github.io/rsp/spec/messages#" xmlns:ex= "http://example.org/" > <rdf:RDF> <rdf:Description rdf:about= "http://example.org/s" > <ex:p rdf:resource= "http://example.org/o" /> </rdf:Description> </rdf:RDF> </rdfm:MessageLog>
Expected result:
Parse error.