require 'ibm_db2'
require 'stringio'
require 'test/unit'

unless ENV['DB2INSTANCE']
  puts 'Database environment is not set up'
  puts 'Run ". /home/db2inst1/sqllib/db2profile" and retry'
  exit -1
end

Dir['tests/test_*.rb'].each do |file|
  next if file =~ /002/ # configuration error?
  next if file =~ /048/ # files don't match
  next if file =~ /066/ # fetch object
  next if file =~ /144/ # safe_mode / PARAM_FILE
  next if file =~ /146/ # stored procedures
  next if file =~ /157/ # deadlock?
  next if file =~ /200/ # statement execute failed
  next if file =~ /201/ # statement execute failed
  next if file =~ /220/ # persistent connections
  next if file =~ /221/ # persistent connections
  next if file =~ /260/ # fetch object
  next if file =~ /261/ # fetch object
  next if file =~ /300/ # server_info
  next if file =~ /310/ # client_info
  require file
end

module Config
  require 'yaml'
  configdata = open('config.yml') {|f| YAML::parse f}
  configdata['connection'].children_with_index.each {|node,name| 
    define_method(name) {node.value}
  }

  alias db database
  alias username user
end

class TestIbmDb2 < Test::Unit::TestCase
  include Config

  ####################################################################
  #                         test support                             #
  ####################################################################

  def setup
    prepconn = DB2::connect database, user, password

    # Drop the test view, in case it exists
    drop = 'DROP TABLE anime_cat'
    result = DB2::exec prepconn, drop rescue nil
    
    # Drop the test table, in case it exists
    drop = 'DROP TABLE animals'
    result = DB2::exec prepconn, drop rescue nil
    
    # Create the test table
    create = 'CREATE TABLE animals (id INTEGER, breed VARCHAR(32), name CHAR(16), weight DECIMAL(7,2))'
    result = DB2::exec prepconn, create
    
    # Populate the test table
    animals = [
        [0, 'cat', 'Pook', 3.2],
        [1, 'dog', 'Peaches', 12.3],
        [2, 'horse', 'Smarty', 350.0],
        [3, 'gold fish', 'Bubbles', 0.1],
        [4, 'budgerigar', 'Gizmo', 0.2],
        [5, 'goat', 'Rickety Ride', 9.7],
        [6, 'llama', 'Sweater', 150]
    ]
    
    insert = 'INSERT INTO animals (id, breed, name, weight) VALUES (?, ?, ?, ?)'
    stmt = DB2::prepare prepconn, insert
    if stmt
        for animal in animals
            result = DB2::execute stmt, animal
        end
    end
    
    # Create test view
    DB2::exec prepconn, 'CREATE VIEW anime_cat AS
        SELECT name, breed FROM animals
        WHERE id = 0'

    DB2::close prepconn
  end

  def prepare_t_string conn
    DB2::exec conn, "drop table t_string" rescue nil
    DB2::exec conn, "create table t_string(a integer, b double, c varchar(100))"
  end

  def teardown
    GC::start
  end

  def capture 
    stdout = $stdout
    buffer = $stdout = StringIO.new
    yield
    $stdout = stdout
    buffer.rewind
    buffer.read.strip
  end

  def expected
    open(caller[1].split(':')[0]) {|f| f.read}.split("\n__END__\n",2)[-1].strip
  end

  def assert_expect &block
    assert_equal expected, capture(&block)
  end

  def assert_expectf &block
    pattern = expected
    '\.[]*?+|(){}^$/'.each_byte { |c| pattern.gsub! c.chr, "\\#{c.chr}" }
    pattern.gsub! '%s', '.*?'
    pattern.gsub! "\n", '\n'

    assert_match Regexp.new('^' + pattern + '$'), capture(&block)
  end

  ####################################################################
  #                        PHP to Ruby mappings                      #
  ####################################################################

  def _GET
    {}
  end

  def isset var
    (var != nil)
  end

  def header data
  end

  NULL = nil

  def var_dump var, indent=''
    case var
    when String:
      puts "#{indent}string(#{var.length}) #{var.inspect}"
    when Fixnum:
      puts "#{indent}int(#{var})"
    when Array:
      puts "#{indent}array(#{var.length}) {"
      var.each_with_index { |child,i|
        puts "#{indent}  [#{i}]=>"
        var_dump child, "#{indent}  "
      }
      puts "#{indent}}"
    when DB2::Connection:
      puts "#{indent}resource(%d) of type (conn struct)"
    when TrueClass:
      puts "#{indent}bool(true)"
    when FalseClass:
      puts "#{indent}bool(false)"
    when NilClass:
      puts "#{indent}NULL"
    else
      puts "#{indent}#{var.class} #{var.inspect}"
    end
  end

  def print_r var
    case var
    when Array:
      puts "Array"
      puts "("
      var.each_with_index { |child,i|
        puts "    [#{i}] => #{child}"
      }
      puts ")"
    when DB2::Statement:
      puts "Resource id #%d"
    else
      puts "#{var.class} #{var.inspect}"
    end
  end

end
