#!/usr/bin/env ruby
#-------------------------------------------------------------------------
# 
# Open Source License/Disclaimer, Forecast Systems Laboratory NOAA/OAR/FSL, 
# 325 Broadway Boulder, CO 80305
# 
# This software is distributed under the Open Source Definition, which may 
# be found at http://www.opensource.org/osd.html.
# 
# In particular, redistribution and use in source and binary forms, with or 
# without modification, are permitted provided that the following conditions
# are met:
# 
#     . Redistributions of source code must retain this notice, this list 
#     of conditions and the following disclaimer. 
# 
#     . Redistributions in binary form must provide access to this notice,
#     this list of conditions and the following disclaimer, and the 
#     underlying source code. 
# 
#     . All modifications to this software must be clearly documented, and
#     are solely the responsibility of the agent making the modifications. 
# 
#     . If significant modifications or enhancements are made to this 
#     software, the FSL Software Policy Manager (softwaremgr@fsl.noaa.gov)
#     should be notified. 
# 
#-------------------------------------------------------------------------
# 
# THIS SOFTWARE AND ITS DOCUMENTATION ARE IN THE PUBLIC DOMAIN AND ARE 
# FURNISHED "AS IS." THE AUTHORS, THE UNITED STATES GOVERNMENT, ITS 
# INSTRUMENTALITIES, OFFICERS, EMPLOYEES, AND AGENTS MAKE NO WARRANTY, 
# EXPRESS OR IMPLIED, AS TO THE USEFULNESS OF THE SOFTWARE AND DOCUMENTATION 
# FOR ANY PURPOSE. THEY ASSUME NO RESPONSIBILITY (1) FOR THE USE OF THE
# SOFTWARE AND DOCUMENTATION; OR (2) TO PROVIDE TECHNICAL SUPPORT TO USERS.
# 
#-------------------------------------------------------------------------
# 
#
# WARNING: This is OPAQUE Facility Division (FD) Software. All OPAQUE FD 
# Software is subject to change without notice.

# TODO - address the sort issue, which can confuse tests

require 'runit/testcase'
require 'runit/cui/testrunner'
require 'runit/testsuite'

require 'postgres'
$:.unshift '../lib'
$:.unshift './lib'
require 'btpgsql.rb'


DBNAME = 'btpgsql_unit_test' 

$verbose = false 

$passwd    = nil
$pgport    = nil
$pgoptions = nil
$pgtty     = nil
$dbname    = ARGV[0] || DBNAME 
$login     = nil
$passwd    = nil


$pgconn = PGconn.new $pghost,$pgport,$pgoptions,
		     $pgtty,$dbname,$login,$passwd


module BtPgsql

  class TestSchema < RUNIT::TestCase

    def setup
      @parent     = Relation.new 'parent'
      @child      = Relation.new 'child'
      @grandchild = Relation.new 'grandchild'

      @parent.truncate     
      @child.truncate      
      @grandchild.truncate 
    end


    def test_A_seq_insert
      @parent.transaction do
	@parent.seq_insert [0,'parent 0','-infinity','epoch']
	@parent.seq_insert [0,'parent 0','epoch','infinity']
      end

      tuples = @parent.select

      expected = 
      [ 
	[
	  '0', 'parent 0',
	  '-infinity', '1970-01-01 00:00:00',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '0',
	],
	[
	  '0', 'parent 0',
	  '1970-01-01 00:00:00', 'infinity',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '1',
	],
      ]
#      expected.each do |tuple|
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort


      @child.transaction do
	@child.seq_insert [0,0,'child 0','-infinity','epoch'],
			  [0,0,'child 0','epoch','infinity']
      end

      tuples = @child.select

      expected = 
      [ 
	[
	  '0', '0', 'child 0',
	  '-infinity', '1970-01-01 00:00:00',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '0',
	],
	[
	  '0', '0', 'child 0',
	  '1970-01-01 00:00:00', 'infinity',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '1',
	],
      ]
