From 32e62b000a7ebea0dde4f0be5f7f256f3bdd3a51 Mon Sep 17 00:00:00 2001 From: Michael Date: Sun, 23 Nov 2008 05:34:27 -0800 Subject: [PATCH] refactored redland tests for better coverage removed activerdf-redland/test/test_person_data.nt. conflicted with test/test_person_data.nt activerdf-redland/lib/activerdf_redland/redland.rb: improved mysql/postgres handling added support for sqlite added support for literal datatyping close now flushes model and disables adapter from further use added count? support query now yields results if block is provided lib/active_rdf/objectmanager/literal.rb: Literal moved into RDFS module => RDFS::Literal created class constants for xsd types changed method name to_ntriple to to_literal_s (this is used by query2SPARQL, not just for ntriples) LocalizedString#to_literal_s now $activerdf_without_xsdtype aware Time objects use xmlschema rather than default string format lib/active_rdf/federation/federation_manager.rb count for federated queries fixed --- .../lib/activerdf_rdflite/rdflite.rb | 4 +- activerdf-rdflite/test/test_bnode_data.nt | 5 - .../lib/activerdf_redland/redland.rb | 507 +++++++++--------- activerdf-redland/test/test_person_data.nt | 42 -- .../test/test_redland_adapter.rb | 271 +++------- .../federation/federation_manager.rb | 5 +- lib/active_rdf/objectmanager/literal.rb | 125 +++-- lib/active_rdf/objectmanager/resource.rb | 4 +- lib/active_rdf/queryengine/ntriples_parser.rb | 4 +- lib/active_rdf/queryengine/query.rb | 2 +- lib/active_rdf/queryengine/query2sparql.rb | 2 +- test/objectmanager/test_literal.rb | 37 +- test/test_activerdf_adapter.rb | 146 +++++ test/test_bnode_capable_adapter.rb | 31 ++ test/test_bnode_data.nt | 8 + {activerdf-rdflite/test => test}/test_data.nt | 3 - .../test => test}/test_escaped_data.nt | 0 test/test_persistent_adapter.rb | 32 ++ test/test_read_only_adapter.rb | 15 + test/test_writable_adapter.rb | 109 ++++ 20 files changed, 775 insertions(+), 577 deletions(-) delete mode 100644 activerdf-rdflite/test/test_bnode_data.nt delete mode 100644 activerdf-redland/test/test_person_data.nt create mode 100755 test/test_activerdf_adapter.rb create mode 100644 test/test_bnode_capable_adapter.rb create mode 100644 test/test_bnode_data.nt rename {activerdf-rdflite/test => test}/test_data.nt (95%) rename {activerdf-rdflite/test => test}/test_escaped_data.nt (100%) create mode 100644 test/test_persistent_adapter.rb create mode 100755 test/test_read_only_adapter.rb create mode 100755 test/test_writable_adapter.rb diff --git a/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb b/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb index 14b06588..775ece77 100644 --- a/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb +++ b/activerdf-rdflite/lib/activerdf_rdflite/rdflite.rb @@ -538,7 +538,7 @@ def internalise(r) if r.nil? or r.is_a? Symbol nil else - r.to_ntriple + r.to_literal_s end end @@ -547,7 +547,7 @@ def serialise(r) if r.nil? nil else - r.to_ntriple + r.to_literal_s end end diff --git a/activerdf-rdflite/test/test_bnode_data.nt b/activerdf-rdflite/test/test_bnode_data.nt deleted file mode 100644 index 90f54a19..00000000 --- a/activerdf-rdflite/test/test_bnode_data.nt +++ /dev/null @@ -1,5 +0,0 @@ -_:1 . -_:1 "27" . -_:1 "Eyal Oren" . -_:2 "27" . -_:2 "blue" . diff --git a/activerdf-redland/lib/activerdf_redland/redland.rb b/activerdf-redland/lib/activerdf_redland/redland.rb index 399eadeb..f6a423ff 100644 --- a/activerdf-redland/lib/activerdf_redland/redland.rb +++ b/activerdf-redland/lib/activerdf_redland/redland.rb @@ -9,273 +9,294 @@ # Adapter to Redland database # uses SPARQL for querying class RedlandAdapter < ActiveRdfAdapter - $activerdflog.info "loading Redland adapter" - ConnectionPool.register_adapter(:redland,self) - - # instantiate connection to Redland database - def initialize(params = {}) + $activerdflog.info "RedlandAdapter: loading Redland adapter" + ConnectionPool.register_adapter(:redland,self) + + # instantiate connection to Redland database + def initialize(params = {}) super() + # defaults + @reads = true + @writes = truefalse(params[:write], true) + @new = truefalse(params[:new], false) + @contexts = truefalse(params[:contexts], true) + location = params[:location] + name = params[:name] || '' + options = {} + options[:write],options[:new],options[:contexts] = [@writes,@new,@contexts].collect{|bool| bool ? 'yes' : 'no'} - if params[:location] and params[:location] == :postgresql - initialize_postgresql(params) - return - end - - if params[:location] and params[:location] != :memory - # setup file defaults for redland database - type = 'bdb' - want_new = false # create new or use existing store - write = true - contexts = true - - if params[:want_new] == true - want_new = true - end - if params[:write] == false - write = false - end - if params[:contexts] == false - contexts = false - end - - if params[:location].include?('/') - path, file = File.split(params[:location]) + # supported storage modules: mysql, postgresql, sqlite, hashes(as 'memory' or 'bdb') + # unsupported storage modules: uri, file, memory, tstore, trees + # see http://librdf.org/docs/api/redland-storage-modules.html + case location + when 'postgresql','mysql','sqlite' + store_type = location + if location == 'postgresql' or location == 'mysql' + [:host, :port, :database, :user, :password].each{|k| options[k] = params[k] if params[k]} + options[:host] ||= 'localhost' + end + when 'memory',nil + # use storage module hashes with hash-type 'memory' instead of non-indexing storage module memory + store_type = 'hashes' + options[:hash_type] = 'memory'; + options.delete(:new) # not used with this hash-type else - path = '.' - file = params[:location] - end - else - # fall back to in-memory redland - type = 'memory'; path = ''; file = '.'; want_new = false; write = true; contexts = true - end - - - begin - @store = Redland::HashStore.new(type, file, path, want_new, write, contexts) - @model = Redland::Model.new @store - @reads = true - @writes = true - $activerdflog.info "initialised Redland adapter to #{@model.inspect}" - - rescue Redland::RedlandError => e - raise ActiveRdfError, "could not initialise Redland database: #{e.message}" - end - end - - # instantiate connection to Redland database in Postgres - def initialize_postgresql(params = {}) - # author: Richard Dale - type = 'postgresql' - name = params[:name] - - options = [] - options << "new='#{params[:new]}'" if params[:new] - options << "bulk='#{params[:bulk]}'" if params[:bulk] - options << "merge='#{params[:merge]}'" if params[:merge] - options << "host='#{params[:host]}'" if params[:host] - options << "database='#{params[:database]}'" if params[:database] - options << "user='#{params[:user]}'" if params[:user] - options << "password='#{params[:password]}'" if params[:password] - options << "port='#{params[:port]}'" if params[:port] - - - $activerdflog.info "RedlandAdapter: initializing with type: #{type} name: #{name} options: #{options.join(',')}" - - begin - @store = Redland::TripleStore.new(type, name, options.join(',')) - @model = Redland::Model.new @store - @reads = true - @writes = true - rescue Redland::RedlandError => e - raise ActiveRdfError, "could not initialise Redland database: #{e.message}" - end - end - - # load a file from the given location with the given syntax into the model. - # use Redland syntax strings, e.g. "ntriples" or "rdfxml", defaults to "ntriples" - def load(location, syntax="ntriples") + # use storage module hashes with hash-type 'bdb' instead of non-indexing storage module file + store_type = 'hashes' + options[:hash_type] = 'bdb' + + if location.include?('/') + options[:dir], name = File.split(location) + else + options[:dir] = '.' + name = location + end + end + + hash_type = options.delete(:hash_type) + options = options.collect{|k,v| "#{k}='#{v}'"}.join(',') + options << "hash-type='#{hash_type}'" if hash_type # convert option key from hash_type to hash-type. :hash-type is an invalid symbol + @model = Redland::Model.new Redland::TripleStore.new(store_type, name, options) + @options = options + $activerdflog.info "RedlandAdapter: initialized adapter with type=\'#{store_type}\', name=\'#{name}\' options: #{options} => #{@model.inspect}" + + rescue Redland::RedlandError => e + raise ActiveRdfError, "RedlandAdapter: could not initialise Redland database: #{e.message}\nstore_type=\'#{store_type}\', name=\'#{name}\' options: #{options}" + end + + # load a file from the given location with the given syntax into the model. + # use Redland syntax strings, e.g. "ntriples" or "rdfxml", defaults to "ntriples" + def load(location, syntax="ntriples") + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled parser = Redland::Parser.new(syntax, "", nil) if location =~ /^http/ parser.parse_into_model(@model, location) else parser.parse_into_model(@model, "file:#{location}") end - end + save if ConnectionPool.auto_flush? + rescue Redland::RedlandError => e + $activerdflog.warn "RedlandAdapter: loading #{location} failed in Redland library: #{e}" + return false + end - # yields query results (as many as requested in select clauses) executed on data source - def query(query) - qs = Query2SPARQL.translate(query) + # yields query results (as many as requested in select clauses) executed on data source + def query(query, &block) + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled + qs = Query2SPARQL.translate(query) $activerdflog.debug "RedlandAdapter: executing SPARQL query #{qs}" - - clauses = query.select_clauses.size - redland_query = Redland::Query.new(qs, 'sparql') - query_results = @model.query_execute(redland_query) - - # return Redland's answer without parsing if ASK query - return [[query_results.get_boolean?]] if query.ask? - - $activerdflog.debug "RedlandAdapter: found #{query_results.size} query results" - - # verify if the query has failed - if query_results.nil? - $activerdflog.debug "RedlandAdapter: query has failed with nil result" - return false - end - if not query_results.is_bindings? - $activerdflog.debug "RedlandAdapter: query has failed without bindings" - return false - end - - - # convert the result to array - #TODO: if block is given we should not parse all results into array first - results = query_result_to_array(query_results) - - if block_given? - results.each do |clauses| - yield(*clauses) - end - else - results - end - end - - # executes query and returns results as SPARQL JSON or XML results - # requires svn version of redland-ruby bindings - # * query: ActiveRDF Query object - # * result_format: :json or :xml - def get_query_results(query, result_format=nil) - get_sparql_query_results(Query2SPARQL.translate(query), result_format) - end - - # executes sparql query and returns results as SPARQL JSON or XML results - # * query: sparql query string - # * result_format: :json or :xml - def get_sparql_query_results(qs, result_format=nil) - # author: Eric Hanson - - # set uri for result formatting - result_uri = - case result_format - when :json + + redland_query = Redland::Query.new(qs, 'sparql') + query_results = @model.query_execute(redland_query) + + # return Redland's answer without parsing if ASK query + return [[query_results.get_boolean?]] if query.ask? + + # $activerdflog.debug "RedlandAdapter: found #{query_results.size} query results" + + # verify if the query has failed + if query_results.nil? + $activerdflog.debug "RedlandAdapter: query has failed with nil result" + return false + end + if not query_results.is_bindings? + $activerdflog.debug "RedlandAdapter: query has failed without bindings" + return false + end + + if query.count? + while not query_results.finished? + query_results.next + end + [[query_results.count]] + else + # convert the results to array + query_result_to_array(query_results, &block) + end + end + + # executes query and returns results as SPARQL JSON or XML results + # requires svn version of redland-ruby bindings + # * query: ActiveRDF Query object + # * result_format: :json or :xml + def get_query_results(query, result_format=nil) + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled + get_sparql_query_results(Query2SPARQL.translate(query), result_format) + end + + # executes sparql query and returns results as SPARQL JSON or XML results + # * query: sparql query string + # * result_format: :json or :xml + def get_sparql_query_results(qs, result_format=nil) + # author: Eric Hanson + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled + + # set uri for result formatting + result_uri = + case result_format + when :json Redland::Uri.new('http://www.w3.org/2001/sw/DataAccess/json-sparql/') when :xml Redland::Uri.new('http://www.w3.org/TR/2004/WD-rdf-sparql-XMLres-20041221/') - end + end - # query redland + # query redland redland_query = Redland::Query.new(qs, 'sparql') query_results = @model.query_execute(redland_query) - # get string representation in requested result_format (json or xml) - query_results.to_string() + # get string representation in requested result_format (json or xml) + query_results.to_string(result_uri) + end + + # add triple to datamodel + def add(s,p,o,c=nil) + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled + $activerdflog.warn "RedlandAdapter: adapter does not support contexts" if (!@contexts and !c.nil?) + $activerdflog.debug "RedlandAdapter: adding triple #{s} #{p} #{o} #{c}" + + # verify input + if s.nil? || p.nil? || o.nil? + $activerdflog.debug "RedlandAdapter: cannot add triple with empty element, exiting" + return false + end + + unless s.respond_to?(:uri) && p.respond_to?(:uri) + $activerdflog.debug "RedlandAdapter: cannot add triple where s/p are not resources, exiting" + return false + end + quad = [s,p,o,c].collect{|e| to_redland(e)} + + @model.add(*quad) + save if ConnectionPool.auto_flush? + rescue Redland::RedlandError => e + $activerdflog.warn "RedlandAdapter: adding triple(#{quad}) failed in Redland library: #{e}" + return false + end + + # deletes triple(s,p,o) from datastore + # nil parameters match anything: delete(nil,nil,nil) will delete all triples + def delete(s,p,o,c=nil) + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled + quad = [s,p,o,c].collect{|e| to_redland(e)} + if quad.all?{|t| t.nil?} + clear + elsif quad[0..2].any?{|t| t.nil?} + @model.find(*quad).each{|stmt| @model.delete_statement(stmt,c)} + else + @model.delete(*quad) + end + save if ConnectionPool.auto_flush? + rescue Redland::RedlandError => e + $activerdflog.warn "RedlandAdapter: deleting triple failed in Redland library: #{e}" + return false + end + + # saves updates to the model into the redland file location + def save + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled + Redland::librdf_model_sync(@model.model).nil? + end + alias flush save + + # returns all triples in the datastore + def dump + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled + @model.to_string('ntriples') end - - # add triple to datamodel - def add(s, p, o) - $activerdflog.debug "adding triple #{s} #{p} #{o}" - - # verify input - if s.nil? || p.nil? || o.nil? - $activerdflog.debug "cannot add triple with empty subject, exiting" - return false - end - - unless s.respond_to?(:uri) && p.respond_to?(:uri) - $activerdflog.debug "cannot add triple where s/p are not resources, exiting" - return false - end - - begin - @model.add(wrap(s), wrap(p), wrap(o)) - save if ConnectionPool.auto_flush? - rescue Redland::RedlandError => e - $activerdflog.warn "RedlandAdapter: adding triple failed in Redland library: #{e}" - return false - end - end - - # deletes triple(s,p,o) from datastore - # nil parameters match anything: delete(nil,nil,nil) will delete all triples - def delete(s,p,o) - s = wrap(s) unless s.nil? - p = wrap(p) unless p.nil? - o = wrap(o) unless o.nil? - @model.delete(s,p,o) - end - - # saves updates to the model into the redland file location - def save - Redland::librdf_model_sync(@model.model).nil? - end - alias flush save - - # returns all triples in the datastore - def dump - Redland.librdf_model_to_string(@model.model, nil, 'ntriples') - end - - # returns size of datasources as number of triples - # warning: expensive method as it iterates through all statements - def size - # we cannot use @model.size, because redland does not allow counting of - # file-based models (@model.size raises an error if used on a file) - # instead, we just dump all triples, and count them + + # returns size of datasources as number of triples + # warning: expensive method as it iterates through all statements + def size + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled + # we cannot use @model.size, because redland does not allow counting of + # file-based models (@model.size raises an error if used on a file) + # instead, we just dump all triples, and count them @model.triples.size - end + end # clear all real triples of adapter def clear - @model.find(nil, nil, nil) {|s,p,o| @model.delete(s,p,o)} + raise ActiveRdfError, "RedlandAdapter: adapter is closed" unless @enabled + @model.triples.each{|stmt| @model.delete_statement(stmt)} end - - # close adapter and remove it from the ConnectionPool - def close + + # close adapter and remove it from the ConnectionPool + def close ConnectionPool.remove_data_source(self) + flush # sync model with datastore + @model = nil # remove reference to model for removal by GC + @enabled = false + end + + private + ################ helper methods #################### + def truefalse(val, default) + raise ArgumentError, "truefalse: default must be true or false" unless default == true || default == false + case val + when true,/^yes|y$/i then true + when false,/^no|n$/i then false + else default + end + end + + def query_result_to_array(query_results, &block) + results = [] + number_bindings = query_results.binding_names.size + + # redland results are set that needs to be iterated + while not query_results.finished? + # we collect the bindings in each row and add them to results + row = (0..number_bindings-1).collect do |i| + # node is the query result for one binding + node = query_results.binding_value(i) + + # we determine the node type + if node.literal? + dt_uri_ref = Redland.librdf_node_get_literal_value_datatype_uri(node.node) + type = RDFS::Resource.new(Redland::Uri.new(dt_uri_ref).to_s) if dt_uri_ref + value = Redland.librdf_node_get_literal_value(node.node) + RDFS::Literal.typed(value,type) + elsif node.blank? + # blank nodes are not currently supported + nil + else + # other nodes are rdfs:resources + RDFS::Resource.new(node.uri.to_s) + end + end + if block_given? + yield row + else + results << row + end + # iterate through result set + query_results.next + end + results unless block_given? + end + + def to_redland(obj) + case obj + when RDFS::Resource + Redland::Uri.new(obj.uri) + when RDFS::Literal + str = obj.kind_of?(Time) ? obj.xmlschema : obj.to_s + if not $activerdf_without_xsdtype + if obj.kind_of?(RDFS::LocalizedString) + Redland::Literal.new(str, obj.lang) + else + Redland::Literal.new(str,nil,Redland::Uri.new(obj.xsd_type.uri)) + end + else + Redland::Literal.new(str) + end + when Class + raise ActiveRdfError, "RedlandAdapter: class must inherit from RDFS::Resource" unless obj.ancestors.include?(RDFS::Resource) + Redland::Uri.new(obj.class_uri.to_s) + when Symbol, nil + nil + else + Redland::Literal.new(obj.to_s) + end end - - private - ################ helper methods #################### - #TODO: if block is given we should not parse all results into array first - def query_result_to_array(query_results) - results = [] - number_bindings = query_results.binding_names.size - - # walk through query results, and construct results array - # by looking up each result (if it is a resource) and adding it to the result-array - # for literals we only add the values - - # redland results are set that needs to be iterated - while not query_results.finished? - # we collect the bindings in each row and add them to results - results << (0..number_bindings-1).collect do |i| - # node is the query result for one binding - node = query_results.binding_value(i) - - # we determine the node type - if node.literal? - # for literal nodes we just return the value - Redland.librdf_node_get_literal_value(node.node) - elsif node.blank? - # blank nodes we ignore - nil - else - # other nodes are rdfs:resources - RDFS::Resource.new(node.uri.to_s) - end - end - # iterate through result set - query_results.next - end - results - end - - def wrap node - case node - when RDFS::Resource - Redland::Uri.new(node.uri) - else - Redland::Literal.new(node.to_s) - end - end end diff --git a/activerdf-redland/test/test_person_data.nt b/activerdf-redland/test/test_person_data.nt deleted file mode 100644 index e5a8ab34..00000000 --- a/activerdf-redland/test/test_person_data.nt +++ /dev/null @@ -1,42 +0,0 @@ -@prefix rdf: . -@prefix rdfs: . -@prefix ar: . - -ar:Person a rdfs:Class . -# each class is subclass of resource -ar:Person rdfs:subClassOf rdfs:Resource . - -ar:eyal a ar:Person . -ar:eyal ar:age "27". -ar:eyal ar:eye "blue". -# inferred statements about eyal - -# all properties of Person are also properties of Resource -ar:age rdfs:domain rdfs:Resource . -ar:eye rdfs:domain rdfs:Resource . -ar:car rdfs:domain rdfs:Resource . - -ar:age a rdf:Property . -ar:eye a rdf:Property . -ar:car a rdf:Property . -ar:age rdfs:domain ar:Person . -ar:age rdfs:range rdf:Literal . -ar:eye rdfs:domain ar:Person . -ar:eye rdfs:range rdf:Literal . -ar:car rdfs:domain ar:Person . -ar:car rdfs:range rdf:Literal . - -# everything is a resource -ar:Person a rdfs:Resource . -ar:eye a rdfs:Resource . -ar:eyal a rdfs:Resource . -ar:age a rdfs:Resource . -ar:car a rdfs:Resource . - -# standard stuff -rdfs:Class a rdfs:Class . -rdfs:Class a rdfs:Resource . -rdf:Property a rdfs:Class . -rdf:Property a rdfs:Resource . -rdf:type rdfs:domain rdfs:Resource . -rdf:type rdfs:range rdfs:Class . diff --git a/activerdf-redland/test/test_redland_adapter.rb b/activerdf-redland/test/test_redland_adapter.rb index 967544de..dc5a4099 100644 --- a/activerdf-redland/test/test_redland_adapter.rb +++ b/activerdf-redland/test/test_redland_adapter.rb @@ -3,223 +3,82 @@ # License:: LGPL require 'test/unit' -require 'rubygems' -require 'active_rdf' -require 'federation/federation_manager' -require 'queryengine/query' - -class TestRedlandAdapter < Test::Unit::TestCase - def setup - ConnectionPool.clear - end - - def teardown - end - - def test_registration - adapter = ConnectionPool.add_data_source(:type => :redland) - assert_instance_of RedlandAdapter, adapter - end - - #def test_redland_postgres - # adapter = ConnectionPool.add(:type => :redland, :name => 'db1', :location => :postgresql, - # :host => 'localhost', :database => 'redland_test', - # :user => 'eyal', :password => 'lief1234') - #end - - def test_redland_connections - adapter = RedlandAdapter.new({}) - assert_instance_of RedlandAdapter, adapter - end - - def test_simple_query - adapter = ConnectionPool.add_data_source(:type => :redland) - - eyal = RDFS::Resource.new 'eyaloren.org' - age = RDFS::Resource.new 'foaf:age' - test = RDFS::Resource.new 'test' - - adapter.add(eyal, age, test) - result = Query.new.distinct(:s).where(:s, :p, :o).execute(:flatten) - - assert_instance_of RDFS::Resource, result - assert_equal 'eyaloren.org', result.uri - end - - def test_federated_query - adapter1 = ConnectionPool.add_data_source(:type => :redland) - adapter2 = ConnectionPool.add_data_source(:type => :redland, :fake_symbol_to_get_unique_adapter => true) - - eyal = RDFS::Resource.new 'eyaloren.org' - age = RDFS::Resource.new 'foaf:age' - test = RDFS::Resource.new 'test' - test2 = RDFS::Resource.new 'test2' - - adapter1.add(eyal, age, test) - adapter2.add(eyal, age, test2) - - # assert only one distinct subject is found (same one in both adapters) - assert_equal 1, Query.new.distinct(:s).where(:s, :p, :o).execute.size - - # assert two distinct objects are found - results = Query.new.distinct(:o).where(:s, :p, :o).execute - assert_equal 2, results.size - - results.all? {|result| assert result.instance_of?(RDFS::Resource) } - end - - def test_query_with_block - adapter = ConnectionPool.add_data_source(:type => :redland) - - eyal = RDFS::Resource.new 'eyaloren.org' - age = RDFS::Resource.new 'foaf:age' - test = RDFS::Resource.new 'test' - - adapter.add(eyal, age, test) - Query.new.select(:s,:p).where(:s,:p,:o).execute do |s,p| - assert_equal 'eyaloren.org', s.uri - assert_equal 'foaf:age', p.uri - end - end +require 'tmpdir' +require 'fileutils' +common_test_dir = File.join(File.dirname(File.expand_path(__FILE__)),'..','..','test') +require "#{common_test_dir}/test_writable_adapter" +require "#{common_test_dir}/test_persistent_adapter" + +module TestRedlandAdapter + include TestWritableAdapter - def test_load_from_file - adapter = ConnectionPool.add_data_source :type => :redland - # adapter.load("/tmp/test_person_data.nt", "turtle") - # adapter.load("/home/metaman/workspaces/deri-workspace/activerdf/test/test_person_data.nt", "turtle") - adapter.load("#{File.dirname(__FILE__)}/test_person_data.nt", "turtle") - assert_equal 28, adapter.size - end + def test_sparql_query + @adapter.add(@@eyal, @@age, @@ageval) - def test_remote_load - adapter = ConnectionPool.add_data_source :type => :redland - adapter.load('http://www.eyaloren.org/foaf.rdf', 'rdfxml') - assert_equal 9, adapter.size - end + @adapter.flush - def test_load_and_clear - adapter = ConnectionPool.add_data_source :type => :redland - adapter.load('http://www.eyaloren.org/foaf.rdf', 'rdfxml') - assert_equal 9, adapter.size - adapter.clear - assert_equal 0, adapter.size + query = Query.new.distinct(:s).where(:s,:p,:o) + sparql_query = @adapter.get_query_results(query) + assert sparql_query.include?(TEST::eyal.uri) end +end - def test_close - adapter = ConnectionPool.add_data_source :type => :redland, :location => '/tmp/test.db' - adapter.load('http://www.eyaloren.org/foaf.rdf', 'rdfxml') - assert_equal 9, adapter.size - adapter.close - assert_equal 0, ConnectionPool.adapters.size - end - - def test_person_data - ConnectionPool.add_data_source :type => :redland, :location => 'test/test-person' - Namespace.register(:test, 'http://activerdf.org/test/') - - eyal = Namespace.lookup(:test, :eyal) - eye = Namespace.lookup(:test, :eye) - person = Namespace.lookup(:test, :Person) - type = Namespace.lookup(:rdf, :type) - resource = Namespace.lookup(:rdfs,:resource) - - color = Query.new.select(:o).where(eyal, eye,:o).execute - assert 'blue', color - assert_instance_of String, color - - ObjectManager.construct_classes - assert eyal.instance_of?(TEST::Person) - assert eyal.instance_of?(RDFS::Resource) - end - - def test_federated_query - adapter1 = ConnectionPool.add_data_source(:type => :redland) - adapter2 = ConnectionPool.add_data_source(:type => :redland, :fake_symbol_to_get_unique_adapter => true) - - eyal = RDFS::Resource.new 'eyaloren.org' - age = RDFS::Resource.new 'foaf:age' - test = RDFS::Resource.new 'test' - test2 = RDFS::Resource.new 'test2' - - adapter1.add(eyal, age, test) - adapter2.add(eyal, age, test2) - - # assert only one distinct subject is found (same one in both adapters) - assert_equal 1, Query.new.distinct(:s).where(:s, :p, :o).execute.size - - # assert two distinct objects are found - results = Query.new.distinct(:o).where(:s, :p, :o).execute - assert_equal 2, results.size - - results.all? {|result| assert result.instance_of?(RDFS::Resource) } - end - - def test_query_with_block - adapter = ConnectionPool.add_data_source(:type => :redland) - - eyal = RDFS::Resource.new 'eyaloren.org' - age = RDFS::Resource.new 'foaf:age' - test = RDFS::Resource.new 'test' +class TestRedlandAdapterMemory < Test::Unit::TestCase + include TestRedlandAdapter + # not persistent - adapter.add(eyal, age, test) - Query.new.select(:s,:p).where(:s,:p,:o).execute do |s,p| - assert_equal 'eyaloren.org', s.uri - assert_equal 'foaf:age', p.uri - end + def setup + @adapter_args = {:type => :redland, :location => "memory"} + super end +end - def test_person_data - adapter = ConnectionPool.add_data_source :type => :redland - adapter.load("#{File.dirname(__FILE__)}/test_person_data.nt", "turtle") - - Namespace.register(:test, 'http://activerdf.org/test/') - - eyal = Namespace.lookup(:test, :eyal) - eye = Namespace.lookup(:test, :eye) - person = Namespace.lookup(:test, :Person) - type = Namespace.lookup(:rdf, :type) - resource = Namespace.lookup(:rdfs,:resource) - - assert_equal 'blue', eyal.test::eye - - ObjectManager.construct_classes - assert eyal.instance_of?(TEST::Person) - assert eyal.instance_of?(RDFS::Resource) - end - - def test_write_to_file_and_reload - require 'tmpdir' - location = "#{Dir.tmpdir}/redland-temp" - adapter = ConnectionPool.add_data_source(:type => :redland, :location => location) +lass TestRedlandAdapterFile < Test::Unit::TestCase + include TestRedlandAdapter + include TestPersistentAdapter - eyal = RDFS::Resource.new 'eyaloren.org' - age = RDFS::Resource.new 'foaf:age' - test = RDFS::Resource.new 'test' + def setup + @location = File.join(Dir.tmpdir,"redland-temp") + @adapter_args = {:type => :redland, :location => @location} + super + end + def teardown + FileUtils.rm Dir.glob(@location + '-*') + end +nd - adapter.add(eyal, age, test) - adapter.save - - # flush the pool and freshly load the file we just wrote into - ConnectionPool.clear - adapter2 = ConnectionPool.add_data_source(:type => :redland, :location => location) +class TestRedlandAdapterSqlite < Test::Unit::TestCase + include TestRedlandAdapter + # not persistent - assert adapter2.object_id != adapter.object_id - assert_equal 1, adapter2.size + def setup + @adapter_args = {:type => :redland, :location => 'sqlite'} + super end +end - def test_sparql_query - adapter = ConnectionPool.add_data_source :type => :redland - - eyal = RDFS::Resource.new 'eyaloren.org' - age = RDFS::Resource.new 'foaf:age' - test = RDFS::Resource.new 'test' - adapter.add(eyal, age, test) - - adapter.save - query = Query.new.distinct(:s).where(:s,:p,:o) - results = adapter.get_query_results(query) +#class TestRedlandAdapterMySQL < Test::Unit::TestCase +# include TestRedlandAdapter +# include TestPersistentAdapter +# +# def setup +# @adapter_args = {:type => :redland, :name => 'db1', :location => 'mysql', +# :host => 'localhost', :database => 'redland_test', +# :user => '', :password => '', :new => 'yes'} +# super +# @adapter.clear +# end +#end + +#class TestRedlandAdapterPostgres < Test::Unit::TestCase +# include TestPersistentAdapter +# include TestRedlandAdapter +# +# def setup +# @adapter_args = {:type => :redland, :name => 'db1', :location => 'postgresql', +# :host => 'localhost', :database => 'redland_test', +# :user => '', :password => '', :new => 'yes'} +# super +# end +#end - # TODO: test if results are correct; but we do this only when redland - # supports this method in release - assert results.include?('eyaloren.org') - end -end diff --git a/lib/active_rdf/federation/federation_manager.rb b/lib/active_rdf/federation/federation_manager.rb index 4c0963c8..c215e653 100644 --- a/lib/active_rdf/federation/federation_manager.rb +++ b/lib/active_rdf/federation/federation_manager.rb @@ -47,6 +47,9 @@ def FederationManager.query(q, options={:flatten => true}) end end + # count + return results.flatten.inject{|mem,c| mem + c} if q.count? + # filter the empty results results.reject {|ary| ary.empty? } @@ -61,7 +64,7 @@ def FederationManager.query(q, options={:flatten => true}) results.flatten! if q.select_clauses.size == 1 or q.ask? # remove array (return single value or nil) if asked to - if options[:flatten] or q.count? + if options[:flatten] case results.size when 0 results = nil diff --git a/lib/active_rdf/objectmanager/literal.rb b/lib/active_rdf/objectmanager/literal.rb index 351f2de8..5251e858 100644 --- a/lib/active_rdf/objectmanager/literal.rb +++ b/lib/active_rdf/objectmanager/literal.rb @@ -1,71 +1,96 @@ require 'active_rdf' require 'time' -module Literal - Namespace.register :xsd, 'http://www.w3.org/2001/XMLSchema#' - def xsd_type - case self - when String - XSD::string - when Integer - XSD::integer - when Float - XSD::double - when TrueClass, FalseClass - XSD::boolean - when DateTime, Date, Time - XSD::date +module RDFS + module Literal + Namespace.register :xsd, 'http://www.w3.org/2001/XMLSchema#' + XSD::String = RDFS::Resource.new('http://www.w3.org/2001/XMLSchema#string') + XSD::Integer = RDFS::Resource.new('http://www.w3.org/2001/XMLSchema#integer') + XSD::Double = RDFS::Resource.new('http://www.w3.org/2001/XMLSchema#double') + XSD::Boolean = RDFS::Resource.new('http://www.w3.org/2001/XMLSchema#boolean') + XSD::Date = RDFS::Resource.new('http://www.w3.org/2001/XMLSchema#date') + Class_uri = Namespace.lookup(:rdfs, :Literal) + + def self.class_uri + Class_uri end - end - def self.typed(value, type) - case type - when XSD::string - String.new(value) - when XSD::date - DateTime.parse(value) - when XSD::boolean - value == 'true' or value == 1 - when XSD::integer - value.to_i - when XSD::double - value.to_f + def self.typed(value, type) + case type + when XSD::String + String.new(value) + when XSD::Integer + value.to_i + when XSD::Double + value.to_f + when XSD::Boolean + value == 'true' or value == 1 + when XSD::Date + DateTime.parse(value) + else + value + end end - end - def to_ntriple - if $activerdf_without_xsdtype - "\"#{to_s}\"" - else - "\"#{to_s}\"^^#{xsd_type}" + def xsd_type + case self + when String + XSD::String + when Integer + XSD::Integer + when Float + XSD::Double + when TrueClass, FalseClass + XSD::Boolean + when DateTime, Date, Time + XSD::Date + end + end + + def to_literal_s + unless $activerdf_without_xsdtype + s = kind_of?(Time) ? xmlschema : to_s + "\"#{s}\"^^#{xsd_type}" + else + "\"#{to_s}\"" + end end end end -class String; include Literal; end -class Integer; include Literal; end -class Float; include Literal; end -class DateTime; include Literal; end -class Date; include Literal; end -class Time; include Literal; end -class TrueClass; include Literal; end -class FalseClass; include Literal; end - class LocalizedString < String - include Literal + include RDFS::Literal + attr_reader :lang - def initialize value, lang=nil + def initialize(value, lang) super(value) + @lang = lang =~ /^@/ ? lang[1..-1] : lang + end - @lang = lang - @lang = lang[1..-1] if @lang[0..0] == '@' + def xsd_type + XSD::String unless @lang # don't return xsd_type if language is set (only lang or datatype may be set) end - def to_ntriple - if @lang - "\"#{to_s}\"@#@lang" + # returns quoted string with language type if present. + # xsd:string isn't appended when lang missing (xsd:string should be considered the default type) + def to_literal_s + unless $activerdf_without_xsdtype + if @lang + "\"#{self}\"@#@lang" + else + "\"#{self}\"^^#{XSD::String}" + end else - super + "\"#{self}\"" end end end + +class String; include RDFS::Literal; end +class Integer; include RDFS::Literal; end +class Float; include RDFS::Literal; end +class DateTime; include RDFS::Literal; end +class Date; include RDFS::Literal; end +class Time; include RDFS::Literal; end +class TrueClass; include RDFS::Literal; end +class FalseClass; include RDFS::Literal; end diff --git a/lib/active_rdf/objectmanager/resource.rb b/lib/active_rdf/objectmanager/resource.rb index 242db786..17d85a5f 100644 --- a/lib/active_rdf/objectmanager/resource.rb +++ b/lib/active_rdf/objectmanager/resource.rb @@ -66,8 +66,8 @@ def hash; uri.hash; end # overriding sort based on uri def <=>(other); uri <=> other.uri; end - def to_ntriple; "<#{uri}>"; end - def self.to_ntriple; "<#{class_uri.uri}>"; end + def to_literal_s; "<#{uri}>"; end + def self.to_literal_s; "<#{class_uri.uri}>"; end def to_xml base = Namespace.expand(Namespace.prefix(self),'').chop diff --git a/lib/active_rdf/queryengine/ntriples_parser.rb b/lib/active_rdf/queryengine/ntriples_parser.rb index 7e765dd0..1b6b3be7 100644 --- a/lib/active_rdf/queryengine/ntriples_parser.rb +++ b/lib/active_rdf/queryengine/ntriples_parser.rb @@ -14,7 +14,7 @@ def self.parse_node input when MatchLiteral value = fix_unicode($1) if $2 - Literal.typed(value, RDFS::Resource.new($2)) + RDFS::Literal.typed(value, RDFS::Resource.new($2)) else value end @@ -62,7 +62,7 @@ def self.parse(input) when MatchLiteral value = fix_unicode($1) if $2 - Literal.typed(value, RDFS::Resource.new($2)) + RDFS::Literal.typed(value, RDFS::Resource.new($2)) else value end diff --git a/lib/active_rdf/queryengine/query.rb b/lib/active_rdf/queryengine/query.rb index 4f49339b..46843059 100644 --- a/lib/active_rdf/queryengine/query.rb +++ b/lib/active_rdf/queryengine/query.rb @@ -209,7 +209,7 @@ def to_sp private def parametrise s case s - when Symbol, RDFS::Resource, Literal, Class + when Symbol, RDFS::Resource, RDFS::Literal, Class s when nil nil diff --git a/lib/active_rdf/queryengine/query2sparql.rb b/lib/active_rdf/queryengine/query2sparql.rb index 38dcd295..48d8e7fb 100644 --- a/lib/active_rdf/queryengine/query2sparql.rb +++ b/lib/active_rdf/queryengine/query2sparql.rb @@ -60,7 +60,7 @@ def self.construct_clause(term) if term.is_a?(Symbol) "?#{term}" else - term.to_ntriple + term.to_literal_s end end diff --git a/test/objectmanager/test_literal.rb b/test/objectmanager/test_literal.rb index 5582e55b..29013a2d 100644 --- a/test/objectmanager/test_literal.rb +++ b/test/objectmanager/test_literal.rb @@ -4,7 +4,6 @@ require 'test/unit' require 'active_rdf' -require "#{File.dirname(__FILE__)}/../common" class TestLiteral < Test::Unit::TestCase def setup @@ -12,41 +11,41 @@ def setup @adapter = get_adapter end - def teardown - end - - def test_xsd_string - test = Literal.typed('test', XSD::string) - assert_equal '"test"^^', test.to_ntriple - end - def test_automatic_conversion - # infer string test = 'test' - assert_equal '"test"^^', test.to_ntriple + assert_equal '"test"^^', test.to_literal_s # infer integer test = 18 - assert_equal '"18"^^', test.to_ntriple + assert_equal '"18"^^', test.to_literal_s + + # infer float + test = 3.1415 + assert_equal '"3.1415"^^', test.to_literal_s # infer boolean test = true - assert_equal '"true"^^', test.to_ntriple + assert_equal '"true"^^', test.to_literal_s + + # infer Date + test = Time.parse("Sat Nov 22 00:33:23 -0800 2008") + assert_equal '"2008-11-22T00:33:23-08:00"^^', test.to_literal_s + end def test_equality test1 = 'test' - test2 = Literal.typed('test', XSD::string) - assert_equal test2.to_ntriple, test1.to_ntriple + test2 = RDFS::Literal.typed('test', XSD::string) + assert_equal test2.to_literal_s, test1.to_literal_s end def test_language_tag cat = 'cat' cat_en = LocalizedString.new('cat', '@en') - assert_equal '"cat"@en', cat_en.to_ntriple - assert_not_equal cat.to_ntriple, cat_en.to_ntriple + assert_equal '"cat"@en', cat_en.to_literal_s + assert_not_equal cat.to_literal_s, cat_en.to_literal_s - assert_equal '"dog"@en-GB', LocalizedString.new('dog', '@en-GB').to_ntriple - assert_equal '"dog"@en@test', LocalizedString.new('dog', '@en@test').to_ntriple + assert_equal '"dog"@en-GB', LocalizedString.new('dog', '@en-GB').to_literal_s + assert_equal '"dog"@en@test', LocalizedString.new('dog', '@en@test').to_literal_s end end diff --git a/test/test_activerdf_adapter.rb b/test/test_activerdf_adapter.rb new file mode 100755 index 00000000..eb1d82a1 --- /dev/null +++ b/test/test_activerdf_adapter.rb @@ -0,0 +1,146 @@ +require 'active_rdf' +Namespace.register(:test, 'http://activerdf.org/test/') + +module TestActiveRdfAdapter + @@test = TEST::test + @@eyal = TEST::eyal + @@eye = TEST::eye + @@name = TEST::name + @@mbox = TEST::mbox + @@age = TEST::age + @@ageval = 23 + @@mboxval = 'aahfgiouhfg' + + # override setup in TestCase. define @adapter_args & finally call super + def setup + ConnectionPool.clear + @adapter = ConnectionPool.add(@adapter_args) + end + + def teardown + ConnectionPool.remove_data_source(@adapter) + @adapter.close if @adapter.instance_eval{@enabled} # close if not closed already + end + + def test_simple_query + @adapter.add(@@eyal, @@name, "eyal oren") + @adapter.add(@@eyal, @@age, @@ageval) + + result = Query.new.distinct(:s).where(:s, :p, :o).execute(:flatten => true) + assert_instance_of RDFS::Resource, result + assert_equal @@eyal.uri, result.uri + + result = Query.new.distinct(:o).where(@@eyal,@@age,:o).execute(:flatten => true) + assert_equal 23, result + end + + def test_query_with_block + @adapter.add(@@eyal, @@age, @@ageval) + Query.new.select(:s,:p,:o).where(:s,:p,:o).execute(:flatten => false) do |s,p,o| + assert_equal @@eyal.uri, s.uri + assert_equal @@age.uri, p.uri + assert_equal 23, o + end + end + + def test_close + @adapter.add(@@eyal, @@age, @@test) + results = Query.new.select(:s,:p,:o).where(:s,:p,:o).execute + assert results.flatten.size > 0 + + @adapter.close + assert_equal 0, ConnectionPool.adapters.size + assert_raises ActiveRdfError do + results = Query.new.select(:s,:p,:o).where(:s,:p,:o).execute + end + end + + def test_dump + @adapter.add(@@eyal, @@age, @@test) + + dump = @adapter.dump + assert_kind_of String, dump + end + + def test_size + @adapter.add(@@eyal, @@age, @@test) + assert 1, @adapter.size + end + + +# def test_escaped_literals +# string = 'test\nbreak\"quoted\"' +# interpreted = "test\nbreak\"quoted\"" +# +# @adapter.add(@@eyal, TEST::newline_quotes_string, string) +# assert_equal string, @@eyal.newline_quotes_string +# +# @adapter.add(@@eyal, TEST::newline_quotes_interpreted, interpreted) +# assert_equal interpreted, @@eyal.newline_quotes_interpreted +# +# string = 'ümlaut and \u00ebmlaut' +# interpreted = "ümlaut and ëmlaut" +# +# @adapter.add(@@eyal, TEST::umlaut_string, string) +# assert_equal string, @@eyal.umlaut_string +# +# @adapter.add(@@eyal, TEST::umlaut_interpreted, interpreted) +# assert_equal string, @@eyal.umlaut_interpreted +# end + + def test_retrieve_a_triple_with_only_uris + @adapter.add(@@eyal, @@age, @@test) + result = Query.new.distinct(:o).where(@@eyal, :p, :o).execute + assert_equal 1, result.flatten.size + + result = Query.new.distinct(:p, :o).where(@@eyal, :p, :o).execute + assert_equal 2, result.flatten.size + + result = Query.new.distinct(:o).where(@@eyal, @@age, :o).execute + assert_equal 1, result.flatten.size + + result = Query.new.distinct(:s).where(:s, @@age, @@test).execute + assert_equal 1, result.flatten.size + + result = Query.new.distinct(:p).where(@@eyal, :p, @@test).execute + assert_equal 1, result.flatten.size + end + + def test_retrieve_a_triple_with_string + @adapter.add(@@eyal, @@mbox, @@mboxval) + result = Query.new.distinct(:o).where(@@eyal, :p, :o).execute + assert_equal 1, result.flatten.size + + result = Query.new.distinct(:p, :o).where(@@eyal, :p, :o).execute + assert_equal 2, result.flatten.size + + result = Query.new.distinct(:o).where(@@eyal, @@mbox, :o).execute + assert_equal 1, result.flatten.size + + result = Query.new.distinct(:s).where(:s, @@mbox, @@mboxval).execute + assert_equal 1, result.flatten.size + + result = Query.new.distinct(:p).where(@@eyal, :p, @@mboxval).execute + assert_equal 1, result.flatten.size + #@adapter.close + end +# + def test_retrieve_a_triple_with_fixnum + @adapter.add(@@eyal, @@age, @@ageval) + result = Query.new.distinct(:o).where(@@eyal, :p, :o).execute + assert_equal 1, result.flatten.size + + result = Query.new.distinct(:p, :o).where(@@eyal, :p, :o).execute + assert_equal 2, result.flatten.size + + result = Query.new.distinct(:o).where(@@eyal, @@age, :o).execute + assert_equal 1, result.flatten.size + + result = Query.new.distinct(:s).where(:s, @@age, @@ageval).execute + assert_equal 1, result.flatten.size + + result = Query.new.distinct(:p).where(@@eyal, :p, @@ageval).execute + assert_equal 1, result.flatten.size + end + +end \ No newline at end of file diff --git a/test/test_bnode_capable_adapter.rb b/test/test_bnode_capable_adapter.rb new file mode 100644 index 00000000..ab2d2196 --- /dev/null +++ b/test/test_bnode_capable_adapter.rb @@ -0,0 +1,31 @@ +module TestBnodeCapableAdapter + def test_load_bnodes + @adapter.load(File.dirname(File.expand_path(__FILE__)) + '/test_bnode_data.nt') + + # loaded five triples in total + assert_equal 8, @adapter.size + + # collecting the bnodes + bnodes = Query.new.distinct(:s).where(:s,:p,:o).execute + + # triples contain two distinct bnodes + assert_equal 3, bnodes.size + + # assert that _:a1 occurs in three triples + assert_equal 3, Query.new.select(:p,:o).where(bnodes[0], :p, :o).execute.size + # assert that _:a2 occurs in two triples + assert_equal 2, Query.new.select(:p,:o).where(bnodes[1], :p, :o).execute.size + # assert that _:a3 occurs in two triples + assert_equal 3, Query.new.select(:p,:o).where(bnodes[2], :p, :o).execute.size + end + + def test_bnodes + @adapter.load(File.dirname(File.expand_path(__FILE__)) + '/test_bnode_data.nt') + + #ObjectManager.construct_classes + people = TEST::Person.find_all + assert_equal 2, people.size + assert_equal 29, people[1].age + assert_equal "Another Person", TEST::Person.find_all[1].name + end +end \ No newline at end of file diff --git a/test/test_bnode_data.nt b/test/test_bnode_data.nt new file mode 100644 index 00000000..e3221dc2 --- /dev/null +++ b/test/test_bnode_data.nt @@ -0,0 +1,8 @@ +_:a1 . +_:a1 "27" . +_:a1 "Eyal Oren" . +_:a2 "27" . +_:a2 "blue" . +_:a3 . +_:a3 "Another Person" . +_:a3 "29" . diff --git a/activerdf-rdflite/test/test_data.nt b/test/test_data.nt similarity index 95% rename from activerdf-rdflite/test/test_data.nt rename to test/test_data.nt index 980af1c5..9fd4a8b1 100644 --- a/activerdf-rdflite/test/test_data.nt +++ b/test/test_data.nt @@ -27,6 +27,3 @@ . . . -_:#1 "29" . -_:#1 "Another Person" . -_:#1 . diff --git a/activerdf-rdflite/test/test_escaped_data.nt b/test/test_escaped_data.nt similarity index 100% rename from activerdf-rdflite/test/test_escaped_data.nt rename to test/test_escaped_data.nt diff --git a/test/test_persistent_adapter.rb b/test/test_persistent_adapter.rb new file mode 100644 index 00000000..6097ada3 --- /dev/null +++ b/test/test_persistent_adapter.rb @@ -0,0 +1,32 @@ +require File.join(File.dirname(File.expand_path(__FILE__)), 'test_writable_adapter') + +module TestPersistentAdapter + include TestWritableAdapter + + def test_close_and_reload_persistence + @adapter.add(@@eyal, @@name, "eyal oren") + @adapter.add(@@eyal, @@age, @@ageval) + + dump1 = @adapter.dump + @adapter.close + ConnectionPool.clear + + (args = @adapter_args.dup).delete(:new) # remove possible new key to prevent reinitialization of datastore on adapter creation where applicable + adapter2 = ConnectionPool.add(args) + assert_not_equal @adapter.object_id, adapter2.object_id + + assert_equal dump1, adapter2.dump + adapter2.close + end + + def test_clear_on_new + @adapter.load(@@test_person_data) + @adapter.close + ConnectionPool.clear + (args = @adapter_args.dup).update(:new => 'yes') + adapter = ConnectionPool.add args + assert_equal 0, adapter.size, "datastore not cleared when requested" + adapter.close + end + +end \ No newline at end of file diff --git a/test/test_read_only_adapter.rb b/test/test_read_only_adapter.rb new file mode 100755 index 00000000..307f8b15 --- /dev/null +++ b/test/test_read_only_adapter.rb @@ -0,0 +1,15 @@ +require File.join(File.dirname(File.expand_path(__FILE__)), 'test_activerdf_adapter') + +module TestReadOnlyAdapter + include TestActiveRdfAdapter + + def test_refuse_to_write + # NameError gets thown if the method is unknown + assert_raises NoMethodError do + @adapter.add + end + assert_raises NoMethodError do + @adapter.load + end + end +end \ No newline at end of file diff --git a/test/test_writable_adapter.rb b/test/test_writable_adapter.rb new file mode 100755 index 00000000..be36af48 --- /dev/null +++ b/test/test_writable_adapter.rb @@ -0,0 +1,109 @@ +require File.join(File.dirname(File.expand_path(__FILE__)), 'test_activerdf_adapter') + +module TestWritableAdapter + include TestActiveRdfAdapter + + dir = File.dirname(File.expand_path(__FILE__)) + @@test_data = File.join(dir,'test_data.nt') + @@test_person_data = File.join(dir,'test_person_data.nt') + @@test_escaped_data = File.join(dir,'test_escaped_data.nt') + + def test_count_query + @adapter.load(@@test_data) + assert_kind_of Fixnum, Query.new.count(:s).where(:s,:p,:o).execute + assert_equal 29, Query.new.count(:s).where(:s,:p,:o).execute + end + + def test_update_value + @adapter.load @@test_person_data + + assert_equal 1, @@eyal.all_age.size + assert_equal 27, @@eyal.age + + # << doesn't work on Fixnums + @@eyal.age << 30 + assert_equal 1, @@eyal.all_age.size + assert !@@eyal.all_age.include?(30) + assert @@eyal.all_age.include?(27) + + @@eyal.age = 40 + assert_equal 1, @@eyal.all_age.size + assert @@eyal.age == 40 + end + +# def test_load_escaped_literals +# @adapter.load(@@test_escaped_data) +# +# assert_equal 2, @adapter.size +# assert_equal "ümlauts and ëmlauts", @@eyal.comment +# assert_equal "line\nbreaks,

