require File.join(File.dirname(__FILE__), 'spec_helper')
describe "Graphs" do
before(:all) do
@ex = Namespace.new("http://example.org/", "ex")
@foaf = Namespace.new("http://xmlns.com/foaf/0.1/", "foaf")
@bn_ctx = {}
end
subject { Graph.new(:store => ListStore.new) }
it "should allow you to add one or more triples" do
lambda do
subject.add_triple(BNode.new, URIRef.new("http://xmlns.com/foaf/0.1/knows"), BNode.new)
end.should_not raise_error
end
it "should support << as an alias for add_triple" do
lambda do
subject << Triple.new(BNode.new, URIRef.new("http://xmlns.com/foaf/0.1/knows"), BNode.new)
end.should_not raise_error
subject.size.should == 1
end
it "should return bnode subjects" do
bn = BNode.new
subject.add_triple(bn, URIRef.new("http://xmlns.com/foaf/0.1/knows"), bn)
subject.subjects.should == [bn]
end
it "should be able to determine whether or not it has existing BNodes" do
foaf = Namespace.new("http://xmlns.com/foaf/0.1/", "foaf")
john = BNode.new('john', @bn_ctx)
jane = BNode.new('jane', @bn_ctx)
jack = BNode.new('jack', @bn_ctx)
subject << Triple.new(john, foaf.knows, jane)
subject.has_bnode_identifier?(john).should be_true
subject.has_bnode_identifier?(jane).should be_true
subject.has_bnode_identifier?(jack).should_not be_true
end
it "should allow you to create and bind Namespace objects" do
subject.bind(Namespace.new("http://xmlns.com/foaf/0.1/", "foaf")).should be_a(Namespace)
subject.nsbinding["foaf"].uri.should == "http://xmlns.com/foaf/0.1/"
end
it "should bind namespace" do
foaf = Namespace.new("http://xmlns.com/foaf/0.1/", "foaf")
subject.bind(foaf).should == foaf
end
it "should not allow you to bind things other than namespaces" do
lambda do
subject.bind(false)
end.should raise_error
end
it "should follow the specification as to output identical triples" do
subject.add_triple(@ex.a, @ex.b, @ex.c)
subject.add_triple(@ex.a, @ex.b, @ex.c)
subject.size.should == 1
end
it "should parse into existing graph" do
n3_string = " \"Gregg Kellogg\" . "
graph = subject.parse(n3_string, nil, :type => :n3)
graph.should == subject
graph.identifier.should be_a(BNode)
subject.size.should == 1
subject[0].subject.to_s.should == "http://example.org/"
subject[0].predicate.to_s.should == "http://xmlns.com/foaf/0.1/name"
subject[0].object.to_s.should == "Gregg Kellogg"
end
it "should add multiple triples" do
subject.add(Triple.new(@ex.a, @ex.b, @ex.c), Triple.new(@ex.a, @ex.b, @ex.d))
subject.size.should == 2
end
it "should freeze when destroyed" do
subject.destroy
subject.frozen?.should be_true
end
describe "with identifier" do
before(:all) { @identifier = URIRef.new("http://foo.bar") }
subject { Graph.new(:identifier => @identifier) }
it "should retrieve identifier" do
subject.identifier.should == @identifier
subject.identifier.should == @identifier.to_s
end
end
describe "with named store" do
before(:all) do
@identifier = URIRef.new("http://foo.bar")
@store = ListStore.new(:identifier => @identifier)
end
subject {
g = Graph.new(:identifier => @identifier, :store => @store)
g.add_triple(@ex.john, @foaf.knows, @ex.jane)
g.add_triple(@ex.john, @foaf.knows, @ex.rick)
g.add_triple(@ex.jane, @foaf.knows, @ex.rick)
g.bind(@foaf)
g
}
it "should retrieve identifier" do
subject.identifier.should == @identifier
subject.identifier.should == @identifier.to_s
end
it "should be same as graph with same store and identifier" do
g = Graph.new(:store => @store, :identifier => @identifier)
subject.should == g
end
end
describe "with XML Literal objects" do
subject {
dc = Namespace.new("http://purl.org/dc/elements/1.1/", "dc")
xhtml = Namespace.new("http://www.w3.org/1999/xhtml", "")
g = Graph.new(:store => ListStore.new)
g << Triple.new(
URIRef.new("http://www.w3.org/2006/07/SWD/RDFa/testsuite/xhtml1-testcases/0011.xhtml"),
URIRef.new("http://purl.org/dc/elements/1.1/title"),
Literal.typed("E = mc2: The Most Urgent Problem of Our Time",
"http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral",
g.nsbinding)
)
g.bind(dc)
g.bind(xhtml)
g
}
it "should output NTriple" do
nt = ' "E = mc2: The Most Urgent Problem of Our Time"^^ .' + "\n"
subject.to_ntriples.should == nt
end
it "should output RDF/XML" do
rdfxml = <<-HERE
E = mc2>/sup>: The Most Urgent Problem of Our Time
HERE
subject.to_rdfxml.should include("E = mc2: The Most Urgent Problem of Our Time")
end
end
describe "with bnodes" do
subject {
g = Graph.new(:store => ListStore.new)
a = BNode.new("a")
b = BNode.new("b")
g << Triple.new(a, @foaf.name, Literal.untyped("Manu Sporny"))
g << Triple.new(a, @foaf.knows, b)
g << Triple.new(b, @foaf.name, Literal.untyped("Ralph Swick"))
g.bind(@foaf)
g
}
it "should return bnodes" do
subject.bnodes.keys.length.should == 2
subject.bnodes.values.should == [2, 2]
end
it "should output RDF/XML" do
rdfxml = <<-HERE
Manu Sporny
Ralph Swick
HERE
xml = subject.to_rdfxml
xml.should include("Ralph Swick")
xml.should include("Manu Sporny")
end
end
describe "with triples" do
subject {
g = Graph.new(:store => ListStore.new)
g.add_triple(@ex.john, @foaf.knows, @ex.jane)
g.add_triple(@ex.john, @foaf.knows, @ex.rick)
g.add_triple(@ex.jane, @foaf.knows, @ex.rick)
g.bind(@foaf)
g
}
it "should detect included triple" do
subject.contains?(subject[0]).should be_true
end
it "should tell you how large the graph is" do
subject.size.should == 3
end
it "should return unique subjects" do
subject.subjects.should == [@ex.john.uri.to_s, @ex.jane.uri.to_s]
end
it "should return unique predicates" do
subject.predicates.should == [@foaf.knows.uri.to_s]
end
it "should return unique objects" do
subject.objects.should == [@ex.jane.uri.to_s, @ex.rick.uri.to_s]
end
it "should allow you to select resources" do
subject.triples(Triple.new(@ex.john, nil, nil)).size.should == 2
end
it "should allow iteration" do
count = 0
subject.triples do |t|
count = count + 1
t.class.should == Triple
end
count.should == 3
end
it "should allow iteration over a particular subject" do
count = 0
subject.triples(Triple.new(@ex.john, nil, nil)) do |t|
count = count + 1
t.class.should == Triple
t.subject.should == @ex.john
end
count.should == 2
end
it "should give you a list of resources of a particular type" do
subject.add_triple(@ex.john, RDF_TYPE, @foaf.Person)
subject.add_triple(@ex.jane, RDF_TYPE, @foaf.Person)
subject.get_by_type("http://xmlns.com/foaf/0.1/Person").should == [@ex.john, @ex.jane]
end
it "should remove a triple" do
subject.add(Triple.new(@ex.john, RDF_TYPE, @foaf.Person))
subject.size.should == 4
subject.remove(Triple.new(@ex.john, RDF_TYPE, @foaf.Person))
subject.size.should == 3
end
it "should remove all triples" do
subject.remove(Triple.new(nil, nil, nil))
subject.size.should == 0
end
describe "find triples" do
it "should find subjects" do
subject.triples(Triple.new(@ex.john, nil, nil)).size.should == 2
subject.triples(Triple.new(@ex.jane, nil, nil)).size.should == 1
end
it "should find predicates" do
subject.triples(Triple.new(nil, @foaf.knows, nil)).size.should == 3
end
it "should find objects" do
subject.triples(Triple.new(nil, nil, @ex.rick)).size.should == 2
end
it "should find object with regexp" do
subject.triples(Triple.new(nil, nil, @ex.rick)).size.should == 2
end
it "should find combinations" do
subject.triples(Triple.new(@ex.john, nil, @ex.rick)).size.should == 1
end
end
describe "encodings" do
it "should output NTriple" do
nt = " .\n .\n .\n"
subject.to_ntriples.should == nt
end
it "should output RDF/XML" do
rdfxml = <<-HERE
HERE
subject.to_rdfxml.should be_equivalent_xml(rdfxml)
end
end
end
describe "which are merged" do
it "should be able to integrate another graph" do
subject.add_triple(BNode.new, URIRef.new("http://xmlns.com/foaf/0.1/knows"), BNode.new)
g = Graph.new(:store => ListStore.new)
g.merge!(subject)
g.size.should == 1
end
it "should not merge with non graph" do
lambda do
h.merge!("")
end.should raise_error
end
# One does not, in general, obtain the merge of a set of graphs by concatenating their corresponding
# N-Triples documents and constructing the graph described by the merged document. If some of the
# documents use the same node identifiers, the merged document will describe a graph in which some of the
# blank nodes have been 'accidentally' identified. To merge N-Triples documents it is necessary to check
# if the same nodeID is used in two or more documents, and to replace it with a distinct nodeID in each
# of them, before merging the documents.
it "should remap bnodes to avoid duplicate bnode identifiers" do
subject.add_triple(BNode.new("a1", @bn_ctx), URIRef.new("http://xmlns.com/foaf/0.1/knows"), BNode.new("a2", @bn_ctx))
g = Graph.new(:store => ListStore.new)
g.add_triple(BNode.new("a1", @bn_ctx), URIRef.new("http://xmlns.com/foaf/0.1/knows"), BNode.new("a2", @bn_ctx))
g.merge!(subject)
g.size.should == 2
s1, s2 = g.triples.map(&:subject)
p1, p2 = g.triples.map(&:predicate)
o1, o2 = g.triples.map(&:object)
s1.should_not == s2
p1.should == p1
o1.should_not == o2
end
it "should remove duplicate triples" do
subject.add_triple(@ex.a, URIRef.new("http://xmlns.com/foaf/0.1/knows"), @ex.b)
g = Graph.new(:store => ListStore.new)
g.add_triple(@ex.a, URIRef.new("http://xmlns.com/foaf/0.1/knows"), @ex.b)
g.merge!(subject)
g.size.should == 1
end
end
describe "that can be compared" do
{
"ListStore" => :list_store,
"MemoryStore" => :memory_store
}.each_pair do |t, s|
describe "using #{t}" do
subject { Graph.new(:store => s)}
it "should be true for empty graphs" do
subject.should == Graph.new(:store => s, :identifier => subject.identifier)
end
it "should be false for different graphs" do
f = Graph.new(:store => s, :identifier => subject.identifier)
f.add_triple(URIRef.new("http://example.org/joe"), URIRef.new("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"), URIRef.new("http://xmlns.com/foaf/0.1/Person"))
subject.should_not == f
end
it "should be true for equivalent graphs with different BNode identifiers" do
subject.add_triple(@ex.a, @foaf.knows, BNode.new("a1", @bn_ctx))
subject.add_triple(BNode.new("a1", @bn_ctx), @foaf.knows, @ex.a)
f = Graph.new(:store => s, :identifier => subject.identifier)
f.add_triple(@ex.a, @foaf.knows, BNode.new("a2", @bn_ctx))
f.add_triple(BNode.new("a2", @bn_ctx), @foaf.knows, @ex.a)
subject.should == f
end
it "should be true for graphs with literals" do
subject.add_triple(@ex.a, @foaf.knows, Literal.untyped("foo"))
f = Graph.new(:store => s, :identifier => subject.identifier)
f.add_triple(@ex.a, @foaf.knows, Literal.untyped("foo"))
subject.should == f
end
end
end
end
end