#
# Copyright (c) 2004-2012, Ashok P. Nadkarni
# All rights reserved.
#
# See the file LICENSE for license

# This file contains tests for commands from the eventlog.tcl

package require tcltest
eval tcltest::configure $argv

source [file join [file dirname [info script]] testutil.tcl]
load_twapi_package twapi_eventlog

# TBD - notes for testing
if {0} {
(twapi) 61 % set hpub [evt_open_publisher_metadata Microsoft-Windows-EventSystem]
5 EVT_HANDLE
(twapi) 62 % evt_publisher_events_metadata $hpub -id -messageid
{-id 512 -messageid 512} {-id 2147488002 -messageid 2147488002} {-id 2147488003 -messageid 2147488003} {-id 2147488004 -messageid 2147488004} {-id 2147488005 -messageid 2147488005} {-id 2147488006 -messageid 2147488006} {-id 2147488007 -messageid 2147488007} {-id 2147488009 -messageid 2147488009} {-id 2147488010 -messageid 2147488010} {-id 3221230081 -messageid 3221230081} {-id 3221230082 -messageid 3221230082} {-id 3221230083 -messageid 3221230083} {-id 3221230084 -messageid 3221230084} {-id 3221230085 -messageid 3221230085} {-id 3221230086 -messageid 3221230086} {-id 3221230087 -messageid 3221230087} {-id 3221230088 -messageid 3221230088} {-id 3221230089 -messageid 3221230089} {-id 3221230090 -messageid 3221230090} {-id 3221230091 -messageid 3221230091} {-id 3221230092 -messageid 3221230092} {-id 3221230093 -messageid 3221230093} {-id 3221230094 -messageid 3221230094} {-id 3221230095 -messageid 3221230095} {-id 3221230096 -messageid 3221230096} {-id 1073746449 -messageid 1073746449}
(twapi) 63 % evt_format_publisher_message $hpub 512
The substitution string for insert index (%1) could not be found.
(twapi) 64 % evt_format_publisher_message $hpub 512 -values $ubuf
86400
(twapi) 65 % evt_format_publisher_message $hpub 2147488004
The substitution string for insert index (%1) could not be found.
(twapi) 66 % evt_format_publisher_message $hpub 512 -values $ubuf
86400
(twapi) 67 % evt_format_publisher_message $hpub 2147488004 -values $ubuf
The COM+ Event System failed to create an instance of the subscriber SuppressDuplicateDuration.  Software\Microsoft\EventSystem\EventLog returned HRESULT 86400.
(twapi) 68 % evt_get_event_system_fields $hevt
-providername Microsoft-Windows-EventSystem -providerguid {{899DAACE-4868-4295-AFCD-9EB8FB497561}} -eventid 4625 -qualifiers 16384 -level 4 -task 0 -opcode 0 -keywords {} -timecreated 129146191710000000 -eventrecordid 4 -activityid {} -relatedactivityid {} -processid 0 -threadid 0 -channel Application -computer 37L4247E20-12 -userid {} -version 0
(twapi) 69 % format %x 4625
1211
(twapi) 70 % format %x 2147488004
80001104
(twapi) 71 % format %x 1073746449
40001211
(twapi) 72 % evt_format_publisher_message $hpub 4625 -values $ubuf
the message resource is present but the message is not found in the string/message table
(twapi) 73 % evt_format_publisher_message $hpub 0x40001211 -values $ubuf
The EventSystem sub system is suppressing duplicate event log entries for a duration of 86400 seconds.  The suppression timeout can be controlled by a REG_DWORD value named SuppressDuplicateDuration under the following registry key: HKLM\Software\Microsoft\EventSystem\EventLog.
(twapi) 74 % evt_format_publisher_message $hpub 0x40001211 -values $ubuf
The EventSystem sub system is suppressing duplicate event log entries for a duration of 86400 seconds.  The suppression timeout can be controlled by a REG_DWORD value named SuppressDuplicateDuration under the following registry key: HKLM\Software\Microsoft\EventSystem\EventLog.
(twapi) 74 % format %x 16384
4000


Above implies that the message lookup is done by using -qualifiers (16384)
field from event system fields as the top 16 bits of event id ? Or perhaps
the 4 comes from the level ?

}


