package require tcltest
namespace import ::tcltest::*
package require argparse
set currentDir [file normalize [file dirname [info script]]]


set templateProcStr {proc templateProc {args} {
    set arguments [argparse @additionalArgs@ {
        @definitions@
    }]
    set resultDict {}
    if {$arguments ne {}} {
        set exclude {args resultDict exclude}
    } else {
        set exclude {args resultDict arguments exclude}
    }
    foreach locVar [info locals] {
        if {$locVar in $exclude} {
            continue
        } else {
            dict append resultDict $locVar [subst $[subst $locVar]]
        }
    }
    return $resultDict
}}

proc testTemplate {testName descr arguments definitionsStr inputStr refStr} {
    variable templateProcStr
    test $testName $descr -body {
        eval [string map [list @definitions@ $definitionsStr @additionalArgs@ $arguments] $templateProcStr]
        if {[catch {set result [templateProc {*}$inputStr]} errorStr]} {
            return $errorStr
        } else {
            return $result
        }
    } -result $refStr -cleanup {
        rename templateProc {}
    }
}


### Only switches test without arguments
testTemplate onlySwitchNoArgsTest-1 {} {} {
-a
-b
-c} {-a -c} {a {} c {}}

testTemplate onlySwitchNoArgsTest-2 {} {} {
-a
-b
-c} {-a} {a {}}

testTemplate onlySwitchNoArgsTest-3 {} {} {
-a
-b
-c} {-a -c -b} {a {} b {} c {}}

testTemplate onlySwitchNoArgsTest-4 {} {} {
-a
-b
-c} {-a -c -b -k} {bad switch "-k": must be -a, -b, or -c}

testTemplate onlySwitchNoArgsTest-5 {} {} {
-a
-b
-c} {-a -c 1 -b} {too many arguments}

testTemplate onlySwitchNoArgsTest-6 {explicit -switch in element definition} {} {
{a -switch}
-b
-c} {-a -c} {a {} c {}}

testTemplate onlySwitchNoArgsTest-7 {} {} {
-a
-b
{-c -catchall}} {-a -c 1 2 3} {a {} c {1 2 3}}

testTemplate onlySwitchNoArgsTest-8 {} {} {
-a
{-b -require c}
{-c}} {-a -b} {-b requires -c}

testTemplate onlySwitchNoArgsTest-9 {} {} {
-a
{-b -require c}
{-c}} {-c -a -b} {a {} b {} c {}}

testTemplate onlySwitchNoArgsTest-10 {} {} {
-a
{-b -require {k c}}
-h
-c
-k} {-a -b} {-b requires -k}

testTemplate onlySwitchNoArgsTest-11 {} {} {
-a
{-b -require {k c}}
-h
-c
-k} {-a -b -k} {-b requires -c}

testTemplate onlySwitchNoArgsTest-12 {} {} {
-a
{-b -require {k c} -reciprocal}
-h
-c
-k} {-c} {-c requires -b}

testTemplate onlySwitchNoArgsTest-13 {} {} {
-a
{-b -require {k c} -reciprocal}
{-h -standalone}
-c
-k} {-c -h} {h {} c {}}

testTemplate onlySwitchNoArgsTest-14 {} {} {
-a
{-b -forbid {k c}}
-h
-c
-k} {-b -h -k} {-b conflicts with -k}

testTemplate onlySwitchNoArgsTest-14 {} {} {
-a
{-b -forbid {k c}}
-h
-c
-k} {-b -h} {h {} b {}}

testTemplate onlySwitchNoArgsTest-15 {} {} {
-a
-b
{-c -catchall}} {-c 1 2 3 -a} {c {1 2 3 -a}}

testTemplate onlySwitchNoArgsTest-16 {} {} {
{-a -key k}
-b
-c} {-a -c -b} {b {} c {} k {}}

# Bug?
testTemplate onlySwitchNoArgsTest-17 {} {} {
{-a -key k}
{-b -key k}
-c} {-a -c} {c {} k a}

testTemplate onlySwitchNoArgsTest-18 {} {} {
{-a -key k}
{-b -key k}
-c} {-a -c -b} {-a conflicts with -b}

testTemplate onlySwitchWArgsTest-19 {} {} {
-a
{-b -ignore}
-h
-c
-k} {-a -b -k -c} {a {} c {} k {}}

testTemplate onlySwitchWArgsTest-20 {} {} {
-a
{-be|b}
-h
-c
-k} {-a -be -k -c} {a {} b {} c {} k {}}

testTemplate onlySwitchWArgsTest-21 {} {} {
-a
{-b -alias be}
-h
-c
-k} {-a -be -k -c} {a {} b {} c {} k {}}

testTemplate onlySwitchNoArgsTest-22 {} {} {
-a
-b
-c} {-a -d} {bad switch "-d": must be -a, -b, or -c}

testTemplate onlySwitchNoArgsTest-23 {} {} {
-a} {-d} {bad switch "-d": must be -a}

### Only switches tests with arguments
testTemplate onlySwitchWArgsTest-1 {} {} {
-a=
-b=
-c=} {-a 1 -b 2 -c 3} {a 1 b 2 c 3}

testTemplate onlySwitchWArgsTest-2 {} {} {
-a=
-b=
-c=} {-a 1 -c 3} {a 1 c 3}

testTemplate onlySwitchWArgsTest-3 {} {} {
-a=
-b=
-c=} {-a 1 -c 3 -d 8} {bad switch "-d": must be -a, -b, or -c}

testTemplate onlySwitchWArgsTest-4 {} {} {
-a=
{-b= -required}
-c=} {-a 1 -c 3} {missing required switch: -b}

testTemplate onlySwitchWArgsTest-5 {} {} {
-a=
{-b= -required}
-c=} {-a 1 -c 3 -b} {-b requires an argument}

testTemplate onlySwitchWArgsTest-6 {} {} {
{a -switch -argument}
-b=
-c=} {-a 1 -b 2 -c 3} {a 1 b 2 c 3}

testTemplate onlySwitchWArgsTest-7 {} {} {
-a=
-b=
{-c= -catchall}} {-a 2 -b 3 -c 1 2 3} {a 2 b 3 c {1 2 3}}

testTemplate onlySwitchWArgsTest-8 {} {} {
-a=
-b=
{-c= -catchall}} {-a 2 -c 1 2 3 -b 3} {a 2 c {1 2 3 -b 3}}

testTemplate onlySwitchWArgsTest-9 {} {} {
-a=
{-b= -require {k c}}
-h=
-c=
-k=} {-a 1 -b 2 -k 3} {-b requires -c}

testTemplate onlySwitchWArgsTest-10 {} {} {
-a=
{-b= -require {k c}}
-h=
-c=
-k=} {-a 1 -b 2 -k 3 -c 2} {a 1 b 2 c 2 k 3}

testTemplate onlySwitchWArgsTest-11 {} {} {
-a=
{-b= -require {k c} -reciprocal}
-h=
-c=
-k=} {-c 2} {-c requires -b}

testTemplate onlySwitchWArgsTest-12 {} {} {
-a=
{-b= -require {k c} -reciprocal}
{-h= -standalone}
-c=
-k=} {-c 5 -h 10} {h 10 c 5}

testTemplate onlySwitchWArgsTest-13 {} {} {
-a=
{-b= -forbid {k c}}
-h=
-c=
-k=} {-b 1 -h 2 -k 3} {-b conflicts with -k}

testTemplate onlySwitchWArgsTest-14 {} {} {
-a=
{-b= -ignore}
-h=
-c=
-k=} {-a 1 -b 2 -k 3 -c 2} {a 1 c 2 k 3}

testTemplate onlySwitchWArgsTest-15 {} {} {
{-a= -default 10}
-b=
-h=
{-c= -default 20}
-k=} {-a 1 -b 2 -k 3} {a 1 b 2 c 20 k 3}

testTemplate onlySwitchWArgsTest-16 {} {} {
{-a -boolean}
-b=
-h=
{-c= -default 20}
-k=} {-b 2 -k 3} {a 0 b 2 c 20 k 3}

testTemplate onlySwitchWArgsTest-17 {} {} {
{-a -boolean}
-b=
-h=
{-c= -default 20}
-k=} {-a -b 2 -k 3} {a 1 b 2 c 20 k 3}

# Bug? -keep doesn't work as intended
testTemplate onlySwitchWArgsTest-18 {} {} {
-a=
-b=
-h=
{-c -keep}
-k=} {-a 5 -b 2 -k 3} {a 5 b 2 k 3}

