package require tcltest namespace eval ::testspace { namespace import ::tcltest::* variable common { set result "" } test parse_withdef_leaders_ordering_defaults {Test ordering of leaders when some have defaults}\ -setup $common -body { set argd [punk::args::parse {a b} withdef @leaders x {y -default 1}] set vals [dict get $argd leaders] set result $vals }\ -cleanup { }\ -result [list\ x a y b ] test parse_withdef_option_ordering_defaults {Test ordering of options when some have defaults}\ -setup $common -body { #for consistency with leaders and values dicts - try to maintain definition order for options too set argd [punk::args::parse {-x a -y b} withdef @opts -x {-y -default 1}] set vals [dict get $argd opts] set result $vals }\ -cleanup { }\ -result [list\ -x a -y b ] test parse_withdef_option_ordering_defaults2 {Test ordering of options when some have defaults and -any is true}\ -setup $common -body { #for consistency with leaders and values dicts - try to maintain definition order for options too set argd [punk::args::parse {-blah etc -x a -y b -solo -z c} withdef {@opts -any 1} -x {-y -default 1} {-solo -type none} -z] set vals [dict get $argd opts] set result $vals }\ -cleanup { }\ -result [list\ -x a -y b -solo 1 -z c -blah etc ] test parse_withdef_values_ordering_defaults {Test ordering of values when some have defaults}\ -setup $common -body { set argd [punk::args::parse {a b} withdef @values x {y -default 1}] set vals [dict get $argd values] set result $vals }\ -cleanup { }\ -result [list\ x a y b ] test parse_withdef_values_no_phantom_default {Test no phantom default with intermediate optional argument}\ -setup $common -body { #y was not received, and has no default, so should not appear in 'values' element #we don't want to see {x a y {} z b} set argd [punk::args::parse {a b} withdef @values x {y -optional 1} z] set vals [dict get $argd values] set result $vals }\ -cleanup { }\ -result [list\ x a z b ] test parse_withdef_value_multiple1 {Test named value with -multiple true and required trailing value}\ -setup $common -body { set argd [punk::args::parse {a b c} withdef @values {arg -type string -multiple 1} endval] lappend result [dict get $argd leaders] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {} {arg {a b} endval c} ] test parse_withdef_value_multiple2 {Test named value followed by named value with -multiple true and a default}\ -setup $common -body { set argd [punk::args::parse {a b c} withdef @values A {arg -type string -multiple 1 -default X}] lappend result [dict get $argd leaders] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {} {A a arg {b c}} ] test parse_withdef_leader_multiple1 {Test named leader with -multiple true and 1 value required}\ -setup $common -body { set argd [punk::args::parse {a b c} withdef {@leaders -min 0} {L -multiple 1} {@values -min 1 -max 1} V] lappend result [dict get $argd leaders] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {L {a b}} {V c} ] test parse_withdef_leader_min_max1 {Test unnamed leaders with @leaders -min and -max}\ -setup $common -body { set argd [punk::args::parse {a b c d} withdef {@leaders -min 1 -max 3 -unnamed true} {@values -unnamed true} ] lappend result [dict get $argd leaders] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {0 a 1 b 2 c} {3 d} ] test parse_withdef_leader_min_max_with_required_value {Test unnamed leaders with -min and -max followed by required unnamed value}\ -setup $common -body { #should not error - should allocate d to values set argd [punk::args::parse {a b c d} withdef {@leaders -min 1 -max 4 -unnamed true} {@values -min 1 -max 1 -unnamed true}] lappend result [dict get $argd leaders] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {0 a 1 b 2 c} {3 d} ] test parse_withdef_leaderclause_trailing_optional_members_followed_by_value {Test that last leader clause with optional members works with following required value}\ -setup $common -body { set argd [punk::args::parse {a z} withdef {@leaders} {ldr -type {char ?int? ?int?}} {@values} val] lappend result [dict get $argd leaders] set argd [punk::args::parse {a 1 z} withdef {@leaders} {ldr -type {char ?int? ?int?}} {@values} val] lappend result [dict get $argd leaders] set argd [punk::args::parse {a 1 2 z} withdef {@leaders} {ldr -type {char ?int? ?int?}} {@values} val] lappend result [dict get $argd leaders] }\ -cleanup { }\ -result [list\ {ldr {a {} {}}}\ {ldr {a 1 {}}}\ {ldr {a 1 2}}\ ] test parse_withdef_leaderclause_trailing_optional_members_followed_by_optional_leader_and_value {Test that last leader clause with optional members works with following required value}\ -setup $common -body { set argd [punk::args::parse {x y z} withdef {@leaders} {ldr -type {char ?int? ?int?}} {ldr2 -type string -optional 1} {@values} val] lappend result [dict get $argd leaders] set argd [punk::args::parse {x 1 z} withdef {@leaders} {ldr -type {char ?int? ?int?}} {ldr2 -type string -optional 1} {@values} val] lappend result [dict get $argd leaders] set argd [punk::args::parse {x 1 y z} withdef {@leaders} {ldr -type {char ?int? ?int?}} {ldr2 -type string -optional 1} {@values} val] lappend result [dict get $argd leaders] set argd [punk::args::parse {x 1 2 y z} withdef {@leaders} {ldr -type {char ?int? ?int?}} {ldr2 -type string -optional 1} {@values} val] lappend result [dict get $argd leaders] }\ -cleanup { }\ -result [list\ {ldr {x {} {}} ldr2 y}\ {ldr {x 1 {}}}\ {ldr {x 1 {}} ldr2 y}\ {ldr {x 1 2} ldr2 y}\ ] test parse_withdef_value_clause_typedefaults {test clause with optional element and -typedefaults specified}\ -setup $common -body { set argd [punk::args::parse {1} withdef @values {v -type {int ?int?} -typedefaults {"" 12}}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {v {1 12}} ] test parse_withdef_value_clause_typedefaults2 {test clause with optional element and -typedefaults specified - entire arg optional -default}\ -setup $common -body { #-default has deliberate type violations - should still produce result as default is not meant to be subject to validation. set argd [punk::args::parse {} withdef @values {v -type {int ?int?} -typedefaults {"" 12} -default {x y} -optional 1}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {v {x y}} ] test parse_withdef_value_clause_defaulted_optional {test clause with optional element and -typedefaults not matching all types}\ -setup $common -body { #-typedefaults has deliberate type violations - should still produce result as defaulted value is not meant to be subject to validation. #(uses the ?defaulted-? typelist mechanism) set argd [punk::args::parse {1} withdef @values {v -type {int ?int?} -typedefaults {"" xxx}}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {v {1 xxx}} ] test parse_withdef_value_clause_missing_optional {test clause with optional element and no -typedefaults}\ -setup $common -body { #an optional clause member will be replaced with empty string when missing if there is no -typedefaults #This empty string needs to be in the result, but not be subject to validation #(uses the ?ommitted-? typelist mechanism) set argd [punk::args::parse {1} withdef @values {v -type {int ?int?}}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {v {1 {}}} ] test parse_withdef_value_clause_arity1 {Test value clause result with optional member}\ -setup $common -body { #default for missing optional member ?literal(then)? should be empty string set argd [punk::args::parse {elseif 1 x} withdef {@values} {"elseifclause" -type {literal(elseif) expr ?literal(then)? any}}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {elseifclause {elseif 1 {} x}} ] test parse_withdef_value_clause_missing_optional_multiple {test -multiple true clauses with optional members}\ -setup $common -body { #this test is applicable to situations such as the elseif clause in the ::if definition: #e.g literal(elseif) expr ?literal(then)? script #the 'then' needs to be omitable arbitrarily in a list of elseif clauses #first test with all values supplied set argd [punk::args::parse {x 1 y x 2 y} withdef @values {triple -type {literal(x) ?int? literal(y)} -multiple 1}] lappend result [dict get $argd values] #missing value in second instance only set argd [punk::args::parse {x 1 y x y} withdef @values {triple -type {literal(x) ?int? literal(y)} -multiple 1}] lappend result [dict get $argd values] #missing value in first instance only #this can trigger a problem whereby the missing value in the first instance (which is empty string) gets processed in validation against 'int' and fails. #(updating of required type to a validationless value such as ... ?omitted-int? ... needs to be tied to specific clause instances) set argd [punk::args::parse {x y x 2 y} withdef @values {triple -type {literal(x) ?int? literal(y)} -multiple 1}] lappend result [dict get $argd values] #for completeness - no optional values supplid set argd [punk::args::parse {x y x y} withdef @values {triple -type {literal(x) ?int? literal(y)} -multiple 1}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {triple {{x 1 y} {x 2 y}}}\ {triple {{x 1 y} {x {} y}}}\ {triple {{x {} y} {x 2 y}}}\ {triple {{x {} y} {x {} y}}}\ ] test parse_withdef_value_clause_arity2 {Test value clause result with missing optional member in optional clauses at tail}\ -setup $common -body { set argd [punk::args::parse {1 2 x 1 y} withdef {@values -unnamed true} {arg -multiple 1} {X -type {literal(x) any} -optional 1} {Y -type {literal(y) ?int?} -optional 1}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {arg {1 2} X {x 1} Y {y {}}} ] test parse_withdef_value_clause_arity3 {Test value clause result with filled optional member in optional clauses at tail}\ -setup $common -body { set argd [punk::args::parse {1 2 x 1 y 2} withdef {@values -unnamed true} {arg -multiple 1} {X -type {literal(x) any} -optional 1} {Y -type {literal(y) ?int?} -optional 1}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {arg {1 2} X {x 1} Y {y 2}} ] #todo - test L1 parsed to Lit1 not arg #punk::args::parse {x y L1} withdef @values (arg -multiple 1) {lit1 -type literal(L1) -optional 1} {lit2 -type literal(L2) -optional 1} #todo #see i -form 1 file copy -- x #fix end-of-opts handling #see also file copy -force x #(not handled by punk::args as the command does..) test parse_withdef_leader_clause {Test leader clause with multiple}\ -setup $common -body { #see for example ::tcl::dict::create which has a clause length of 2 set argd [punk::args::parse {k v e k1 v1 k2 v2} withdef {@leaders} {"key val etc" -type {any any any} -multiple 0} {"key val" -type {any any} -multiple 1} {@values -min 0 -max 0}] lappend result [dict get $argd leaders] }\ -cleanup { }\ -result [list\ {{key val etc} {k v e} {key val} {{k1 v1} {k2 v2}}} ] test parse_withdef_value_clause_multiple {Test value clause with multiple}\ -setup $common -body { #see for example ::tcl::dict::create which has a clause length of 2 set argd [punk::args::parse {k v e k1 v1 k2 v2} withdef {@values} {"key val etc" -type {any any any} -multiple 0} {"key val" -type {any any} -multiple 1}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {{key val etc} {k v e} {key val} {{k1 v1} {k2 v2}}} ] test parse_withdef_value_clause_error {Test value clause with error due to not enough args for clause}\ -setup $common -body { #see for example ::tcl::dict::create which has a clause length of 2 if {[catch {punk::args::parse {k v} withdef {@values} {"key val etc" -type {any any any} -multiple 0}} emsg eopts]} { set expected [dict get $eopts -errorcode] if {[lindex $expected 0] eq "PUNKARGS" && [lindex $expected 1] eq "VALIDATION" && [lindex $expected 2 0] eq "missingrequiredvalue"} { lappend result "RECEIVED_EXPECTED_ERROR" } else { lappend result "WRONG_ERROR_RECEIVED - $expected (expected PUNKARGS VALIDATION {missingrequiredvalue ...} ..." } } else { lappend result "MISSING_REQUIRED_ERROR" } }\ -cleanup { }\ -result [list\ "RECEIVED_EXPECTED_ERROR" ] test parse_withdef_parsekey_repeat_ordering {Ensure last flag has precedence}\ -setup $common -body { #It must always be possible to override earlier (non -multiple) options set argd [punk::args::parse {-incr -decr -incr} withdef {@opts -type none -parsekey -direction} {-incr -typedefaults u} {-decr -typedefaults u}] lappend result [dict get $argd opts] }\ -cleanup { }\ -result [list\ {-direction u} ] test parse_withdef_leader_literalprefix_fullvalue {leaders - ensure supplying a prefix of literalprefix(test) returns full value 'test'}\ -setup $common -body { set argd [punk::args::parse {t} withdef @leaders {A -type literalprefix(test)}] lappend result [dict get $argd leaders] }\ -cleanup { }\ -result [list\ {A test} ] test parse_withdef_value_literalprefix_fullvalue {values - ensure supplying a prefix of literalprefix(test) returns full value 'test'}\ -setup $common -body { set argd [punk::args::parse {t} withdef @values {A -type literalprefix(test)}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {A test} ] test parse_withdef_value_literal_alternates_case {values - ensure literal alternates work and preserve case}\ -setup $common -body { set argd [punk::args::parse {abc} withdef @values {A -type literal(abc)|literal(DeF)}] lappend result [dict get $argd values] set argd [punk::args::parse {DeF} withdef @values {A -type literal(abc)|literal(DeF)}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {A abc} {A DeF} ] test parse_withdef_value_literalprefix_literal_combo {values - ensure literal/literalprefix prefix calculation works}\ -setup $common -body { set argd [punk::args::parse {test} withdef @values {A -type literalprefix(testinfo)|literal(test)}] lappend result [dict get $argd values] set argd [punk::args::parse {testin} withdef @values {A -type literalprefix(testinfo)|literal(test)}] lappend result [dict get $argd values] }\ -cleanup { }\ -result [list\ {A test} {A testinfo} ] test parse_withdef_value_alternatetypes {values - ensure alternate types (in simple-syntax) pass validation}\ -setup $common -body { #both should pass validation set argd [punk::args::parse {a} withdef @values {A -type int|char}] lappend result [dict get $argd values] set argd [punk::args::parse {11} withdef @values {A -type char|int}] lappend result [dict get $argd values] #todo RPN? #set argd [punk::args::parse {11} withdef @values {A -type {char int OR}}] #set argd [punk::args::parse {11} withdef @values {A -type {char int stringstartswith | OR}}] }\ -cleanup { }\ -result [list\ {A a} {A 11} ] }