diff --git a/lib/rdf/spec.rb b/lib/rdf/spec.rb index c127223..d21a0ab 100644 --- a/lib/rdf/spec.rb +++ b/lib/rdf/spec.rb @@ -68,5 +68,22 @@ def self.triples require 'rdf/ntriples' (@triples ||= RDF::NTriples::Reader.new(File.open(TRIPLES_FILE)).to_a).dup end + + # Logger used for Specs; allows clearing and converting to string + require 'logger' + def self.logger + logger = Logger.new(StringIO.new) + def logger.clear + @logdev.instance_variable_set(:@dev, StringIO.new) + end + def logger.to_s + dev = @logdev.instance_variable_get(:@dev) + dev.rewind + dev.read + end + logger.level = Logger::DEBUG + logger.formatter = lambda {|severity, datetime, progname, msg| "#{msg}\n"} + logger + end end # Spec end # RDF diff --git a/lib/rdf/spec/matchers.rb b/lib/rdf/spec/matchers.rb index 36e75aa..7a80658 100644 --- a/lib/rdf/spec/matchers.rb +++ b/lib/rdf/spec/matchers.rb @@ -1,4 +1,5 @@ require 'rspec/matchers' # @see http://rubygems.org/gems/rspec +require 'rdf/isomorphic' # @see http://rubygems.org/gems/rdf-isomorphic module RDF; module Spec ## @@ -258,6 +259,85 @@ def io_name {:output => "standard output", :error => "standard error"}[io] end end + + Info = Struct.new(:id, :logger, :action, :result) + + RSpec::Matchers.define :be_equivalent_graph do |expected, info| + match do |actual| + def normalize(graph) + case graph + when RDF::Enumerable then graph + when IO, StringIO + RDF::Repository.new(graph, base_uri: @info.action) + else + # Figure out which parser to use + r = RDF::Repository.new + reader_class = RDF::Reader.for(graph) + reader_class.new(graph, base_uri: @info.action).each {|s| r << s} + r + end + end + + @info = if (info.id rescue false) + info + elsif info.is_a?(Logger) + Info.new("", info) + elsif info.is_a?(Hash) + Info.new(info[:id], info[:logger], info[:action], info[:result], info[:metadata]) + else + Info.new(info) + end + @expected = normalize(expected) + @actual = normalize(actual) + @actual.isomorphic_with?(@expected) rescue false + end + + failure_message do |actual| + trace = case @info.logger + when Logger then @info.logger.to_s + when Array then @info.logger.join("\n") + end + info = @info.respond_to?(:information) ? @info.information : @info.inspect + if @expected.is_a?(RDF::Enumerable) && @actual.size != @expected.size + "Graph entry counts differ:\nexpected: #{@expected.size}\nactual: #{@actual.size}\n" + else + "Graphs differ\n" + end + + "\n#{info + "\n" unless info.empty?}" + + + "Expected:\n#{@expected.dump(:ttl, standard_prefixes: true, literal_shorthand: false)}" + + "Results:\n#{@actual.dump(:ttl, standard_prefixes: true, literal_shorthand: false)}" + + (trace ? "\nDebug:\n#{trace}" : "") + end + end + + RSpec::Matchers.define :produce do |expected, info| + match do |actual| + @info = if (info.id rescue false) + info + elsif info.is_a?(Logger) + Info.new("", info) + elsif info.is_a?(Hash) + Info.new(info[:id], info[:logger], info[:action], info[:result], info[:metadata]) + else + Info.new(info) + end + expect(actual).to eq expected + end + + failure_message do |actual| + trace = case @info.logger + when Logger then @info.logger.to_s + when Array then @info.logger.join("\n") + end + info = @info.respond_to?(:information) ? @info.information : @info.inspect + + "Expected: #{expected.is_a?(String) ? expected : expected.to_json(JSON_STATE) rescue 'malformed json'}\n" + + "Actual : #{actual.is_a?(String) ? actual : actual.to_json(JSON_STATE) rescue 'malformed json'}\n" + + "\n#{info + "\n" unless info.empty?}" + + + + (trace ? "\nDebug:\n#{trace}" : "") + end + end + end # Matchers end; end # RDF::Spec diff --git a/rdf-spec.gemspec b/rdf-spec.gemspec index a95e3f9..2a4b2f7 100755 --- a/rdf-spec.gemspec +++ b/rdf-spec.gemspec @@ -27,10 +27,11 @@ Gem::Specification.new do |gem| gem.required_ruby_version = '>= 1.9.2' gem.requirements = [] - gem.add_runtime_dependency 'rdf', '~> 1.99' - gem.add_runtime_dependency 'rspec', '~> 3.0' - gem.add_runtime_dependency 'rspec-its', '~> 1.0' - gem.add_runtime_dependency 'webmock', '~> 1.17' - gem.add_development_dependency 'yard' , '~> 0.8' + gem.add_runtime_dependency 'rdf', '~> 1.99' + gem.add_runtime_dependency 'rdf-isomorphic', '~> 1.99' + gem.add_runtime_dependency 'rspec', '~> 3.0' + gem.add_runtime_dependency 'rspec-its', '~> 1.0' + gem.add_runtime_dependency 'webmock', '~> 1.17' + gem.add_development_dependency 'yard' , '~> 0.8' gem.post_install_message = nil end