# Tests for eggdrop-pisg.tcl, run outside eggdrop with a mock of the eggdrop commands: # tclsh8.6 scripts/eggdrop-pisg-test.tcl # They never touch a real users file: everything happens in a temporary folder. set here [file dirname [file normalize [info script]]] set tmp [file join [expr {[info exists ::env(TMPDIR)] ? $::env(TMPDIR) : "/tmp"}] "pisgtest.[pid]"] file mkdir $tmp # ---- a mock of the eggdrop commands the script uses --------------------------------------- set ::sent {}; set ::binds {}; set ::logs {}; set ::acctreply {} proc bind {type flags cmd proc} { lappend ::binds [list $type $flags $cmd $proc] } proc putserv {line} { lappend ::sent $line } proc puthelp {line} { lappend ::sent $line } proc putlog {line} { lappend ::logs $line } proc timer {args} {} proc matchattr {hand flags} { return [expr {$hand eq "boss"}] } proc getaccount {nick} { if {[dict exists $::acctreply $nick]} { return [dict get $::acctreply $nick] } else { return "" } } source [file join $here eggdrop-pisg.tcl] set pisg::usersfile [file join $tmp users.cfg] set pisg::maincfg [file join $tmp pisg.cfg] set pisg::minsecs 0 set fails 0; set passes 0 proc ok {cond msg} { if {$cond} { incr ::passes } else { incr ::fails; puts " FAIL: $msg" } } # run a command as if typed in a private message; returns what the bot said (NOTICE texts) proc say {cmd nick uhost hand arg} { set ::sent {} pisg::dispatch $cmd $nick $uhost $hand $arg set out {} foreach l $::sent { regexp {^NOTICE \S+ :(.*)$} $l -> t; lappend out $t } return $out } proc first {lines} { return [lindex $lines 0] } proc filetext {} { return [pisg::read_file $pisg::usersfile] } proc reset {} { file delete -force $pisg::usersfile; file delete -force $pisg::maincfg; array unset pisg::hist; set ::acctreply {} } set ALICE "~u@alice.users.undernet.org" set BOB "~b@bob.users.undernet.org" set ANON "~x@dsl-123.example.net" puts "1. identity" reset ok [string match "*Log in to X*" [first [say info Alice $ANON * "Alice male"]]] "someone not logged in to X gets login instructions" ok [expr {[pisg::account Alice $ALICE] eq "alice"}] "account name from the host" ok [expr {[pisg::account Alice $ANON] eq ""}] "no account for an ordinary host" set ::acctreply [dict create Alice "AliceAcct"] ok [expr {[pisg::account Alice $ANON] eq "aliceacct"}] "getaccount is used first, lower-cased" set ::acctreply [dict create Alice "*"] ok [expr {[pisg::account Alice $ALICE] eq "alice"}] "getaccount '*' (not logged in) falls back to the host" set ::acctreply {} ok [string match "*Log in to X*" [first [say info Alice $ANON * "Alice male"]]] "still no login: still no edit" ok [expr {![file exists $pisg::usersfile]}] "nothing written for an unidentified user" puts "2. creating and updating a profile" reset set r [first [say info Alice $ALICE * "Alice male https://example.org/me.png https://example.org"]] ok [string match "Saved*" $r] "profile saved: $r" set t [filetext] ok [string match {**} $t] "file line is right: $t" ok [string match "*do not edit below this line*" $t] "marker written" set r [first [say info Alice $ALICE * "Alice female"]] set t [filetext] ok [string match {*sex="f"*} $t] "sex updated" ok [string match {*pic="https://example.org/me.png"*} $t] "picture kept when only sex changes" ok [string match "*female*" $r] "reply describes the profile" say info Alice $ALICE * "Alice link=mailto-not https://new.example.org/x" ;# an invalid token must change nothing ok [string match {*link="https://example.org"*} [filetext]] "invalid input changes nothing" ok [string match "*don't understand*" [first [say info Alice $ALICE * "Alice blah"]]] "unknown word explained" puts "3. claiming names" reset ok [string match "*only create a profile for the nick you are using*" [first [say info Bob $BOB * "Alice male"]]] "cannot create a profile for a nick you are not using" say info Alice $ALICE * "Alice male" ok [string match "*already taken*" [first [say info Alice $BOB * "Alice male"]]] "cannot take a name somebody has" ok [string match "*don't have a profile called Alice*" [first [say merge Bob $BOB * "Alice"]]] "cannot merge into somebody else's profile" say info Bob $BOB * "Bob male" ok [string match "*already have a profile named Bob*" [first [say info Bob $BOB * "Zed male"]]] "one profile per account" ok [string match "*already have a profile named Bob*" [first [say info Bob2 $BOB * "Bob2 male"]]] "still one profile per account" puts "4. merging nicks" reset say info Alice $ALICE * "Alice male" ok [string match "Done*" [first [say merge Alice_ $ALICE * "Alice"]]] "Alice_ merged into Alice" ok [string match {*alias="Alice_"*} [filetext]] "alias written" ok [string match "*already counted*" [first [say merge Alice_ $ALICE * "Alice"]]] "merging twice is harmless" ok [string match "*already Alice*" [first [say merge Alice $ALICE * "Alice"]]] "merging the main nick into itself is refused" say info Bob $BOB * "Bob male" ok [string match "*already used by another profile*" [first [say merge Alice_ $BOB * "Bob"]]] "an alias held by someone else cannot be taken" say merge Alice- $ALICE * "Alice" ok [string match {*alias="Alice_ Alice-"*} [filetext]] "second alias appended" ok [string match "Done*" [first [say unmerge Alice $ALICE * "Alice_"]]] "unmerge works" ok [string match {*alias="Alice-"*} [filetext]] "alias removed" ok [string match "*not one of your aliases*" [first [say unmerge Alice $ALICE * "Nobody"]]] "unmerge of a stranger refused" puts "5. your hand-written lines are protected and preserved" reset set f [open $pisg::maincfg w]; puts $f "# main\n"; close $f set f [open $pisg::usersfile w]; puts $f "# my notes\n"; close $f ok [string match "*already taken*" [first [say info Zed "~z@zed.users.undernet.org" * "Zed male"]]] "a nick from pisg.cfg cannot be claimed" ok [string match "*already taken*" [first [say info Zeddy "~z@zeddy.users.undernet.org" * "Zeddy male"]]] "an alias from pisg.cfg cannot be claimed" ok [string match "*already taken*" [first [say info Manny "~m@manny.users.undernet.org" * "Manny male"]]] "a hand-written line in users.cfg cannot be claimed" say info Alice $ALICE * "Alice male"; say info Bob $BOB * "Bob male" set t [filetext] ok [string match "*# my notes*" $t] "your comment survives" ok [string match {**} $t] "your line survives untouched" ok [expr {[string first "# my notes" $t] < [string first "managed by" $t]}] "your part stays above the marker" ok [expr {[string first {nick="Alice"} $t] < [string first {nick="Bob"} $t]}] "managed entries are sorted" ok [string match "*set by hand*" [first [say show Alice $ALICE * "Zed"]]] "show says a hand-written profile exists" puts "6. hostile and invalid input" reset foreach bad { "Alice male http://example.org/me.png" "Alice male javascript:alert(1)" "Alice male https://localhost/me.png" "Alice male https://127.0.0.1/me.png" "Alice male https://example.org/a\"b.png" "Alice male https://example.org/me.png?x=