# 2007 August 23
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    May you do good and not evil.
#    May you find forgiveness for yourself and forgive others.
#    May you share freely, never taking more than you give.
#
#***********************************************************************
#
# $Id: crash3.test,v 1.1 2007/08/23 11:07:10 danielk1977 Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

ifcapable !crashtest {
  finish_test
  return
}

proc do_test2 {name tcl res1 res2} {
  set script [subst -nocommands {
    do_test $name {
      set res1 {$res1}
      set res2 {$res2}
      set res [eval {$tcl}]
      if {[set res] eq [set res1] || [set res] eq [set res2]} {
        set res "{[set res1]} or {[set res2]}"
      }
      set res
    } {{$res1} or {$res2}}
  }]
  uplevel $script
}

# Each iteration of the following loop sets up the database to contain
# the following schema and data:
#
#    CREATE TABLE abc(a, b, c);
#    INSERT INTO abc VALUES(1, 2, 3);
#
# Then execute the SQL statement, scheduling a crash for part-way through
# the first sync() of either the database file or the journal file (often
# the journal file is not required - meaning no crash occurs).
#
# After the crash (or absence of a crash), open the database and 
# verify that:
#
#   * The integrity check passes, and
#   * The contents of table abc is either {1 2 3} or the value specified
#     to the right of the SQL statement below.
#
# The procedure is repeated 10 times for each SQL statement. Five times
# with the crash scheduled for midway through the first journal sync (if 
# any), and five times with the crash midway through the database sync.
#
set tn 1
foreach {sql res2} [list \
  {INSERT INTO abc VALUES(4, 5, 6)}                    {1 2 3 4 5 6} \
  {DELETE FROM abc}                                    {}    \
  {INSERT INTO abc SELECT * FROM abc}                  {1 2 3 1 2 3} \
  {UPDATE abc SET a = 2}                               {2 2 3}       \
  {INSERT INTO abc VALUES(4, 5, randstr(1000,1000))}   {n/a} \
  {CREATE TABLE def(d, e, f)}                          {n/a} \
] {
  for {set ii 0} {$ii < 10} {incr ii} {

    db close
    file delete -force test.db test.db-journal
    sqlite3 db test.db
    do_test crash3-1.$tn.1 {
      execsql {
        BEGIN;
        CREATE TABLE abc(a, b, c);
        INSERT INTO abc VALUES(1, 2, 3);
        COMMIT;
      }
    } {}
    db close
  
    set crashfile test.db
    if {($ii%2)==0} { append crashfile -journal }
    set rand "SELECT randstr($tn,$tn);"
    do_test crash3-1.$tn.2 [subst {
      crashsql -file $crashfile -char atomic {$rand $sql}
      sqlite3 db test.db
      execsql { PRAGMA integrity_check; }
    }] {ok}
  
    do_test2 crash3-1.$tn.3 {
      execsql { SELECT * FROM abc }
    } {1 2 3} $res2

    incr tn
  }
}

finish_test