testTemplate onlySwitchWArgsTest-19 {} {} {
{-a -key letter -value 1a}
{-b -key letter -value 1b}
{-h -key letter -value 1h}
{-c -key letter -value 1c}
-k=} {-a -k 3} {letter 1a k 3}

testTemplate onlySwitchWArgsTest-20 {} {} {
{-a -key letter -value 1a}
{-b -key letter -value 1b}
{-h -key letter -value 1h}
{-c -key letter -value 1c}
-k=} {-a -k 3 -c} {-a conflicts with -c}

testTemplate onlySwitchWArgsTest-21 {} {} {
{-a -key letter -value 1a}
{-b -key letter -value 1b}
{-h -key letter -value 1h}
{-c -key letter -value 1c -default 1c}
-k=} {-k 3} {letter 1c k 3}

testTemplate onlySwitchWArgsTest-22 {} {} {
-a=
{-b= -imply {-c} -required}
-c=} {-b 1 2} {b 1 c 2}

testTemplate onlySwitchWArgsTest-23 {} {} {
{-a= -argument}
-b=
-c=} {-a 1 -b 2 -c 3} {a 1 b 2 c 3}

testTemplate onlySwitchWArgsTest-24 {} {} {
-a=
{-b|ba= -required}
-c=} {-a 1 -c 3} {missing required switch: -b|ba}

testTemplate onlySwitchWArgsTest-25 {} {} {
{-a= -required}
{-b= -required}
-c=} {-c 3} {missing required switches: -a and -b}

testTemplate onlySwitchWArgsTest-26 {} {} {
{-a= -required}
{-b= -required}
{-c= -required}} {} {missing required switches: -a, -b, and -c}

### Only parameters tests 
testTemplate onlyParametersTest-1 {} {} {
a
b
c} {1 2 3} {a 1 b 2 c 3}

testTemplate onlyParametersTest-2 {} {} {
a
b?
c} {1 2} {a 1 c 2}

testTemplate onlyParametersTest-3 {} {} {
a
b?
c} {1 2 3} {a 1 b 2 c 3}

testTemplate onlyParametersTest-4 {} {} {
a
b
c?} {1 2} {a 1 b 2}

testTemplate onlyParametersTest-5 {} {} {
a
b
c?} {1 2 3} {a 1 b 2 c 3}

testTemplate onlyParametersTest-6 {} {} {
a?
b
c?
d
f?} {1 2} {d 2 b 1}

testTemplate onlyParametersTest-7 {} {} {
a?
b
c?
d
f?} {1 2 3} {d 3 a 1 b 2}

testTemplate onlyParametersTest-8 {} {} {
a?
b
c?
d
f?} {1 2 3 4} {d 4 a 1 b 2 c 3}

testTemplate onlyParametersTest-9 {} {} {
{a -optional}
b
c?
d
f?} {1 2 3 4 5} {d 4 a 1 f 5 b 2 c 3}

testTemplate onlyParametersTest-10 {} {} {
a?
b
c?
d
f?} {1 2 3 4 5 6} {too many arguments}

testTemplate onlyParametersTest-11 {} {} {
a
{b -forbid a}
c} {1 2 3} {b conflicts with a}

testTemplate onlyParametersTest-12 {} {} {
{a? -default 10}
b?
c} {1} {a 10 c 1}

testTemplate onlyParametersTest-13 {} {} {
{a? -default 10}
b
c} {1 2} {a 10 b 1 c 2}

testTemplate onlyParametersTest-14 {} {} {
{a? -default 10}
b?
c} {1 2} {a 1 c 2}

testTemplate onlyParametersTest-15 {} {} {
{a? -default 10}
b?
c} {1 2 3} {a 1 b 2 c 3}

testTemplate onlyParametersTest-16 {} {} {
{a? -require f}
b
c?
d
f?} {1 2 3} {a requires f}

testTemplate onlyParametersTest-17 {} {} {
{a? -ignore}
b
c?
d
f?} {1 2 3} {d 3 b 2}

testTemplate onlyParametersTest-18 {} {} {
{a? -ignore}
{b -ignore}
c?
d
f?} {1 2 3} {d 3}

# doesnt work, same as with -switch element
testTemplate onlyParametersTest-19 {} {} {
{a? -keep}
b
c?
d
f?} {1 2} {d 2 b 1}

testTemplate onlyParametersTest-20 {} {} {
a
b
c} {1 2} {missing required parameter: c}

testTemplate onlyParametersTest-21 {} {} {
a
b
c} {1} {missing required parameters: b and c}

testTemplate onlyParametersTest-22 {} {} {
a
b
c} {} {missing required parameters: a, b, and c}

### Combination of switches and parameters tests 
testTemplate switchesParametersCombsTest-1 {} {} {
{-a= -required}
{-b= -default 10}
-c
d
e} {-a 1 -c 5 6} {d 5 e 6 a 1 b 10 c {}}

testTemplate switchesParametersCombsTest-2 {} {} {
{-a= -required}
{-b= -default 10}
-c
d
e} {-a 1 -b 9 -c 5 6} {d 5 e 6 a 1 b 9 c {}}

testTemplate switchesParametersCombsTest-3 {} {} {
{-a= -required}
{-b= -default 10}
-c
d
e} {-a 1 -b 9 -c 5 6} {d 5 e 6 a 1 b 9 c {}}

testTemplate switchesParametersCombsTest-4 {} {} {
-c
d
{-a= -required}
{-b= -default 10}
e} {-a 1 -b 9 -c 5 6} {d 5 e 6 a 1 b 9 c {}}

testTemplate switchesParametersCombsTest-5 {} {} {
-a=
{-b= -require {c k} -reciprocal}
{-h= -standalone}
-c=
{k -optional}} {-b 5 -h 10} {h 10 b 5}

testTemplate switchesParametersCombsTest-6 {} {} {
-a=
{-b= -require {c k}}
-h= 
-c=
{k -optional}} {-b 5 -c 10 1} {b 5 k 1 c 10}

testTemplate switchesParametersCombsTest-7 {} {} {
-a=
{-b= -require {c k}}
-h= 
-c=
{k -optional}} {-b 5 -c 10} {-b requires k}

### Wrong elements definitions tests
testTemplate wrongDefsTest-1 {} {} {
{-a -switch -argument}
-b=
-c=} {-a 1 -b 2 -c 3} {bad element name: -a}

### Check -exact option and prefixes of switches
testTemplate exactAndPrefixesTest-1 {} {} {
-cer=
-dta=
-art=
-bet=
-e=} {-ce 1 -be 9 -dt 5 -a 6 -e 1} {e 1 dta 5 cer 1 art 6 bet 9}

testTemplate exactAndPrefixesTest-2 {} {} {
-cer=
-cer1=
-art=
-bet=
-e=} {-ce 1 -be 9 -dt 5 -a 6 -e 1} {bad switch "-ce": must be -art, -bet, -cer, -cer1, or -e}

testTemplate exactAndPrefixesTest-3 {} {} {
-cer2=
-cer1=
-art=
-bet=
-e=} {-cer1 1 -be 9 -a 6 -e 1} {e 1 art 6 bet 9 cer1 1}

testTemplate exactAndPrefixesTest-4 {} {-exact} {
-cer=
-dta=
-art=
-bet=
-e=} {-ce 1 -be 9 -dt 5 -a 6 -e 1} {bad switch "-ce": must be -art, -bet, -cer, -dta, or -e}

testTemplate exactAndPrefixesTest-5 {} {-exact} {
-cer=
-dta=
-art=
-bet=
-e=} {-cer 1 -bet 9 -dta 5 -art 6 -e 1} {e 1 dta 5 cer 1 art 6 bet 9}

### Check -long option for switches
# add checking with mixed arguments and -- switch
testTemplate longTest-1 {} {-long} {
-cer=
-dta=
-art=
-bet=
-e=} {-cer 1 -bet 9 --dta 5 -art 6 --e 1} {e 1 dta 5 cer 1 art 6 bet 9}

testTemplate longTest-2 {} {} {
-cer=
-dta=
-art=
-bet=
-e=} {-cer 1 -bet 9 --dta 5 -art 6 --e 1} {too many arguments}

testTemplate longTest-3 {} {-long} {
-cer=
-dta=
-art=
-bet=
-e=} {-cer 1 -bet 9 --dta 5 -art 6 ---e 1} {too many arguments}

### Check -equalarg option for switches
testTemplate equalargTest-1 {} {-equalarg} {
-cer=
-dta=
-art=
-bet=
-e=} {-cer 1 -bet=9 -dta 5 -art 6 -e=1} {e 1 dta 5 cer 1 art 6 bet 9}