's and \"quotes\"", @@eyal.encoded +# end + + def test_person_data + @adapter.load(@@test_person_data) + + color = Query.new.select(:o).where(@@eyal,@@eye,:o).execute(:flatten => true) + + assert_instance_of String, color + assert 'blue', color + assert_equal 'blue', @@eyal.test::eye + + assert @@eyal.instance_of?(TEST::Person) + assert @@eyal.instance_of?(RDFS::Resource) + end + + def test_delete_data + @adapter.add(@@eyal, @@mbox, @@mboxval) + + @adapter.add(@@eyal, @@age, @@ageval) + @adapter.delete(@@eyal, @@age, @@ageval) + assert_equal 1, @adapter.size + + @adapter.add(@@eyal, @@age, @@ageval) + @adapter.delete(:s, :p, @@ageval) + assert_equal 1, @adapter.size + + @adapter.add(@@eyal, @@age, @@ageval) + @adapter.delete(:s, @@age, :o) + assert_equal 1, @adapter.size + + @adapter.add(@@eyal, @@age, @@ageval) + @adapter.delete(@@eyal, :p, :o) + assert_equal 0, @adapter.size + + @adapter.load(@@test_data) + assert_equal 29, @adapter.size + + @adapter.delete(@@eyal, nil, nil) + assert_equal 24, @adapter.size + + @adapter.delete(nil, nil, nil) + assert_equal 0, @adapter.size + end + + def test_clear + @adapter.add(@@eyal, @@age, @@test) + assert 0 < @adapter.size + + @adapter.clear + assert_equal 0, @adapter.size + end + + def test_load_from_file_and_clear + @adapter.load(@@test_person_data) + assert_equal 30, @adapter.size + @adapter.clear + assert_equal 0, @adapter.size + end + + def test_remote_load_and_clear + @adapter.load('http://www.w3.org/2000/10/rdf-tests/rdfcore/ntriples/test.nt') + assert_equal 30, @adapter.size + + @adapter.clear + assert_equal 0, @adapter.size + + @adapter.load('http://www.w3.org/2000/10/rdf-tests/rdfcore/testSchema.rdf', 'rdfxml') + assert_equal 76, @adapter.size + end +end \ No newline at end of file