#! /usr/bin/ruby -w

#=================================================================================================
# Test cases of Villa for Ruby
#                                                       Copyright (C) 2000-2005 Mikio Hirabayashi
# This file is part of QDBM, Quick Database Manager.
# QDBM is free software; you can redistribute it and/or modify it under the terms of the GNU
# Lesser General Public License as published by the Free Software Foundation; either version
# 2.1 of the License or any later version.  QDBM is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
# details.
# You should have received a copy of the GNU Lesser General Public License along with QDBM; if
# not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# 02111-1307 USA.
#=================================================================================================


require 'villa'


# main routine
def main()
  $0.gsub!(/.*\//, "")
  (ARGV.length >= 1) || usage()
  if(ARGV[0] == "write")
    rv = runwrite()
  elsif(ARGV[0] == "read")
    rv = runread()
  elsif(ARGV[0] == "misc")
    rv = runmisc()
  else
    usage()
  end
  return rv
end


# print the usage and exit
def usage()
  printf(STDERR, "%s: test cases for Villa for Ruby\n", $0)
  printf(STDERR, "\n")
  printf(STDERR, "usage:\n")
  printf(STDERR, "  %s write name rnum\n", $0)
  printf(STDERR, "  %s read name\n", $0)
  printf(STDERR, "  %s misc name\n", $0)
  printf(STDERR, "\n")
  exit(1)
end


# parse arguments of write command
def runwrite()
  name = nil
  rnum = -1
  i = 1
  while(i < ARGV.length)
    if(!name && ARGV[i] =~ /^-/)
      usage()
    elsif(!name)
      name = ARGV[i]
    elsif(rnum < 0)
      rnum = ARGV[i].to_i()
    else
      usage()
    end
    i += 1
  end
  (name && rnum > 0) || usage()
  dowrite(name, rnum)
  return 0
end


# parse arguments of read command
def runread()
  name = nil
  i = 1
  while(i < ARGV.length)
    if(!name && ARGV[i] =~ /^-/)
      usage()
    elsif(!name)
      name = ARGV[i]
    else
      usage()
    end
    i += 1
  end
  (name) || usage()
  doread(name)
  return 0
end


# parse arguments of misc command
def runmisc()
  name = nil
  i = 1
  while(i < ARGV.length)
    if(!name && ARGV[i] =~ /^-/)
      usage()
    elsif(!name)
      name = ARGV[i]
    else
      usage()
    end
    i += 1
  end
  (name) || usage()
  domisc(name)
  return 0
end


# perform write command
def dowrite(name, rnum)
  printf("<Writing Test>\n  name=%s  rnum=%d\n\n", name, rnum)
  villa = nil
  begin
    # open a database
    villa = Villa::new(name, Villa::OWRITER | Villa::OCREAT | Villa::OTRUNC)
    # loop for each record
    STDOUT.sync = true
    1.upto(rnum) do |i|
      buf = sprintf("%08d", i)
      # store a record
      villa.put(buf, buf)
      # print progression
      if(rnum > 250 && i % (rnum / 250) == 0)
        print(".")
        if(i == rnum || i % (rnum / 10) == 0)
          printf(" (%08d)\n", i)
        end
      end
    end
  rescue
    printf("%s: %s: %s\n", $0, name, $!)
    return 1
  ensure
    begin
      # close the database
      (villa) && villa.close()
    rescue
      return 1
    end
  end
  printf("ok\n\n")
  return 0
end


# perform read command
def doread(name)
  printf("<Reading Test>\n  name=%s\n\n", name)
  villa = nil
  begin
    # open a database
    villa = Villa::new(name)
    # get the number of record
    rnum = villa.rnum()
    # loop for each record
    STDOUT.sync = true
    1.upto(rnum) do |i|
      buf = sprintf("%08d", i)
      # store a record
      villa.get(buf)
      # print progression
      if(rnum > 250 && i % (rnum / 250) == 0)
        print(".")
        if(i == rnum || i % (rnum / 10) == 0)
          printf(" (%08d)\n", i)
        end
      end
    end
  rescue
    printf("%s: %s: %s\n", $0, name, $!)
    return 1
  ensure
    begin
      # close the database
      (villa) && villa.close()
    rescue
      return 1
    end
  end
  printf("ok\n\n")
  return 0
end


# perform misc command
def domisc(name)
  loopnum = 500
  threadnum = 10
  printf("<Miscellaneous Test>\n  name=%s\n\n", name)
  villa = nil
  begin
    # open the database
    printf("Creating a database ... ")
    villa = Villa::open("casket", Villa::OWRITER | Villa::OCREAT | Villa::OTRUNC)
    printf("ok\n")
    # store records
    printf("Storing records ... ")
    1.upto(loopnum) do |i|
      buf =  sprintf("%08d", i)
      villa[buf] = buf
    end
    printf("ok\n")
    # retrieve records
    printf("Retrieving records ... ")
    1.upto(loopnum) do |i|
      buf =  sprintf("%08d", i)
      (villa[buf] == buf) || raise("key and value does not match")
    end
    printf("ok\n")
    # traverse records
    printf("Traversing records ... ")
    villa.each() do |key, val|
      (key == val) || raise("key and value does not match")
    end
    villa.keys()
    villa.values()
    printf("ok\n")
    # silent mode operations
    printf("Silent mode operations ... ")
    villa.silent = true
    villa.put("foo", "bar", Villa::DKEEP)
    villa.put("foo", "bar", Villa::DKEEP)
    villa.get("foo")
    villa.out("foo")
    villa.out("foo")
    villa.get("nil")
    villa.fetch("nil", "void");
    villa.keys()
    villa.values()
    printf("ok\n")
  rescue
    printf("%s: %s: %s\n", $0, name, $!)
    return 1
  ensure
    # close the database
    printf("Closing the database ... ")
    (villa) && villa.close()
    printf("ok\n")
  end
  # test iterator and threads
  printf("Processing with iterator, threads and transactions ... ")
  Villa::new("casket", Villa::OWRITER) do |villa|
    (villa.rnum() == loopnum) || raise("record number is invalid")
    villa.clear()
    threads = []
    1.upto(threadnum) do |i|
      t = Thread::new() do
        1.upto(loopnum) do |j|
          buf = sprintf("%08d", j)
          villa.put(buf, "*", Villa::DDUP)
        end
        villa.tranbegin()
        1.upto(loopnum) do |j|
          buf = sprintf("%08d", j)
          villa.put(buf, "*", Villa::DDUP)
        end
        villa.trancommit()
      end
      threads.push(t)
    end
    threads.each do |t|
      t.join()
    end
    1.upto(loopnum) do |i|
      buf = sprintf("%08d", i)
      (villa.vnum(buf) == threadnum * 2) || raise("thread writing is invalid")
    end
    (villa.index("*")) || raise("thread writing is invalid")
  end
  printf("ok\n")
  printf("all ok\n\n")
  return 0
end


# execute main
$0.gsub!(/.*\//, "")
exit(main())



# END OF FILE