testTemplate equalargTest-2 {} {} {
-cer=
-dta=
-art=
-bet=
-e=} {-cer 1 -bet=9 -dta 5 -art 6 -e=1} {too many arguments}

### Check -inline option for switches
testTemplate inlineTest-1 {} {-inline} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {-cer 1 -bet 9 -dta 5 -art 6 -e 1 4 5} {arguments {cer 1 bet 9 dta 5 art 6 e 1 lab 4 had 5}}

### Check -mixed option
testTemplate mixedTest-1 {} {-mixed} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {-cer 1 -bet 9 4 5 -dta 5 -art 6 -e 1} {had 5 e 1 dta 5 cer 1 lab 4 art 6 bet 9}

testTemplate mixedTest-2 {} {-mixed} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {-cer 1 -bet 9 4 -dta 5 -art 6 5 -e 1} {had 5 e 1 dta 5 cer 1 lab 4 art 6 bet 9}

testTemplate mixedTest-3 {} {-mixed} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {4 -cer 1 -bet 9 -dta 5 -art 6 5 -e 1} {had 5 e 1 dta 5 cer 1 lab 4 art 6 bet 9}

testTemplate mixedTest-4 {} {-mixed} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {4 -cer 1 -bet 9 -dta 5 -art 6 5 -e 1} {had 5 e 1 dta 5 cer 1 lab 4 art 6 bet 9}

testTemplate mixedTest-5 {} {-mixed} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {-cer 1 -bet 9 -dta 5 -art 6 -e 1 -- 5 -likeaswitch} {had -likeaswitch e 1 dta 5 cer 1 lab 5 art 6 bet 9}

testTemplate mixedTest-6 {} {-mixed} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {-cer 1 -bet 9 -dta 5 -art 6 -e 1 5 -likeaswitch} {bad switch "-likeaswitch": must be -art, -bet, -cer, -dta, or -e}

testTemplate mixedTest-7 {} {-mixed} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {5 -likeaswitch -cer 1 -bet 9 -dta 5 -art 6 -e 1} {bad switch "-likeaswitch": must be -art, -bet, -cer, -dta, or -e}

testTemplate mixedTest-8 {} {} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {-cer 1 -bet 9 -dta 5 -art 6 -e 1 5 -likeaswitch} {had -likeaswitch e 1 dta 5 cer 1 lab 5 art 6 bet 9}

testTemplate mixedTest-9 {} {-mixed} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {-cer 1 -bet 9 -dta 5 -art 6 -e 1 -- 1 5} {had 5 e 1 dta 5 cer 1 lab 1 art 6 bet 9}

### Check -reciprocal option
testTemplate reciprocalTest-1 {} {-reciprocal} {
{-cer= -require {bet e}}
-dta=
-art=
-bet=
-e=
lab
had} {-bet 9 -dta 5 -art 6 -e 1 4 5} {-bet requires -cer}

### Check -pass option
testTemplate passTest-1 {} {-pass rest} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {-bet 9 -dta 5 -art 6 -e 1 -k -l 786 4 5} {had 4 e 1 dta 5 rest {-k -l 5} lab 786 art 6 bet 9}

testTemplate passTest-2 {} {-pass rest} {
-cer=
-dta=
-art=
-bet=
-e=
lab
had} {-bet 9 -dta 5 -art 6 -e 1 -k 90 -l 786 4 5} {had -l e 1 dta 5 rest {-k 786 4 5} lab 90 art 6 bet 9}

testTemplate passTest-3 {} {-pass rest} {
-cer=
-dta=
-art=
-bet=
-e=} {-bet 9 -dta 5 -art 6 -e 1 -k 90 -l 786 4 5} {e 1 dta 5 rest {-k 90 -l 786 4 5} art 6 bet 9}

testTemplate passTest-4 {} {-pass rest} {
-cer=
-dta=
-art=
-bet=
{-e= -catchall}} {-bet 9 -dta 5 -art 6 -e 1 -k 90 -l 786 4 5} {e {1 -k 90 -l 786 4 5} dta 5 rest {} art 6 bet 9}

testTemplate passTest-5 {} {-pass rest} {
-cer=
-dta=
-art=
-bet=
{e -catchall}
lab
had} {4 5 -e 1 2 3} {had 3 e {4 5 -e 1} rest {} lab 2}
 
testTemplate passTest-6 {} {-pass rest} {
-cer=
-dta=
-art=
-bet=
{e -catchall -pass rest1}
lab
had} {- 5 -e 1 2 3} {had 3 rest {} lab 2 rest1 {-- - 5 -e 1}}

testTemplate passTest-7 {} {-pass rest} {
-cer=
-dta=
-art=
-bet=
{e -catchall}
lab
had} {- 5 -e 1 2 3} {had 3 e {- 5 -e 1} rest {} lab 2}

### Check -keep option
# doesn't work as it should? or if work as it should, what is the point if the option?
testTemplate keepTest-1 {} {-keep} {
-a=
-b=
-c
d
e} {1 2} {d 1 e 2}

### Check -normalize option
testTemplate normalizeTest-1 {} {-normalize -equalarg} {
-a=
-b=
{-c= -pass rest}
d
e} {-c=5 -a=4 1 2} {d 1 e 2 a 4 rest {-c 5}}

testTemplate normalizeTest-2 {} {-equalarg} {
-a=
-b=
{-c= -pass rest}
d
e} {-c=5 -a=4 1 2} {d 1 e 2 a 4 rest -c=5}

testTemplate normalizeTest-3 {} {-normalize -equalarg -long} {
{-a= -pass rest}
{-b= -pass rest}
{-c= -pass rest}
d
e} {-c=5 -a=4 --b 8 1 2} {d 1 e 2 rest {-c 5 -a 4 -b 8}}

testTemplate normalizeTest-4 {} {-normalize -equalarg -long} {
{-a= -pass rest -default 5}
{-b= -pass rest}
{-c= -pass rest}
d
e} {-b=4 1 2} {d 1 e 2 rest {-b 4 -a 5}}

testTemplate normalizeTest-5 {} {-equalarg -long} {
{-a= -pass rest -default 5}
{-b= -pass rest}
{-c= -pass rest}
d
e} {-b=4 1 2} {d 1 e 2 rest -b=4}

testTemplate normalizeTest-6 {} {-normalize -equalarg -long} {
{-a= -pass rest -default 5}
{-b= -pass rest}
{-c= -pass rest}
{d -optional -pass rest -default 10}
e} {-b=4 1} {e 1 rest {-b 4 -a 5 10}}

testTemplate normalizeTest-7 {} {-equalarg -long} {
{-a= -pass rest -default 5}
{-b= -pass rest}
{-c= -pass rest}
{d -optional -pass rest -default 10}
e} {-b=4 1} {e 1 rest -b=4}

testTemplate normalizeTest-8 {} {-normalize -equalarg -long -mixed} {
{-a= -pass rest -default 5}
{-b= -pass rest -default 6}
{-c= -pass rest -default 7}
{d -optional -pass rest -default 10}
{e -optional -pass rest -default 11}
{k -optional -pass rest -default 12}} {-b=4 1} {rest {-b 4 -a 5 -c 7 1 11 12}}

testTemplate normalizeTest-9 {} {-equalarg -long -mixed} {
{-a= -pass rest -default 5}
{-b= -pass rest -default 6}
{-c= -pass rest -default 7}
{d -optional -pass rest -default 10}
{e -optional -pass rest -default 11}
{k -optional -pass rest -default 12}} {-b=4 1} {rest {-b=4 1}}

testTemplate normalizeTest-10 {} {-normalize -mixed} {
{d -optional -pass rest -default 10}
{e -optional -pass rest -default 11}
{k -optional -pass rest -default 12}} {-1 2} {rest {-- -1 2 12}}

testTemplate normalizeTest-11 {} {-normalize -equalarg} {
-a=
-b=
{-cabn= -pass rest}
d
e} {-c=5 -a=4 1 2} {d 1 e 2 a 4 rest {-cabn 5}}

testTemplate normalizeTest-12 {} {} {
-a=
-b=
{-cabn= -pass rest}
d
e} {-c 5 -a 4 1 2} {d 1 e 2 a 4 rest {-c 5}}

testTemplate normalizeTest-13 {} {-normalize -mixed} {
{d -optional -pass rest }
{e -optional -pass rest -default 11}
{k -optional -pass rest -default 12}} {} {rest {11 12}}