#      expected.each do |tuple|
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end
      
      assert tuples.sort == expected.sort

      @grandchild.transaction do
	@grandchild.seq_insert [
	  [0,0,'grandchild 0','-infinity','epoch'],
	  [0,0,'grandchild 0','epoch','infinity'],
	]
      end

      tuples = @grandchild.select

      expected = 
      [ 
	[
	  '0', '0', 'grandchild 0',
	  '-infinity', '1970-01-01 00:00:00',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '0',
	],
	[
	  '0', '0', 'grandchild 0',
	  '1970-01-01 00:00:00', 'infinity',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '1',
	],
      ]
#      expected.each do |tuple|
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end
      
      assert tuples.sort == expected.sort


      assert_exception RuntimeError do
	@child.transaction do
	  @child.seq_insert [
	    [0,0,'child 0','-infinity','epoch'],
	  ]
	end
      end

      assert_exception RuntimeError do
	@grandchild.transaction do
	  @grandchild.seq_insert [
	    [0,42,'grandchild 0','-infinity','epoch'],
	  ]
	end
      end
    end

    def test_B_foreign_key_coverage
      assert_no_exception do
	@parent.transaction do
	  @parent.seq_insert [
	    [0,'parent 0','-infinity','epoch'],
	    [0,'parent 0','epoch','infinity'],
	  ]
	end
	@child.transaction do
	  @child.seq_insert [
	    [0,0,'child 0','-infinity','infinity'],
	  ]
	end
	@grandchild.transaction do
	  @grandchild.seq_insert [
	    [0,0,'grandchild 0','-infinity','epoch'],
	    [0,0,'grandchild 0','epoch','infinity'],
	  ]
	end
      end
    end

    def test_C_foreign_key_coverage
      assert_no_exception do
	@parent.transaction do
	  @parent.seq_insert [
	    [0,'parent 0','-infinity','epoch'],
	    [0,'parent 0','epoch','2002-01-01'],
	    [0,'parent 0','2002-01-01','infinity'],
	  ]
	end
	@child.transaction do
	  @child.seq_insert [
	    [0,0,'child 0','-infinity','1970-01-01'],
	    [0,0,'child 0','1970-01-01','infinity'],
	  ]
	end
	@grandchild.transaction do
	  @grandchild.seq_insert [
	    [0,0,'grandchild 0','-infinity','infinity'],
	  ]
	end
      end
    end

    def test_C_foreign_key_coverage
      assert_no_exception do
	@parent.transaction do
	  @parent.seq_insert [
	    [0,'parent 0','-infinity','epoch'],
	    [0,'parent 0','epoch','2002-01-01'],
	    [0,'parent 0','2002-01-01','infinity'],
	  ]
	end
	@child.transaction do
	  @child.seq_insert [
	    [0,0,'child 0','-infinity','1970-01-01'],
	    [0,0,'child 0','1970-01-01','infinity'],
	  ]
	end
	@grandchild.transaction do
	  @grandchild.seq_insert [
	    [0,0,'grandchild 0','-infinity','infinity'],
	  ]
	end
      end
    end

    def test_D_foreign_key_coverage
      assert_exception RuntimeError do
	@parent.transaction do
	  # note the gap in there!
	  @parent.seq_insert [
	    [0,'parent 0','-infinity','epoch'],
	    [0,'parent 0','epoch','2002-01-01'],
	    [0,'parent 0','2002-02-01','infinity'],
	  ]
	end
	@child.transaction do
	  @child.seq_insert [
	    [0,0,'child 0','-infinity','1970-01-01'],
	    [0,0,'child 0','1970-01-01','infinity'],
	  ]
	end
      end
    end

    def test_E_foreign_key_coverage
      assert_exception RuntimeError do
	@parent.transaction do
	  @parent.seq_insert [
	    [0,'parent 0','epoch','2002-01-01'],
	    [0,'parent 0','2002-02-01','infinity'],
	  ]
	end
	@child.transaction do
	  @child.seq_insert [
	    [0,0,'child 0','-infinity','1970-01-01'],
	    [0,0,'child 0','1970-01-01','infinity'],
	  ]
	end
      end
    end

#[0,'parent 0','-infinity','epoch'],
#[0,'parent 0','epoch','infinity'],
#[0,0,'child 0','-infinity','epoch'],
#[0,0,'child 0','epoch','infinity'],
#[0,0,'grandchild 0','-infinity','epoch'],
#[0,0,'grandchild 0','epoch','infinity'],

    def test_F_seq_delete
      populate
