############################################################################### # # 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 unset -nocomplain byteArray; 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 unset -nocomplain byteArray; 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 ConflictValue 0\ OldValue 1 {"inserted: Alpha Bravo Charlie Delta Echo"} NewValue 1\ ConflictValue 1 TableName t1 NumberOfColumns 2\ OperationCode Update Indirect False PrimaryKeyColumns {[True, False]} OldValue\ 0 2 NewValue 0 ConflictValue 0 OldValue 1 {"inserted:\ Foxtrot Golf Hotel India Juliet"} NewValue 1 {"updated: Uniform Victor Whiskey\ X-ray Yankee"} ConflictValue 1 TableName t1 NumberOfColumns 2\ OperationCode Update Indirect False PrimaryKeyColumns {[True, False]} OldValue\ 0 3 NewValue 0 ConflictValue 0 OldValue 1 {"inserted:\ Kilo Lima Mike November Oscar"} NewValue 1 {"updated: Uniform Victor Whiskey\ X-ray Yankee"} ConflictValue 1 TableName t1 NumberOfColumns 2\ OperationCode Insert Indirect False PrimaryKeyColumns {[True, False]} OldValue\ 0 NewValue 0 4 ConflictValue 0 OldValue 1\ NewValue 1 {"inserted: Papa Quebec Romeo Sierra Tango"}\ ConflictValue 1 }} ############################################################################### 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] false set connection [getDbConnection] set session [$connection -alias CreateSession main] lappend result IsEnabled [$session IsEnabled] $session AttachTable null lappend result IsEnabled [$session IsEnabled] $session SetToDisabled lappend result IsEnabled [$session IsEnabled] makeSomeChanges $db [list insert] false lappend result IsEmpty [$session IsEmpty] unset -nocomplain byteArray; set byteArray null $session -alias CreateChangeSet byteArray set rawData [createByteArray [arrayToList byteArray]] object removeref $rawData lappend result Length [$rawData Length] $session SetToEnabled lappend result IsEnabled [$session IsEnabled] makeSomeChanges $db [list insert] false lappend result IsEmpty [$session IsEmpty] unset -nocomplain byteArray; 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 {IsEnabled\ True IsEnabled True IsEnabled False IsEmpty True Length 0 IsEnabled True\ IsEmpty False {TableName t1 NumberOfColumns 2 OperationCode Insert Indirect\ False PrimaryKeyColumns {[True, False]}}}} ############################################################################### runTest {test session-1.4 {session direct/indirect state} -setup { setupDb [set fileName session-1.4.db] cleanupSomeText } -body { createTheSchema $db makeSomeChanges $db [list insert] false set connection [getDbConnection] set session [$connection -alias CreateSession main] lappend result IsIndirect [$session IsIndirect] $session AttachTable null lappend result IsIndirect [$session IsIndirect] $session SetToIndirect lappend result IsIndirect [$session IsIndirect] makeSomeChanges $db [list insert] false lappend result IsEmpty [$session IsEmpty] unset -nocomplain byteArray; set byteArray null $session -alias CreateChangeSet byteArray set rawData [createByteArray [arrayToList byteArray]] object removeref $rawData $session SetToDirect lappend result IsIndirect [$session IsIndirect] makeSomeChanges $db [list insert] false lappend result IsEmpty [$session IsEmpty] unset -nocomplain byteArray; 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 \ {IsIndirect False IsIndirect False IsIndirect True IsEmpty False IsIndirect\ False IsEmpty False {TableName t1 NumberOfColumns 2 OperationCode Insert\ Indirect True 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