testTemplate normalizeTest-14 {} {-normalize} {
{-a|ban= -pass rest -default 10}
-b=
{-cabn= -pass rest}
d
e} {-c 5 -a 15 1 2} {d 1 e 2 rest {-cabn 5 -ban 15}}

testTemplate normalizeTest-15 {} {-normalize} {
{-a|ban= -pass rest -default 10}
-b=
{-cabn= -pass rest}
d
e} {-c 5 -a 15 1 2} {d 1 e 2 rest {-cabn 5 -ban 15}}

testTemplate normalizeTest-16 {} {-normalize} {
{-a|ban= -pass rest -default 10}
-b=
{-cabn= -pass rest}
d
e} {-c 5 -a 15 1 2} {d 1 e 2 rest {-cabn 5 -ban 15}}

testTemplate normalizeTest-17 {} {-normalize -pass rest1} {
{-a|ban= -pass rest -default 10}
-b=
{-cabn= -pass rest}
d
e} {-c 5 -a 15 1 2} {d 1 e 2 rest {-cabn 5 -ban 15} rest1 {}}

testTemplate normalizeTest-18 {} {-normalize -mixed} {
{d -optional -pass rest1 -default -}
{e -optional -pass rest -default -}
{k -optional -pass rest -default -}} {-} {rest {-- - -} rest1 {-- -}}

### Check -boolean option
testTemplate booleanTest-1 {} {-boolean} {
-a
-b
-c} {-a} {a 1 b 0 c 0}

### Check global -validate option
testTemplate validateTest-1 {} {-validate [dict create check1 {[string is double $arg]} check2 {[string is integer $arg]}]} {
{-a= -validate check1}
-b=
{-c= -validate check2}} {-a 1 -b 2 -c 4} {a 1 b 2 c 4}

testTemplate validateTest-2 {} {-validate [dict create check1 {[string is double $arg]} check2 {[string is integer $arg]}]} {
{-a= -validate check1}
-b=
{-c= -validate check2}} {-a n -b 2 -c 4} {-a value "n" fails check1 validation}

testTemplate validateTest-3 {} {-validate [dict create check1 {[string is double $arg]} check2 {[string is integer $arg]}]} {
{-a= -validate check1}
-b=
{-c= -validate check2}} {-a 1 -b 2 -c 4.5} {-c value "4.5" fails check2 validation}

testTemplate validateTest-4 {} {-validate [dict create check1 {[string is double $arg]} check2 {[string is integer $arg]}]} {
{a -validate check1}
-b=
{c -validate check2}} {-b 1 2 4} {a 2 b 1 c 4}

testTemplate validateTest-5 {} {-validate [dict create check1 {[string is double $arg]} check2 {[string is integer $arg]}]} {
{a -validate check1}
-b=
{c -validate check2}} {-b 1 n 4} {a value "n" fails check1 validation}

testTemplate validateTest-6 {} {-validate [dict create check1 {[string is double $arg]} check2 {[string is integer $arg]}]} {
{a -validate check1}
-b=
{c -validate check2}} {-b 1 1 4.5} {c value "4.5" fails check2 validation}

### Check inline -validate option
testTemplate validateInlineTest-1 {} {} {
{-a= -validate {[string is double $arg]}}
-b=
{-c= -validate {[string is integer $arg]}}} {-a 1 -b 2 -c 4} {a 1 b 2 c 4}

testTemplate validateInlineTest-2 {} {} {
{-a= -validate {[string is double $arg]}}
-b=
{-c= -validate {[string is integer $arg]}}} {-a n -b 2 -c 4} {-a value "n" fails validation: [string is double $arg]}

testTemplate validateInlineTest-3 {} {} {
{-a= -validate {[string is double $arg]}}
-b=
{-c= -validate {[string is integer $arg]}}} {-a 1 -b 2 -c 4.5} {-c value "4.5" fails validation: [string is integer $arg]}

testTemplate validateInlineTest-4 {} {} {
{a -validate {[string is double $arg]}}
-b=
{c -validate {[string is integer $arg]}}} {-b 1 2 4} {a 2 b 1 c 4}

testTemplate validateInlineTest-5 {} {} {
{a -validate {[string is double $arg]}}
-b=
{c -validate {[string is integer $arg]}}} {-b 1 n 4} {a value "n" fails validation: [string is double $arg]}

testTemplate validateInlineTest-6 {} {} {
{a -validate {[string is double $arg]}}
-b=
{c -validate {[string is integer $arg]}}} {-b 1 1 4.5} {c value "4.5" fails validation: [string is integer $arg]}

testTemplate validateInlineTest-7 {} {} {
{-a= -validate {[string is double $arg]} -catchall}
-b=
{-c= -validate {[string is integer $arg]}}} {-b 2 -c 4 -a 1 2 3} {a {1 2 3} b 2 c 4}


### Check global -enum option
testTemplate enumTest-1 {} {-enum [dict create check1 {i o p} check2 {k m o}]} {
{-a= -enum check1}
-b=
{-c= -enum check2}} {-a o -b 2 -c m} {a o b 2 c m}

testTemplate enumTest-2 {} {-enum [dict create check1 {i o p} check2 {k m o}]} {
{-a= -enum check1}
-b=
{-c= -enum check2}} {-a y -b 2 -c m} {bad -a value "y": must be i, o, or p}

testTemplate enumTest-3 {} {-enum [dict create check1 {i o p} check2 {k m o}]} {
{-a= -enum check1}
-b=
{-c= -enum check2}} {-a o -b 2 -c p} {bad -c value "p": must be k, m, or o}

testTemplate enumTest-4 {} {-enum [dict create check1 {i o p} check2 {k m o}]} {
{a -enum check1}
-b=
{c -enum check2}} {-b 1 o m} {a o b 1 c m}

testTemplate enumTest-5 {} {-enum [dict create check1 {i o p} check2 {k m o}]} {
{a -enum check1}
-b=
{c -enum check2}} {-b 1 y m} {bad a value "y": must be i, o, or p}

testTemplate enumTest-6 {} {-enum [dict create check1 {i o p} check2 {k m o}]} {
{a -enum check1}
-b=
{c -enum check2}} {-b 1 o p} {bad c value "p": must be k, m, or o}

testTemplate enumTest-7 {} {-exact -enum [dict create check1 {i ort p} check2 {k m o}]} {
{-a= -enum check1}
-b=
{-c= -enum check2}} {-a o -b 2 -c m} {bad -a value "o": must be i, ort, or p}

testTemplate enumTest-8 {} {-enum [dict create check1 {i ort p} check2 {k m o}]} {
{-a= -enum check1}
-b=
{-c= -enum check2}} {-a o -b 2 -c m} {a ort b 2 c m}

### Check inline -enum option
testTemplate enumInlineTest-1 {} {} {
{-a= -enum {i o p}}
-b=
{-c= -enum {k m o}}} {-a o -b 2 -c m} {a o b 2 c m}

testTemplate enumInlineTest-2 {} {} {
{-a= -enum {i o p}}
-b=
{-c= -enum {k m o}}} {-a y -b 2 -c m} {bad -a value "y": must be i, o, or p}

testTemplate enumInlineTest-3 {} {} {
{-a= -enum {i o p}}
-b=
{-c= -enum {k m o}}} {-a o -b 2 -c p} {bad -c value "p": must be k, m, or o}

testTemplate enumInlineTest-4 {} {} {
{a -enum {i o p}}
-b=
{c -enum {k m o}}} {-b 1 o m} {a o b 1 c m}

testTemplate enumInlineTest-5 {} {} {
{a -enum {i o p}}
-b=
{c -enum {k m o}}} {-b 1 y m} {bad a value "y": must be i, o, or p}

testTemplate enumInlineTest-6 {} {} {
{a -enum {i o p}}
-b=
{c -enum {k m o}}} {-b 1 o p} {bad c value "p": must be k, m, or o}

testTemplate enumInlineTest-7 {} {} {
{-a= -enum {inp o p}}
-b=
{-c= -enum {k m o}}} {-b 1 -a i -c m} {a inp b 1 c m}

testTemplate enumInlineTest-8 {} {-exact} {
{-a= -enum {inp o p}}
-b=
{-c= -enum {k m o}}} {-b 1 -a i -c m} {bad -a value "i": must be inp, o, or p}

testTemplate enumInlineTest-9 {} {} {
{-a= -enum {inp o p} -catchall}
-b=
{-c= -enum {k m o}}} {-b 1 -c m -a i o p} {a {inp o p} b 1 c m}

testTemplate enumInlineTest-10 {} {} {
{a -enum {inp o p}}
-b=
{-c= -enum {k m o}}} {-b 1 -c m i} {a inp b 1 c m}

