System.Data.SQLite
Artifact Content
Not logged in

Artifact 909056c3a8e84b6c50e5170d96b3cf27cd7f7501:


###############################################################################
#
# session.eagle --
#
# Written by Joe Mistachkin.
# Released to the public domain, use at your own risk!
#
###############################################################################

package require Eagle
package require Eagle.Library
package require Eagle.Test

runTestPrologue

###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

proc getSomeText { random count } {
  set items [list \
      Alpha Bravo Charlie Delta Echo Foxtrot Golf Hotel \
      India Juliet Kilo Lima Mike November Oscar Papa \
      Quebec Romeo Sierra Tango Uniform Victor Whiskey X-ray \
      Yankee Zulu]

  if {!$random} then {
    variable some_text_index

    if {![info exists some_text_index]} then {
      set some_text_index 0
    }
  }

  set length [llength $items]
  set result [list]

  for {set i 0} {$i < $count} {incr i} {
    if {$random} then {
      set item [lindex $items [expr {int(rand() * $length)}]]
    } else {
      set item [lindex $items $some_text_index]
      incr some_text_index

      if {$some_text_index >= $length} then {
        set some_text_index 0
      }
    }

    lappend result $item
  }

  return $result
}

###############################################################################

proc cleanupSomeText {} {
  variable some_text_index
  unset -nocomplain some_text_index
}

###############################################################################

proc forDisplay { object member } {
  set isArray false

  if {[isObjectHandle $object] && $object ne "null"} then {
    set value [object invoke -create -- $object $member]

    if {[isObjectHandle $value] && $value ne "null"} then {
      set isArray [object invoke -- $value GetType.IsArray]
    }
  } else {
    set value null
  }

  if {$isArray} then {
    return [object invoke -flags +NonPublic \
        -parametertypes Array System.Data.SQLite.HelperMethods \
        ToDisplayString $value]
  } else {
    return [object invoke -flags +NonPublic \
        System.Data.SQLite.HelperMethods ToDisplayString $value]
  }
}

###############################################################################

proc changeSetToString { changeSet includeValues } {
  set result [list]

  if {[isObjectHandle $changeSet] && $changeSet ne "null"} then {
    object foreach -alias item $changeSet {
      lappend result TableName [$item TableName]
      lappend result NumberOfColumns [$item NumberOfColumns]
      lappend result OperationCode [$item OperationCode]
      lappend result Indirect [$item Indirect]

      lappend result PrimaryKeyColumns \
          [forDisplay $item PrimaryKeyColumns]

      if {$includeValues} then {
        set numberOfColumns [$item NumberOfColumns]

        for {set index 0} {$index < $numberOfColumns} {incr index} {
          set oldValue [$item GetOldValue $index]

          lappend result OldValue $index \
              [forDisplay $oldValue GetObject]

          set newValue [$item GetNewValue $index]

          lappend result NewValue $index \
              [forDisplay $newValue GetObject]

          set conflictValue [$item GetConflictValue $index]

          lappend result ConflictValue $index \
              [forDisplay $conflictValue GetObject]
        }
      }
    }
  }

  return $result
}

###############################################################################

proc createTheSchema { db } {
  sql execute $db {
    CREATE TABLE t1(x INTEGER PRIMARY KEY, y TEXT);
  }
}

###############################################################################

proc makeSomeChanges { db types random {count 5} } {
  foreach type $types {
    switch -nocase -- $type {
      insert {
        set text [appendArgs "inserted: " [getSomeText $random $count]]

        sql execute $db {
          INSERT INTO t1(y) VALUES(?);
        } [list param1 String $text]
      }
      update {
        set text [appendArgs "updated: " [getSomeText $random $count]]

        sql execute $db {
          UPDATE t1 SET y = ? WHERE x NOT IN (
            (SELECT MIN(x) FROM t1), (SELECT MAX(x) FROM t1)
          );
        } [list param1 String $text]
      }
      delete {
        sql execute $db {
          DELETE FROM t1 WHERE x = (SELECT MIN(x) FROM t1);
        }
      }
    }
  }
}

