#
# signal.test
#
# Tests for the signal and kill commands.
#---------------------------------------------------------------------------
# Copyright 1992-1999 Karl Lehenbauer and Mark Diekhans.
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted, provided
# that the above copyright notice appear in all copies.  Karl Lehenbauer and
# Mark Diekhans make no representations about the suitability of this
# software for any purpose.  It is provided "as is" without express or
# implied warranty.
#------------------------------------------------------------------------------
# $Id: signal.test,v 1.3 2002/04/03 02:44:21 hobbs Exp $
#------------------------------------------------------------------------------
#

if {[cequal [info procs Test] {}]} {
    source [file join [file dirname [info script]] testlib.tcl]
}

if [cequal $tcl_platform(platform) windows] {
    echo "    * The signal tests have not been ported to Win32" 
    return
}

#
# Fork without exec will not work under Tk, skip this test
#
if ![lempty [info commands button]] {
    puts "*************************************************************"
    puts "Signal tests are constructed in a way that does not work"
    puts "under Tk.  Test skipped."
    puts "*************************************************************"
    puts ""
    return
}

Test signal-1.1 {signal tests} {
    signal ignore SIGHUP
    kill HUP [id process]
} 0 {}

Test signal-1.2 {signal tests} {
    global errorInfo
    set errorInfo {}
    signal error HUP
    proc KillMe3 {} {kill SIGHUP [id process]}
    proc KillMe2 {} {KillMe3}
    proc KillMe1 {} {KillMe2}
    list [catch {KillMe1} msg] $msg $errorInfo
} 0 {1 {SIGHUP signal received} {SIGHUP signal received
    while executing
"kill SIGHUP [id process]"
    (procedure "KillMe3" line 1)
    invoked from within
"KillMe3"
    (procedure "KillMe2" line 1)
    invoked from within
"KillMe2"
    (procedure "KillMe1" line 1)
    invoked from within
"KillMe1"}}

Test signal-1.3 {signal tests} {
    signal error {HUP SIGTERM}
    set one [list [catch {kill HUP  [id process]} msg] $msg]
    set two [list [catch {kill TERM [id process]} msg] $msg]
    list $one $two
} 0 {{1 {SIGHUP signal received}} {1 {SIGTERM signal received}}}

Test signal-1.4 {signal tests} {
    set signalWeGot {}
    signal trap 1 {set signalWeGot %S}
    kill SIGHUP [id process]
    signal default 1
    set signalWeGot
} 0 {SIGHUP}

Test signal-1.41 {signal tests} {
    set signalWeGot {}
    set signalTrash {}
    signal trap 1 {set signalWeGot %S; set signalTrash "%%"}
    kill SIGHUP [id process]
    signal default 1
    list $signalWeGot $signalTrash
} 0 {SIGHUP %%}

Test signal-1.42 {signal tests} {
    signal trap 1 {set signalWeGot %s; set signalTrash "%%"}
    kill SIGHUP [id process]
} 1 {bad signal trap command formatting specification "%s", expected one of "%%" or "%S"}
signal default SIGHUP

Test signal-1.5 {signal tests} {
    signal default {SIGHUP SIGINT}
    signal get {SIGHUP SIGINT}
} 0 {{SIGHUP {default 0 {} 0}} {SIGINT {default 0 {} 0}}}

Test signal-1.6 {signal tests} {
    signal default SIGHUP
    signal ignore  SIGINT
    signal get {SIGHUP SIGINT}
} 0 {{SIGHUP {default 0 {} 0}} {SIGINT {ignore 0 {} 0}}}

Test signal-1.7 {signal tests} {
    signal trap {SIGHUP SIGINT} {error "Should not get this signal"}
    signal get {SIGHUP SIGINT}
} 0 [list {SIGHUP {trap 0 {error "Should not get this signal"} 0}} \
          {SIGINT {trap 0 {error "Should not get this signal"} 0}} ]