testTemplate enumInlineTest-11 {} {} {
{a -enum {inp o p} -catchall}
-b=
{-c= -enum {k m o}}} {-b 1 -c m i o p} {a {inp o p} b 1 c m}

### Check -upvar option
test upvarTest-1 {} -body {
    proc upvarProc {args} {
        argparse {
            {a -upvar}
            b
            c
        }
        set a "$b+$c"
    }
    upvarProc p 1 2
    return $p
} -result 1+2 -cleanup {
    rename upvarProc {}
    unset p
}

test upvarTest-2 {} -body {
    proc upvarProc {args} {
        argparse {
            {-a= -upvar}
            b
            c
        }
        set a "$b+$c"
    }
    upvarProc -a p 1 2
    return $p
} -result 1+2 -cleanup {
    rename upvarProc {}
    unset p
}

test upvarTest-3 {} -body {
    proc upvarProc {args} {
        argparse {
            {-a= -key j -upvar}
            {-b= -key j -upvar}
            c
        }
        set a $c
        set b $c
    }
    catch {upvarProc -a p -b p 1} errorStr
    return $errorStr
} -result {multiple upvars to the same variable: a b} -cleanup {
    rename upvarProc {}
    unset errorStr
}

### Check -- option
testTemplate --Test-6 {} {-normalize -equalarg -long --} {
{-a= -pass rest -default 5}
{-b= -pass rest}
{-c= -pass rest}
{d -optional -pass rest -default 10}
e} {-b=4 1} {e 1 rest {-b 4 -a 5 10}}

### Check -template option
test templateTest-1 {} -body {
    proc templateOptProc {args} {
        argparse -template apopts(%) {
            a
            b
            c
        }
        foreach {name value} [array get apopts] {
            dict append result $name $value
        }
        return $result
    }
    templateOptProc p 1 2
} -result {a p b 1 c 2} -cleanup {
    rename templateOptProc {}
}

test templateTest-2 {} -body {
    proc templateOptProc {args} {
        argparse -template apopts(%) {
            a
            b
            -c=
        }
        foreach {name value} [array get apopts] {
            dict append result $name $value
        }
        return $result
    }
    templateOptProc -c 2 p 1 
} -result {a p b 1 c 2} -cleanup {
    rename templateOptProc {}
}

test templateTest-3 {} -body {
    proc templateOptProc {args} {
        argparse {
            {a -key apopts(a)}
            {b -key apopts(b)}
            {-c= -key apopts(-c)}
        }
        foreach {name value} [array get apopts] {
            dict append result $name $value
        }
        return $result
    }
    templateOptProc -c 2 p 1 
} -result {-c 2 a p b 1} -cleanup {
    rename templateOptProc {}
}

test templateTest-4 {} -body {
    proc templateOptProc {args} {
        argparse -template apopts(%) {
            a
            b^
            -c=
        }
        foreach {name value} [array get apopts] {
            dict append result $name $value
        }
        return $result
    }
    catch {templateOptProc -c 2 p 1} errorStr
    return $errorStr
} -result {bad variable name "apopts(b)": can't create a scalar variable that looks like an array element} -cleanup {
    rename templateOptProc {}
    unset errorStr
}

testTemplate templateTest-5 {} {-template %_%_%} {
a
b
-c=} {-c 2 p 1 } {b_b_b 1 a_a_a p c_c_c 2}
### Check specific options variants
test specOptsTest-1 {} -body {
    proc specOptsProc {args} {
        argparse {} {} {}
        return
    }
    catch {specOptsProc p 1 2} errorStr
    return $errorStr
} -result {too many arguments} -cleanup {
    rename specOptsProc {}
}

test specOptsTest-2 {} -body {
    proc specOptsProc {args} {
        argparse
        return
    }
    catch {specOptsProc p 1 2} errorStr
    return $errorStr
} -result {missing required parameter: definition} -cleanup {
    rename specOptsProc {}
}

test specOptsTest-3 {} -body {
    proc specOptsProc {} {
        argparse {} {}
        return
    }
    catch {specOptsProc} errorStr
    return $errorStr
} -result {} -cleanup {
    rename specOptsProc {}
}

test specOptsTest-4 {} -body {
    proc specOptsProc {args} {
        argparse {
            b
            c
        } $args
        return [list $b $c]
    }
    specOptsProc 2 3
} -result {2 3} -cleanup {
    rename specOptsProc {}
}

