# Commands covered:  switch
#
# This file contains a collection of tests for one or more of the Tcl
# built-in commands.  Sourcing this file into Tcl runs the tests and
# generates output for errors.  No output means no errors were found.
#
# Copyright (c) 1993 The Regents of the University of California.
# Copyright (c) 1994 Sun Microsystems, Inc.
# Copyright (c) 1998-1999 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
#
# RCS: @(#) $Id: switch.test,v 1.13 2005/06/01 11:00:35 dkf Exp $

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest
    namespace import -force ::tcltest::*
}

test switch-1.1 {simple patterns} {
    switch a a {format 1} b {format 2} c {format 3} default {format 4}
} 1
test switch-1.2 {simple patterns} {
    switch b a {format 1} b {format 2} c {format 3} default {format 4}
} 2
test switch-1.3 {simple patterns} {
    switch x a {format 1} b {format 2} c {format 3} default {format 4}
} 4
test switch-1.4 {simple patterns} {
    switch x a {format 1} b {format 2} c {format 3}
} {}
test switch-1.5 {simple pattern matches many times} {
    switch b a {format 1} b {format 2} b {format 3} b {format 4}
} 2
test switch-1.6 {simple patterns} {
    switch default a {format 1} default {format 2} c {format 3} default {format 4}
} 2
test switch-1.7 {simple patterns} {
    switch x a {format 1} default {format 2} c {format 3} default {format 4}
} 4
test switch-1.8 {simple patterns with -nocase} {
    switch -nocase b a {format 1} b {format 2} c {format 3} default {format 4}
} 2
test switch-1.9 {simple patterns with -nocase} {
    switch -nocase B a {format 1} b {format 2} c {format 3} default {format 4}
} 2
test switch-1.10 {simple patterns with -nocase} {
    switch -nocase b a {format 1} B {format 2} c {format 3} default {format 4}
} 2
test switch-1.11 {simple patterns with -nocase} {
    switch -nocase x a {format 1} default {format 2} c {format 3} default {format 4}
} 4

test switch-2.1 {single-argument form for pattern/command pairs} {
    switch b {
	a {format 1}
	b {format 2}
	default {format 6}
    }
} {2}
test switch-2.2 {single-argument form for pattern/command pairs} {
    list [catch {switch z {a 2 b}} msg] $msg
} {1 {extra switch pattern with no body}}

test switch-3.1 {-exact vs. -glob vs. -regexp} {
    switch -exact aaaab {
	^a*b$	{concat regexp}
	*b	{concat glob}
	aaaab	{concat exact}
	default	{concat none}
    }
} exact
test switch-3.2 {-exact vs. -glob vs. -regexp} {
    switch -regexp aaaab {
	^a*b$	{concat regexp}
	*b	{concat glob}
	aaaab	{concat exact}
	default	{concat none}
    }
} regexp
test switch-3.3 {-exact vs. -glob vs. -regexp} {
    switch -glob aaaab {
	^a*b$	{concat regexp}
	*b	{concat glob}
	aaaab	{concat exact}
	default	{concat none}
    }
} glob
test switch-3.4 {-exact vs. -glob vs. -regexp} {
    switch aaaab {^a*b$} {concat regexp} *b {concat glob} \
	    aaaab {concat exact} default {concat none}
} exact
test switch-3.5 {-exact vs. -glob vs. -regexp} {
    switch -- -glob {
	^g.*b$	{concat regexp}
	-*	{concat glob}
	-glob	{concat exact}
	default {concat none}
    }
} exact
test switch-3.6 {-exact vs. -glob vs. -regexp} {
    list [catch {switch -foo a b c} msg] $msg
} {1 {bad option "-foo": must be -exact, -glob, -indexvar, -matchvar, -nocase, -regexp, or --}}
test switch-3.7 {-exact vs. -glob vs. -regexp with -nocase} {
    switch -exact -nocase aaaab {
	^a*b$	{concat regexp}
	*b	{concat glob}
	aaaab	{concat exact}
	default	{concat none}
    }
} exact
test switch-3.8 {-exact vs. -glob vs. -regexp with -nocase} {
    switch -regexp -nocase aaaab {
	^a*b$	{concat regexp}
	*b	{concat glob}
	aaaab	{concat exact}
	default	{concat none}
    }
} regexp
test switch-3.9 {-exact vs. -glob vs. -regexp with -nocase} {
    switch -glob -nocase aaaab {
	^a*b$	{concat regexp}
	*b	{concat glob}
	aaaab	{concat exact}
	default	{concat none}
    }
} glob
test switch-3.10 {-exact vs. -glob vs. -regexp with -nocase} {
    switch -nocase aaaab {^a*b$} {concat regexp} *b {concat glob} \
	    aaaab {concat exact} default {concat none}
} exact
test switch-3.11 {-exact vs. -glob vs. -regexp with -nocase} {
    switch -nocase -- -glob {
	^g.*b$	{concat regexp}
	-*	{concat glob}
	-glob	{concat exact}
	default {concat none}
    }
} exact