#puts ''
#puts @parent
      assert_no_exception do
	@parent.transaction do
	  tuples = @parent.select
	  @parent.seq_delete '1960-01-01','1980-01-01',tuples
	end
      end

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','1970-01-01 00:00:00',
	  tuples[0]['tt_start'], tuples[0]['tt_stop'],
	  '0', '0',
	],
	[
	  '0','parent 0',
	  '1970-01-01 00:00:00','infinity',
	  tuples[0]['tt_start'], tuples[0]['tt_stop'],
	  '0', '1',
	],
	[
	  '0','parent 0',
	  '-infinity','1960-01-01 00:00:00',
	  tuples[2]['tt_start'], 'infinity',
	  '0', '2',
	],
	[
	  '0','parent 0',
	  '1980-01-01 00:00:00','infinity',
	  tuples[2]['tt_start'], 'infinity',
	  '0', '3',
	],
      ]
#      expected.each do |tuple|
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}


if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end

puts ''
tuples.size.times do |i|
  tuples[i].size.times do |j|
    puts "expected[#{i}][#{j}] == tuples[#{i}][#{j}] ? #{expected[i][j] == tuples[i][j]}"
    puts "#{expected[i][j]} == #{tuples[i][j]} ? #{expected[i][j] == tuples[i][j]}"
  end
end
end

#exit
#puts parent
      assert tuples.sort == expected.sort

    end

    def test_G_seq_update
      populate
      assert_no_exception do
	@parent.transaction do
	  tuples = @parent.select
	  @parent.seq_update '1960-01-01','1980-01-01',tuples,
	    'description' => 'PARENT 0'
	end
      end


      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

#puts @parent
#puts tuples

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','1970-01-01 00:00:00',
	  tuples[0]['tt_start'], tuples[0]['tt_stop'],
	  '0', '0',
	],
	[
	  '0','parent 0',
	  '1970-01-01 00:00:00','infinity',
	  tuples[0]['tt_start'], tuples[0]['tt_stop'],
	  '0', '1',
	],
	[
	  '0','parent 0',
	  '-infinity','1960-01-01 00:00:00',
	  tuples[2]['tt_start'], 'infinity',
	  '0', '2',
	],
	[
	  '0','PARENT 0',
	  '1960-01-01 00:00:00', '1970-01-01 00:00:00',
	  tuples[2]['tt_start'], 'infinity',
	  '0', '3',
	],
	[
	  '0','PARENT 0',
	  '1970-01-01 00:00:00', '1980-01-01 00:00:00',
	  tuples[2]['tt_start'], 'infinity',
	  '0', '5',
	],
	[
	  '0','parent 0',
	  '1980-01-01 00:00:00', 'infinity',
	  tuples[2]['tt_start'], 'infinity',
	  '0', '4',
	],
      ]
#      expected.each do |tuple|
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end

  puts ''
  tuples.size.times do |i|
    tuples[i].size.times do |j|
      puts "expected[#{i}][#{j}] == tuples[#{i}][#{j}] ? #{expected[i][j] == tuples[i][j]}"
      puts "#{expected[i][j]} == #{tuples[i][j]} ? #{expected[i][j] == tuples[i][j]}"
    end
  end
end

#exit
      assert tuples.sort == expected.sort
    end

    def test_H_warp
      @parent.transaction do
	@parent.seq_insert [
	  [0,'parent 0','-infinity','2002-01-01'],
	  [0,'parent 0','2002-01-01','infinity'],
	]
      end
      @child.transaction do
	@child.seq_insert [
	  [0,0,'child 0','-infinity','2002-01-01'],
	  [0,0,'child 0','2002-01-01','infinity'],
	]
      end
      @grandchild.transaction do
	@grandchild.seq_insert [
	  [0,0,'grandchild 0','-infinity','2002-01-01'],
	  [0,0,'grandchild 0','2002-01-01','infinity'],
	]
      end

      assert_no_exception do
	@parent.transaction do
	  @parent.warp 'epoch'
	end
      end

      #puts @parent
      #puts @child
      #puts @grandchild