Test signal-1.8 {signal tests} {
    signal error {SIGHUP SIGINT}
    signal get {SIGHUP SIGINT}
} 0 {{SIGHUP {error 0 {} 0}} {SIGINT {error 0 {} 0}}}

Test signal-1.8.1 {signal tests} {
    signal error {SIGHUP SIGINT}
    set sigkl [signal get *]
    list [keylget sigkl SIGHUP]  [keylget sigkl SIGINT]
} 0 {{error 0 {} 0} {error 0 {} 0}}

Test signal-1.8.2 {signal tests} {
    set sigkl [signal get *]
    list [keylget sigkl SIGALRM {}] [keylget sigkl SIGPIPE {}] \
        [keylget sigkl SIGINT {}]
} 0 {1 1 1}

Test signal-1.8.3 {signal tests} {
    signal error {SIGHUP SIGINT}
    set sigkl [signal get *]
    signal default {SIGHUP SIGINT}
    signal set $sigkl
    signal get {SIGHUP SIGINT}
} 0 {{SIGHUP {error 0 {} 0}} {SIGINT {error 0 {} 0}}}

if [infox have_signal_restart] {
    Test signal-1.8.4 {signal tests} {
        signal -restart error {SIGHUP SIGINT}
        signal get {SIGHUP SIGINT}
    } 0 {{SIGHUP {error 0 {} 1}} {SIGINT {error 0 {} 1}}}
}

Test signal-1.9 {signal tests} {
    global errorInfo
    set errorInfo {}
    proc KillMe3 {} {kill SIGHUP [id process]}
    proc KillMe2 {} {KillMe3}
    proc KillMe1 {} {KillMe2}
    signal trap SIGHUP {error "Blew it in the trap code"}
    list [catch {KillMe1} msg ] $msg $errorInfo
} 0 {1 {Blew it in the trap code} {Blew it in the trap code
    while executing
"error "Blew it in the trap code""
    while executing signal trap code for SIGHUP signal
    invoked from within
"kill SIGHUP [id process]"
    (procedure "KillMe3" line 1)
    invoked from within
"KillMe3"
    (procedure "KillMe2" line 1)
    invoked from within
"KillMe2"
    (procedure "KillMe1" line 1)
    invoked from within
"KillMe1"}}