test switch-4.1 {error in executed command} {
    list [catch {switch a a {error "Just a test"} default {format 1}} msg] \
	    $msg $errorInfo
} {1 {Just a test} {Just a test
    while executing
"error "Just a test""
    ("a" arm line 1)
    invoked from within
"switch a a {error "Just a test"} default {format 1}"}}
test switch-4.2 {error: not enough args} {
    list [catch {switch} msg] $msg
} {1 {wrong # args: should be "switch ?switches? string pattern body ... ?default body?"}}
test switch-4.3 {error: pattern with no body} {
    list [catch {switch a b} msg] $msg
} {1 {extra switch pattern with no body}}
test switch-4.4 {error: pattern with no body} {
    list [catch {switch a b {format 1} c} msg] $msg
} {1 {extra switch pattern with no body}}
test switch-4.5 {error in default command} {
    list [catch {switch foo a {error switch1} b {error switch 3} \
	    default {error switch2}} msg] $msg $errorInfo
} {1 switch2 {switch2
    while executing
"error switch2"
    ("default" arm line 1)
    invoked from within
"switch foo a {error switch1} b {error switch 3}  default {error switch2}"}}

test switch-5.1 {errors in -regexp matching} {
    list [catch {switch -regexp aaaab {
	*b	{concat glob}
	aaaab	{concat exact}
	default	{concat none}
    }} msg] $msg
} {1 {couldn't compile regular expression pattern: quantifier operand invalid}}

test switch-6.1 {backslashes in patterns} {
    switch -exact {\a\$\.\[} {
	\a\$\.\[	{concat first}
	\a\\$\.\\[	{concat second}
	\\a\\$\\.\\[	{concat third}
	{\a\\$\.\\[}	{concat fourth}
	{\\a\\$\\.\\[}	{concat fifth}
	default		{concat none}
    }
} third
test switch-6.2 {backslashes in patterns} {
    switch -exact {\a\$\.\[} {
	\a\$\.\[	{concat first}
	{\a\$\.\[}	{concat second}
	{{\a\$\.\[}}	{concat third}
	default		{concat none}
    }
} second

test switch-7.1 {"-" bodies} {
    switch a {
	a -
	b -
	c {concat 1}
	default {concat 2}
    }
} 1
test switch-7.2 {"-" bodies} {
    list [catch {
	switch a {
	    a -
	    b -
	    c -
	}
    } msg] $msg
} {1 {no body specified for pattern "c"}}
test switch-7.3 {"-" bodies} {
    list [catch {
	switch a {
	    a -
	    b -foo
	    c -
	}
    } msg] $msg
} {1 {no body specified for pattern "c"}}

test switch-8.1 {empty body} {
    set msg {}
    switch {2} {
    	1 {set msg 1}
        2 {}
        default {set msg 2}
    }
} {}

test switch-9.1 {empty pattern/body list} {
    list [catch {switch x} msg] $msg
} {1 {wrong # args: should be "switch ?switches? string pattern body ... ?default body?"}}
test switch-9.2 {empty pattern/body list} {
    list [catch {switch -- x} msg] $msg
} {1 {wrong # args: should be "switch ?switches? string pattern body ... ?default body?"}}
test switch-9.3 {empty pattern/body list} {
    list [catch {switch x {}} msg] $msg
} {1 {wrong # args: should be "switch ?switches? string {pattern body ... ?default body?}"}}
test switch-9.4 {empty pattern/body list} {
    list [catch {switch -- x {}} msg] $msg
} {1 {wrong # args: should be "switch ?switches? string {pattern body ... ?default body?}"}}
test switch-9.5 {unpaired pattern} {
    list [catch {switch x a {} b} msg] $msg
} {1 {extra switch pattern with no body}}
test switch-9.6 {unpaired pattern} {
    list [catch {switch x {a {} b}} msg] $msg
} {1 {extra switch pattern with no body}}
test switch-9.7 {unpaired pattern} {
    list [catch {switch x a {} # comment b} msg] $msg
} {1 {extra switch pattern with no body}}
test switch-9.8 {unpaired pattern} {
    list [catch {switch x {a {} # comment b}} msg] $msg
} {1 {extra switch pattern with no body, this may be due to a comment incorrectly placed outside of a switch body - see the "switch" documentation}}
test switch-9.9 {unpaired pattern} {
    list [catch {switch x a {} x {} # comment b} msg] $msg
} {1 {extra switch pattern with no body}}
test switch-9.10 {unpaired pattern} {
    list [catch {switch x {a {} x {} # comment b}} msg] $msg
} {1 {extra switch pattern with no body, this may be due to a comment incorrectly placed outside of a switch body - see the "switch" documentation}}

test switch-10.1 {compiled -exact switch} {
    if 1 {switch -exact -- a {a {format 1} b {format 2}}}
} 1
test switch-10.2 {compiled -exact switch} {
    if 1 {switch -exact -- b {a {format 1} b {format 2}}}
} 2
test switch-10.3 {compiled -exact switch} {
    if 1 {switch -exact -- c {a {format 1} b {format 2}}}
} {}
test switch-10.4 {compiled -exact switch} {
    if 1 {
	set x 0
	switch -exact -- c {a {format 1} b {format 2}}
    }
} {}
test switch-10.5 {compiled -exact switch} {
    if 1 {switch -exact -- a {a - aa {format 1} b {format 2}}}
} 1
test switch-10.6 {compiled -exact switch} {
    if 1 {switch -exact -- b {a {
	set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1
	set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1
	set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1
	set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1
	set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1
	set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1
	set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1
	set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1;set x 1
    } b {format 2}}}
} 2

# Command variants are:
#    c* are compiled switches, i* are interpreted
#    *-glob use glob matching, *-exact use exact matching
#    *2* include a default clause (different results too.)
proc cswtest-glob s {
    set x 0; set y 0
    foreach c [split $s {}] {
	switch -glob -- $c {
	    a {incr x}
	    b {incr y}
	}
    }
    set x [expr {$x*100}]; set y [expr {$y*100}]
    foreach c [split $s {}] {
	switch -glob -- $c a {incr x} b {incr y}
    }
    return $x,$y
}
proc iswtest-glob s {
    set x 0; set y 0; set switch switch
    foreach c [split $s {}] {
	$switch -glob -- $c {
	    a {incr x}
	    b {incr y}
	}
    }
    set x [expr {$x*100}]; set y [expr {$y*100}]
    foreach c [split $s {}] {
	$switch -glob -- $c a {incr x} b {incr y}
    }
    return $x,$y
}
proc cswtest-exact s {
    set x 0; set y 0
    foreach c [split $s {}] {
	switch -exact -- $c {
	    a {incr x}
	    b {incr y}
	}
    }
    set x [expr {$x*100}]; set y [expr {$y*100}]
    foreach c [split $s {}] {
	switch -exact -- $c a {incr x} b {incr y}
    }
    return $x,$y
}
proc iswtest-exact s {
    set x 0; set y 0; set switch switch
    foreach c [split $s {}] {
	$switch -exact -- $c {
	    a {incr x}
	    b {incr y}
	}
    }
    set x [expr {$x*100}]; set y [expr {$y*100}]
    foreach c [split $s {}] {
	$switch -exact -- $c a {incr x} b {incr y}
    }
    return $x,$y
}
proc cswtest2-glob s {
    set x 0; set y 0; set z 0
    foreach c [split $s {}] {
	switch -glob -- $c {
	    a {incr x}
	    b {incr y}
	    default {incr z}
	}
    }
    set x [expr {$x*100}]; set y [expr {$y*100}]; set z [expr {$z*100}]
    foreach c [split $s {}] {
	switch -glob -- $c a {incr x} b {incr y} default {incr z}
    }
    return $x,$y,$z
}
proc iswtest2-glob s {
    set x 0; set y 0; set z 0; set switch switch
    foreach c [split $s {}] {
	$switch -glob -- $c {
	    a {incr x}
	    b {incr y}
	    default {incr z}
	}
    }
    set x [expr {$x*100}]; set y [expr {$y*100}]; set z [expr {$z*100}]
    foreach c [split $s {}] {
	$switch -glob -- $c a {incr x} b {incr y} default {incr z}
    }
    return $x,$y,$z
}
proc cswtest2-exact s {
    set x 0; set y 0; set z 0
    foreach c [split $s {}] {
	switch -exact -- $c {
	    a {incr x}
	    b {incr y}
	    default {incr z}
	}
    }
    set x [expr {$x*100}]; set y [expr {$y*100}]; set z [expr {$z*100}]
    foreach c [split $s {}] {
	switch -exact -- $c a {incr x} b {incr y} default {incr z}
    }
    return $x,$y,$z
}
proc iswtest2-exact s {
    set x 0; set y 0; set z 0; set switch switch
    foreach c [split $s {}] {
	$switch -exact -- $c {
	    a {incr x}
	    b {incr y}
	    default {incr z}
	}
    }
    set x [expr {$x*100}]; set y [expr {$y*100}]; set z [expr {$z*100}]
    foreach c [split $s {}] {
	$switch -exact -- $c a {incr x} b {incr y} default {incr z}
    }
    return $x,$y,$z
}

test switch-10.7 {comparison of compiled and interpreted behaviour of switch, exact matching} {
    cswtest-exact abcb
} [iswtest-exact abcb]
test switch-10.8 {comparison of compiled and interpreted behaviour of switch, glob matching} {
    cswtest-glob abcb
} [iswtest-glob abcb]
test switch-10.9 {comparison of compiled and interpreted behaviour of switch, exact matching with default} {
    cswtest2-exact abcb
} [iswtest2-exact abcb]
test switch-10.10 {comparison of compiled and interpreted behaviour of switch, glob matching with default} {
    cswtest2-glob abcb
} [iswtest2-glob abcb]
proc cswtest-default-exact {x} {
    switch -- $x {
	a* {return b}
	aa {return c}
	default {return d}
    }
}
test switch-10.11 {default to exact matching when compiled} {
    cswtest-default-exact a
} d
test switch-10.12 {default to exact matching when compiled} {
    cswtest-default-exact aa
} c
test switch-10.13 {default to exact matching when compiled} {
    cswtest-default-exact a*
} b
test switch-10.14 {default to exact matching when compiled} {
    cswtest-default-exact a**
} d
rename cswtest-default-exact {}
rename cswtest-glob {}
rename iswtest-glob {}
rename cswtest2-glob {}
rename iswtest2-glob {}
rename cswtest-exact {}
rename iswtest-exact {}
rename cswtest2-exact {}
rename iswtest2-exact {}

# Added due to TIP#75
test switch-11.1 {regexp matching with -matchvar} {
    switch -regexp -matchvar x -- abc {.(.). {set x}}
} {abc b}
test switch-11.2 {regexp matching with -matchvar} {
    set x GOOD
    switch -regexp -matchvar x -- abc {.(.).. {list $x z}}
    set x
} GOOD
test switch-11.3 {regexp matching with -matchvar} {
    switch -regexp -matchvar x -- "a b c" {.(.). {set x}}
} {{a b} { }}
test switch-11.4 {regexp matching with -matchvar} {
    set x BAD
    switch -regexp -matchvar x -- "a b c" {
	bc {list $x YES}
	default {list $x NO}
    }
} {{} NO}
test switch-11.5 {-matchvar without -regexp} {
    set x {}
    list [catch {switch -glob -matchvar x -- abc . {set x}} msg] $x $msg
} {1 {} {-matchvar option requires -regexp option}}
test switch-11.6 {-matchvar unwritable} {
    set x {}
    list [catch {switch -regexp -matchvar x(x) -- abc . {set x}} msg] $x $msg
} {1 {} {can't set "x(x)": variable isn't array}}

test switch-12.1 {regexp matching with -indexvar} {
    switch -regexp -indexvar x -- abc {.(.). {set x}}
} {{0 3} {1 2}}
test switch-12.2 {regexp matching with -indexvar} {
    set x GOOD
    switch -regexp -indexvar x -- abc {.(.).. {list $x z}}
    set x
} GOOD
test switch-12.3 {regexp matching with -indexvar} {
    switch -regexp -indexvar x -- "a b c" {.(.). {set x}}
} {{0 3} {1 2}}
test switch-12.4 {regexp matching with -indexvar} {
    set x BAD
    switch -regexp -indexvar x -- "a b c" {
	bc {list $x YES}
	default {list $x NO}
    }
} {{} NO}
test switch-12.5 {-indexvar without -regexp} {
    set x {}
    list [catch {switch -glob -indexvar x -- abc . {set x}} msg] $x $msg
} {1 {} {-indexvar option requires -regexp option}}
test switch-12.6 {-indexvar unwritable} {
    set x {}
    list [catch {switch -regexp -indexvar x(x) -- abc . {set x}} msg] $x $msg
} {1 {} {can't set "x(x)": variable isn't array}}

test switch-13.1 {-indexvar -matchvar combinations} {
    switch -regexp -indexvar x -matchvar y abc {
	. {list $x $y}
    }
} {{{0 1}} a}
test switch-13.2 {-indexvar -matchvar combinations} {
    switch -regexp -indexvar x -matchvar y abc {
	.$ {list $x $y}
    }
} {{{2 3}} c}
test switch-13.3 {-indexvar -matchvar combinations} {
    switch -regexp -indexvar x -matchvar y abc {
	(.)(.)(.) {list $x $y}
    }
} {{{0 3} {0 1} {1 2} {2 3}} {abc a b c}}
test switch-13.4 {-indexvar -matchvar combinations} {
    set x -
    set y -
    switch -regexp -indexvar x -matchvar y abc {
	(.)(.)(.). -
	default {list $x $y}
    }
} {{} {}}
test switch-13.5 {-indexvar -matchvar combinations} {
    set x -
    set y -
    list [catch {
	switch -regexp -indexvar x(x) -matchvar y abc {. {list $x $y}}
    } msg] $x $y $msg
} {1 - - {can't set "x(x)": variable isn't array}}
test switch-13.6 {-indexvar -matchvar combinations} {
    set x -
    set y -
    list [catch {
	switch -regexp -indexvar x -matchvar y(y) abc {. {list $x $y}}
    } msg] $x $y $msg
} {1 {{0 1}} - {can't set "y(y)": variable isn't array}}

# cleanup
::tcltest::cleanupTests
return