#exit

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','2002-01-01 00:00:00',
	  tuples[0]['tt_start'], tuples[0]['tt_stop'],
	  '0', '0',
	],
	[
	  '0','parent 0',
	  '2002-01-01 00:00:00','infinity',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '1',
	],
	[
	  '0','parent 0',
	  '1970-01-01 00:00:00','2002-01-01 00:00:00',
	  tuples[2]['tt_start'], 'infinity',
	  '0', '2',
	],
      ]
#      expected.taint
#      expected.each do |tuple|
#	tuple.taint
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

#puts ''
#tuples.size.times do |i|
#puts "#{i}"
#puts tuples[i] == expected[i]
#  tuples[0].size.times do |j|
#    puts "expected[#{i}][#{j}] == tuples[#{i}][#{j}] ? #{expected[i][j] == tuples[i][j]}"
#    puts "#{expected[i][j]} == #{tuples[i][j]} ? #{expected[i][j] == tuples[i][j]}"
#  end
#end
if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort
    end

    def test_I_seq_push

      assert_no_exception do
	@parent.seq_push [0,'parent 0']
	@parent.seq_push [0,'Parent 0','1970-01-01 00:00:00']
	@parent.seq_push [0,'PArent 0','1980-01-01 00:00:00']
	@parent.seq_push [0,'PARent 0','1990-01-01 00:00:00']
      end


      @parent.truncate
      assert_no_exception do
	@parent.seq_push [0,'parent 0','-infinity','infinity']
      end

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','infinity',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '0',
	],
      ]
#      expected.taint
#      expected.each do |tuple|
#	tuple.taint
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}


if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort

      @parent.truncate

      assert_no_exception do
	@parent.seq_push [0,'parent 0','-infinity',]
      end

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','infinity',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '0',
	],
      ]
#      expected.taint
#      expected.each do |tuple|
#	tuple.taint
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort
    end

    def test_J_seq_push
      assert_no_exception do
	@parent.seq_push [0,'parent 0','-infinity','epoch']
	@parent.seq_push [0,'PARENT 0','epoch','infinity']
      end

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','1970-01-01 00:00:00',
	  tuples[0]['tt_start'], 'infinity',
	  '0', '0',
	],
	[
	  '0','PARENT 0',
	  '1970-01-01 00:00:00', 'infinity',
	  tuples[1]['tt_start'], 'infinity',
	  '0', '1',
	],
      ]
#      expected.taint
#      expected.each do |tuple|
#	tuple.taint
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort
    end

    def test_K_seq_push
      assert_no_exception do
	@parent.transaction do
	  @parent.seq_push [0,'parent 0','-infinity']
	  @parent.seq_push [0,'Parent 0','epoch']
	  @parent.seq_push [0,'PArent 0','1980-01-01']
	  @parent.seq_push [0,'PARent 0','1990-01-01']
	  @parent.seq_push [0,'PAREnt 0','2000-01-01']
	  @parent.seq_push [0,'PARENt 0','2001-01-01']
	  @parent.seq_push [0,'PARENT 0','2002-01-01']
	end
      end

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','infinity',
	  tuples[0]['tt_start'], tuples[0]['tt_stop'],
	  '0', '0',
	],
	[
	  '0','parent 0',
	  '-infinity','1970-01-01 00:00:00',
	  tuples[0]['tt_stop'], 'infinity',
	  '0', '1',
	],
	[
	  '0','Parent 0',
	  '1970-01-01 00:00:00', 'infinity',
	  tuples[0]['tt_stop'], tuples[0]['tt_stop'],
	  '0', '2',
	],
	[
	  '0','Parent 0',
	  '1970-01-01 00:00:00', '1980-01-01 00:00:00',
	  tuples[0]['tt_stop'], 'infinity',
	  '0', '3',
	],
	[
	  '0','PArent 0',
	  '1980-01-01 00:00:00', 'infinity',
	  tuples[0]['tt_stop'], tuples[0]['tt_stop'],
	  '0', '4',
	],
	[
	  '0','PArent 0',
	  '1980-01-01 00:00:00', '1990-01-01 00:00:00',
	  tuples[0]['tt_stop'], 'infinity',
	  '0', '5',
	],
	[
	  '0','PARent 0',
	  '1990-01-01 00:00:00', 'infinity',
	  tuples[0]['tt_stop'], tuples[0]['tt_stop'],
	  '0', '6',
	],
	[
	  '0','PARent 0',
	  '1990-01-01 00:00:00', '2000-01-01 00:00:00',
	  tuples[0]['tt_stop'], 'infinity',
	  '0', '7',
	],
	[
	  '0','PAREnt 0',
	  '2000-01-01 00:00:00', 'infinity',
	  tuples[0]['tt_stop'], tuples[0]['tt_stop'],
	  '0', '8',
	],
	[
	  '0','PAREnt 0',
	  '2000-01-01 00:00:00', '2001-01-01 00:00:00',
	  tuples[0]['tt_stop'], 'infinity',
	  '0', '9',
	],
	[
	  '0','PARENt 0',
	  '2001-01-01 00:00:00', 'infinity',
	  tuples[0]['tt_stop'], tuples[0]['tt_stop'],
	  '0', '10',
	],
	[
	  '0','PARENt 0',
	  '2001-01-01 00:00:00', '2002-01-01 00:00:00',
	  tuples[0]['tt_stop'], 'infinity',
	  '0', '11',
	],
	[
	  '0','PARENT 0',
	  '2002-01-01 00:00:00', 'infinity',
	  tuples[0]['tt_stop'], 'infinity',
	  '0', '12',
	],
      ]
