# coding: utf-8 require 'rdf/spec' share_as :RDF_Literal do XSD = RDF::XSD before :each do raise '+@new+ must be defined in a before(:each) block' unless instance_variable_get('@new') end def self.literal(selector) case selector when :empty then [''] when :plain then ['Hello'] when :empty_lang then ['', {:language => :en}] when :plain_lang then ['Hello', {:language => :en}] when :false then [false] when :true then [true] when :int then [123] when :long then [9223372036854775807] when :double then [3.1415] when :date then [Date.new(2010)] when :datetime then [DateTime.new(2011)] when :time then [Time.parse('01:02:03Z')] when :date then [Date.new(2010)] when :xml_no_ns then ["foo bar baz!", {:datatype => RDF.XMLLiteral}] when :xml_ns then ["foo bar baz!", {:datatype => RDF.XMLLiteral, :namespaces => {"dc" => RDF::DC.to_s}}] when :xml_ns2 then ["foo bar baz!", {:datatype => RDF.XMLLiteral, :namespaces => {"" => RDF::DC.to_s}}] when :xml_ns_lang then ["foo bar baz!", {:datatype => RDF.XMLLiteral, :namespaces => {"dc" => RDF::DC.to_s}, :language => :fr}] when :xml_lang_em then ["foo barbaz", {:datatype => RDF.XMLLiteral, :namespaces => {"dc" => RDF::DC.to_s}, :language => :fr}] when :xml_def_ns then ["foo bar baz!", {:datatype => RDF.XMLLiteral, :namespaces => {"" => RDF::DC.to_s}}] else raise("unexpected literal: :#{selector}") end end def self.literals(*selector) selector.inject([]) do |ary, sel| ary += case sel when :all_plain_no_lang then [:empty, :plain].map {|sel| literal(sel)} when :all_plain_lang then [:empty_lang, :plain_lang].map {|sel| literal(sel)} when :all_native then [:false, :true, :int, :long, :double, :time, :date, :datetime].map {|sel| literal(sel)} when :all_xml then [:xml_no_ns, :xml_ns, :xml_ns2, :xml_ns_lang, :xml_lang_em, :xml_def_ns].map {|sel| literal(sel)} when :all_plain then literals(:all_plain_no_lang, :all_plain_lang) else literals(:all_plain, :all_native, :all_xml) end end end describe "new" do it "instantiates empty string" do lambda { @new.call('') }.should_not raise_error end it "instantiates empty string with language" do lambda { @new.call('', :language => :en) }.should_not raise_error end it "instantiates from native datatype" do lambda { @new.call(123) }.should_not raise_error end describe "c18n" do it "normalizes language to lower-case" do @new.call('Upper', :language => :EN, :canonicalize => true).language.should == :en end it "supports sub-taged language specification" do @new.call('Hi', :language => :"en-us", :canonicalize => true).language.should == :"en-us" end { "true" => "true", "false" => "false", "tRuE" => "true", "FaLsE" => "false", "1" => "true", "0" => "false", }.each_pair do |value, str| it "does not normalize boolean '#{value}' by default" do @new.call(value, :datatype => RDF::XSD.boolean, :canonicalize => false).to_s.should == value end it "normalizes boolean '#{value}' to '#{str}'" do @new.call(value, :datatype => RDF::XSD.boolean, :canonicalize => true).to_s.should == str end it "instantiates '#{value}' as RDF::Literal::Boolean" => true do @new.call(value, :datatype => RDF::XSD.boolean, :canonicalize => true).should be_a(RDF::Literal::Boolean) end it "causes normalized '#{value}' to be == '#{str}'" do @new.call(value, :datatype => RDF::XSD.boolean, :canonicalize => true).should == @new.call(str, :datatype => RDF::XSD.boolean, :canonicalize => false) end end { "01" => "1", "1" => "1", "-1" => "-1", "+1" => "1", }.each_pair do |value, str| it "does not normalize integer '#{value}' by default" do @new.call(value, :datatype => RDF::XSD.integer, :canonicalize => false).to_s.should == value end it "normalizes integer '#{value}' to '#{str}'" do @new.call(value, :datatype => RDF::XSD.integer, :canonicalize => true).to_s.should == str end it "instantiates '#{value}' as RDF::Literal::Integer" => true do @new.call(value, :datatype => RDF::XSD.integer, :canonicalize => true).should be_a(RDF::Literal::Integer) end it "causes normalized '#{value}' to be == '#{str}'" do @new.call(value, :datatype => RDF::XSD.integer, :canonicalize => true).should == @new.call(str, :datatype => RDF::XSD.integer, :canonicalize => false) end end { "1" => "1.0", "-1" => "-1.0", "1." => "1.0", "1.0" => "1.0", "1.00" => "1.0", "+001.00" => "1.0", "123.456" => "123.456", "2.345" => "2.345", "1.000000000" => "1.0", "2.3" => "2.3", "2.234000005" => "2.234000005", "2.2340000000000005" => "2.2340000000000005", "2.23400000000000005" => "2.234", "2.23400000000000000000005" => "2.234", "1.2345678901234567890123457890" => "1.2345678901234567", }.each_pair do |value, str| it "does not normalize decimal '#{value}' by default" do @new.call(value, :datatype => RDF::XSD.decimal, :canonicalize => false).to_s.should == value end it "normalizes decimal '#{value}' to '#{str}'" do @new.call(value, :datatype => RDF::XSD.decimal, :canonicalize => true).to_s.should == str end it "instantiates '#{value}' as RDF::Literal::Decimal" => true do @new.call(value, :datatype => RDF::XSD.decimal, :canonicalize => true).should be_a(RDF::Literal::Decimal) end it "causes normalized '#{value}' to be == '#{str}'" do @new.call(value, :datatype => RDF::XSD.decimal, :canonicalize => true).should == @new.call(str, :datatype => RDF::XSD.decimal, :canonicalize => false) end end { "1" => "1.0E0", "-1" => "-1.0E0", "+01.000" => "1.0E0", #"1." => "1.0E0", "1.0" => "1.0E0", "123.456" => "1.23456E2", "1.0e+1" => "1.0E1", "1.0e-10" => "1.0E-10", "123.456e4" => "1.23456E6", }.each_pair do |value, str| it "does not normalize double '#{value}' by default" do @new.call(value, :datatype => RDF::XSD.double, :canonicalize => false).to_s.should == value end it "normalizes double '#{value}' to '#{str}'" do @new.call(value, :datatype => RDF::XSD.double, :canonicalize => true).to_s.should == str end it "instantiates '#{value}' as RDF::Literal::Double" => true do @new.call(value, :datatype => RDF::XSD.double, :canonicalize => true).should be_a(RDF::Literal::Double) end it "causes normalized '#{value}' to be == '#{str}'" do @new.call(value, :datatype => RDF::XSD.double, :canonicalize => true).should == @new.call(str, :datatype => RDF::XSD.double, :canonicalize => false) end end # DateTime { "2010-01-01T00:00:00Z" => "2010-01-01T00:00:00Z", "2010-01-01T00:00:00.0000Z" => "2010-01-01T00:00:00Z", "2010-01-01T00:00:00" => "2010-01-01T00:00:00Z", "2010-01-01T00:00:00+00:00" => "2010-01-01T00:00:00Z", "2010-01-01T01:00:00+01:00" => "2010-01-01T00:00:00Z", "2009-12-31T23:00:00-01:00" => "2010-01-01T00:00:00Z", "-2010-01-01T00:00:00Z" => "-2010-01-01T00:00:00Z", }.each_pair do |value, str| it "does not normalize dateTime '#{value}' by default" do @new.call(value, :datatype => RDF::XSD.dateTime, :canonicalize => false).to_s.should == value end it "normalizes dateTime '#{value}' to '#{str}'" do @new.call(value, :datatype => RDF::XSD.dateTime, :canonicalize => true).to_s.should == str end it "instantiates '#{value}' as RDF::Literal::DateTime" => true do @new.call(value, :datatype => RDF::XSD.dateTime, :canonicalize => true).should be_a(RDF::Literal::DateTime) end it "causes normalized '#{value}' to be == '#{str}'" do @new.call(value, :datatype => RDF::XSD.dateTime, :canonicalize => true).should == @new.call(str, :datatype => RDF::XSD.dateTime, :canonicalize => false) end end # Date { "2010-01-01Z" => "2010-01-01Z", "2010-01-01" => "2010-01-01Z", "2010-01-01+00:00" => "2010-01-01Z", "2010-01-01+01:00" => "2010-01-01Z", "2009-12-31-01:00" => "2009-12-31Z", "-2010-01-01Z" => "-2010-01-01Z", }.each_pair do |value, str| it "does not normalize date '#{value}' by default" do @new.call(value, :datatype => RDF::XSD.date, :canonicalize => false).to_s.should == value end it "normalizes date '#{value}' to '#{str}'" do @new.call(value, :datatype => RDF::XSD.date, :canonicalize => true).to_s.should == str end it "instantiates '#{value}' as RDF::Literal::Date" => true do @new.call(value, :datatype => RDF::XSD.date, :canonicalize => true).should be_a(RDF::Literal::Date) end it "causes normalized '#{value}' to be == '#{str}'" do @new.call(value, :datatype => RDF::XSD.date, :canonicalize => true).should == @new.call(str, :datatype => RDF::XSD.date, :canonicalize => false) end end # Time { "00:00:00Z" => "00:00:00Z", "00:00:00.0000Z" => "00:00:00Z", "00:00:00+00:00" => "00:00:00Z", "01:00:00+01:00" => "00:00:00Z", "23:00:00-01:00" => "00:00:00Z", }.each_pair do |value, str| it "does not normalize dateTime '#{value}' by default" do @new.call(value, :datatype => RDF::XSD.time, :canonicalize => false).to_s.should == value end it "normalizes time '#{value}' to '#{str}'" do @new.call(value, :datatype => RDF::XSD.time, :canonicalize => true).to_s.should == str end it "instantiates '#{value}' as RDF::Literal::Time" => true do @new.call(value, :datatype => RDF::XSD.time, :canonicalize => true).should be_a(RDF::Literal::Time) end it "causes normalized '#{value}' to be == '#{str}'" do @new.call(value, :datatype => RDF::XSD.time, :canonicalize => true).should == @new.call(str, :datatype => RDF::XSD.time, :canonicalize => false) end end end end describe "#plain?" do literals(:all_plain_no_lang).each do |args| it "returns true for #{args.inspect}" do literal = @new.call(*args) literal.plain?.should be_true end end literals(:all_plain_lang, :all_native, :all_xml).each do |args| it "returns false for #{args.inspect}" do literal = @new.call(*args) literal.plain?.should be_false end end end describe "#language" do literals(:all_plain_no_lang, :all_native, :all_xml).each do |args| it "returns nil for #{args.inspect}" do literal = @new.call(*args) literal.language.should be_nil end end literals(:all_plain_lang).each do |args| it "returns language for #{args.inspect}" do literal = @new.call(*args) literal.language.should == :en end end end describe "#datatype" do literals(:all_plain).each do |args| it "returns nil for #{args.inspect}" do literal = @new.call(*args) literal.datatype.should be_nil end end { 123 => "integer", true => "boolean", false => "boolean", 9223372036854775807 => "integer", 3.1415 => "double", Date.new(2010) => "date", DateTime.new(2011) => "dateTime", Time.parse("01:02:03Z") => "time" }.each_pair do |value, type| it "returns xsd.#{type} for #{value.inspect} #{value.class}" do @new.call(value).datatype.should == XSD[type] end end literals(:all_xml).each do |args| it "returns datatype for #{args.inspect}" do literal = @new.call(*args) literal.datatype.should == RDF.XMLLiteral end end end describe "#typed?" do literals(:all_plain).each do |args| it "returns false for #{args.inspect}" do literal = @new.call(*args) literal.typed?.should be_false end end literals(:all_native, :all_xml).each do |args| it "returns true for #{args.inspect}" do literal = @new.call(*args) literal.typed?.should be_true end end end describe "#==" do literals(:all_plain).each do |args| it "returns true for #{args.inspect}" do literal = @new.call(*args) literal.should == @new.call(*args) end end literals(:all_plain_no_lang).each do |args| it "returns true for value of #{args.inspect}" do literal = @new.call(*args) literal.should == literal.value end end literals(:all_plain_lang).each do |args| it "returns false for value of #{args.inspect}" do literal = @new.call(*args) literal.should_not == literal.value end end literals(:all_native).each do |args| it "returns true for #{args.inspect}" do literal = @new.call(*args) literal.should == @new.call(*args) end it "returns true for value of #{args.inspect}" do literal = @new.call(*args) #literal.should == literal.value # FIXME: fails on xsd:date, xsd:time, and xsd:dateTime end end literals(:all_xml).each do |args| it "returns true for #{args.inspect}" do literal = @new.call(*args) literal.should == @new.call(*args) end it "returns false for value of #{args.inspect}" do literal = @new.call(*args) literal.should_not == literal.value end end end describe "#to_s" do literals(:all_plain).each do |args| it "returns value for #{args.inspect}" do literal = @new.call(*args) literal.to_s.should eql(literal.value) end end { literal(:int) => "123", literal(:true) => "true", literal(:false) => "false", literal(:long) => "9223372036854775807", literal(:double) => "3.1415", literal(:date) => "2010-01-01Z", literal(:datetime) => "2011-01-01T00:00:00Z", literal(:time) => "01:02:03Z" }.each_pair do |args, rep| it "returns #{rep} for #{args.inspect}" do literal = @new.call(*args) literal.to_s.should eql(rep) end end { literal(:xml_no_ns) => %("foo bar baz!"^^), literal(:xml_ns) => %("foo bar baz!"^^), literal(:xml_ns_lang) => %("foo bar baz!"^^), literal(:xml_lang_em) => %("foo barbaz"^^), literal(:xml_def_ns) => %("foo bar baz!"^^), literal(:xml_ns2) => %(fixme), }.each_pair do |args, rep| it "returns n3 rep for #{args.inspect}" do literal = @new.call(*args) pending {literal.to_s.should == rep} end end end describe "#object" do literals(:all_plain).each do |args| it "returns value for #{args.inspect}" do literal = @new.call(*args) literal.object.should eql(literal.value) end end { literal(:int) => 123, literal(:true) => true, literal(:false) => false, literal(:long) => 9223372036854775807, literal(:double) => 3.1415, literal(:date) => Date.new(2010), literal(:datetime) => DateTime.new(2011), literal(:time) => Time.parse('01:02:03Z') }.each_pair do |args, value| it "returns object for #{args.inspect}" do literal = @new.call(*args) literal.object.should eql(value) end end end describe "#anonymous?" do it "returns false" do @new.call("").anonymous?.should be_false end end describe "#valid?" do # Boolean { "true" => "true", "false" => "false", "tRuE" => "true", "FaLsE" => "false", "1" => "true", "0" => "false", }.each_pair do |value, str| it "validates boolean '#{value}'" do @new.call(value, :datatype => RDF::XSD.boolean).valid?.should be_true @new.call(value, :datatype => RDF::XSD.boolean).invalid?.should be_false end end # Integer { "01" => "1", "1" => "1", "-1" => "-1", "+1" => "1", }.each_pair do |value, str| it "validates integer '#{value}'" do @new.call(value, :datatype => RDF::XSD.integer).valid?.should be_true @new.call(value, :datatype => RDF::XSD.integer).invalid?.should be_false end end # Decimal { "1" => "1.0", "-1" => "-1.0", "1." => "1.0", "1.0" => "1.0", "1.00" => "1.0", "+001.00" => "1.0", "123.456" => "123.456", "2.345" => "2.345", "1.000000000" => "1.0", "2.3" => "2.3", "2.234000005" => "2.234000005", "2.2340000000000005" => "2.2340000000000005", "2.23400000000000005" => "2.234", "2.23400000000000000000005" => "2.234", "1.2345678901234567890123457890" => "1.2345678901234567", }.each_pair do |value, str| it "validates decimal '#{value}'" do @new.call(value, :datatype => RDF::XSD.decimal).valid?.should be_true @new.call(value, :datatype => RDF::XSD.decimal).invalid?.should be_false end end # Double { "1" => "1.0E0", "-1" => "-1.0E0", "+01.000" => "1.0E0", #"1." => "1.0E0", "1.0" => "1.0E0", "123.456" => "1.23456E2", "1.0e+1" => "1.0E1", "1.0e-10" => "1.0E-10", "123.456e4" => "1.23456E6", }.each_pair do |value, str| it "validates double '#{value}'" do @new.call(value, :datatype => RDF::XSD.double).valid?.should be_true @new.call(value, :datatype => RDF::XSD.double).invalid?.should be_false end end # DateTime { "2010-01-01T00:00:00Z" => "2010-01-01T00:00:00Z", "2010-01-01T00:00:00.0000Z" => "2010-01-01T00:00:00Z", "2010-01-01T00:00:00" => "2010-01-01T00:00:00Z", "2010-01-01T00:00:00+00:00" => "2010-01-01T00:00:00Z", "2010-01-01T01:00:00+01:00" => "2010-01-01T01:00:00+01:00", "2009-12-31T23:00:00-01:00" => "2009-12-31T23:00:00-01:00", "-2010-01-01T00:00:00Z" => "-2010-01-01T00:00:00Z", }.each_pair do |value, str| it "validates dateTime '#{value}'" do @new.call(value, :datatype => RDF::XSD.dateTime).valid?.should be_true @new.call(value, :datatype => RDF::XSD.dateTime).invalid?.should be_false end end # Date { "2010-01-01Z" => "2010-01-01Z", "2010-01-01" => "2010-01-01Z", "2010-01-01+00:00" => "2010-01-01Z", "2010-01-01+01:00" => "2010-01-01Z", "2009-12-31-01:00" => "2009-12-31Z", "-2010-01-01Z" => "-2010-01-01Z", }.each_pair do |value, str| it "validates date '#{value}'" do @new.call(value, :datatype => RDF::XSD.date).valid?.should be_true @new.call(value, :datatype => RDF::XSD.date).invalid?.should be_false end end # Time { "00:00:00Z" => "00:00:00Z", "00:00:00.0000Z" => "00:00:00Z", "00:00:00" => "00:00:00Z", "00:00:00+00:00" => "00:00:00Z", "01:00:00+01:00" => "00:00:00Z", "23:00:00-01:00" => "00:00:00Z", }.each_pair do |value, str| it "validates time '#{value}'" do @new.call(value, :datatype => RDF::XSD.time).valid?.should be_true @new.call(value, :datatype => RDF::XSD.time).invalid?.should be_false end end end describe "#invalid?" do { "foo" => RDF::XSD.boolean, "xyz" => RDF::XSD.integer, "12xyz" => RDF::XSD.integer, "12.xyz" => RDF::XSD.decimal, "xy.z" => RDF::XSD.double, "+1.0z" => RDF::XSD.double, "+2010-01-01T00:00:00Z" => RDF::XSD.dateTime, "2010-01-01T00:00:00FOO" => RDF::XSD.dateTime, "02010-01-01T00:00:00" => RDF::XSD.dateTime, "2010-01-01" => RDF::XSD.dateTime, "2010-1-1T00:00:00" => RDF::XSD.dateTime, "0000-01-01T00:00:00" => RDF::XSD.dateTime, "+2010-01-01Z" => RDF::XSD.date, "2010-01-01TFOO" => RDF::XSD.date, "02010-01-01" => RDF::XSD.date, "2010-1-1" => RDF::XSD.date, "0000-01-01" => RDF::XSD.date, "+00:00:00Z" => RDF::XSD.time, "-00:00:00Z" => RDF::XSD.time, }.each_pair do |value, datatype| it "does not validate for '#{value}'" do @new.call(value, :datatype => datatype).invalid?.should be_true @new.call(value, :datatype => datatype).valid?.should be_false end end end end