###############################################################################

proc getChangeSetFileName { {suffix ""} } {
  return [file join \
      [getTemporaryDirectory] [appendArgs changes $suffix .bin]]
}

###############################################################################

proc arrayToList { varName } {
  set result [list]

  upvar 1 $varName array

  if {[array exists array]} then {
    foreach name [lsort -integer [array names array]] {
      lappend result $array($name)
    }
  }

  return $result
}

###############################################################################

proc createByteArray { list } {
  set length [llength $list]
  set result [object create -alias System.Byte\[\] $length]

  for {set index 0} {$index < $length} {incr index} {
    set element [lindex $list $index]
    set value [object invoke -create Byte Parse $element]
    $result SetValue $value $index
  }

  return $result
}

###############################################################################

runTest {test session-1.1 {basic session extension usage} -setup {
  setupDb [set fileName(0) session-1.1.db]

  set fileName(1) [getChangeSetFileName 1]
  set fileName(2) [getChangeSetFileName 2]

  cleanupSomeText
} -body {
  createTheSchema $db
  makeSomeChanges $db [list insert] true

  set connection [getDbConnection]

  set session [$connection -alias CreateSession main]
  $session AttachTable null

  makeSomeChanges $db [list insert update delete] true

  set byteArray null
  $session -alias CreateChangeSet byteArray
  set rawData [createByteArray [arrayToList byteArray]]
  object removeref $rawData

  set stream(1) [object create -alias \
      System.IO.FileStream $fileName(1) Create Write]

  $stream(1) Write $rawData 0 [$rawData Length]
  $stream(1) Flush; $stream(1) Close

  set stream(2) [object create -alias \
      System.IO.FileStream $fileName(2) Create Write]

  $session -alias CreateChangeSet $stream(2)
  $stream(2) Flush; $stream(2) Close

  list [expr {[file size $fileName(1)] > 0}] \
      [string equal [readFile $fileName(1)] [readFile $fileName(2)]]
} -cleanup {
  cleanupSomeText

  unset -nocomplain stream rawData byteArray session

  freeDbConnection

  unset -nocomplain connection

  cleanupFile $fileName(2)
  cleanupFile $fileName(1)

  cleanupDb $fileName(0)

  unset -nocomplain db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite SQLiteInterop\
defineConstant.System.Data.SQLite.INTEROP_SESSION_EXTENSION} -result \
{True True}}

###############################################################################