#      expected.taint
#      expected.each do |tuple|
#	tuple.taint
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort
    end

    def test_L_ri_violators
      sql = <<-sql
	insert into parent
	  values (0,'parent 0','-infinity','epoch','now','infinity',0);
	insert into parent
	  values (0,'parent 0','1960-01-01','1980-01-01','now','infinity',0);
      
	insert into child
	  values (0,0,'child 0','-infinity','epoch','now','infinity',0);
      sql
      $pgconn.exec sql

      violators = @parent.ri_violators

      assert violators['pk'].size == 2 

      violators = @child.ri_violators

      assert violators['fk'].size == 1
    end


    def test_L_coalesce
      @parent.transaction do
	@parent.seq_insert [
	  [0,'parent 0','-infinity','1960-01-01'],
	  [0,'parent 0','1960-01-01','1970-01-01'],
	  [1,'parent 1','-infinity','1960-01-01'],
	  [1,'parent 1','1960-01-01','1970-01-01'],
	  [0,'parent 0','1980-01-01','1990-01-01'],
	  [0,'parent 0','1990-01-01','2000-01-01'],
	  [0,'parent 0','2000-01-01','infinity'],
	  [2,'parent 2','-infinity','infinity'],
	  [1,'parent 1','1970-01-01','infinity'],
	]
      end

#puts @parent

    @parent.coalesce

#puts @parent
#exit

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','1970-01-01 00:00:00',
	  tuples[0]['tt_start'], 'infinity',
	  '0', tuples[0]['btid'],
	],
	[
	  '0','parent 0',
	  '1980-01-01 00:00:00', 'infinity',
	  tuples[1]['tt_start'], 'infinity',
	  '0', tuples[1]['btid'],
	],
	[
	  '1','parent 1',
	  '-infinity', 'infinity',
	  tuples[2]['tt_start'], 'infinity',
	  '1', tuples[2]['btid'],
	],
	[
	  '2','parent 2',
	  '-infinity', 'infinity',
	  tuples[3]['tt_start'], 'infinity',
	  '2', tuples[3]['btid'],
	],
      ]
#      expected.taint
#      expected.each do |tuple|
#	tuple.taint
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort

    end

    def test_M_coalesce

      @parent.coalesce

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
      ]
#      expected.taint
#      expected.each do |tuple|
#	tuple.taint
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort
    end

    def test_N_coalesce
      @parent.transaction do
	@parent.seq_insert [
	  [0,'parent 0','-infinity','1960-01-01'],
	  [0,'parent 0','1960-01-01','1970-01-01'],
	]
      end

      @parent.coalesce

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','1970-01-01 00:00:00',
	  tuples[0]['tt_start'], 'infinity',
	  '0', tuples[0]['btid'],
	],
      ]
