404 lines
15 KiB
Elixir
404 lines
15 KiB
Elixir
defmodule RDF.Turtle.DecoderTest do
|
|
use ExUnit.Case, async: false
|
|
|
|
doctest RDF.Turtle.Decoder
|
|
|
|
import RDF.Sigils
|
|
|
|
alias RDF.{Turtle, Graph, NS}
|
|
|
|
use RDF.Vocabulary.Namespace
|
|
|
|
defvocab EX,
|
|
base_iri: "http://example.org/#",
|
|
terms: [], strict: false
|
|
|
|
defvocab P,
|
|
base_iri: "http://www.perceive.net/schemas/relationship/",
|
|
terms: [], strict: false
|
|
|
|
|
|
test "an empty string is deserialized to an empty graph" do
|
|
assert Turtle.Decoder.decode!("") == Graph.new
|
|
assert Turtle.Decoder.decode!(" \n\r\r\n ") == Graph.new
|
|
end
|
|
|
|
test "comments" do
|
|
assert Turtle.Decoder.decode!("# just a comment") == Graph.new
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#S> <http://example.org/#p> _:1 . # a comment
|
|
""") == Graph.new({EX.S, EX.p, RDF.bnode("1")})
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
# a comment
|
|
<http://example.org/#S> <http://example.org/#p> <http://example.org/#O> .
|
|
""") == Graph.new({EX.S, EX.p, EX.O})
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#S> <http://example.org/#p> <http://example.org/#O> .
|
|
# a comment
|
|
""") == Graph.new({EX.S, EX.p, EX.O})
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
# Header line 1
|
|
# Header line 2
|
|
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
|
# 1st comment
|
|
<http://example.org/#S1> <http://example.org/#p2> <http://example.org/#O2> . # 2nd comment
|
|
# last comment
|
|
""") == Graph.new([
|
|
{EX.S1, EX.p1, EX.O1},
|
|
{EX.S1, EX.p2, EX.O2},
|
|
])
|
|
end
|
|
|
|
test "empty lines" do
|
|
assert Turtle.Decoder.decode!("""
|
|
|
|
<http://example.org/#spiderman> <http://www.perceive.net/schemas/relationship/enemyOf> <http://example.org/#green_goblin> .
|
|
""") == Graph.new({EX.spiderman, P.enemyOf, EX.green_goblin})
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#spiderman> <http://www.perceive.net/schemas/relationship/enemyOf> <http://example.org/#green_goblin> .
|
|
|
|
""") == Graph.new({EX.spiderman, P.enemyOf, EX.green_goblin})
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
|
|
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
|
|
|
|
|
<http://example.org/#S1> <http://example.org/#p2> <http://example.org/#O2> .
|
|
|
|
""") == Graph.new([
|
|
{EX.S1, EX.p1, EX.O1},
|
|
{EX.S1, EX.p2, EX.O2},
|
|
])
|
|
end
|
|
|
|
|
|
describe "statements" do
|
|
test "a N-Triple-style statement" do
|
|
assert Turtle.Decoder.decode!(
|
|
"<http://example.org/#Aaron> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/#Person> ."
|
|
) == Graph.new({EX.Aaron, RDF.type, EX.Person})
|
|
end
|
|
|
|
test "a statement with the 'a' keyword" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Aaron> a <http://example.org/#Person> .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person})
|
|
end
|
|
|
|
test "multiple N-Triple-style statement" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
|
<http://example.org/#S1> <http://example.org/#p2> <http://example.org/#O2> .
|
|
""") == Graph.new([
|
|
{EX.S1, EX.p1, EX.O1},
|
|
{EX.S1, EX.p2, EX.O2},
|
|
])
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
|
<http://example.org/#S1> <http://example.org/#p2> <http://example.org/#O2> .
|
|
<http://example.org/#S2> <http://example.org/#p3> <http://example.org/#O3> .
|
|
""") == Graph.new([
|
|
{EX.S1, EX.p1, EX.O1},
|
|
{EX.S1, EX.p2, EX.O2},
|
|
{EX.S2, EX.p3, EX.O3}
|
|
])
|
|
end
|
|
|
|
test "statement with multiple objects" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> "baz", 1, true .
|
|
""") == Graph.new([
|
|
{EX.Foo, EX.bar, "baz"},
|
|
{EX.Foo, EX.bar, 1},
|
|
{EX.Foo, EX.bar, true},
|
|
])
|
|
end
|
|
|
|
test "statement with multiple predications" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> "baz";
|
|
<http://example.org/#baz> 42 .
|
|
""") == Graph.new([
|
|
{EX.Foo, EX.bar, "baz"},
|
|
{EX.Foo, EX.baz, 42},
|
|
])
|
|
end
|
|
end
|
|
|
|
describe "blank node property lists" do
|
|
test "blank node property list on object position" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> [ <http://example.org/#baz> 42 ] .
|
|
""") == Graph.new([
|
|
{EX.Foo, EX.bar, RDF.bnode("b0")},
|
|
{RDF.bnode("b0"), EX.baz, 42},
|
|
])
|
|
end
|
|
|
|
test "blank node property list on subject position" do
|
|
assert Turtle.Decoder.decode!("""
|
|
[ <http://example.org/#baz> 42 ] <http://example.org/#bar> false .
|
|
""") == Graph.new([
|
|
{RDF.bnode("b0"), EX.baz, 42},
|
|
{RDF.bnode("b0"), EX.bar, false},
|
|
])
|
|
end
|
|
|
|
test "a single blank node property list" do
|
|
assert Turtle.Decoder.decode!("[ <http://example.org/#foo> 42 ] .") ==
|
|
Graph.new([{RDF.bnode("b0"), EX.foo, 42}])
|
|
end
|
|
|
|
test "nested blank node property list" do
|
|
assert Turtle.Decoder.decode!("""
|
|
[ <http://example.org/#p1> [ <http://example.org/#p2> <http://example.org/#o2> ] ; <http://example.org/#p> <http://example.org/#o> ].
|
|
""") == Graph.new([
|
|
{RDF.bnode("b0"), EX.p1, RDF.bnode("b1")},
|
|
{RDF.bnode("b1"), EX.p2, EX.o2},
|
|
{RDF.bnode("b0"), EX.p, EX.o},
|
|
])
|
|
end
|
|
|
|
test "blank node via []" do
|
|
assert Turtle.Decoder.decode!("""
|
|
[] <http://xmlns.com/foaf/0.1/name> "Aaron Swartz" .
|
|
""") == Graph.new({RDF.bnode("b0"), ~I<http://xmlns.com/foaf/0.1/name>, "Aaron Swartz"})
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> [] .
|
|
""") == Graph.new({EX.Foo, EX.bar, RDF.bnode("b0")})
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> [ ] .
|
|
""") == Graph.new({EX.Foo, EX.bar, RDF.bnode("b0")})
|
|
end
|
|
end
|
|
|
|
|
|
test "blank node" do
|
|
assert Turtle.Decoder.decode!("""
|
|
_:foo <http://example.org/#p> <http://example.org/#O> .
|
|
""") == Graph.new({RDF.bnode("foo"), EX.p, EX.O})
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#S> <http://example.org/#p> _:1 .
|
|
""") == Graph.new({EX.S, EX.p, RDF.bnode("1")})
|
|
assert Turtle.Decoder.decode!("""
|
|
_:foo <http://example.org/#p> _:bar .
|
|
""") == Graph.new({RDF.bnode("foo"), EX.p, RDF.bnode("bar")})
|
|
end
|
|
|
|
describe "quoted literals" do
|
|
test "an untyped string literal" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#spiderman> <http://www.perceive.net/schemas/relationship/realname> "Peter Parker" .
|
|
""") == Graph.new({EX.spiderman, P.realname, RDF.literal("Peter Parker")})
|
|
end
|
|
|
|
test "an untyped long quoted string literal" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#spiderman> <http://www.perceive.net/schemas/relationship/realname> '''Peter Parker''' .
|
|
""") == Graph.new({EX.spiderman, P.realname, RDF.literal("Peter Parker")})
|
|
end
|
|
|
|
test "a typed literal" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#spiderman> <http://example.org/#p> "42"^^<http://www.w3.org/2001/XMLSchema#integer> .
|
|
""") == Graph.new({EX.spiderman, EX.p, RDF.literal(42)})
|
|
end
|
|
|
|
test "a typed literal with type as a prefixed name" do
|
|
assert Turtle.Decoder.decode!("""
|
|
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
|
|
<http://example.org/#spiderman> <http://example.org/#p> "42"^^xsd:integer .
|
|
""") == Graph.new({EX.spiderman, EX.p, RDF.literal(42)}, prefixes: %{xsd: NS.XSD})
|
|
end
|
|
|
|
test "a language tagged literal" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#S> <http://example.org/#p> "foo"@en .
|
|
""") == Graph.new({EX.S, EX.p, RDF.literal("foo", language: "en")})
|
|
end
|
|
|
|
test "a '@prefix' or '@base' language tagged literal" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#S> <http://example.org/#p> "foo"@prefix .
|
|
""") == Graph.new({EX.S, EX.p, RDF.literal("foo", language: "prefix")})
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#S> <http://example.org/#p> "foo"@base .
|
|
""") == Graph.new({EX.S, EX.p, RDF.literal("foo", language: "base")})
|
|
end
|
|
end
|
|
|
|
describe "shorthand literals" do
|
|
test "boolean" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> true .
|
|
""") == Graph.new({EX.Foo, EX.bar, RDF.true})
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> false .
|
|
""") == Graph.new({EX.Foo, EX.bar, RDF.false})
|
|
end
|
|
|
|
test "integer" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> 42 .
|
|
""") == Graph.new({EX.Foo, EX.bar, RDF.integer(42)})
|
|
end
|
|
|
|
test "decimal" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> 3.14 .
|
|
""") == Graph.new({EX.Foo, EX.bar, RDF.decimal("3.14")})
|
|
end
|
|
|
|
test "double" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<http://example.org/#Foo> <http://example.org/#bar> 1.2e3 .
|
|
""") == Graph.new({EX.Foo, EX.bar, RDF.double("1.2e3")})
|
|
end
|
|
end
|
|
|
|
|
|
describe "prefixed names" do
|
|
test "non-empty prefixed names" do
|
|
prefixes = RDF.PrefixMap.new(ex: ~I<http://example.org/#>)
|
|
assert Turtle.Decoder.decode!("""
|
|
@prefix ex: <http://example.org/#> .
|
|
ex:Aaron <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ex:Person .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes)
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
@prefix ex: <http://example.org/#> .
|
|
ex:Aaron <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ex:Person .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes)
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
PREFIX ex: <http://example.org/#>
|
|
ex:Aaron <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ex:Person .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes)
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
prefix ex: <http://example.org/#>
|
|
ex:Aaron <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> ex:Person .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes)
|
|
end
|
|
|
|
test "empty prefixed name" do
|
|
prefixes = RDF.PrefixMap.new("": ~I<http://example.org/#>)
|
|
assert Turtle.Decoder.decode!("""
|
|
@prefix : <http://example.org/#> .
|
|
:Aaron <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> :Person .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes)
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
PREFIX : <http://example.org/#>
|
|
:Aaron <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> :Person .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes)
|
|
end
|
|
end
|
|
|
|
describe "collections" do
|
|
test "non-empty collection" do
|
|
assert Turtle.Decoder.decode!("""
|
|
@prefix : <http://example.org/#> .
|
|
:subject :predicate ( :a :b :c ) .
|
|
""") == Graph.new([
|
|
{EX.subject, EX.predicate, RDF.bnode("b0")},
|
|
{RDF.bnode("b0"), RDF.first, EX.a},
|
|
{RDF.bnode("b0"), RDF.rest, RDF.bnode("b1")},
|
|
{RDF.bnode("b1"), RDF.first, EX.b},
|
|
{RDF.bnode("b1"), RDF.rest, RDF.bnode("b2")},
|
|
{RDF.bnode("b2"), RDF.first, EX.c},
|
|
{RDF.bnode("b2"), RDF.rest, RDF.nil},
|
|
], prefixes: %{"": ~I<http://example.org/#>})
|
|
end
|
|
|
|
test "empty collection" do
|
|
assert Turtle.Decoder.decode!("""
|
|
@prefix : <http://example.org/#> .
|
|
:subject :predicate () .
|
|
""") == Graph.new({EX.subject, EX.predicate, RDF.nil}, prefixes: %{"": ~I<http://example.org/#>})
|
|
end
|
|
|
|
test "nested collection" do
|
|
assert Turtle.Decoder.decode!("""
|
|
@prefix : <http://example.org/#> .
|
|
:subject :predicate ( :a (:b :c) ) .
|
|
""") == Graph.new([
|
|
{EX.subject, EX.predicate, RDF.bnode("b0")},
|
|
{RDF.bnode("b0"), RDF.first, EX.a},
|
|
{RDF.bnode("b0"), RDF.rest, RDF.bnode("b3")},
|
|
{RDF.bnode("b3"), RDF.first, RDF.bnode("b1")},
|
|
{RDF.bnode("b3"), RDF.rest, RDF.nil},
|
|
|
|
{RDF.bnode("b1"), RDF.first, EX.b},
|
|
{RDF.bnode("b1"), RDF.rest, RDF.bnode("b2")},
|
|
{RDF.bnode("b2"), RDF.first, EX.c},
|
|
{RDF.bnode("b2"), RDF.rest, RDF.nil},
|
|
], prefixes: %{"": ~I<http://example.org/#>})
|
|
end
|
|
end
|
|
|
|
|
|
describe "relative IRIs" do
|
|
test "without explicit in-doc base and no document_base option option given" do
|
|
assert_raise RuntimeError, fn ->
|
|
Turtle.Decoder.decode!(
|
|
"<#Aaron> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <#Person> .")
|
|
end
|
|
end
|
|
|
|
test "without explicit in-doc base, but document_base option given" do
|
|
assert Turtle.Decoder.decode!("""
|
|
<#Aaron> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <#Person> .
|
|
""", base: "http://example.org/") ==
|
|
Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I<http://example.org/>)
|
|
end
|
|
|
|
test "with @base given" do
|
|
assert Turtle.Decoder.decode!("""
|
|
@base <http://example.org/> .
|
|
<#Aaron> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <#Person> .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I<http://example.org/>)
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
@base <http://example.org/#> .
|
|
<#Aaron> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <#Person> .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I<http://example.org/#>)
|
|
end
|
|
|
|
test "with BASE given" do
|
|
assert Turtle.Decoder.decode!("""
|
|
BASE <http://example.org/>
|
|
<#Aaron> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <#Person> .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I<http://example.org/>)
|
|
|
|
assert Turtle.Decoder.decode!("""
|
|
base <http://example.org/#>
|
|
<#Aaron> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <#Person> .
|
|
""") == Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I<http://example.org/#>)
|
|
end
|
|
|
|
test "when a given base is itself relative" do
|
|
assert_raise RuntimeError, fn ->
|
|
Turtle.Decoder.decode!("""
|
|
@base <foo> .
|
|
<#Aaron> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <#Person> .
|
|
""")
|
|
end
|
|
assert_raise RuntimeError, fn ->
|
|
Turtle.Decoder.decode!(
|
|
"<#Aaron> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <#Person> .",
|
|
base: "foo")
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|