### Check comments in definition
testTemplate commentTest-1 {} {} {
-a
# comment1
-b
{# comment2}
-c} {-a -c} {a {} c {}}

testTemplate commentTest-2 {} {} {
-a
# comment1
-b
{#comment2}
-c} {-a -c} {bad element shorthand: #comment2}

testTemplate commentTest-3 {} {} {
-a
#
-b
{# comment2}
-c} {-a -c} {a {} c {}}

### Conflicting and wrong definitions tests
testTemplate conflictsInDefsTest-1 {} {} {
{-a -parameter}} {} {bad element name: -a}

testTemplate conflictsInDefsTest-2 {} {} {
{a -parameter -switch}} {} {-switch and -parameter conflict}

testTemplate conflictsInDefsTest-3 {} {} {
{-a -switch}} {} {bad element name: -a}

testTemplate conflictsInDefsTest-4 {} {} {
{-a -ignore -key A}} {} {-ignore and -key conflict}

testTemplate conflictsInDefsTest-5 {} {} {
{-a -ignore -pass A}} {} {-ignore and -pass conflict}

testTemplate conflictsInDefsTest-6 {} {} {
{-a -ignore -pass A}} {} {-ignore and -pass conflict}

testTemplate conflictsInDefsTest-7 {} {} {
{-a -default 1 -required}} {} {-required and -default conflict}
# issue with keep?
testTemplate conflictsInDefsTest-8 {} {} {
{-a -default 1 -keep}} {} {a 1}

testTemplate conflictsInDefsTest-9 {} {-inline} {
{-a -keep }} {} {-inline and -keep conflict}

testTemplate conflictsInDefsTest-10 {} {} {
{-a= -value A}} {} {-argument and -value conflict}

testTemplate conflictsInDefsTest-11 {} {} {
{a -value A}} {} {-parameter and -value conflict}

testTemplate conflictsInDefsTest-12 {} {-inline -keep} {
{-a}} {} {-inline and -keep conflict}

testTemplate conflictsInDefsTest-13 {} {-inline} {
{-a= -upvar}} {} {-upvar and -inline conflict}
# add upvar conflicts!

testTemplate conflictsInDefsTest-14 {} {} {
{a -switch -optional -catchall}} {} {-switch -optional -catchall is a disallowed combination}

testTemplate conflictsInDefsTest-15 {} {} {
{a -switch -optional -upvar}} {} {-switch -optional -upvar is a disallowed combination}

testTemplate conflictsInDefsTest-16 {} {} {
{a -switch -optional -default 1}} {} {-switch -optional -default is a disallowed combination}

# bug?? should be '-switch -optional -boolean is a disallowed combination'
testTemplate conflictsInDefsTest-17 {} {} {
{a -switch -boolean -optional}} {} {-argument and -boolean conflict}

testTemplate conflictsInDefsTest-18 {} {} {
{a -parameter -optional -required}} {} {-parameter -optional -required is a disallowed combination}

testTemplate conflictsInDefsTest-19 {} {} {
{a -catchall}
{b -catchall}} {1 1} {multiple catchall parameters: a and b}

testTemplate conflictsInDefsTest-20 {} {} {
{-a= -upvar -type double}
{b -catchall}} {1 1} {-type and -upvar conflict}

### Requirements tests
testTemplate requirementsTest-1 {} {} {
{-a= -reciprocal}
-b
-a} {-a -b} {-reciprocal requires -require}

testTemplate requirementsTest-2 {} {} {
{-a= -level}
-b
-a} {-a -b} {-level requires -upvar}

### Misc tests
testTemplate miscTest-1 {} {} {
-a
{}
-b
{# comment2}
-c} {-a -c} {element definition cannot be empty}

testTemplate miscTest-2 {} {} {
{-a= -enum}
-b
-c} {-a -c} {-enum requires an argument}

testTemplate miscTest-3 {} {} {
-a= 
-b
-a} {-a -b} {element name collision: a}

testTemplate miscTest-4 {} {} {
{-a= -alias $a} 
-b
-a} {-a -b} {bad alias: $a}

testTemplate miscTest-5 {} {} {
{-a= -alias n} 
{-b= -alias n} 
-a} {-a -b} {element alias collision: n}

testTemplate miscTest-5 {} {} {
-b|p= 
{-b= -alias n} 
-a=} {-a 1 -b 1} {collision of switch -p alias with the -b switch}

testTemplate miscTest-6 {} {} {
{-a= -require t} 
{-b= -alias n} 
-g} {-a -b} {a -require references undefined element: t}

testTemplate miscTest-7 {} {} {
{-a= -key t} 
{-b= -alias n} 
{g -key t}} {-a -b} {a cannot use -argument because it shares a key with g}

testTemplate miscTest-8 {} {} {
{-a -key t} 
{-b= -alias n} 
{g -key t}} {-a -b} {g cannot be a parameter because it shares a key with a}

testTemplate miscTest-9 {} {} {
{-a -key t -default 1} 
{-g -key t -default 2}} {-a -g} {a and g cannot both use -default because they share a key}

testTemplate miscTest-10 {} {} {
{-a -key t -value 1} 
{-g -key t -value 2}} {-a -g} {-a conflicts with -g}

testTemplate miscTest-11 {} {} {
{-a -key t -value 1} 
{-g -key t -value 2}
{-k -key t -value 3}} {-a} {t 1}

testTemplate miscTest-12 {} {-normalize} {
-cer=
-dta=
-art=
-bet=
{-e= -catchall -pass rest}
lab
had} {-cer 1 -e 2 io p 4 5} {had 5 rest {-e 2 io p} cer 1 lab 4}

testTemplate miscTest-13 {} {} {
-cer=
-dta=
-art=
-bet=
{-e= -catchall -pass rest}
lab
had} {-cer 1 -e 2 io p 4 5} {had 5 rest {-e 2 io p} cer 1 lab 4}

testTemplate miscTest-14 {} {-normalize -equalarg} {
-cer=
-dta=
-art=
-bet=
-e
lab
had} {-e=1 -cer 1 4 5} {-e doesn't allow an argument}

testTemplate miscTest-15 {} {-normalize -equalarg} {
-cer=
-dta=
-art=
-bet=
{-e -pass rest}
lab
had} {-e -cer 1 4 5} {had 5 cer 1 rest -e lab 4}

testTemplate miscTest-16 {} {-normalize -equalarg} {
{-cer= -key j -optional}
-dta=
-art=
-bet=
{-e -key y}
lab
had} {-e -cer 1 4 5} {had 5 y {} j {{} 1} lab 4}

testTemplate miscTest-17 {} {-normalize -equalarg} {
{-cer= -optional -pass a}
-dta=
-art=
-bet=
{-e -key y}
{lab -optional}
had} {-e -cer 5} {had 5 a -cer y {}}

testTemplate miscTest-18 {} {-equalarg} {
{-cer= -optional -pass a}
-dta=
-art=
-bet=
{-e -key y}
{lab -optional}
had} {-e -cer 5} {had 5 a -cer y {}}

testTemplate miscTest-19 {} {-normalize -equalarg} {
{-cer= -optional}
-dta=
-art=
-bet=
{-e -key y}
{lab -optional}
had} {-e -cer 5} {had 5 y {} cer {}}

testTemplate miscTest-20 {} {-normalize -equalarg} {
{-cer= -key j -catchall}
-dta=
-art=
-bet=
{-e -key y}
lab
had} {-e 4 5} {had 5 y {} j {} lab 4}

### Check -type in definitions 
testTemplate typeTest-1 {} {} {
{-a= -type alpha}
{-b= -type boolean}
{c -type integer}} {-a y -b False 10} {a y b False c 10}

testTemplate typeTest-2 {} {} {
{-a= -type alpha1}
{-b= -type boolean}
{c -type integer}} {-a y -b False 10} {type alpha1 is not in the list of allowed types, must be alnum, alpha, ascii,\
        boolean, control, dict, digit, double, graph, integer, list, lower, print, punct, space, upper, wideinteger,\
        wordchar or xdigit}

testTemplate typeTest-3 {} {} {
{-a= -type alpha}
{-b= -type boolean}
{c -type integer}} {-a y -b False 10.1} {c value "10.1" is not of the type integer}

testTemplate typeTest-4 {} {} {
{-a= -type alpha}
{-b= -type boolean}
{c -type integer}} {-a y -b False -1} {a y b False c -1}

testTemplate typeTest-5 {} {} {
{-a= -type alpha}
{-b= -type boolean}
{c -type integer}} {-a y! -b False -1} {-a value "y!" is not of the type alpha}

testTemplate typeTest-6 {} {-mixed} {
{-a= -type alpha -catchall}
{-b= -type boolean}
{c -type integer}} {-b False 1 -a y ty qwq} {a {y ty qwq} b False c 1}

testTemplate typeTest-7 {} {-mixed} {
{-a= -type alpha -catchall}
{-b= -type boolean}
{c -type integer}} {-b False 1 -a y ty 1} {-a value "1" is not of the type alpha}

testTemplate typeTest-8 {} {} {
{-a= -type alpha}
{-b= -type boolean}
{-nterms= -default 3 -type integer -validate {$arg>0}\
                 -errormsg {Number of terms -nterms must be more than zero}\
                 -help {Number of terms of interpolation polynom}}} {-a y -b False -nterms 10.5}\
        {-nterms value "10.5" is not of the type integer}

testTemplate typeTest-9 {} {} {
{-a= -type double -catchall}
-b=
{-c= -type integer}} {-b 2 -c 4 -a 1 2 3} {a {1 2 3} b 2 c 4}

if {[package vsatisfies [package provide Tcl] 9.0-]} {
    testTemplate typeTest-10 {} {} {
    {-a= -type double -catchall}
    -b=
    {-c= -type dict}} {-b 2 -c {a n u k} -a 1 2 3} {a {1 2 3} b 2 c {a n u k}}

    testTemplate typeTest-11 {} {} {
    {-a= -type double -catchall}
    -b=
    {-c= -type dict}} {-b 2 -c {a n u} -a 1 2 3} {-c value "a n u" is not of the type dict}
}

### Check -allow in definitions 
testTemplate allowTest-1 {} {} {
{-a= -allow {c}}
-b=
-c=
-d=
-e=
{f -optional}
g} {-a 1 -c 4 4 5} {a doesn't allow f}

testTemplate allowTest-2 {} {} {
{-a= -allow {c}}
-b=
-c=
-d=
-e=
{f -optional}
g} {-a 1 -c 4 5} {a doesn't allow g}

testTemplate allowTest-3 {} {} {
{-a= -allow {g}}
-b=
-c=
-d=
-e=
{f -optional}
g} {-a 1 5} {a 1 g 5}

testTemplate allowTest-4 {} {} {
{-a= -allow {g f c}}
-b=
-c=
-d=
-e=
{f -optional}
g} {-a 1 5} {a 1 g 5}

testTemplate allowTest-5 {} {} {
{-a= -allow {g f c}}
-b=
-c=
-d=
-e=
{f -optional}
g} {-c 2 -a 1 5} {a 1 g 5 c 2}

testTemplate allowTest-6 {} {} {
{-a= -allow {g f c}}
-b=
-c=
-d=
-e=
{f -optional}
g} {-c 2 -e 8 -a 1 5} {a doesn't allow e}

testTemplate allowTest-7 {} {} {
{-a= -allow {g f c u}}
-b=
-c=
-d=
-e=
{f -optional}
g} {-c 2 -a 1 5} {a -allow references undefined element: u}

testTemplate allowTest-8 {} {} {
{-a= -allow}
-b=
-c=
-d=
-e=
{f -optional}
g} {-c 2 -a 1 5} {-allow requires an argument}

testTemplate allowTest-9 {} {} {
{-a= -allow {g f c}}
-b=
-c=
{-d= -standalone}
-e=
{f -optional}
g} {-c 2 -e 8 -d 9 -a 1 5} {d 9 a 1 e 8 f 5 c 2}

testTemplate allowTest-8 {} {} {
{-a= -allow {}}
-b=
-c=
-d=
-e=
{f -optional}
g} {-c 2 -a 1 5} {a doesn't allow c}

### Check -help global switch
testTemplate helpTest-1 {} {-help {Description of procedure} -helpret} {
{-a -required -help {Description 1} -type double -validate {\[string is double \$arg\]}}
{-b -help {Description 2} -require h -forbid e}
{-hjk|por|res|h= -help {Description 3} -require {a b} -imply y}
{-c= -help {Description 4} -optional -require {a b c}}
{-d -required -optional -help {Description 5}}
{-ty= -help {Description 5} -upvar}
{-e -boolean -help {Description 3}}
-k=
{-poy= -enum {a 2 t 6}}
{p -allow {b h}}
{y -optional -help {Description 9}}
{-l -catchall}} {-help} {Description of procedure. Can accepts unambiguous prefixes instead of switches
names. Accepts switches only before parameters.
    Switches:
        -a value - Required. Description 1. Type double.
        -b - Description 2. Requires h. Forbids e.
        -h value - Description 3. Requires a or b. Aliases are hjk, por or res.
            Expects two arguments.
        -c ?value? - Description 4. Requires a, b or c.
        -d ?value? - Required. Description 5.
        -ty value - Description 5. Links caller variable.
        -e - Boolean. Description 3.
        -k value
        -poy value - Value must be one of: a, 2, t or 6.
        -l value - Collects unassigned arguments.
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.
    Parameters:
        p - Allows b or h.
        y - Optional. Description 9.}

testTemplate helpTest-2 {} {-help {Description of procedure} -helpret} {
{-exact      -key match}
{-glob       -key match -default glob}
{-regexp     -key match}
{-sorted     -forbid {glob regexp}}
-all
-inline
-not
-start=
{-ascii      -key format -value text -default text}
{-dictionary -key format}
{-integer    -key format}
{-nocase     -key format}
{-real       -key format}
{-increasing -key order -require sorted -default increasing}
{-decreasing -key order -require sorted}
{-bisect     -imply -sorted -forbid {all not}}
-index=
{-subindices -require index}
list
pattern} {-help} {Description of procedure. Can accepts unambiguous prefixes instead of switches
names. Accepts switches only before parameters.
    Switches:
        -exact - Forbids glob or regexp.
        -glob - Forbids exact or regexp.
        -regexp - Forbids exact or glob.
        -sorted - Forbids glob or regexp.
        -all
        -inline
        -not
        -start value
        -ascii - Forbids dictionary, integer, nocase or real.
        -dictionary - Forbids ascii, integer, nocase or real.
        -integer - Forbids ascii, dictionary, nocase or real.
        -nocase - Forbids ascii, dictionary, integer or real.
        -real - Forbids ascii, dictionary, integer or nocase.
        -increasing - Requires sorted. Forbids decreasing.
        -decreasing - Requires sorted. Forbids increasing.
        -bisect - Forbids all or not. Expects two arguments.
        -index value
        -subindices - Requires index.
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.
    Parameters:
        list
        pattern}

testTemplate helpTest-3 {} {-help {Procedure generates sequence of numbers} -helpret} {
# {Optional sequence control switches}
{-from= -default 1 -type double -help {Provides start of sequence}}
{-to= -default 10 -type double -help {Provides end of sequence}}
{-step= -default 1 -type double -help {Provides step between adjacent numbers of sequence}}
{-prec= -default 1 -type double -help {Provides precision of numbers in the sequence}}
} {-help} {Procedure generates sequence of numbers. Can accepts unambiguous prefixes
instead of switches names. Accepts switches only before parameters.
    Switches:
        -from value - Provides start of sequence. Default value is 1. Type
            double.
        -to value - Provides end of sequence. Default value is 10. Type double.
        -step value - Provides step between adjacent numbers of sequence.
            Default value is 1. Type double.
        -prec value - Provides precision of numbers in the sequence. Default
            value is 1. Type double.
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.}

testTemplate helpTest-4 {} {-help {} -helpret} {
# {Optional sequence control switches}
{-from= -default 1 -type double -help {Provides start of sequence}}
{-to= -default 10 -type double}
{-st|rt|step= -default 1 -type double -help {Provides step between adjacent numbers of sequence}}
{-pre|prec= -default 1 -type double -help {Provides precision of numbers in the sequence}}
} {-help} {Can accepts unambiguous prefixes instead of switches names. Accepts switches
only before parameters.
    Switches:
        -from value - Provides start of sequence. Default value is 1. Type
            double.
        -to value - Default value is 10. Type double.
        -step value - Provides step between adjacent numbers of sequence.
            Default value is 1. Aliases are st or rt. Type double.
        -prec value - Provides precision of numbers in the sequence. Default
            value is 1. Alias is pre. Type double.
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.}

testTemplate helpTest-5 {} {-help {} -helpret -inline\
                                    -validate {date {\[string is double \$arg\]}\
                                                       time {\[string is double \$arg\]}}} {
        {date -validate date}
        {time -validate time}
        {-allday -allow {date time}}
        {-duration= -allow {date time} -validate time}
        {-endtime= -allow {date time} -validate time}
} {-help} {Can accepts unambiguous prefixes instead of switches names. Accepts switches
only before parameters.
    Switches:
        -allday - Allows date or time.
        -duration value - Allows date or time.
        -endtime value - Allows date or time.
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.
    Parameters:
        date
        time}

testTemplate helpTest-6 {} {-helplevel 3 -help {} -helpret -inline\
                                          -validate {date {\[string is double \$arg\]}\
                                                             time {\[string is double \$arg\]}}} {
        {date -validate date}
        {time -validate time}
        {-allday -allow {date time}}
        {-duration= -allow {date time} -validate time}
        {-endtime= -allow {date time} -validate time}
} {-help} {Can accepts unambiguous prefixes instead of switches names. Accepts switches
only before parameters.
    Switches:
        -allday - Allows date or time.
        -duration value - Allows date or time.
        -endtime value - Allows date or time.
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 3
            levels above the current level.
    Parameters:
        date
        time}

testTemplate helpTest-7 {} {-help {} -helpret -inline -pfirst\
                                          -validate {date {\[string is double \$arg\]}\
                                                             time {\[string is double \$arg\]}}} {
        {date -validate date}
        {time -validate time}
        {-allday -allow {date time}}
        {-duration= -allow {date time} -validate time}
        {-endtime= -allow {date time} -validate time}
} {-help} {Can accepts unambiguous prefixes instead of switches names. Required parameters
must appear before switches.
    Switches:
        -allday - Allows date or time.
        -duration value - Allows date or time.
        -endtime value - Allows date or time.
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.
    Parameters:
        date
        time}

testTemplate helpTest-8 {} {-help {} -helpret -inline -pfirst\
                                          -validate {date {\[string is double \$arg\]}\
                                                             time {\[string is double \$arg\]}}} {
        {date -validate date -hsuppress}
        {time -validate time}
        {-allday -allow {date time}}
        {-duration= -allow {date time} -validate time}
        {-endtime= -allow {date time} -validate time}
} {-help} {Can accepts unambiguous prefixes instead of switches names. Required parameters
must appear before switches.
    Switches:
        -allday - Allows date or time.
        -duration value - Allows date or time.
        -endtime value - Allows date or time.
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.
    Parameters:
        time}

testTemplate helpTest-9 {} {-help {} -helpret -inline -pfirst\
                                          -validate {date {\[string is double \$arg\]}\
                                                             time {\[string is double \$arg\]}}} {
        {date -validate date -hsuppress}
        {time -validate time}
        {-allday -allow {date time}}
        {-duration= -allow {date time} -validate time -hsuppress}
        {-endtime= -allow {date time} -validate time}
} {-help} {Can accepts unambiguous prefixes instead of switches names. Required parameters
must appear before switches.
    Switches:
        -allday - Allows date or time.
        -endtime value - Allows date or time.
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.
    Parameters:
        time}

testTemplate helpTest-10 {} {-help {Help information string} -helpret} {} {-help} {Help information string.\
Can accepts unambiguous prefixes instead of switches
names. Accepts switches only before parameters.
    Switches:
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.}
testTemplate helpTest-11 {} {-help {Help information string} -helpret} { } {-help} {Help information string.\
Can accepts unambiguous prefixes instead of switches
names. Accepts switches only before parameters.
    Switches:
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.}
testTemplate helpTest-12 {} {-help {Help information string} -helpret} {   
} {-help} {Help information string. Can accepts unambiguous prefixes instead of switches
names. Accepts switches only before parameters.
    Switches:
        -help - Help switch, when provided, forces ignoring all other switches
            and parameters, prints the help message to stdout, and returns up to 2
            levels above the current level.}

### Check multiple aliases support
testTemplate multipleAliasesTest-1 {} {} {
-a|e|i=
-e|b
-c
r} {-w 1 -c} {element alias collision: e}

testTemplate multipleAliasesTest-2 {} {} {
-a|w|i=
-b
-c
r} {-w 1 -c} {i 1 r -c}

testTemplate multipleAliasesTest-3 {} {} {
-a|b|i=
-b
-c
r} {-a 1 -c} {collision of switch -i alias with the -b switch}

testTemplate multipleAliasesTest-4 {} {} {
{-i= -alias {a b}}
-b
-c
r} {-b 1 -c} {collision of switch -i alias with the -b switch}

testTemplate multipleAliasesTest-5 {} {} {
{-i= -alias {a b y} -required}
-uib
-cab
r} {-y 1 -cab 1} {i 1 r 1 cab {}}

testTemplate multipleAliasesTest-6 {} {} {
{-i= -alias {a b y} -required}
-uib
-cab
r} {-cab 1} {missing required switch: -a|b|y|i}

testTemplate multipleAliasesTest-7 {} {} {
{-i= -alias {a b y} -required}
{-uib -alias {po kl y}}
-cab
r} {-cab 1} {element alias collision: po kl y}

### Check -pfirst global switch
testTemplate pfirstTest-1 {} {-pfirst} {
-a|e|i=
-b
-c
r
l
{m -optional}} {1 -8 5} {l -8 m 5 r 1}

testTemplate pfirstTest-2 {} {-pfirst} {
-a|e|i=
-b
-c
r
l} {1 -8 -c -a 2} {l -8 i 2 r 1 c {}}

testTemplate pfirstTest-3 {} {-pfirst} {
-a|e|i=
-b
-c
r
l
{m -catchall}} {1 -8 5 8 9 0} {l -8 m {5 8 9 0} r 1}

testTemplate pfirstTest-4 {} {-pfirst} {
-a|e|i=
-b
-c
r
l
{m -optional}
{k -optional}} {1 -8 5 0} {l -8 m 5 r 1 k 0}

testTemplate pfirstTest-5 {} {-pfirst} {
r
-a|e|i=
-b
-c
{m -optional}
l
{k -optional}} {1 -8 -a 2 5 0} {l -8 m 5 i 2 r 1 k 0}

testTemplate pfirstTest-6 {} {-pfirst} {
r
-a|e|i=
-b
-c
{m -optional}
l
{k -optional}} {1 -a 8 5 0} {too many arguments}

testTemplate pfirstTest-7 {} {-pfirst} {
r
-a|e|i=
-b
-c
{m -optional}
l
{k -optional}} {1 -a 8 5 -a 2} {l -a m 8 i 2 r 1 k 5}

testTemplate pfirstTest-8 {} {-pfirst} {
r
-a|e|i=
-b
-c
{m -optional}
l
{k -optional}} {9 1 -a 8 5} {l 1 m 5 i 8 r 9}

testTemplate pfirstTest-9 {} {-pfirst -mixed} {
r
-a|e|i=
-b
-c
{m -optional}
l
{k -optional}} {1 -i 8 5 -a 2 9} {-mixed and -pfirst conflict}

testTemplate pfirstTest-10 {} {-pfirst} {
-a|e|i=
-b
-c
r
l
{m -optional}} {1 -b 5} {l -b m 5 r 1}

testTemplate pfirstTest-11 {} {-pfirst} {
r
-a|e|i=
-b
-c
{m -optional}
l
{k -optional}} {1 -a 8 -a 2} {l -a m 8 i 2 r 1}

testTemplate pfirstTest-12 {} {-pfirst} {
r
-a|e|i=
-b
-c
{m -optional}
l
{k -optional}} {1 -a -a 2 10} {l -a m 10 i 2 r 1}

### Check custom error message for validation fail 
testTemplate errormsgTest-1 {} {} {
{a -validate {[string is double $arg]}}
-b=
{c -validate {[string is integer $arg]} -errormsg {validation failed for switch $name with value $arg}}} {-b 1 2 4.0}\
        {validation failed for switch c with value 4.0}

testTemplate errormsgTest-2 {} {} {
{a -validate {[string is double $arg]}}
-b=
{c -validate {[string is integer $arg]}\
         -errormsg {validation [dict get $opt validate] failed for switch $name with value $arg}}} {-b 1 2 4.0}\
        {validation [string is integer $arg] failed for switch c with value 4.0}

testTemplate errormsgTest-3 {} {} {
{a -validate {[string is double $arg]}}
-b=
{c -errormsg {validation [dict get $opt validate] failed for switch $name with value $arg}}} {-b 1 2 4.0}\
        {-errormsg requires -validate}
### Check wrong element switch
testTemplate onlySwitchNoArgsTest-1 {} {} {
    {-a= -defauldt 1}
-b
-c} {-a -c} {bad option "-defauldt": must be -alias, -argument, -boolean, -catchall, -default, -enum, -forbid, -ignore,\
-imply, -keep, -key, -level, -optional, -parameter, -pass, -reciprocal, -require, -required, -standalone, -switch,\
-upvar, -validate, -value, -type, -allow, -help, -errormsg, or -hsuppress}

### Check the constraints of elements with shared keys
testTemplate helpTest-2 {} {} {
{-exact      -key match}
{-glob       -key match -default glob}
{-regexp     -key match}
{-sorted     -forbid {glob regexp}}
-all
-inline
-not
-start=
{-ascii      -key format -value text -default text}
{-dictionary -key format}
{-integer    -key format}
{-nocase     -key format}
{-real       -key format}
{-increasing -key order -require {sorted ascii} -default increasing}
{-decreasing -key order -require sorted}
{-bisect     -imply -sorted -forbid {all not}}
-index=
{-subindices -require index}
list
pattern} {-exact -regexp 1 2} {-exact conflicts with -regexp}

### Some tests from other packages

testTemplate 3rdPackagesTest-1 {} {-pfirst} {
    y
    {winsize -type integer}
    -x=} {{11 12 13 14 15 16 17} 3 -x {0 1 2 3 4 5 6 7 8 9 10}}\
        {x {0 1 2 3 4 5 6 7 8 9 10} winsize 3 y {11 12 13 14 15 16 17}}
testTemplate 3rdPackagesTest-2 {} {-pfirst} {
    {-model= -required -help {Name of the model}}
    {-area= -help {Emitter scale factor}}
    {-areac= -help {Collector scale factor}}
    {-areab= -help {Base scale factor}}
    {-m= -help {Multiplier of area and perimeter}}
    {-ic= -validate {[llength $arg]==2} -help {Initial conditions for vds and vgs, in form of two element list}}
    {-temp= -forbid {dtemp} -help {Device temperature}}
    {-dtemp= -forbid {temp} -help {Temperature offset}}
    {-ns= -help {Name of node connected to substrate pin}}
    {-tj= -require {ns} -help {Name of node connected to thermal pin}}
    {-off -boolean -help {Initial state}}
    {name -help {Name of the device without first-letter designator}}
    {nc -help {Name of node connected to collector pin}}
    {nb -help {Name of node connected to base pin}}
    {ne -help {Name of node connected to emitter pin}}}\
{1 netc netb nete -model bjtmod -ns nets -tj nettj -area 1e-3 -temp 25 -ic {1 2}}\
{nb netb ic {1 2} nc netc name 1 area 1e-3 ns nets model bjtmod temp 25 tj nettj off 0 ne nete}
testTemplate 3rdPackagesTest-3 {} {-inline -help {Initialize object 'Dataset'}} {
    {name -pass rest -help {Name of the trace}}
    {type -pass rest -help {Type of trace}}
    {len -pass rest -help {Total number of points}}
    {axis -help {Name of axis that is linked to trace}}
    {numtype -pass rest -optional -default real -help {Numerical type of trace}}}\
        {{v(m1#body diode)} voltage 51 complex} {arguments {rest {{v(m1#body diode)} voltage 51} axis complex}}
testTemplate 3rdPackagesTest-4 {} {-inline -help {Initialize object 'Dataset'}} {
    {-name= -pass rest -help {Name of the trace}}
    {type -pass rest -help {Type of trace}}
    {len -pass rest -help {Total number of points}}
    {axis -help {Name of axis that is linked to trace}}
    {numtype -pass rest -optional -default real -help {Numerical type of trace}}}\
        {-name {v(m1#body diode)} voltage 51 complex}\
        {arguments {rest {-name {v(m1#body diode)} voltage 51} axis complex}}

### Tests for found bugs
test bugTest-16 "Crash on multiple interpreters" -body {
argparse {-a} {}
interp create ip
ip eval {package req argparse}
ip eval {argparse {-a} {}}
interp delete ip
argparse {-a} {} } -result {} -returnCodes ok

test bugTest-17-1 "Crash on invalid definition list format" -body {
    argparse \{ a
} -result {unmatched open brace in list} -returnCodes error

test bugTest-17-2 "Crash on invalid argument format" -body {
    argparse a \{
} -result {unmatched open brace in list} -returnCodes error


cleanupTests