runTest {test session-1.2 {session change set enumeration} -setup {
  setupDb [set fileName session-1.2.db]

  cleanupSomeText
} -body {
  createTheSchema $db
  makeSomeChanges $db [list insert insert insert] false

  set connection [getDbConnection]

  set session [$connection -alias CreateSession main]
  $session AttachTable null

  makeSomeChanges $db [list insert update delete] false

  set byteArray null
  $session -alias CreateChangeSet byteArray
  set rawData [createByteArray [arrayToList byteArray]]
  object removeref $rawData

  set changeSet(1) [$connection -alias CreateChangeSet $rawData]

  changeSetToString $changeSet(1) true
} -cleanup {
  cleanupSomeText

  unset -nocomplain oldValue newValue conflictValue
  unset -nocomplain changeSet rawData byteArray session

  freeDbConnection

  unset -nocomplain connection

  cleanupDb $fileName

  unset -nocomplain db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite SQLiteInterop\
defineConstant.System.Data.SQLite.INTEROP_SESSION_EXTENSION} -result {TableName\
t1 NumberOfColumns 2 OperationCode Delete Indirect False PrimaryKeyColumns\
{[True, False]} OldValue 0 1 NewValue 0 <nullObject> ConflictValue 0\
<nullObject> OldValue 1 {"inserted: Alpha Bravo Charlie Delta Echo"} NewValue 1\
<nullObject> ConflictValue 1 <nullObject> TableName t1 NumberOfColumns 2\
OperationCode Update Indirect False PrimaryKeyColumns {[True, False]} OldValue\
0 2 NewValue 0 <nullObject> ConflictValue 0 <nullObject> OldValue 1 {"inserted:\
Foxtrot Golf Hotel India Juliet"} NewValue 1 {"updated: Uniform Victor Whiskey\
X-ray Yankee"} ConflictValue 1 <nullObject> TableName t1 NumberOfColumns 2\
OperationCode Update Indirect False PrimaryKeyColumns {[True, False]} OldValue\
0 3 NewValue 0 <nullObject> ConflictValue 0 <nullObject> OldValue 1 {"inserted:\
Kilo Lima Mike November Oscar"} NewValue 1 {"updated: Uniform Victor Whiskey\
X-ray Yankee"} ConflictValue 1 <nullObject> TableName t1 NumberOfColumns 2\
OperationCode Insert Indirect False PrimaryKeyColumns {[True, False]} OldValue\
0 <nullObject> NewValue 0 4 ConflictValue 0 <nullObject> OldValue 1\
<nullObject> NewValue 1 {"inserted: Papa Quebec Romeo Sierra Tango"}\
ConflictValue 1 <nullObject>}}

###############################################################################

runTest {test session-1.3 {session enabled/disabled state} -setup {
  setupDb [set fileName session-1.3.db]

  cleanupSomeText
} -body {
  createTheSchema $db
  makeSomeChanges $db [list insert insert insert] false

  set connection [getDbConnection]

  set session [$connection -alias CreateSession main]
  lappend result [$session IsEnabled]

  $session AttachTable null
  lappend result [$session IsEnabled]

  $session SetToDisabled
  lappend result [$session IsEnabled]

  makeSomeChanges $db [list insert update delete] false

  set byteArray null
  $session -alias CreateChangeSet byteArray
  set rawData [createByteArray [arrayToList byteArray]]
  object removeref $rawData

  lappend result [$rawData Length]

  $session SetToEnabled
  lappend result [$session IsEnabled]

  makeSomeChanges $db [list insert update delete] false

  set byteArray null
  $session -alias CreateChangeSet byteArray
  set rawData [createByteArray [arrayToList byteArray]]
  object removeref $rawData

  set changeSet(1) [$connection -alias CreateChangeSet $rawData]
  lappend result [changeSetToString $changeSet(1) false]
} -cleanup {
  cleanupSomeText

  unset -nocomplain oldValue newValue conflictValue
  unset -nocomplain result changeSet rawData byteArray session

  freeDbConnection

  unset -nocomplain connection

  cleanupDb $fileName

  unset -nocomplain db fileName
} -constraints {eagle command.object monoBug28 command.sql compile.DATA SQLite\
System.Data.SQLite SQLiteInterop\
defineConstant.System.Data.SQLite.INTEROP_SESSION_EXTENSION} -result {True True\
False 0 True {TableName t1 NumberOfColumns 2 OperationCode Delete Indirect\
False PrimaryKeyColumns {[True, False]} TableName t1 NumberOfColumns 2\
OperationCode Update Indirect False PrimaryKeyColumns {[True, False]} TableName\
t1 NumberOfColumns 2 OperationCode Update Indirect False PrimaryKeyColumns\
{[True, False]} TableName t1 NumberOfColumns 2 OperationCode Insert Indirect\
False PrimaryKeyColumns {[True, False]}}}}

###############################################################################

rename createByteArray ""
rename arrayToList ""
rename getChangeSetFileName ""
rename makeSomeChanges ""
rename createTheSchema ""
rename changeSetToString ""
rename forDisplay ""
rename cleanupSomeText ""
rename getSomeText ""

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue