# coding: utf-8
$:.unshift "."
require File.join(File.dirname(__FILE__), 'spec_helper')

describe "RDF::N3::Reader" do
    context "discovery" do
      {
        "n3" => RDF::Reader.for(:n3),
        "etc/foaf.n3" => RDF::Reader.for("etc/foaf.n3"),
        "etc/foaf.ttl" => RDF::Reader.for("etc/foaf.ttl"),
        "foaf.n3" => RDF::Reader.for(:file_name      => "foaf.n3"),
        "foaf.ttl" => RDF::Reader.for(:file_name      => "foaf.ttl"),
        ".n3" => RDF::Reader.for(:file_extension => "n3"),
        ".ttl" => RDF::Reader.for(:file_extension => "ttl"),
        "text/n3" => RDF::Reader.for(:content_type   => "text/n3"),
        "text/turtle" => RDF::Reader.for(:content_type   => "text/turtle"),
      }.each_pair do |label, format|
        it "should discover '#{label}'" do
          format.should == RDF::N3::Reader
        end
      end
    end

    context :interface do
      before(:each) do
        @sampledoc = <<-EOF;
          @prefix dc: <http://purl.org/dc/elements/1.1/>.
          @prefix po: <http://purl.org/ontology/po/>.
          @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>.
          _:broadcast
           a po:Broadcast;
           po:schedule_date """2008-06-24T12:00:00Z""";
           po:broadcast_of _:version;
           po:broadcast_on <http://www.bbc.co.uk/programmes/service/6music>;
          .
          _:version
           a po:Version;
          .
          <http://www.bbc.co.uk/programmes/b0072l93>
           dc:title """Nemone""";
           a po:Brand;
          .
          <http://www.bbc.co.uk/programmes/b00c735d>
           a po:Episode;
           po:episode <http://www.bbc.co.uk/programmes/b0072l93>;
           po:version _:version;
           po:long_synopsis """Actor and comedian Rhys Darby chats to Nemone.""";
           dc:title """Nemone""";
           po:synopsis """Actor and comedian Rhys Darby chats to Nemone.""";
          .
          <http://www.bbc.co.uk/programmes/service/6music>
           a po:Service;
           dc:title """BBC 6 Music""";
          .

          #_:abcd a po:Episode.
      EOF
    end
    
    it "should yield reader" do
      inner = mock("inner")
      inner.should_receive(:called).with(RDF::N3::Reader)
      RDF::N3::Reader.new(@sampledoc) do |reader|
        inner.called(reader.class)
      end
    end
    
    it "should return reader" do
      RDF::N3::Reader.new(@sampledoc).should be_a(RDF::N3::Reader)
    end
    
    it "should yield statements" do
      inner = mock("inner")
      inner.should_receive(:called).with(RDF::Statement).exactly(15)
      RDF::N3::Reader.new(@sampledoc).each_statement do |statement|
        inner.called(statement.class)
      end
    end
    
    it "should yield triples" do
      inner = mock("inner")
      inner.should_receive(:called).exactly(15)
      RDF::N3::Reader.new(@sampledoc).each_triple do |subject, predicate, object|
        inner.called(subject.class, predicate.class, object.class)
      end
    end
  end

  describe "with simple ntriples" do
    context "simple triple" do
      before(:each) do
        n3_string = %(<http://example.org/> <http://xmlns.com/foaf/0.1/name> "Gregg Kellogg" .)
        @graph = parse(n3_string)
        @statement = @graph.statements.first
      end
      
      it "should have a single triple" do
        @graph.size.should == 1
      end
      
      it "should have subject" do
        @statement.subject.to_s.should == "http://example.org/"
      end
      it "should have predicate" do
        @statement.predicate.to_s.should == "http://xmlns.com/foaf/0.1/name"
      end
      it "should have object" do
        @statement.object.to_s.should == "Gregg Kellogg"
      end
    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
          parse(statement).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" .',
        "resumé" => ':a :resume  "resum\u00E9" .',
      }.each_pair do |contents, triple|
        specify "test #{triple}" do
          graph = parse(triple, :base_uri => "http://a/b")
          statement = graph.statements.first
          graph.size.should == 1
          statement.object.value.should == contents
        end
      end
      
      {
        'Dürst' => ':a :b "Dürst" .',
        "é" => ':a :b  "é" .',
        "€" => ':a :b  "€" .',
        "resumé" => ':a :resume  "resumé" .',
      }.each_pair do |contents, triple|
        specify "test #{triple}" do
          graph = parse(triple, :base_uri => "http://a/b")
          statement = graph.statements.first
          graph.size.should == 1
          statement.object.value.should == contents
        end
      end
      
      it "should parse long literal with escape" do
        n3 = %(@prefix : <http://example.org/foo#> . :a :b "\\U00015678another" .)
        if defined?(::Encoding)
          statement = parse(n3).statements.first
          statement.object.value.should == "\u{15678}another"
        else
          pending("Not supported in Ruby 1.8")
        end
      end

      it "should parse multi-line literal" do
        graph = parse(%(
  <http://www.example.com/books#book12345> <http://purl.org/dc/terms/title> """
          Foo
          <html:b xmlns:html="http://www.w3.org/1999/xhtml" html:a="b">bar<rdf:Thing xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><a:b xmlns:a="foo:"></a:b>here<a:c xmlns:a="foo:"></a:c></rd
  f:Thing></html:b>
          baz
          <html:i xmlns:html="http://www.w3.org/1999/xhtml">more</html:i>
       """ .
        ))

        graph.size.should == 1
        graph.statements.first.object.value.should == %(
          Foo
          <html:b xmlns:html="http://www.w3.org/1999/xhtml" html:a="b">bar<rdf:Thing xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><a:b xmlns:a="foo:"></a:b>here<a:c xmlns:a="foo:"></a:c></rd
  f:Thing></html:b>
          baz
          <html:i xmlns:html="http://www.w3.org/1999/xhtml">more</html:i>
       )
      end
      
      it "should parse long literal ending in double quote" do
        graph = parse(%(:a :b """ \\"""" .), :base_uri => "http://a/b")
        graph.size.should == 1
        graph.statements.first.object.value.should == ' "'
      end
    end

    it "should create named subject bnode" do
      graph = parse("_:anon <http://example.org/property> <http://example.org/resource2> .")
      graph.size.should == 1
      statement = graph.statements.first
      statement.subject.should be_a(RDF::Node)
      statement.subject.id.should =~ /anon/
      statement.predicate.to_s.should == "http://example.org/property"
      statement.object.to_s.should == "http://example.org/resource2"
    end

    it "should create named predicate bnode" do
      graph = parse("<http://example.org/resource2> _:anon <http://example.org/object> .")
      graph.size.should == 1
      statement = graph.statements.first
      statement.subject.to_s.should == "http://example.org/resource2"
      statement.predicate.should be_a(RDF::Node)
      statement.predicate.id.should =~ /anon/
      statement.object.to_s.should == "http://example.org/object"
    end

    it "should create named object bnode" do
      graph = parse("<http://example.org/resource2> <http://example.org/property> _:anon .")
      graph.size.should == 1
      statement = graph.statements.first
      statement.subject.to_s.should == "http://example.org/resource2"
      statement.predicate.to_s.should == "http://example.org/property"
      statement.object.should be_a(RDF::Node)
      statement.object.id.should =~ /anon/
    end

    {
      "three uris"  => "<http://example.org/resource1> <http://example.org/property> <http://example.org/resource2> .",
      "spaces and tabs throughout" => " 	 <http://example.org/resource3> 	 <http://example.org/property>	 <http://example.org/resource2> 	.	 ",
      "line ending with CR NL" => "<http://example.org/resource4> <http://example.org/property> <http://example.org/resource2> .\r\n",
      "literal escapes (1)" => '<http://example.org/resource7> <http://example.org/property> "simple literal" .',
      "literal escapes (2)" => '<http://example.org/resource8> <http://example.org/property> "backslash:\\\\" .',
      "literal escapes (3)" => '<http://example.org/resource9> <http://example.org/property> "dquote:\"" .',
      "literal escapes (4)" => '<http://example.org/resource10> <http://example.org/property> "newline:\n" .',
      "literal escapes (5)" => '<http://example.org/resource11> <http://example.org/property> "return:\r" .',
      "literal escapes (6)" => '<http://example.org/resource12> <http://example.org/property> "tab:\t" .',
      "Space is optional before final . (1)" => ['<http://example.org/resource13> <http://example.org/property> <http://example.org/resource2>.', '<http://example.org/resource13> <http://example.org/property> <http://example.org/resource2> .'],
      "Space is optional before final . (2)" => ['<http://example.org/resource14> <http://example.org/property> "x".', '<http://example.org/resource14> <http://example.org/property> "x" .'],

      "XML Literals as Datatyped Literals (1)" => '<http://example.org/resource21> <http://example.org/property> ""^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
      "XML Literals as Datatyped Literals (2)" => '<http://example.org/resource22> <http://example.org/property> " "^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
      "XML Literals as Datatyped Literals (3)" => '<http://example.org/resource23> <http://example.org/property> "x"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
      "XML Literals as Datatyped Literals (4)" => '<http://example.org/resource23> <http://example.org/property> "\""^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
      "XML Literals as Datatyped Literals (5)" => '<http://example.org/resource24> <http://example.org/property> "<a></a>"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
      "XML Literals as Datatyped Literals (6)" => '<http://example.org/resource25> <http://example.org/property> "a <b></b>"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
      "XML Literals as Datatyped Literals (7)" => '<http://example.org/resource26> <http://example.org/property> "a <b></b> c"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
      "XML Literals as Datatyped Literals (8)" => '<http://example.org/resource26> <http://example.org/property> "a\n<b></b>\nc"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
      "XML Literals as Datatyped Literals (9)" => '<http://example.org/resource27> <http://example.org/property> "chat"^^<http://www.w3.org/2000/01/rdf-schema#XMLLiteral> .',
      
      "Plain literals with languages (1)" => '<http://example.org/resource30> <http://example.org/property> "chat"@fr .',
      "Plain literals with languages (2)" => '<http://example.org/resource31> <http://example.org/property> "chat"@en .',
      
      "Typed Literals" => '<http://example.org/resource32> <http://example.org/property> "abc"^^<http://example.org/datatype1> .',
    }.each_pair do |name, statement|
      specify "test #{name}" do
        graph = parse([statement].flatten.first)
        graph.size.should == 1
        graph.to_ntriples.chomp.should == [statement].flatten.last.gsub(/\s+/, " ").strip
      end
    end

    it "should allow mixed-case language" do
      n3doc = %(:x2 :p "xyz"@EN .)
      statement = parse(n3doc).statements.first
      statement.object.to_ntriples.should == %("xyz"@EN)
    end

    it "should create typed literals" do
      n3doc = "<http://example.org/joe> <http://xmlns.com/foaf/0.1/name> \"Joe\"^^<http://www.w3.org/2001/XMLSchema#string> ."
      statement = parse(n3doc).statements.first
      statement.object.class.should == RDF::Literal
    end

    it "should create BNodes" do
      n3doc = "_:a a _:c ."
      statement = parse(n3doc).statements.first
      statement.subject.class.should == RDF::Node
      statement.object.class.should == RDF::Node
    end

    describe "should create URIs" do
      {
        %(<http://example.org/joe> <http://xmlns.com/foaf/0.1/knows> <http://example.org/jane> .) => %(<http://example.org/joe> <http://xmlns.com/foaf/0.1/knows> <http://example.org/jane> .),
        %(<joe> <knows> <jane> .) => %(<http://a/joe> <http://a/knows> <http://a/jane> .),
        %(:joe :knows :jane .) => %(<http://a/b#joe> <http://a/b#knows> <http://a/b#jane> .),
        %(<#D%C3%BCrst>  a  "URI percent ^encoded as C3, BC".) => %(<http://a/b#D%C3%BCrst> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> "URI percent ^encoded as C3, BC" .),
      }.each_pair do |n3, nt|
        it "for '#{n3}'" do
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end
      end

      {
        %(<#Dürst> :knows :jane.) => '<http://a/b#D\u00FCrst> <http://a/b#knows> <http://a/b#jane> .',
        %(:Dürst :knows :jane.) => '<http://a/b#D\u00FCrst> <http://a/b#knows> <http://a/b#jane> .',
        %(:bob :resumé "Bob's non-normalized resumé".) => '<http://a/b#bob> <http://a/b#resumé> "Bob\'s non-normalized resumé" .',
        %(:alice :resumé "Alice's normalized resumé".) => '<http://a/b#alice> <http://a/b#resumé> "Alice\'s normalized resumé" .',
        }.each_pair do |n3, nt|
          it "for '#{n3}'" do
            begin
              parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
            rescue
              if defined?(::Encoding)
                raise
              else
                pending("Unicode URIs not supported in Ruby 1.8") {  raise } 
              end
            end
          end
        end

      {
        %(<#Dürst>       a  "URI straight in UTF8".) => %(<http://a/b#D\\u00FCrst> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> "URI straight in UTF8" .),
        #%(:a :related :ひらがな .) => %(<http://a/b#a> <http://a/b#related> <http://a/b#\\u3072\\u3089\\u304C\\u306A> .),
      }.each_pair do |n3, nt|
        it "for '#{n3}'" do
          begin
            parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
          rescue
            if defined?(::Encoding)
              raise
            else
              pending("Unicode URIs not supported in Ruby 1.8") {  raise } 
            end
          end
        end
      end
    end
    
    it "should create URIs" do
      n3doc = "<http://example.org/joe> <http://xmlns.com/foaf/0.1/knows> <http://example.org/jane> ."
      statement = parse(n3doc).statements.first
      statement.subject.class.should == RDF::URI
      statement.object.class.should == RDF::URI
    end

    it "should create literals" do
      n3doc = "<http://example.org/joe> <http://xmlns.com/foaf/0.1/name> \"Joe\"."
      statement = parse(n3doc).statements.first
      statement.object.class.should == RDF::Literal
    end
  end
  
  describe "with n3 grammar" do
    describe "syntactic expressions" do
      it "should create typed literals with qname" do
        n3doc = %(
          @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
          @prefix foaf: <http://xmlns.com/foaf/0.1/> .
          @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
          <http://example.org/joe> foaf:name \"Joe\"^^xsd:string .
        )
        statement = parse(n3doc).statements.first
        statement.object.class.should == RDF::Literal
      end

      it "should use <> as a prefix and as a triple node" do
        n3 = %(@prefix : <> . <> a :a.)
        nt = %(
        <http://a/b> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://a/ba> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should use <#> as a prefix and as a triple node" do
        n3 = %(@prefix : <#> . <#> a :a.)
        nt = %(
        <http://a/b#> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://a/b#a> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should generate rdf:type for 'a'" do
        n3 = %(@prefix a: <http://foo/a#> . a:b a <http://www.w3.org/2000/01/rdf-schema#resource> .)
        nt = %(<http://foo/a#b> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#resource> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should generate rdf:type for '@a'" do
        n3 = %(@prefix a: <http://foo/a#> . a:b @a <http://www.w3.org/2000/01/rdf-schema#resource> .)
        nt = %(<http://foo/a#b> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#resource> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should generate inverse predicate for 'is xxx of'" do
        n3 = %("value" is :prop of :b . :b :prop "value"  .)
        nt = %(<http://a/b#b> <http://a/b#prop> "value" .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should generate inverse predicate for '@is xxx @of'" do
        n3 = %("value" @is :prop @of :b . :b :prop "value" .)
        nt = %(<http://a/b#b> <http://a/b#prop> "value" .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should generate inverse predicate for 'is xxx of' with object list" do
        n3 = %("value" is :prop of :b, :c . )
        nt = %(
        <http://a/b#b> <http://a/b#prop> "value" .
        <http://a/b#c> <http://a/b#prop> "value" .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should generate predicate for 'has xxx'" do
        n3 = %(@prefix a: <http://foo/a#> . a:b has :pred a:c .)
        nt = %(<http://foo/a#b> <http://a/b#pred> <http://foo/a#c> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should generate predicate for '@has xxx'" do
        n3 = %(@prefix a: <http://foo/a#> . a:b @has :pred a:c .)
        nt = %(<http://foo/a#b> <http://a/b#pred> <http://foo/a#c> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should create log:implies predicate for '=>'" do
        n3 = %(@prefix a: <http://foo/a#> . _:a => a:something .)
        nt = %(_:a <http://www.w3.org/2000/10/swap/log#implies> <http://foo/a#something> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should create log:implies inverse predicate for '<='" do
        n3 = %(@prefix a: <http://foo/a#> . _:a <= a:something .)
        nt = %(<http://foo/a#something> <http://www.w3.org/2000/10/swap/log#implies> _:a .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should create owl:sameAs predicate for '='" do
        n3 = %(@prefix a: <http://foo/a#> . _:a = a:something .)
        nt = %(_:a <http://www.w3.org/2002/07/owl#sameAs> <http://foo/a#something> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      {
        %(:a :b @true)  => %(<http://a/b#a> <http://a/b#b> "true"^^<http://www.w3.org/2001/XMLSchema#boolean> .),
        %(:a :b @false)  => %(<http://a/b#a> <http://a/b#b> "false"^^<http://www.w3.org/2001/XMLSchema#boolean> .),
        %(:a :b 1)  => %(<http://a/b#a> <http://a/b#b> "1"^^<http://www.w3.org/2001/XMLSchema#integer> .),
        %(:a :b -1)  => %(<http://a/b#a> <http://a/b#b> "-1"^^<http://www.w3.org/2001/XMLSchema#integer> .),
        %(:a :b +1)  => %(<http://a/b#a> <http://a/b#b> "+1"^^<http://www.w3.org/2001/XMLSchema#integer> .),
        %(:a :b 1.0)  => %(<http://a/b#a> <http://a/b#b> "1.0"^^<http://www.w3.org/2001/XMLSchema#decimal> .),
        %(:a :b 1.0e1)  => %(<http://a/b#a> <http://a/b#b> "1.0e1"^^<http://www.w3.org/2001/XMLSchema#double> .),
        %(:a :b 1.0e-1)  => %(<http://a/b#a> <http://a/b#b> "1.0e-1"^^<http://www.w3.org/2001/XMLSchema#double> .),
        %(:a :b 1.0e+1)  => %(<http://a/b#a> <http://a/b#b> "1.0e+1"^^<http://www.w3.org/2001/XMLSchema#double> .),
      }.each_pair do |n3, nt|
        it "should create typed literal for '#{n3}'" do
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end
      end
      
      it "should accept empty localname" do
        n3 = %(: : : .)
        nt = %(<http://a/b#> <http://a/b#> <http://a/b#> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should accept prefix with empty local name" do
        n3 = %(@prefix foo: <http://foo/bar#> . foo: foo: foo: .)
        nt = %(<http://foo/bar#> <http://foo/bar#> <http://foo/bar#> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "substitutes variable for URI with @forAll" do
        n3 = %(@forAll :x . :x :y :z .)
        g = parse(n3, :base_uri => "http://a/b")
        statement = g.statements.first
        statement.subject.should be_a(RDF::Query::Variable)
        statement.predicate.to_s.should == "http://a/b#y"
        statement.object.to_s.should == "http://a/b#z"
      end

      it "substitutes variable for URIs with @forAll" do
        n3 = %(@forAll :x, :y, :z . :x :y :z .)
        g = parse(n3, :base_uri => "http://a/b")
        statement = g.statements.first
        statement.subject.should be_a(RDF::Query::Variable)
        statement.predicate.should be_a(RDF::Query::Variable)
        statement.object.should be_a(RDF::Query::Variable)
        statement.subject.should_not == statement.predicate
        statement.object.should_not == statement.predicate
        statement.predicate.should_not == statement.object
      end

      it "substitutes node for URI with @forEach" do
        n3 = %(@forSome :x . :x :y :z .)
        g = parse(n3, :base_uri => "http://a/b")
        statement = g.statements.first
        statement.subject.should be_a(RDF::Node)
        statement.predicate.to_s.should == "http://a/b#y"
        statement.object.to_s.should == "http://a/b#z"
      end

      it "substitutes node for URIs with @forEach" do
        n3 = %(@forSome :x, :y, :z . :x :y :z .)
        g = parse(n3, :base_uri => "http://a/b")
        statement = g.statements.first
        statement.subject.should be_a(RDF::Node)
        statement.predicate.should be_a(RDF::Node)
        statement.object.should be_a(RDF::Node)
        statement.subject.should_not == statement.predicate
        statement.object.should_not == statement.predicate
        statement.predicate.should_not == statement.object
      end
    end
    
    describe "prefixes" do
      it "should not append # for http://foo/bar" do
        n3 = %(@prefix : <http://foo/bar> . :a : :b .)
        nt = %(
        <http://foo/bara> <http://foo/bar> <http://foo/barb> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end

      it "should not append # for http://foo/bar/" do
        n3 = %(@prefix : <http://foo/bar/> . :a : :b .)
        nt = %(
        <http://foo/bar/a> <http://foo/bar/> <http://foo/bar/b> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end

      it "should not append # for http://foo/bar#" do
        n3 = %(@prefix : <http://foo/bar#> . :a : :b .)
        nt = %(
        <http://foo/bar#a> <http://foo/bar#> <http://foo/bar#b> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end

      it "should set absolute base" do
        n3 = %(@base <http://foo/bar> . <> :a <b> . <#c> :d </e>.)
        nt = %(
        <http://foo/bar> <http://foo/bar#a> <http://foo/b> .
        <http://foo/bar#c> <http://foo/bar#d> <http://foo/e> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should set absolute base (trailing /)" do
        n3 = %(@base <http://foo/bar/> . <> :a <b> . <#c> :d </e>.)
        nt = %(
        <http://foo/bar/> <http://foo/bar/a> <http://foo/bar/b> .
        <http://foo/bar/#c> <http://foo/bar/d> <http://foo/e> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should set absolute base (trailing #)" do
        n3 = %(@base <http://foo/bar#> . <> :a <b> . <#c> :d </e>.)
        nt = %(
        <http://foo/bar#> <http://foo/bar#a> <http://foo/b> .
        <http://foo/bar#c> <http://foo/bar#d> <http://foo/e> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should set relative base" do
        n3 = %(
        @base <http://example.org/products/>.
        <> :a <b>, <#c>.
        @base <prod123/>.
        <> :a <b>, <#c>.
        @base <../>.
        <> :a <d>, <#e>.
        )
        nt = %(
        <http://example.org/products/> <http://example.org/products/a> <http://example.org/products/b> .
        <http://example.org/products/> <http://example.org/products/a> <http://example.org/products/#c> .
        <http://example.org/products/prod123/> <http://example.org/products/prod123/a> <http://example.org/products/prod123/b> .
        <http://example.org/products/prod123/> <http://example.org/products/prod123/a> <http://example.org/products/prod123/#c> .
        <http://example.org/products/> <http://example.org/products/a> <http://example.org/products/d> .
        <http://example.org/products/> <http://example.org/products/a> <http://example.org/products/#e> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "returns defined prefixes" do
        n3 = %(
        @prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
        @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
        @prefix : <http://test/> .
        :foo a rdfs:Class.
        :bar :d :c.
        :a :d :c.
        )
        reader = RDF::N3::Reader.new(n3)
        reader.each {|statement|}
        reader.prefixes.should == {
          :rdf => "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
          :rdfs => "http://www.w3.org/2000/01/rdf-schema#",
          nil => "http://test/"}
      end
    end
    
    describe "keywords" do
      [
        %(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
            parse("@keywords . #{n3}", :base_uri => "http://a/b")
          end.should raise_error(RDF::ReaderError)
        end
      end
      
      [
        %(prefix :<>.),
      ].each do |n3|
        it "parses as local name if keywords set to empty for '#{n3}'" do
          lambda do
            parse("@keywords . #{n3}", :base_uri => "http://a/b")
          end.should_not raise_error(RDF::ReaderError)
        end
      end
      {
        %(:a a :b)  => %(<http://a/b#a> <http://a/b#a> <http://a/b#b> .),
        %(:a :b true) => %(<http://a/b#a> <http://a/b#b> <http://a/b#true> .),
        %(:a :b false) => %(<http://a/b#a> <http://a/b#b> <http://a/b#false> .),
        %(c :a :t)  => %(<http://a/b#c> <http://a/b#a> <http://a/b#t> .),
        %(:c a :t)  => %(<http://a/b#c> <http://a/b#a> <http://a/b#t> .),
        %(:c :a t)  => %(<http://a/b#c> <http://a/b#a> <http://a/b#t> .),
      }.each_pair do |n3, nt|
        it "should use default_ns for '#{n3}'" do
          parse("@keywords . #{n3}", :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end
      end

      {
        %(@keywords true. :a :b true.) => %(<http://a/b#a> <http://a/b#b> "true"^^<http://www.w3.org/2001/XMLSchema#boolean> .),
        %(@keywords false. :a :b false.) => %(<http://a/b#a> <http://a/b#b> "false"^^<http://www.w3.org/2001/XMLSchema#boolean> .),
        %(@keywords a. :a a :b.) => %(<http://a/b#a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://a/b#b> .),
        %(@keywords is. :a is :b @of :c.) => %(<http://a/b#c> <http://a/b#b> <http://a/b#a> .),
        %(@keywords of. :a @is :b of :c.) => %(<http://a/b#c> <http://a/b#b> <http://a/b#a> .),
        %(@keywords has. :a has :b :c.) => %(<http://a/b#a> <http://a/b#b> <http://a/b#c> .),
      }  .each_pair do |n3, nt|
          it "should use keyword for '#{n3}'" do
            parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
          end
        end
      
      it "should raise error if unknown keyword set" do
        n3 = %(@keywords foo.)
        lambda do
          parse(n3, :base_uri => "http://a/b")
        end.should raise_error(RDF::ReaderError, /Undefined keywords used: foo/)
      end
    end
    
    describe "declaration ordering" do
      it "should process _ namespace binding after an initial use as a BNode" do
        n3 = %(
        _:a a :p.
        @prefix _: <http://underscore/> .
        _:a a :p.
        )
        nt = %(
        <http://underscore/a> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://a/b#p> .
        _:a <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://a/b#p> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should allow a prefix to be redefined" do
        n3 = %(
        @prefix a: <http://host/A#>.
        a:b a:p a:v .

        @prefix a: <http://host/Z#>.
        a:b a:p a:v .
        )
        nt = %(
        <http://host/A#b> <http://host/A#p> <http://host/A#v> .
        <http://host/Z#b> <http://host/Z#p> <http://host/Z#v> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end

      it "should process sequential @base declarations (swap base.n3)" do
        n3 = %(
        @base <http://example.com/ontolgies>. <a> :b <foo/bar#baz>.
        @base <path/DFFERENT/>. <a2> :b2 <foo/bar#baz2>.
        @prefix : <#>. <d3> :b3 <e3>.
        )
        nt = %(
        <http://example.com/a> <http://example.com/ontolgies#b> <http://example.com/foo/bar#baz> .
        <http://example.com/path/DFFERENT/a2> <http://example.com/path/DFFERENT/b2> <http://example.com/path/DFFERENT/foo/bar#baz2> .
        <http://example.com/path/DFFERENT/d3> <http://example.com/path/DFFERENT/#b3> <http://example.com/path/DFFERENT/e3> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
    end
    
    describe "BNodes" do
      it "should create BNode for identifier with '_' prefix" do
        n3 = %(@prefix a: <http://foo/a#> . _:a a:p a:v .)
        nt = %(_:bnode0 <http://foo/a#p> <http://foo/a#v> .)
      end
      
      it "should create BNode for [] as subject" do
        n3 = %(@prefix a: <http://foo/a#> . [] a:p a:v .)
        nt = %(_:bnode0 <http://foo/a#p> <http://foo/a#v> .)
        g = parse(n3, :base_uri => "http://a/b")
        normalize_bnodes(g, "bnode0").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug, :compare => :array)
      end
      
      it "should create BNode for [] as predicate" do
        n3 = %(@prefix a: <http://foo/a#> . a:s [] a:o .)
        nt = %(<http://foo/a#s> _:bnode0 <http://foo/a#o> .)
        g = parse(n3, :base_uri => "http://a/b")
        normalize_bnodes(g, "bnode0").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug, :compare => :array, :anon => "bnode")
      end
      
      it "should create BNode for [] as object" do
        n3 = %(@prefix a: <http://foo/a#> . a:s a:p [] .)
        nt = %(<http://foo/a#s> <http://foo/a#p> _:bnode0 .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should create BNode for [] as statement" do
        n3 = %([:a :b] .)
        nt = %(_:bnode0 <http://a/b#a> <http://a/b#b> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should create statements with BNode subjects using [ pref obj]" do
        n3 = %(@prefix a: <http://foo/a#> . [ a:p a:v ] .)
        nt = %(_:bnode0 <http://foo/a#p> <http://foo/a#v> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should create BNode as a single object" do
        n3 = %(@prefix a: <http://foo/a#> . a:b a:oneRef [ a:pp "1" ; a:qq "2" ] .)
        nt = %(
        _:bnode0 <http://foo/a#pp> "1" .
        _:bnode0 <http://foo/a#qq> "2" .
        <http://foo/a#b> <http://foo/a#oneRef> _:bnode0 .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should create a shared BNode" do
        n3 = %(
        @prefix a: <http://foo/a#> .

        a:b1 a:twoRef _:a .
        a:b2 a:twoRef _:a .

        _:a :pred [ a:pp "1" ; a:qq "2" ].
        )
        nt = %(
        <http://foo/a#b1> <http://foo/a#twoRef> _:a .
        <http://foo/a#b2> <http://foo/a#twoRef> _:a .
        _:bnode0 <http://foo/a#pp> "1" .
        _:bnode0 <http://foo/a#qq> "2" .
        _:a :pred _:bnode0 .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should create nested BNodes" do
        n3 = %(
        @prefix a: <http://foo/a#> .

        a:a a:p [ a:p2 [ a:p3 "v1" , "v2" ; a:p4 "v3" ] ; a:p5 "v4" ] .
        )
        nt = %(
        _:bnode0 <http://foo/a#p3> "v1" .
        _:bnode0 <http://foo/a#p3> "v2" .
        _:bnode0 <http://foo/a#p4> "v3" .
        _:bnode1 <http://foo/a#p2> _:bnode0 .
        _:bnode1 <http://foo/a#p5> "v4" .
        <http://foo/a#a> <http://foo/a#p> _:bnode1 .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end

      describe "from paths" do
        it "should create bnode for path x!p" do
          n3 = %(:x2!:y2 :p2 "3" .)
          nt = %(:x2 :y2 _:bnode0 . _:bnode0 :p2 "3" .)
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end
      
        it "should create bnode for path x^p" do
          n3 = %(:x2^:y2 :p2 "3" .)
          nt = %(_:bnode0 :y2 :x2 . _:bnode0 :p2 "3" .)
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end
      
        it "should decode :joe!fam:mother!loc:office!loc:zip as Joe's mother's office's zipcode" do
          n3 = %(
          @prefix fam: <http://foo/fam#> .
          @prefix loc: <http://foo/loc#> .

          :joe!fam:mother!loc:office!loc:zip .
          )
          nt = %(
          :joe <http://foo/fam#mother> _:bnode0 .
          _:bnode0 <http://foo/loc#office> _:bnode1 .
          _:bnode1 <http://foo/loc#zip> _:bnode2 .
          )
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end

        it "should decode :joe!fam:mother^fam:mother Anyone whose mother is Joe's mother." do
          n3 = %(
          @prefix fam: <http://foo/fam#> .
          @prefix loc: <http://foo/loc#> .

          :joe!fam:mother^fam:mother .
          )
          nt = %(
          :joe <http://foo/fam#mother> _:bnode0 .
          _:bnode1 <http://foo/fam#mother> _:bnode0 .
          )
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end

        it "should decode path with property list." do
          n3 = %(
          @prefix a: <http://a/ns#>.
          :a2!a:b2!a:c2 :q1 "3" ; :q2 "4" , "5" .
          )
          nt = %(
          :a2 <http://a/ns#b2> _:bnode0 .
          _:bnode0 <http://a/ns#c2> _:bnode1 .
          _:bnode1 :q1 "3" .
          _:bnode1 :q2 "4" .
          _:bnode1 :q2 "5" .
          )
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end

        it "should decode path as object(1)" do
          n3 = %(:a  :b "lit"^:c.)
          nt = %(
            :a :b _:bnode .
            _:bnode :c "lit" .
          )
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end

        it "should decode path as object(2)" do
          n3 = %(@prefix a: <http://a/ns#>. :r :p :o!a:p1!a:p2 .)
          nt = %(
          :o <http://a/ns#p1> _:bnode0 .
          _:bnode0 <http://a/ns#p2> _:bnode1 .
          :r :p _:bnode1 .
          )
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end
      end
    end
    
    describe "formulae" do
      before(:each) { @repo = RDF::Repository.new }

      it "creates an RDF::Graph instance for formula" do
        n3 = %(:a :b {})
        parse(n3, :graph => @repo, :base_uri => "http://a/b")
        statement = @repo.statements.first
        statement.object.should be_a(RDF::Node)
      end

      it "adds statements with context" do
        
      end

      it "creates variables with ?" do
        
      end
      
      context "contexts" do
        before(:each) do
          n3 = %(
            # Test data in notation3 http://www.w3.org/DesignIssues/Notation3.html
            #    
            @prefix u: <http://www.example.org/utilities#> .
            @prefix : <#> .

            :assumption = { :fred u:knows :john .
                            :john u:knows :mary .} .

            :conclusion = { :fred u:knows :mary . } .

            # The empty context is trivially true.
            # Check that we can input it and output it!

            :trivialTruth = { }.

            # ENDS
          )
          @repo = RDF::Repository.new
          parse(n3, :graph => @repo, :base_uri => "http://a/b")
        end

        it "assumption graph has 2 statements" do
          tt = @repo.first(:subject => RDF::URI.new("http://a/b#assumption"), :predicate => RDF::OWL.sameAs)
          tt.object.should be_a(RDF::Node)
          @repo.query(:context => tt.object).to_a.length.should == 2
        end

        it "conclusion graph has 1 statements" do
          tt = @repo.first(:subject => RDF::URI.new("http://a/b#conclusion"), :predicate => RDF::OWL.sameAs)
          tt.object.should be_a(RDF::Node)
          @repo.query(:context => tt.object).to_a.length.should == 1
        end

        it "trivialTruth equivalent to empty graph" do
          tt = @repo.first(:subject => RDF::URI.new("http://a/b#trivialTruth"), :predicate => RDF::OWL.sameAs)
          tt.object.should be_a(RDF::Node)
          @repo.query(:context => tt.object) do |s|
            puts "statement: #{s}"
          end
        end

      end
    end
    
    describe "object lists" do
      it "should create 2 statements for simple list" do
        n3 = %(:a :b :c, :d)
        nt = %(<http://a/b#a> <http://a/b#b> <http://a/b#c> . <http://a/b#a> <http://a/b#b> <http://a/b#d> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
    end
    
    describe "property lists" do
      it "should parse property list" do
        n3 = %(
        @prefix a: <http://foo/a#> .

        a:b a:p1 "123" ; a:p1 "456" .
        a:b a:p2 a:v1 ; a:p3 a:v2 .
        )
        nt = %(
        <http://foo/a#b> <http://foo/a#p1> "123" .
        <http://foo/a#b> <http://foo/a#p1> "456" .
        <http://foo/a#b> <http://foo/a#p2> <http://foo/a#v1> .
        <http://foo/a#b> <http://foo/a#p3> <http://foo/a#v2> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
    end
    
    describe "lists" do
      it "should parse empty list" do
        n3 = %(@prefix :<http://example.com/>. :empty :set ().)
        nt = %(
        <http://example.com/empty> <http://example.com/set> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should parse list with single element" do
        n3 = %(@prefix :<http://example.com/>. :gregg :wrote ("RdfContext").)
        nt = %(
        _:bnode0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "RdfContext" .
        _:bnode0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
        <http://example.com/gregg> <http://example.com/wrote> _:bnode0 .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should parse list with multiple elements" do
        n3 = %(@prefix :<http://example.com/>. :gregg :name ("Gregg" "Barnum" "Kellogg").)
        nt = %(
        _:bnode0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Gregg" .
        _:bnode0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:bnode1 .
        _:bnode1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Barnum" .
        _:bnode1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:bnode2 .
        _:bnode2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "Kellogg" .
        _:bnode2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
        <http://example.com/gregg> <http://example.com/name> _:bnode0 .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should parse unattached lists" do
        n3 = %(
        @prefix a: <http://foo/a#> .

        ("1" "2" "3") .
        # This is not a statement.
        () .
        )
        nt = %(
        _:bnode0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "1" .
        _:bnode0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:bnode1 .
        _:bnode1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "2" .
        _:bnode1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:bnode2 .
        _:bnode2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "3" .
        _:bnode2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
        )
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
      
      it "should add property to nil list" do
        n3 = %(@prefix a: <http://foo/a#> . () a:prop "nilProp" .)
        nt = %(<http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> <http://foo/a#prop> "nilProp" .)
        parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end

      it "should parse with compound items" do
        n3 = %(
          @prefix a: <http://foo/a#> .
          a:a a:p (
            [ a:p2 "v1" ] 
            <http://resource1>
            <http://resource2>
            ("inner list")
          ) .
          <http://resource1> a:p "value" .
        )
        nt = %(
        <http://foo/a#a> <http://foo/a#p> _:bnode3 .
        <http://resource1> <http://foo/a#p> "value" .
        _:bnode3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> _:bnode5 .
        _:bnode3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:bnode2 .
        _:bnode5 <http://foo/a#p2> "v1" .
        _:bnode2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://resource1> .
        _:bnode2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:bnode1 .
        _:bnode1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> <http://resource2> .
        _:bnode1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> _:bnode0 .
        _:bnode0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> _:bnode4 .
        _:bnode0 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
        _:bnode4 <http://www.w3.org/1999/02/22-rdf-syntax-ns#first> "inner list" .
        _:bnode4 <http://www.w3.org/1999/02/22-rdf-syntax-ns#rest> <http://www.w3.org/1999/02/22-rdf-syntax-ns#nil> .
        )
        g = parse(n3, :base_uri => "http://a/b")
        g.subjects.to_a.length.should == 8
        n = g.first_object(:subject => RDF::URI.new("http://foo/a#a"), :predicate => RDF::URI.new("http://foo/a#p"))
        n.should be_a(RDF::Node)
        seq = RDF::List.new(n, g)
        seq.to_a.length.should == 4
        seq.first.should be_a(RDF::Node)
        seq.second.should == RDF::URI.new("http://resource1")
        seq.third.should == RDF::URI.new("http://resource2")
        seq.fourth.should be_a(RDF::Node)
      end
      
    end
    
     # n3p tests taken from http://inamidst.com/n3p/test/
    describe "with real data tests" do
      dirs = %w(misc lcsh rdflib n3p)
      dirs.each do |dir|
        dir_name = File.join(File.dirname(__FILE__), '..', 'test', 'n3_tests', dir, '*.n3')
        Dir.glob(dir_name).each do |n3|
          it "#{dir} #{n3}" do
            test_file(n3)
          end
        end
      end
    end

    describe "with AggregateGraph tests" do
      describe "with a type" do
        it "should have 3 namespaces" do
          n3 = %(
          @prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
          @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
          @prefix : <http://test/> .
          :foo a rdfs:Class.
          :bar :d :c.
          :a :d :c.
          )
          nt = %(
          <http://test/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Class> .
          <http://test/bar> <http://test/d> <http://test/c> .
          <http://test/a> <http://test/d> <http://test/c> .
          )
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end
      end
    
      describe "with blank clause" do
        it "should have 4 namespaces" do
          n3 = %(
          @prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
          @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
          @prefix : <http://test/> .
          @prefix log: <http://www.w3.org/2000/10/swap/log#>.
          :foo a rdfs:Resource.
          :bar rdfs:isDefinedBy [ a log:Formula ].
          :a :d :e.
          )
          nt = %(
          <http://test/foo> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/01/rdf-schema#Resource> .
          _:g2160128180 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/10/swap/log#Formula> .
          <http://test/bar> <http://www.w3.org/2000/01/rdf-schema#isDefinedBy> _:g2160128180 .
          <http://test/a> <http://test/d> <http://test/e> .
          )
          parse(n3, :base_uri => "http://a/b").should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
        end
      end
    
      describe "with empty subject" do
        before(:each) do
          @graph = parse(%(
          @prefix rdf:  <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
          @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
          @prefix log: <http://www.w3.org/2000/10/swap/log#>.
          @prefix : <http://test/> .
          <> a log:N3Document.
          ), :base_uri => "http://test/")
        end
        
        it "should have 4 namespaces" do
          nt = %(
          <http://test/> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/10/swap/log#N3Document> .
          )
          @graph.should be_equivalent_graph(nt, :about => "http://test/", :trace => @debug)
        end
        
        it "should have default subject" do
          @graph.size.should == 1
          @graph.statements.first.subject.to_s.should == "http://test/"
        end
      end
    end
  end

  describe "canonicalization" do
#    {
#      "<http://foo>"                 =>  "<http://foo>",
#      "<http://foo/a>"               => "<http://foo/a>",
#      "<http://foo#a>"               => "<http://foo#a>",
#
#      "<http://foo/>"                =>  "<http://foo/>",
#      "<http://foo/#a>"              => "<http://foo/#a>",
#
#      "<http://foo#>"                =>  "<http://foo#>",
#      "<http://foo#a>"               => "<http://foo/a>",
#      "<http://foo#/a>"              => "<http://foo/a>",
#      "<http://foo##a>"              => "<http://foo#a>",
#
#      "<http://foo/bar>"             =>  "<http://foo/bar>",
#      "<http://foo/bar>"             => "<http://foo/a>",
#      "<http://foo/bar/a>"           => "<http://foo/a>",
#      "<http://foo/bar#a>"           => "<http://foo/bar#a>",
#
#      "<http://foo/bar/>"            =>  "<http://foo/bar/>",
#      "<http://foo/bar/a>"           => "<http://foo/bar/a>",
#      "<http://foo/bar//a>"          => "<http://foo/a>",
#      "<http://foo/bar/#a>"          => "<http://foo/bar/#a>",
#
#      "<http://foo/bar#>"            =>  "<http://foo/bar#>",
#      "<http://foo/bar#a>"           => "<http://foo/a>",
#      "<http://foo/bar#/a>"          => "<http://foo/a>",
#      "<http://foo/bar##a>"          => "<http://foo/bar#a>",
#
#      "<http://foo/bar##D%C3%BCrst>" => "<http://foo/bar#D%C3%BCrst>",
#      "<http://foo/bar##Dürst>"      => "<http://foo/bar#D\\u00FCrst>",
#    }.each_pair do |input, result|
#      it "returns subject #{result} given #{input}" do
#        n3 = %(#{input} a :b)
#        nt = %(#{result} <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://a/b#b> .)
#        parse(n3, :base_uri => "http://a/b", :canonicalize => true).should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
#      end
#    end

    {
      %("+1"^^xsd:integer) => %("1"^^<http://www.w3.org/2001/XMLSchema#integer>),
      %(+1) => %("1"^^<http://www.w3.org/2001/XMLSchema#integer>),
      %(true) => %("true"^^<http://www.w3.org/2001/XMLSchema#boolean>),
      %("lang"@EN) => %("lang"@en),
    }.each_pair do |input, result|
      it "returns object #{result} given #{input}" do
        n3 = %(@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . :a :b #{input} .)
        nt = %(<http://a/b#a> <http://a/b#b> #{result} .)
        parse(n3, :base_uri => "http://a/b", :canonicalize => true).should be_equivalent_graph(nt, :about => "http://a/b", :trace => @debug)
      end
    end
  end
  
  describe "validation" do
    {
      %(:y :p1 "xyz"^^xsd:integer .) => %r("xyz" is not a valid .*),
      %(:y :p1 "12xyz"^^xsd:integer .) => %r("12xyz" is not a valid .*),
      %(:y :p1 "xy.z"^^xsd:double .) => %r("xy\.z" is not a valid .*),
      %(:y :p1 "+1.0z"^^xsd:double .) => %r("\+1.0z" is not a valid .*),
      %(:a :b .) =>RDF::ReaderError,
      %(:a :b 'single quote' .) => RDF::ReaderError,
      %(:a "literal value" :b .) => RDF::ReaderError,
      %(@keywords prefix. :e prefix :f .) => RDF::ReaderError
    }.each_pair do |n3, error|
      it "should raise '#{error}' for '#{n3}'" do
        lambda {
          parse("@prefix xsd: <http://www.w3.org/2001/XMLSchema#> . #{n3}", :base_uri => "http://a/b", :validate => true)
        }.should raise_error(error)
      end
    end
  end
  
  it "should parse rdf_core testcase" do
    sampledoc = <<-EOF;
<http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/Manifest.rdf#test001> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#PositiveParserTest> .
<http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/Manifest.rdf#test001> <http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#approval> <http://lists.w3.org/Archives/Public/w3c-rdfcore-wg/2002Mar/0235.html> .
<http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/Manifest.rdf#test001> <http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#inputDocument> <http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/test001.rdf> .
<http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/Manifest.rdf#test001> <http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#issue> <http://www.w3.org/2000/03/rdf-tracking/#rdfms-xml-base> .
<http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/Manifest.rdf#test001> <http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#outputDocument> <http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/test001.nt> .
<http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/Manifest.rdf#test001> <http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#status> "APPROVED" .
<http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/test001.nt> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#NT-Document> .
<http://www.w3.org/2000/10/rdf-tests/rdfcore/xmlbase/test001.rdf> <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema#RDF-XML-Document> .
EOF
    graph = parse(sampledoc, :base_uri => "http://www.w3.org/2000/10/rdf-tests/rdfcore/amp-in-url/Manifest.rdf")

    graph.should be_equivalent_graph(sampledoc,
      :about => "http://www.w3.org/2000/10/rdf-tests/rdfcore/amp-in-url/Manifest.rdf",
      :trace => @debug
    )
  end
  
  def parse(input, options = {})
    @debug = []
    graph = options[:graph] || RDF::Graph.new
    RDF::N3::Reader.new(input, {:debug => @debug, :validate => true, :canonicalize => false}.merge(options)).each do |statement|
      graph << statement
    end
    graph
  end

  def test_file(filepath)
    n3_string = File.read(filepath)
    @graph = parse(File.open(filepath), :base_uri => "file:#{filepath}")

    nt_string = File.read(filepath.sub('.n3', '.nt'))
    @graph.should be_equivalent_graph(nt_string,
      :about => "file:#{filepath}",
      :trace => @debug)
  end
end