Test signal-1.10 {signal tests} {
    signal
} 1 {wrong # args: signal ?-restart? action signalList ?command?}

Test signal-1.11 {signal tests} {
    signal ignore foo
} 1 {invalid signal "foo"}

Test signal-1.12 {signal tests} {
    signal ignore sigint "echo foo"
} 1 {command may not be specified for "ignore" action}

Test signal-1.13 {signal tests} {
    signal baz sigint
} 1 {invalid signal action specified: baz: expected one of "default", "ignore", "error", "trap", "get", "set", "block", or "unblock"}

#
# Complex test for the death of a child.
#

proc PollSigChld {} {
    global G_gotChild
    set sleepCnt 0
    while {!$G_gotChild} {
        incr sleepCnt
        if {$sleepCnt > 90} {
            error "signal-1.14: SIGCHLD lost"
        }
        sleep 1
    }
}


proc ForkChild {exitCode} {
    flush stdout  ;# Not going to exec, must clean up the buffers.
    flush stderr
    set childPid [fork]
    if {$childPid == 0} {
        exit $exitCode
    }
    return $childPid
}

if [infox have_posix_signals] {
    set expect {123 {{SIGCHLD {trap 0 {global G_gotChild;set G_gotChild 1;sleep 1} 0}}}}
} else {
    set expect {123 {{SIGCHLD {default 0 {} 0}}}}
}
set expect 
Test signal-1.15 {signal tests} {
    global G_gotChild
    set G_gotChild 0
    signal trap SIGCHLD {global G_gotChild;set G_gotChild 1;sleep 1}
    set pid1 [ForkChild 123] 
    PollSigChld
    set status1 [wait $pid1]
    list [lindex $status1 2] [signal get SIGCHLD]
} 0 $expect

signal default SIGCHLD

#
# Check that the signals are left in the correct state after receiving
# a signal (on SIGCHLD is different if we have Posix signals).
#

Test signal-1.16 {signal tests} {
    global G_gotChild
    set G_gotChild 0
    signal trap SIGCHLD {global G_gotChild;set G_gotChild 1}
    kill SIGCHLD [id process]
    set gotChild1 $G_gotChild
    set G_gotChild 0
    kill SIGCHLD [id process]
    set gotChild2 $G_gotChild
    set G_gotChild 0
    signal trap SIGCHLD {global G_gotChild;set G_gotChild 1}
    kill SIGCHLD [id process]
    set gotChild3 $G_gotChild
    signal default SIGCHLD
    list $gotChild1 $gotChild2 $gotChild3
} 0 [list 1 [infox have_posix_signals] 1]


Test signal-1.17 {signal tests} {
    global G_gotPipe
    set G_gotPipe 0
    signal trap SIGPIPE {global G_gotPipe;set G_gotPipe 1}
    kill SIGPIPE [id process]
    set gotPipe1 $G_gotPipe
    set G_gotPipe 0
    kill SIGPIPE [id process]
    set gotPipe2 $G_gotPipe
    signal default SIGPIPE
    list $gotPipe1 $gotPipe2
} 0 {1 1}

if [infox have_posix_signals] {
    Test signal-1.18 {signal tests} {
        signal error SIGHUP
        signal block SIGHUP
        signal get SIGHUP
    } 0 {{SIGHUP {error 1 {} 0}}}

    Test signal-1.19 {signal tests} {
        signal unblock SIGHUP
        signal get SIGHUP
    } 0 {{SIGHUP {error 0 {} 0}}}

    Test signal-1.18 {signal tests} {
        signal block SIGHUP
        signal error SIGHUP
        signal get SIGHUP
    } 0 {{SIGHUP {error 1 {} 0}}}

    signal unblock SIGHUP
    signal default SIGHUP
}


Test signal-2.1 {kill tests} {
    kill
} 1 {wrong # args: kill ?-pgroup? ?signal? idlist}

signal error SIGINT

Test signal-2.2 {kill tests} {
    kill 2 [id process]
} 1 {SIGINT signal received}

Test signal-2.3 {kill tests} {
    kill INT [id process]
} 1 {SIGINT signal received}

Test signal-2.4 {kill tests} {
    kill SIGINT [id process]
} 1 {SIGINT signal received}

Test signal-2.5 {kill tests} {
    kill 10000 [id process]
} 1 {invalid signal "10000"}

Test signal-2.6 {kill tests} {
    kill SIGFOO [id process]
} 1 {invalid signal "SIGFOO"}

test signal-2.7 {kill tests} {
    kill 0 [id process]
} {}

if [infox have_posix_signals] {
    test signal-2.8 {kill tests} {
        set pgrp [ForkLoopingChild 1]
        kill -pgroup SIGKILL $pgrp
        lrange [wait -pgroup $pgrp] 1 2
    } {SIG SIGKILL}
}

# Check -restart
if ![infox have_signal_restart] {
    echo Notice: restarting of interrupted system calls is not available on this system.
} else {
    test signal-3.0 {kill tests} {
        # Start program on a pipe, but don't doing anything until we send it
        # something to make timing issues smaller.
        set fh [open sigprog.tmp w]
        puts $fh "gets stdin; after 5000; update; puts HELLO; flush stdout"
        close $fh

        set sp [open "|[list $::tcltest::tcltest sigprog.tmp]" r+]
        try_eval {
            set resp BYE
            fconfigure $sp -buffering none
            set gotAlarm 0
            signal -restart trap SIGALRM {set ::gotAlarm 1}
            alarm 1
            puts $sp "GO"
            set resp [gets $sp]
        } {} {
            catch {close $sp}
            alarm 0
        }
        list $resp $gotAlarm

        # Note this this is somewhat timing dependent and might fail
        # on a heavly loaded system.
    } {HELLO 1}
}

file delete sigprog.tmp


# cleanup
::tcltest::cleanupTests
return