#      expected.taint
#      expected.each do |tuple|
#	tuple.taint
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}


if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort

    end

    def test_O_coalesce
      @parent.transaction do
	@parent.seq_insert [
	  [0,'parent 0','-infinity','1960-01-01'],
	]
      end

      @parent.coalesce

      tuples = @parent.select 'order by btpk, tt_start, vt_begin'

      expected = 
      [ 
	[
	  '0','parent 0',
	  '-infinity','1960-01-01 00:00:00',
	  tuples[0]['tt_start'], 'infinity',
	  '0', tuples[0]['btid'],
	],
      ]
#      expected.taint
#      expected.each do |tuple|
#	tuple.taint
#	tuple.each do |cell|
#	  cell.taint
#	end
#      end
      tuples.map {|tuple| tuple.map {|cell| cell.untaint}}

if $verbose
      puts "\n\n" 
      puts 'EXPECTED'
      expected.each do |tuple|
	puts tuple.inspect
      end
      puts 'ACTUAL'
      tuples.each do |tuple|
	puts tuple.inspect
      end
end

      assert tuples.sort == expected.sort
    end


    def populate
      @parent.transaction do
	@parent.seq_insert [
	  [0,'parent 0','-infinity','epoch'],
	  [0,'parent 0','epoch','infinity'],
	]
      end
      @child.transaction do
	@child.seq_insert [
	  [0,0,'child 0','-infinity','epoch'],
	  [0,0,'child 0','epoch','infinity'],
	]
      end
      @grandchild.transaction do
	@grandchild.seq_insert [
	  [0,0,'grandchild 0','-infinity','epoch'],
	  [0,0,'grandchild 0','epoch','infinity'],
	]
      end
    end
  end
end




RUNIT::CUI::TestRunner.run(BtPgsql::TestSchema.suite)

$pgconn.close




# we begin by setting up the required tables, and populating them
BEGIN {
  unless ARGV[0]
    require 'postgres'

    pghost    = nil
    pgport    = nil
    pgoptions = nil
    pgtty     = nil
    dbname    = 'btpgsql_unit_test' 
    login     = nil
    passwd    = nil



    # create the database 'btpgsql_unit_test'

    pgconn = PGconn.new

    begin
      res = pgconn.exec "drop database #{dbname}"
      res.clear
    rescue
    end
    res = pgconn.exec "create database #{dbname}"
    res.clear
    pgconn.close


    # connect to 'btpgsql_unit_test'
    pgconn = PGconn.new pghost,pgport,pgoptions,
			 pgtty,dbname,login,passwd

    # set up the bi-temporal support relations
    sql = (IO.readlines (File.dirname (__FILE__) << File::SEPARATOR << 'btschema.sql')).to_s

    sql.gsub! %r{--.*$}, '' # kill comments
    sql.gsub! %r{\n}, ' '
    sql.split (%r{;}).each do |statement|
      #puts "#{ statement }"
      begin
	res = pgconn.exec statement 
	res.clear
      rescue => pgerror
	raise pgerror unless pgerror.to_s =~ /does not exist/i
      end
    end

    # insert the data specific to this test
    sql = (IO.readlines (File.dirname (__FILE__) << File::SEPARATOR << 'btpgsql.sql')).to_s

# TODO - rename this btpgsql_unit_test

    sql.gsub! %r{--.*$}, '' # kill comments
    sql.gsub! %r{\n}, ' '
    sql.split (%r{;}).each do |statement|
      #puts "#{ statement }"
      begin
	res = pgconn.exec statement 
	res.clear
      rescue => pgerror
	raise pgerror unless pgerror.to_s =~ /does not exist/i
      end
    end

    pgconn.close
  end
}

# we end by blowing away the database 
END {
  unless ARGV[0]
    begin
      $pgconn.close
    rescue
    end
    dbname    = 'btpgsql_unit_test' 
    pgconn = PGconn.new
    begin
      res = pgconn.exec "drop database #{dbname}"
    rescue => pgerror
      raise pgerror unless pgerror.to_s =~ /does not exist/i
    end
    res.clear
    pgconn.close
  end
}