#
# Set up system-specific constants that are used to match test results
namespace eval twapi::eventlog::test {
    namespace import ::tcltest::test
    ::tcltest::testConstraint win2k [twapi::min_os_version 5]
    ::tcltest::testConstraint win6 [twapi::min_os_version 6]
    variable testnum
    variable source
    variable type

    # Read the last entry from the specified event log
    proc get_last_event {source} {
        set hevl [twapi::eventlog_open -source $source]
        set event [lindex [twapi::eventlog_read $hevl -direction back] 0]
        twapi::eventlog_close $hevl
        return $event
    }

    proc verify_event {eventrec} {
        # TBD
        return
    }

    proc verify_winlog_event {e} {

        set messages {}
        foreach fld {
            -channel -taskname -message -providername -eventid -level -levelname -eventrecordid -computer -sid -timecreated
        } {
            if {![dict exists $e $fld]} {
                lappend messages "Field $fld missing from event"
            }
        }
        return $messages
    }

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

    # Monitoring test first !! Else Windows event log
    test eventlog_monitor-1.0 {
        Verify asynchronous monitoring of event log
    } -constraints {
        nt
    } -setup {
        patience eventlog_monitor-1.0
        set hevl [twapi::eventlog_open]
    } -body {
        # Note this test may sometimes fail because event log service
        # restricts frequency of notifications to 5 sec intervals
        # For this reason, we also test start and stop in a single test
        after 6000
        set hevm [twapi::eventlog_monitor_start $hevl {append ::_vwait_result}]
        after 1000;             # Let monitoring take effect
        twapi::eventlog_log "eventlog_monitor test message"
        set after_id [after 2000 {set ::_vwait_result timeout}]
        vwait ::_vwait_result
        after cancel $after_id
        if {$::_vwait_result ne "timeout"} {
            twapi::eventlog_monitor_stop $hevm
            twapi::eventlog_log "eventlog_monitor test message"
            # Wait at least 5 secs before logging one more message else
            # event monitor will not generate event for it anyway
            set after_if [after 6000 {set ::_vwait_result stopped}]
            vwait ::_vwait_result
            after cancel $after_id
        }
        set ::_vwait_result
    } -cleanup {
        twapi::eventlog_close $hevl
    } -result stopped

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

