aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 1 | # @brief Common functions and variables for Tool Under Test (TUT). |
| 2 | # |
| 3 | # The script requires variables: |
| 4 | # TUT_PATH - Assumed absolute path to the directory in which the TUT is located. |
| 5 | # TUT_NAME - TUT name (without path). |
| 6 | # |
| 7 | # The script sets the variables: |
| 8 | # TUT - The path (including the name) of the executable TUT. |
| 9 | # error_prompt - Delimiter on error. |
| 10 | # error_head - Header on error. |
| 11 | |
| 12 | # Complete the path for Tool Under Test (TUT). For example, on Windows, TUT can be located in the Debug or Release |
| 13 | # subdirectory. Note that Release build takes precedence over Debug. |
| 14 | set conftypes {{} Release Debug} |
| 15 | foreach i $conftypes { |
| 16 | if { [file executable "$TUT_PATH/$i/$TUT_NAME"] || [file executable "$TUT_PATH/$i/$TUT_NAME.exe"] } { |
| 17 | set TUT "$TUT_PATH/$i/$TUT_NAME" |
| 18 | break |
| 19 | } |
| 20 | } |
| 21 | if {![info exists TUT]} { |
| 22 | error "$TUT_NAME executable not found" |
| 23 | } |
| 24 | |
| 25 | # prompt of error message |
| 26 | set error_prompt ">>>" |
| 27 | # the beginning of error message |
| 28 | set error_head "$error_prompt Check-failed" |
| 29 | |
| 30 | # Run commands from command line |
| 31 | tcltest::loadTestedCommands |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 32 | |
| 33 | # namespace of internal functions |
| 34 | namespace eval ly::private { |
| 35 | namespace export * |
| 36 | } |
| 37 | |
| 38 | # Run the process with arguments. |
| 39 | # Parameter cmd is a string with arguments. |
| 40 | # Parameter wrn is a flag. Set to 1 if stderr should be ignored. |
| 41 | # Returns a pair where the first is the return code and the second is the output. |
| 42 | proc ly::private::ly_exec {cmd {wrn ""}} { |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 43 | global TUT |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 44 | try { |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 45 | set results [exec -- $TUT {*}$cmd] |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 46 | set status 0 |
| 47 | } trap CHILDSTATUS {results options} { |
| 48 | # return code is not 0 |
| 49 | set status [lindex [dict get $options -errorcode] 2] |
| 50 | } trap NONE results { |
| 51 | if { $wrn == 1 } { |
| 52 | set status 0 |
| 53 | } else { |
| 54 | error "return code is 0 but something was written to stderr:\n$results\n" |
| 55 | } |
| 56 | } trap CHILDKILLED {results options} { |
| 57 | set status [lindex [dict get $options -errorcode] 2] |
| 58 | error "process was killed: $status" |
| 59 | } |
| 60 | list $status $results |
| 61 | } |
| 62 | |
| 63 | # Internal function. |
| 64 | # Check the output with pattern. |
| 65 | # Parameter pattern is a regex or an exact string to match. |
| 66 | # Parameter msg is the output to check. |
| 67 | # Parameter 'opt' is optional. If contains '-ex', then the 'pattern' parameter is |
| 68 | # used as a simple string for exact matching of the output. |
| 69 | proc ly::private::output_check {pattern msg {opt ""}} { |
| 70 | if { $opt eq "" } { |
| 71 | expr {![regexp -- $pattern $msg]} |
| 72 | } elseif { $opt eq "-ex" } { |
| 73 | expr {![string equal "$pattern" $msg]} |
| 74 | } else { |
| 75 | global error_head |
| 76 | error "$error_head unrecognized value of parameter 'opt'" |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | # Execute yanglint with arguments and expect success. |
| 81 | # Parameter cmd is a string of arguments. |
| 82 | # Parameter pattern is a regex or an exact string to match. |
| 83 | # Parameter 'opt' is optional. If contains '-ex', then the 'pattern' parameter is |
| 84 | # used as a simple string for exact matching of the output. |
| 85 | proc ly_cmd {cmd {pattern ""} {opt ""}} { |
| 86 | namespace import ly::private::* |
| 87 | lassign [ly_exec $cmd] rc msg |
| 88 | if { $rc != 0 } { |
| 89 | error "unexpected return code $rc:\n$msg\n" |
| 90 | } |
| 91 | if { $pattern ne "" && [output_check $pattern $msg $opt] } { |
| 92 | error "unexpected output:\n$msg\n" |
| 93 | } |
| 94 | return |
| 95 | } |
| 96 | |
| 97 | # Execute yanglint with arguments and expect error. |
| 98 | # Parameter cmd is a string of arguments. |
| 99 | # Parameter pattern is a regex. |
| 100 | proc ly_cmd_err {cmd pattern} { |
| 101 | namespace import ly::private::* |
| 102 | lassign [ly_exec $cmd] rc msg |
| 103 | if { $rc == 0 } { |
| 104 | error "unexpected return code $rc" |
| 105 | } |
| 106 | if { [output_check $pattern $msg] } { |
| 107 | error "unexpected output:\n$msg\n" |
| 108 | } |
| 109 | return |
| 110 | } |
| 111 | |
| 112 | # Execute yanglint with arguments, expect warning in stderr but success. |
| 113 | # Parameter cmd is a string of arguments. |
| 114 | # Parameter pattern is a regex. |
| 115 | proc ly_cmd_wrn {cmd pattern} { |
| 116 | namespace import ly::private::* |
| 117 | lassign [ly_exec $cmd 1] rc msg |
| 118 | if { $rc != 0 } { |
| 119 | error "unexpected return code $rc:\n$msg\n" |
| 120 | } |
| 121 | if { [output_check $pattern $msg] } { |
| 122 | error "unexpected output:\n$msg\n" |
| 123 | } |
| 124 | return |
| 125 | } |
aPiecek | 6e5844c | 2023-05-22 11:42:09 +0200 | [diff] [blame] | 126 | |
| 127 | # Check if yanglint supports the specified option. |
| 128 | # Parameter opt is a option to be found. |
| 129 | # Return true if option is found otherwise false. |
| 130 | proc ly_opt_exists {opt} { |
| 131 | namespace import ly::private::* |
| 132 | lassign [ly_exec "--help"] rc msg |
| 133 | if { $rc != 0 } { |
| 134 | error "unexpected return code $rc:\n$msg\n" |
| 135 | } |
| 136 | if { [output_check $opt $msg] } { |
| 137 | return false |
| 138 | } else { |
| 139 | return true |
| 140 | } |
| 141 | } |