#!/usr/bin/env ruby

$LOAD_PATH.unshift '../../lib/' # because we're testing dev version

# Exploring a pastiche of the Cwm RDF API
# taking http://www.w3.org/2000/10/swap/pim/toIcal.py as basis
# $Id: sqlgraph.rb,v 1.18 2003/04/21 19:51:36 danbri Exp $ 
# Dan Brickley <danbri@w3.org>
#
#      Current Cwm-like RDF API (llyn.py/thing.py) functionality:
#
#      def each(st)       # iterator for simple statement matcher
#      def statementsMatching(st) # ditto but returns immutable statements
#      def add(st)	  # works for RDFGraph, no impl yet in SimpleSQLGraph 
#      def any(st)        # returns the missing bit for a blanked out node
#      def the(st)        # ditto but complains if multiple answers
#      def Namespace(n)   # haven't sorted out interning, scopes etc though
# 

#<danbri> DanC, in Cwm, is the only difference between each() and statementsMatching() that the 
#latter returns immutable stattements?
#<danbri> ah no, each() only expects one part of the statement to be blanked out, and returns a 
#list of values for that. (right?)
# TODO: fix each()

# Latest: I've moved the library stuff to ../lib/RDF4R/pastiche.rb
#    see:  http://www.w3.org/2001/12/rubyrdf/pack/lib/RDF4R/pastiche.rb
# nearby: http://rdflib.net/latest/doc/triple_store.html RDFLib API
#   
# see http://www.w3.org/2000/10/swap/llyn.py and thing.py
# note that the SQL/stored tests require a local DBI rdfstore, see tiny.rb
#

require 'test/unit'     # unit testing

require 'basicrdf'      # main RubyRdf impl and api
require 'squish' 	# for SimpleSQLGraph impl
require 'RDF4R/pastiche'# Cwm-ish RDF API for general and SQL stores 



######################## Pastiche Tests ##############################

class TC_PasticheAPI < Test::Unit::TestCase

  include RDF4R::Pastiche::SWAP             # vs require? is it w.r.t. files?

  attr_accessor :verbose

  def setup
    @verbose=false
    begin
      pretest = Formula.new(SimpleSQLGraph.new('dbi_driver'=>'DBI:Pg:scutter1', 'dbi_user'=>'danbri'))
    rescue Exception
      raise "Failure connecting to scutter test database, aborting Cwm pastiche tests"
    end
    puts "No setup needed (but scutter1 db must exist)." if verbose
  end
  

  # test fetch'n'load first
  def test_basics
    addr = 'http://rdfweb.org/people/danbri/rdfweb/danbri-foaf.rdf'
    puts "Testing pastiche access to load URI capabilities."
    page = load addr
    assert page!=nil, "We should be able to get a graph from a URI"

    # register some namespace (Why? How? what kind of global db in Cwm...?)

    rdf = Namespace("http://www.w3.org/1999/02/22-rdf-syntax-ns#") 
    foaf = Namespace("http://xmlns.com/foaf/0.1/")

    assert rdf=="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
                 "Namespace() should return the right string (subtyped?)"

    assert("foo"=="foo", "Testing ruby string equality rules.") # to be sure
    # so how do we compare to see if these are same instances? (they're not)

    #this was FOAF= not foaf=, but... issue w/ constants...
    #Hmmph, can't seem do this: complains re dynamic constant assignment
    #I thought this was changed in Ruby to be more liberal. Maybe in 1.8?
    #For now, lowercase it is...

    name=nil
    puts "Testing basic pastiche access to parse and navigation facilities."
    page.each('pred' => foaf+'homepage', 
              'obj'=>'http://rdfweb.org/people/danbri/') do |hp|
      page.each('pred'=> foaf+'name', 'subj'=>hp) do |name|
        puts "Name: "+name if verbose
        assert(name == 'Dan Brickley', "Fetch/parse/read of a foaf doc failed")
      end
    end
       
    hp1 = page.any('pred' => foaf+'homepage','obj'=>'http://rdfweb.org/people/danbri/')
    name2 = page.any('pred'=> foaf+'name', 'subj'=>hp1)
    name3 = page.the('pred'=> foaf+'name', 'subj'=>hp1)

    puts "Testing any() behaviour matches each() result(s)."
    assert name==name2, 
      "Should get same from each() vs any() calls: '#{name}' != '#{name2}'" 
    puts "Testing the() behaviour matches each() result(s)."
    assert name==name3, 
      "Should get same from each() vs the() calls: '#{name}' != '#{name2}'" 

    # puts "page type: "+page.class.to_s #if verbose
    for t in page.each
       puts "got statement: #{t}" if verbose
    end

  end
  
  def test_sqlstore
    # Now try the persistent RDF store (assume data loaded):

    stored = Formula.new(SimpleSQLGraph.new('dbi_driver'=>'DBI:Pg:scutter1', 'dbi_user'=>'danbri'))
    foaf = Namespace("http://xmlns.com/foaf/0.1/")

    #list some photos:
    puts "Testing pastiche access to scutter db (photo data)."
    depictions=[]
    stored.each('pred'=>foaf+'depiction') do |pic|
      puts "Found photo: "+pic if verbose
      depictions.push(pic)
      # note that the pic.objects call isn't Cwm-based. TODO: how would Cwm do this?
    end
    expics=50
    puts "Testing each() returns plausible resultset (should be > #{expics})."
    assert(depictions.size>expics, "Expected DB to have more than #{expics} depictions, found #{depictions.size}")

    #for sql debug:
    #select distinct o, count(o) from simple 
    #where simple.p like 'http://xmlns.com/foaf/0.1/depiction' 
    #group by o ORDER BY count(o) desc;

    images=[] 
    puts "Testing statementsMatching() returns frozen objects."
    readonly_ok=false
    stored.statementsMatching 'pred'=>foaf+'img' do |pic| 
      begin 
        # these statements should be read only
        pic.subject=Node.getResource('http://example.com/dev/null')
      rescue TypeError
        puts "Got the frozen object error as expected: #{$!}." if verbose
        readonly_ok=true
        # if mistakenly no error, we'll break out of the iteration.
      end
      raise "allowed statementMatching reply to change" if !readonly_ok 
      images.push pic.object.to_s
      # puts "Found these foaf:img values: #{images.inspect}"
    end
    assert readonly_ok==true, "We shouldn't be able to alter statementsMatching results"
  end
end

