# coding: utf-8
require File.join(File.dirname(__FILE__), 'spec_helper')
include RdfContext
describe "RDF::N3::Reader" do
before(:each) { @parser = N3Parser.new(:strict => true) }
describe "with simple ntriples" do
it "should parse simple triple" do
n3_string = %( "Tom Morris" .)
@parser.parse(n3_string)
@parser.graph[0].subject.to_s.should == "http://example.org/"
@parser.graph[0].predicate.to_s.should == "http://xmlns.com/foaf/0.1/name"
@parser.graph[0].object.to_s.should == "Tom Morris"
@parser.graph.size.should == 1
end
it "should parse simple triple from class method" do
n3_string = " \"Tom Morris\" . "
graph = N3Parser.new(:strict => true).parse(n3_string)
graph[0].subject.to_s.should == "http://example.org/"
graph[0].predicate.to_s.should == "http://xmlns.com/foaf/0.1/name"
graph[0].object.to_s.should == "Tom Morris"
graph.size.should == 1
end
# NTriple tests from http://www.w3.org/2000/10/rdf-tests/rdfcore/ntriples/test.nt
describe "with blank lines" do
{
"comment" => "# comment lines",
"comment after whitespace" => " # comment after whitespace",
"empty line" => "",
"line with spaces" => " "
}.each_pair do |name, statement|
specify "test #{name}" do
@parser.parse(statement)
@parser.graph.size.should == 0
end
end
end
describe "with literal encodings" do
{
'Dürst' => ':a :b "D\u00FCrst" .',
'simple literal' => ':a :b "simple literal" .',
'backslash:\\' => ':a :b "backslash:\\\\" .',
'dquote:"' => ':a :b "dquote:\"" .',
"newline:\n" => ':a :b "newline:\n" .',
"return\r" => ':a :b "return\r" .',
"tab:\t" => ':a :b "tab:\t" .',
"é" => ':a :b "\u00E9" .',
"€" => ':a :b "\u20AC" .',
}.each_pair do |contents, triple|
specify "test #{contents}" do
@parser.parse(triple, "http://a/b")
@parser.graph.should_not be_nil
@parser.graph.size.should == 1
@parser.graph[0].object.contents.should == contents
end
end
it "should parse long literal with escape" do
n3 = %(@prefix : . :a :b "\\U00015678another" .)
if defined?(::Encoding)
@parser.parse(n3)
@parser.graph[0].object.contents.should == "\u{15678}another"
else
lambda { @parser.parse(n3) }.should raise_error(RdfException, "Long Unicode escapes no supported in Ruby 1.8")
pending("Not supported in Ruby 1.8")
end
end
it "should parse multi-line literal" do
@parser.parse(%(
"""
Foo
barhere
baz
more
""" .
))
@parser.graph.should_not be_nil
@parser.graph.size.should == 1
@parser.graph[0].object.contents.should == %(
Foo
barhere
baz
more
)
end
it "should parse long literal ending in double quote" do
@parser.parse(%(:a :b """ \\"""" .), "http://a/b")
@parser.graph.size.should == 1
@parser.graph[0].object.contents.should == ' "'
end
end
it "should create named subject bnode" do
@parser.parse("_:anon .")
@parser.graph.should_not be_nil
@parser.graph.size.should == 1
triple = @parser.graph[0]
triple.subject.should be_a(BNode)
triple.subject.identifier.should =~ /anon/
triple.predicate.should == "http://example.org/property"
triple.object.should == "http://example.org/resource2"
end
it "should create named predicate bnode" do
@parser.parse(" _:anon .")
@parser.graph.should_not be_nil
@parser.graph.size.should == 1
triple = @parser.graph[0]
triple.subject.should == "http://example.org/resource2"
triple.predicate.should be_a(BNode)
triple.predicate.identifier.should =~ /anon/
triple.object.should == "http://example.org/object"
end
it "should create named object bnode" do
@parser.parse(" _:anon .")
@parser.graph.should_not be_nil
@parser.graph.size.should == 1
triple = @parser.graph[0]
triple.subject.should == "http://example.org/resource2"
triple.predicate.should == "http://example.org/property"
triple.object.should be_a(BNode)
triple.object.identifier.should =~ /anon/
end
{
"three uris" => " .",
"spaces and tabs throughout" => " . ",
"line ending with CR NL" => " .\r\n",
"literal escapes (1)" => ' "simple literal" .',
"literal escapes (2)" => ' "backslash:\\\\" .',
"literal escapes (3)" => ' "dquote:\"" .',
"literal escapes (4)" => ' "newline:\n" .',
"literal escapes (5)" => ' "return:\r" .',
"literal escapes (6)" => ' "tab:\t" .',
"Space is optional before final . (1)" => [' .', ' .'],
"Space is optional before final . (2)" => [' "x".', ' "x" .'],
"XML Literals as Datatyped Literals (1)" => ' ""^^ .',
"XML Literals as Datatyped Literals (2)" => ' " "^^ .',
"XML Literals as Datatyped Literals (3)" => ' "x"^^ .',
"XML Literals as Datatyped Literals (4)" => ' "\""^^ .',
"XML Literals as Datatyped Literals (5)" => ' ""^^ .',
"XML Literals as Datatyped Literals (6)" => ' "a "^^ .',
"XML Literals as Datatyped Literals (7)" => ' "a c"^^ .',
"XML Literals as Datatyped Literals (8)" => ' "a\n\nc"^^ .',
"XML Literals as Datatyped Literals (9)" => ' "chat"^^ .',
"Plain literals with languages (1)" => ' "chat"@fr .',
"Plain literals with languages (2)" => ' "chat"@en .',
"Typed Literals" => ' "abc"^^ .',
}.each_pair do |name, statement|
specify "test #{name}" do
@parser.parse([statement].flatten.first)
@parser.graph.should_not be_nil
@parser.graph.size.should == 1
#puts @parser.graph[0].to_ntriples
@parser.graph[0].to_ntriples.should == [statement].flatten.last.gsub(/\s+/, " ").strip
end
end
it "should create typed literals" do
n3doc = " \"Joe\"^^ ."
@parser.parse(n3doc)
@parser.graph[0].object.class.should == RdfContext::Literal
end
it "should create BNodes" do
n3doc = "_:a a _:c ."
@parser.parse(n3doc)
@parser.graph[0].subject.class.should == RdfContext::BNode
@parser.graph[0].object.class.should == RdfContext::BNode
end
describe "should create URIRefs" do
{
%( .) => %( .),
%( .) => %( .),
%(:joe :knows :jane .) => %( .),
%(<#D%C3%BCrst> a "URI percent ^encoded as C3, BC".) => %( "URI percent ^encoded as C3, BC" .),
}.each_pair do |n3, nt|
it "for '#{n3}'" do
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
end
{
%(<#Dürst> a "URI straight in UTF8".) => %( "URI straight in UTF8" .),
%(:a :related :\u3072\u3089\u304C\u306A.) => %( .),
}.each_pair do |n3, nt|
it "for '#{n3}'" do
begin
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
rescue
if defined?(::Encoding)
raise
else
pending("Unicode URIs not supported in Ruby 1.8") { raise }
end
end
end
end
end
it "should create URIRefs" do
n3doc = " ."
@parser.parse(n3doc)
@parser.graph[0].subject.class.should == RdfContext::URIRef
@parser.graph[0].object.class.should == RdfContext::URIRef
end
it "should create literals" do
n3doc = " \"Joe\"."
@parser.parse(n3doc)
@parser.graph[0].object.class.should == RdfContext::Literal
end
end
describe "with illegal syntax" do
{
%(:y :p1 "xyz"^^xsd:integer .) => %r(Typed literal has an invalid lexical value: .* "xyz"),
%(:y :p1 "12xyz"^^xsd:integer .) => %r(Typed literal has an invalid lexical value: .* "12xyz"),
%(:y :p1 "xy.z"^^xsd:double .) => %r(Typed literal has an invalid lexical value: .* "xy\.z"),
%(:y :p1 "+1.0z"^^xsd:double .) => %r(Typed literal has an invalid lexical value: .* "\+1.0z"),
%(:a :b .) => %r(Illegal statment: ".*" missing object),
%(:a :b 'single quote' .) => RdfException,
%(:a "literal value" :b .) => InvalidPredicate,
%(@keywords prefix. :e prefix :f .) => %r(Keyword ".*" used as expression)
}.each_pair do |n3, error|
it "should raise error for '#{n3}'" do
lambda {
@parser.parse("@prefix xsd: . #{n3}", "http://a/b")
}.should raise_error(error)
end
end
end
describe "with n3 grammer" do
describe "syntactic expressions" do
it "should create typed literals with qname" do
n3doc = %(
@prefix rdf:
@prefix foaf:
@prefix xsd:
foaf:name \"Joe\"^^xsd:string .
)
@parser.parse(n3doc)
@parser.graph[0].object.class.should == RdfContext::Literal
end
it "should map <> to document uri" do
n3doc = "@prefix : <> ."
@parser.parse(n3doc, "http://the.document.itself")
@parser.graph.nsbinding.should == {"" => Namespace.new("http://the.document.itself#", "")}
end
it "should use <> as a prefix and as a triple node" do
n3 = %(@prefix : <> . <> a :a.)
nt = %(
.
)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should use <#> as a prefix and as a triple node" do
n3 = %(@prefix : <#> . <#> a :a.)
nt = %(
.
)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should generate rdf:type for 'a'" do
n3 = %(@prefix a: . a:b a .)
nt = %( .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should generate rdf:type for '@a'" do
n3 = %(@prefix a: . a:b @a .)
nt = %( .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should generate inverse predicate for 'is xxx of'" do
n3 = %("value" is :prop of :b . :b :prop "value" .)
nt = %( "value" .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should generate inverse predicate for '@is xxx @of'" do
n3 = %("value" @is :prop @of :b . :b :prop "value" .)
nt = %( "value" .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should generate inverse predicate for 'is xxx of' with object list" do
n3 = %("value" is :prop of :b, :c . )
nt = %(
"value" .
"value" .
)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should generate predicate for 'has xxx'" do
n3 = %(@prefix a: . a:b has :pred a:c .)
nt = %( .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should generate predicate for '@has xxx'" do
n3 = %(@prefix a: . a:b @has :pred a:c .)
nt = %( .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should create log:implies predicate for '=>'" do
n3 = %(@prefix a: . _:a => a:something .)
nt = %(_:a .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug)
end
it "should create log:implies inverse predicate for '<='" do
n3 = %(@prefix a: . _:a <= a:something .)
nt = %( _:a .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug)
end
it "should create owl:sameAs predicate for '='" do
n3 = %(@prefix a: . _:a = a:something .)
nt = %(_:a .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug)
end
{
%(:a :b @true) => %( "true"^^ .),
%(:a :b @false) => %( "false"^^ .),
%(:a :b 1) => %( "1"^^ .),
%(:a :b -1) => %( "-1"^^ .),
%(:a :b +1) => %( "+1"^^ .),
%(:a :b 1.0) => %( "1.0"^^ .),
%(:a :b 1.0e1) => %( "1.0e1"^^ .),
%(:a :b 1.0e-1) => %( "1.0e-1"^^ .),
%(:a :b 1.0e+1) => %( "1.0e+1"^^ .),
}.each_pair do |n3, nt|
it "should create typed literal for '#{n3}'" do
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug)
end
end
it "should accept empty localname" do
n3 = %(: : : .)
nt = %( .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should accept prefix with empty local name" do
n3 = %(@prefix foo: . foo: foo: foo: .)
nt = %( .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should do something for @forAll"
it "should do something for @forSome"
end
describe "namespaces" do
it "should set absolute base" do
n3 = %(@base . <> :a . <#c> :d .)
nt = %(
.
.
)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should set absolute base (trailing /)" do
n3 = %(@base . <> :a . <#c> :d .)
nt = %(
.
.
)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should set absolute base (trailing #)" do
n3 = %(@base . <> :a . <#c> :d .)
nt = %(
.
.
)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should set relative base" do
n3 = %(
@base .
<> :a , <#c>.
@base .
<> :a , <#c>.
@base <../>.
<> :a , <#e>.
)
nt = %(
.
.
.
.
.
.
)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
it "should bind named namespace" do
n3doc = "@prefix ns: ."
@parser.parse(n3doc, "http://a/b")
@parser.graph.nsbinding.should == {"ns" => Namespace.new("http://the/namespace#", "ns")}
end
it "should bind empty prefix to <%> by default" do
n3doc = "@prefix : <#> ."
@parser.parse(n3doc, "http://the.document.itself")
@parser.graph.nsbinding.should == {"" => Namespace.new("http://the.document.itself#", "")}
end
it "should be able to bind _ as namespace" do
n3 = %(@prefix _: . _:a a _:p.)
nt = %( .)
@parser.parse(n3, "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
end
describe "keywords" do
[
%(prefix :<>.),
%(base <>.),
%(keywords a.),
%(:a is :b of :c.),
%(:a @is :b of :c.),
%(:a is :b @of :c.),
%(:a has :b :c.),
].each do |n3|
it "should require @ if keywords set to empty for '#{n3}'" do
lambda do
@parser.parse("@keywords . #{n3}", "http://a/b")
end.should raise_error(/unqualified keyword '\w+' used without @keyword directive/)
end
end
{
%(:a a :b) => %( .),
%(:a :b true) => %( .),
%(:a :b false) => %( .),
%(c :a :t) => %( .),
%(:c a :t) => %( .),
%(:c :a t) => %( .),
}.each_pair do |n3, nt|
it "should use default_ns for '#{n3}'" do
@parser.parse("@keywords . #{n3}", "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @parser.debug, :compare => :array)
end
end
{
%(@keywords true. :a :b true.) => %( "true"^^ .),
%(@keywords false. :a :b false.) => %( "false"^^ .),
%(@keywords a. :a a :b.) => %( .),
%(@keywords is. :a is :b @of :c.) => %(