    test eventlog_open-1.0 {
        Open the eventlog for reading using defaults
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open]
        twapi::eventlog_close $hevl
    } -result ""
    
    test eventlog_open-1.1 {
        Open the eventlog of a specific source for reading
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open -source system]
        twapi::eventlog_close $hevl
    } -result ""

    test eventlog_open-1.2 {
        Open a backup eventlog
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open -source application]
        set backup [file join $::env(TEMP) twapi_events.bak]
        catch {file delete $backup}
        twapi::eventlog_backup $hevl $backup
        twapi::eventlog_close $hevl
        set hevl [twapi::eventlog_open -file $backup]
        twapi::eventlog_close $hevl
    } -result ""

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

    test eventlog_backup-1.0 {
        Back up the eventlog
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open -source application]
        set backup [file join $::env(TEMP) twapi_events.bak]
        catch {file delete $backup}
        twapi::eventlog_backup $hevl $backup
        twapi::eventlog_close $hevl
        file exists $backup
    } -result 1
    
    ################################################################

    test eventlog_clear-1.0 {
        Clear the event log
    } -constraints {
        nt systemmodificationok
    } -body {
        set hevl [twapi::eventlog_open -source application]
        twapi::eventlog_clear $hevl
        set count [twapi::eventlog_count $hevl]
        twapi::eventlog_close $hevl
        set count
    } -result 0

    test eventlog_clear-1.1 {
        Backup and clear the event log
    } -constraints {
        nt systemmodificationok
    } -body {
        set hevl [twapi::eventlog_open -source application]
        set backup [file join $::env(TEMP) twapi_events.bak]
        catch {file delete $backup}
        twapi::eventlog_clear $hevl -backup $backup
        set count [twapi::eventlog_count $hevl]
        twapi::eventlog_close $hevl
        expr {[file exists $backup] && ($count == 0)}
    } -result 1

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

    test eventlog_is_full-1.0 {
        Test if the eventlog is full using a read handle
    } -constraints {
        nt win2k
    } -body {
        set hevl [twapi::eventlog_open -source application]
        set full [twapi::eventlog_is_full $hevl]
        twapi::eventlog_close $hevl
        expr {$full == 0 || $full == 1}
    } -result 1

    test eventlog_is_full-1.1 {
        Test if the eventlog is full using a write handle
    } -constraints {
        nt win2k
    } -body {
        set hevl [twapi::eventlog_open -write]
        set full [twapi::eventlog_is_full $hevl]
        twapi::eventlog_close $hevl
        expr {$full == 0 || $full == 1}
    } -result 1

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

    test eventlog_oldest-1.0 {
        Get the oldest record number in the event log
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open]
        set oldest [twapi::eventlog_oldest $hevl]
        twapi::eventlog_close $hevl
        string is integer -strict $oldest
    } -result 1

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

    test eventlog_count-1.0 {
        Get the count of records in the event log
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open]
        set count [twapi::eventlog_count $hevl]
        twapi::eventlog_close $hevl
        string is integer -strict $count
    } -result 1

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

    test eventlog_close-1.0 {
        Close a read event log handle
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open]
        twapi::eventlog_close $hevl
        # Should generate error when closing
        catch {twapi::eventlog_close $hevl}
    } -result 1


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

    test eventlog_log-1.0 {
        Log a message to the default log
    } -constraints {
        nt
    } -body {
        twapi::eventlog_log "TWAPI test message"
        twapi::eventlog_format_message [get_last_event application]
    } -match glob -result  "*TWAPI test message"

    test eventlog_log-1.1 {
        Log a message to the application log
    } -constraints {
        nt
    } -body {
        twapi::eventlog_log "TWAPI Application log test message" -source application
        twapi::eventlog_format_message [get_last_event application]
    } -match glob -result  "*TWAPI Application log test message"

    test eventlog_log-1.2 {
        Log a message to the system log
    } -constraints {
        nt
    } -body {
        twapi::eventlog_log "TWAPI System log test message" -source system
        twapi::eventlog_format_message [get_last_event system]
    } -match glob -result  "*TWAPI System log test message"
    
    set testnum 0
    foreach source {application system} {
        foreach type {success error warning information} {
            test eventlog_log-2.[incr testnum] "Log a message of type $type to the $source log" -constraints {
                nt
            } -body {
                twapi::eventlog_log "TWAPI log $type message" -type $type -source $source
                array set event [get_last_event $source]
                set event(-type)
            } -result $type
        }
    }

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

    test eventlog_close_write_handle-1.0 {
        Close a write event log handle
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open -write]
        twapi::eventlog_close $hevl
        # Should generate error when closing
        catch {twapi::eventlog_close $hevl}
    } -result 1

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

    set testnum 0
    foreach source {application system} {
        foreach type {success error warning information} {
            test eventlog_write-1.[incr testnum] "Write a message of type $type to the $source log" -constraints {
                nt
            } -body {
                set hevl [twapi::eventlog_open -source $source -write]
                twapi::eventlog_write $hevl 1 -params [list "TWAPI log $type message"] -type $type
                twapi::eventlog_close $hevl
                set eventrec [get_last_event $source]
                expr {([twapi::kl_get $eventrec -type] == $type) &&
                      [string match "*TWAPI log $type message" [twapi::eventlog_format_message $eventrec]]}
            } -result 1
        }
    }

    test eventlog_write-2.0 {
        Verify -loguser option when writing to event log
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open -write]
        twapi::eventlog_write $hevl 1 -params [list "TWAPI log message with SID"] -loguser
        twapi::eventlog_close $hevl
        twapi::kl_get [get_last_event application] -sid
    } -result [name2sid $::env(USERNAME)]

    test eventlog_write-3.0 {
        Verify -data option with text when writing to event log
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open -write]
        twapi::eventlog_write $hevl 1 -params [list "TWAPI log message with data"] -data "SOME JUNK DATA"
        twapi::eventlog_close $hevl
        twapi::kl_get [get_last_event application] -data
    } -result "SOME JUNK DATA"

    test eventlog_write-3.1 {
        Verify -data option with binary data when writing to event log
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open -write]
        twapi::eventlog_write $hevl 1 -params [list "TWAPI log message with data"] -data [binary format h* abcdef]
        twapi::eventlog_close $hevl
        binary scan [twapi::kl_get [get_last_event application] -data] h* data
        set data
    } -result abcdef

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

    set testnum 0
    foreach source {application system security} {
        test eventlog_read-1.[incr testnum] "Read event log records from the $source log" -constraints {
            nt
        } -body {
            set hevl [twapi::eventlog_open -source $source]
            while {[llength [set events [twapi::eventlog_read $hevl]]]} {
                foreach eventrec $events {
                    lappend msgs [verify_event $eventrec]
                }
            }
            twapi::eventlog_close $hevl
            concat [join $msgs \n]
        } -result ""
    }

    test eventlog_read-2.0 {
        Verify eventlog is read in forward direction by default
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open]
        set recs [twapi::eventlog_read $hevl]
        if {[llength $recs] < 2} {
            lappend recs {*}[twapi::eventlog_read $hevl]
        }
        twapi::eventlog_close $hevl
        expr {[twapi::kl_get [lindex $recs 0] -recordnum] < [twapi::kl_get [lindex $recs 1] -recordnum]}
    } -result 1

    #

    test eventlog_read-2.1 {
        Verify eventlog reading in forward direction
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open]
        set recs [twapi::eventlog_read $hevl -direction forward]
        if {[llength $recs] < 2} {
            lappend recs {*}[twapi::eventlog_read $hevl]
        }
        twapi::eventlog_close $hevl
        expr {[twapi::kl_get [lindex $recs 0] -recordnum] < [twapi::kl_get [lindex $recs 1] -recordnum]}
    } -result 1

    #

    test eventlog_read-2.2 {
        Verify eventlog reading in backward direction
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open]
        set recs [twapi::eventlog_read $hevl -direction backward]
        twapi::eventlog_close $hevl
        expr {[twapi::kl_get [lindex $recs 0] -recordnum] > [twapi::kl_get [lindex $recs 1] -recordnum]}
    } -result 1

    #

    test eventlog_read-3.0 {
        Verify eventlog read from a record position in forward direction
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open]
        set oldest [twapi::eventlog_oldest $hevl]
        set count  [twapi::eventlog_count $hevl]
        set seekpos [expr {$oldest + ($count/2)}]
        set recs [twapi::eventlog_read $hevl -seek $seekpos -direction forward]
        twapi::eventlog_close $hevl
        set first_rec [twapi::kl_get [lindex $recs 0] -recordnum]
        set next_rec  [twapi::kl_get [lindex $recs 1] -recordnum]
        expr {$first_rec == $seekpos && $seekpos == [expr {$next_rec - 1}]}
    } -result 1

    #

    test eventlog_read-3.1 {
        Verify eventlog read from a record position in backward direction
    } -constraints {
        nt
    } -body {
        set hevl [twapi::eventlog_open]
        set oldest [twapi::eventlog_oldest $hevl]
        set count  [twapi::eventlog_count $hevl]
        set seekpos [expr {$oldest + ($count/2)}]
        set recs [twapi::eventlog_read $hevl -seek $seekpos -direction backward]
        twapi::eventlog_close $hevl
        set first_rec [twapi::kl_get [lindex $recs 0] -recordnum]
        set next_rec  [twapi::kl_get [lindex $recs 1] -recordnum]
        expr {$first_rec == $seekpos && $seekpos == [expr {$next_rec + 1}]}
    } -result 1

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

    set testnum 0
    foreach source {application system security} {
        test eventlog_format_message-1.[incr testnum] "Format event messages from the $source log" -constraints {
            nt
        } -body {
            set hevl [twapi::eventlog_open -source $source]
            while {[llength [set events [twapi::eventlog_read $hevl]]]} {
                foreach eventrec $events {
                    twapi::eventlog_format_message $eventrec
                }
            }
            twapi::eventlog_close $hevl
        } -result ""
    }

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

    set testnum 0
    foreach source {application system} {
        test eventlog_format_category-1.[incr testnum] "Format event category from the $source log" -constraints {
            nt
        } -body {
            set hevl [twapi::eventlog_open -source $source]
            while {[llength [set events [twapi::eventlog_read $hevl]]]} {
                foreach eventrec $events {
                    twapi::eventlog_format_category $eventrec
                }
            }
            twapi::eventlog_close $hevl
        } -result ""
    }

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

    test evt_channels-1.0 {
        Evt channels
    } -constraints {
        win6
    } -body {
        set chans [twapi::evt_channels]
        list [expr {"Application" in $chans}] [expr {"System" in $chans}]
    } -result {1 1}


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

    test evt_clear_log-1.0 {
        Clear the event log
    } -constraints {
        win6 systemmodificationok
    } -body {
        twapi::evt_clear_log Application
        set hevl [twapi::evt_open_log_info -channel Application]
        dict get [twapi::evt_log_info $hevl -numberoflogrecords] -numberoflogrecords
    } -cleanup {
        twapi::evt_close $hevl
    } -result 0

    test evt_log_clear-1.1 {
        Backup and clear the event log
    } -constraints {
        win6 systemmodificationok
    } -setup {
        set backup [file join [tcltest::temporaryDirectory] twapi_events.bak]
        if {[file exists $backup]} {file delete $backup}
    } -body {
        twapi::evt_clear_log Application -backup $backup
        set hevl [twapi::evt_open_log_info -channel Application]
        # On some systems, the clearing of log itself writes a new event
        # so number after clearing may be 0 or 1
        list [expr {[dict get [twapi::evt_log_info $hevl -numberoflogrecords] -numberoflogrecords] < 2}] [file exists $backup]
    } -cleanup {
        twapi::evt_close $hevl
        file delete $backup
    } -result {1 1}

    test evt_log_clear-2.0 {
        Backup and clear the event log -session
    } -constraints {
        TBD win6 systemmodificationok
    } -setup {
        TBD
    } -body {
        TBD
    } -cleanup {
        TBD
    } -result {1 1}

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

    test evt_export_log-1.0 {
        Export the eventlog
    } -constraints {
        win6
    } -setup {
        set backup [file join $::env(TEMP) twapi_events.bak]
        if {[file exists $backup]} {file delete $backup}
    } -body {
        set count [twapi::winlog_event_count -channel System]
        twapi::evt_export_log $backup -channel System
        expr {[twapi::winlog_event_count -file $backup] == $count}
    } -cleanup {
        file delete $backup
    } -result 1

    test evt_export_log-10.0 {
        Export the eventlog -session -file -query -ignorequeryerrors
    } -constraints {
        TBD win6
    } -setup {
        TBD
    } -body {
        TBD
    } -cleanup {
        TBD
    } -result TBD


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

    test evt_publishers-1.0 {
        Evt publishers
    } -constraints {
        win6
    } -body {
        set pubs [twapi::evt_publishers]
        list [expr {"Microsoft-Windows-WMI" in $pubs}] \
            [expr {"Application" in $pubs}] \
            [expr {".NET Runtime" in $pubs}]
    } -result {1 1 1}

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

    test evt_query-1.0 {
        Event query -channel
    } -constraints {
        win6
    } -body {
        set hq [twapi::evt_query -channel system]
        lassign [twapi::evt_next $hq -count 2] hevt1 hevt2
        array set first [twapi::evt_decode_event $hevt1]
        array set second [twapi::evt_decode_event $hevt2]
        # Verify default forward direction
        expr {
              $first(-timecreated) <= $second(-timecreated)
              &&
              $first(-eventrecordid) < $second(-eventrecordid)
          }
    } -cleanup {
        twapi::evt_close $hq
        twapi::evt_close $hevt1
        twapi::evt_close $hevt2
    } -result 1

    test evt_query-2.0 {
        Event query -direction forward
    } -constraints {
        win6
    } -body {
        set hq [twapi::evt_query -channel system -direction forward]
        lassign [twapi::evt_next $hq -count 2] hevt1 hevt2
        array set first [twapi::evt_decode_event $hevt1]
        array set second [twapi::evt_decode_event $hevt2]
        # Verify default forward direction
        expr {
              $first(-timecreated) <= $second(-timecreated)
              &&
              $first(-eventrecordid) <= $second(-eventrecordid)
          }
    } -cleanup {
        twapi::evt_close $hq
        twapi::evt_close $hevt1
        twapi::evt_close $hevt2
    } -result 1

    test evt_query-2.1 {
        Event query -direction backward
    } -constraints {
        win6
    } -body {
        set hq [twapi::evt_query -channel system -direction backward]
        lassign [twapi::evt_next $hq -count 2] hevt1 hevt2
        array set first [twapi::evt_decode_event $hevt1]
        array set second [twapi::evt_decode_event $hevt2]
        # Verify default forward direction
        expr {
              $first(-timecreated) >= $second(-timecreated)
              &&
              $first(-eventrecordid) >= $second(-eventrecordid)
          }
    } -cleanup {
        twapi::evt_close $hq
        twapi::evt_close $hevt1
        twapi::evt_close $hevt2
    } -result 1
        
    
    test evt_query-10.0 {
        Event query -session -file -query -ignorequeryerrors
    } -constraints {
        TBD win6
    } -setup {
        TBD
    } -body {
        TBD
    } -cleanup {
        TBD
    } -result TBD

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

    test evt_decode_event-1.0 {
        Event query -session -file -query -ignorequeryerrors
    } -constraints {
        TBD win6
    } -setup {
        TBD
    } -body {
        TBD
    } -cleanup {
        TBD
    } -result TBD

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

    test evt_decode_events-1.0 {
        Event query -session -file -query -ignorequeryerrors
    } -constraints {
        TBD win6
    } -setup {
        TBD
    } -body {
        TBD
    } -cleanup {
        TBD
    } -result TBD

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

    test winlog_backup-1.0 {
        Back up the eventlog, also covers winlog_event_count-2.0
    } -body {
        set backup [file join $::env(TEMP) twapi_winlog_test.bak]
        twapi::winlog_backup Application $backup
        set count [twapi::winlog_event_count -channel Application]
        set count2 [twapi::winlog_event_count -file $backup]
        expr {$count == $count2}
    } -cleanup {
        file delete $backup
    } -result 1

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

    test winlog_close-1.0 {
        Close a event log handle
    } -body {
        set hevl [twapi::winlog_open]
        twapi::winlog_close $hevl
        # Should generate error when closing
        catch {twapi::winlog_close $hevl}
    } -result 1

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

    test winlog_event_count-1.0 {
        winlog_event_count -channel
    } -body {
        twapi::eventlog_log "TWAPI test winlog_event_count-1.0 [clock seconds]" -source Application
        set count [twapi::winlog_event_count -channel Application]
        expr {$count > 0}
    } -result 1

    test winlog_event_count-2.0 {
        winlog_event_count -file
    } -constraints {
        coveredelsewhere
    } -body {
        Covered by winlog_backup-1.0
    } -result ""

    test winlog_event_count-3.0 {
        winlog_event_count -system
    } -body {
        set count1 [twapi::winlog_event_count -channel Application -system $::env(COMPUTERNAME)]
        twapi::eventlog_log "TWAPI test winlog_event_count-1.0" -source Application -system $::env(COMPUTERNAME)
        set count2 [twapi::winlog_event_count -channel Application -system $::env(COMPUTERNAME)]
        expr {$count2 == ($count1 + 1)}
    } -result 1

    test winlog_event_count-3.1 {
        winlog_event_count -system (fail) - make sure -system option is actually seen
    } -body {
        list [catch {twapi::winlog_event_count -channel Application -system NOSUCHSYSTEM}] [errorcode]
    } -result {1 {TWAPI_WIN32 1722}}

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

    test winlog_open-1.0 {
        winlog_open
    } -constraints {
        coveredelsewhere
    } -body {
        Convered by winlog_read
    } -result ""

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

    set testnum -1
    foreach source {application system security} {
        test winlog_read-1.[incr testnum] "winlog_read event log records from the $source log" -body {
            patience "Reading events"
            set hevl [twapi::winlog_open -channel $source]
            set msgs ""
            set count 0
            while {[twapi::recordarray size [set events [twapi::winlog_read $hevl]]]} {
                foreach eventrec [twapi::recordarray getlist $events -format dict] {
                    incr count
                    set msgs [verify_winlog_event $eventrec]
                    if {[llength $msgs]} break
                }
                if {[llength $msgs]} break
            }
            twapi::winlog_close $hevl
            list [expr {$count > 0}] [llength $msgs]
        } -result {1 0}
    }

    test winlog_read-2.0 {
        Verify winlog is read in forward direction by default
    } -body {
        set hevl [twapi::winlog_open]
        set recs [twapi::winlog_read $hevl]
        if {[twapi::recordarray size $recs] < 5} {
            set recs [twapi::recordarray concat $recs [twapi::winlog_read $hevl]]
        }
        set ok 1
        set rec_id 0
        foreach rec [twapi::recordarray getlist $recs -format dict] {
            set rec_next [dict get $rec -eventrecordid]
            if {$rec_next <= $rec_id} {
                set ok 0
                break
            }
            set rec_id $rec_next
        }
        twapi::winlog_close $hevl
        set ok
    } -result 1

    test winlog_read-2.1 {
        Verify winlog_read forward
    } -body {
        set hevl [twapi::winlog_open -direction forward]
        set recs [twapi::winlog_read $hevl]
        if {[twapi::recordarray size $recs] < 5} {
            set recs [twapi::recordarray concat $recs [twapi::winlog_read $hevl]]
        }
        set ok 1
        set rec_id 0
        foreach rec [twapi::recordarray getlist $recs -format dict] {
            set rec_next [dict get $rec -eventrecordid]
            if {$rec_next <= $rec_id} {
                set ok 0
                break
            }
            set rec_id $rec_next
        }
        twapi::winlog_close $hevl
        set ok
    } -result 1

    test winlog_read-2.2 {
        Verify winlog_read backward
    } -body {
        set hevl [twapi::winlog_open -direction backward]
        set recs [twapi::winlog_read $hevl]
        if {[twapi::recordarray size $recs] < 5} {
            set recs [twapi::recordarray concat $recs [twapi::winlog_read $hevl]]
        }
        set ok 1
        set rec_id 0x7fffffff
        foreach rec [twapi::recordarray getlist $recs -format dict] {
            set rec_next [dict get $rec -eventrecordid]
            if {$rec_next >= $rec_id} {
                set ok 0
                break
            }
            set rec_id $rec_next
        }
        twapi::winlog_close $hevl
        set ok
    } -result 1


    test winlog_read-3.0 {
        Verify winlog read with -system 
    } -body {
        set hevl [twapi::winlog_open -system $::env(COMPUTERNAME)]
        set recs [twapi::winlog_read $hevl]
        foreach eventrec [twapi::recordarray getlist $recs -format dict] {
            set msgs [verify_winlog_event $eventrec]
            if {[llength $msgs]} break
        }
        twapi::winlog_close $hevl
        set msgs
    } -result ""

    test winlog_read-3.1 {
        Verify winlog read with -system (fail - to verify -system option is obeyed)
    } -body {
        list [catch {twapi::winlog_open -system NOSUCHSYSTEM}] [errorcode]
    } -result {1 {TWAPI_WIN32 1722}}


    test winlog_read-4.0 {
        winlog_read event log records from file
    } -setup {
        set backup [file join $::env(TEMP) winlog_read_file.bak]
        twapi::winlog_backup Application $backup
    } -body {
        patience "Reading events"
        set hevl [twapi::winlog_open -file $backup]
        set msgs ""
        set count 0
        while {[twapi::recordarray size [set events [twapi::winlog_read $hevl]]]} {
            foreach eventrec [twapi::recordarray getlist $events -format dict] {
                incr count
                set msgs [verify_winlog_event $eventrec]
                if {[llength $msgs]} break
            }
            if {[llength $msgs]} break
        }
        twapi::winlog_close $hevl
        list [expr {$count > 0}] [llength $msgs]
    } -cleanup {
        file delete $backup
    } -result {1 0}



    test winlog_read-100.0 {
        winlog_read -lcid
    } -constraints {
        TBD
    } -body {} -result {}

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

    #NOTE - KEEP THESE WINLOG CLEAR TESTS AT THE END AFTER ANY READ TESTS

    test winlog_clear-1.0 {
        Clear the event log
    } -constraints {
        systemmodificationok
    } -setup {
        # Make sure there are events in the log
        twapi::eventlog_log "TWAPI Test winlog_clear-1.0" -source Application
        if {[twapi::winlog_event_count -channel Application] == 0} {
            error "No events in event log"
        }
    } -body {
        twapi::winlog_clear Application
        twapi::winlog_event_count -channel Application
    } -result 0

    test winlog_clear-1.1 {
        Backup and clear the event log
    } -constraints {
        systemmodificationok
    } -setup {
        # Make sure there are events in the log
        twapi::eventlog_log "TWAPI Test winlog_clear-1.1" -source Application
        if {[twapi::winlog_event_count -channel Application] == 0} {
            error "No events in event log"
        }
    } -body {
        set backup [file join $::env(TEMP) twapi_events_clear_test_[clock microseconds].bak]
        set count1 [twapi::winlog_event_count -channel Application]
        twapi::winlog_clear Application -backup $backup
        set count2 [twapi::winlog_event_count -channel Application]
        set count3 [twapi::winlog_event_count -file $backup]
        list [expr {$count1 == $count3}] $count2
    } -result {1 0}

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

    test winlog_subscribe-1.0 {
        Verify asynchronous monitoring of event log
    } -setup {
        patience winlog_subscribe-1.0
        # Note this test may sometimes fail because event log service
        # restricts frequency of notifications to 5 sec intervals
        # For this reason, we also test start and stop in a single test
        after 6000
    } -body {
        lassign [twapi::winlog_subscribe Application] hevl hevent
        # The read has to fail before events are sent. So read all
        # events first
        while {[twapi::recordarray size [twapi::winlog_read $hevl]]} {}
        # Write a message
        twapi::eventlog_log "winlog_subscribe test message"
        twapi::wait_on_handle $hevent -wait 6000

        # NOTE - on XP / 2k3 THIS WILL LIKELY FAIL BECAUSE IT USES
        # PULSE EVENT WHICH REQUIRES A SEPARATE THREAD TO BE WAITING
        # WHICH IS WHAT eventlog_monitor does

    } -cleanup {
        twapi::winlog_close $hevl
    } -result signalled

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

    #
    # Clean up
    ::tcltest::cleanupTests
}

namespace delete ::twapi::eventlog::test
