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 | |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 12 | package require Expect |
| 13 | |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 14 | # Complete the path for Tool Under Test (TUT). For example, on Windows, TUT can be located in the Debug or Release |
| 15 | # subdirectory. Note that Release build takes precedence over Debug. |
| 16 | set conftypes {{} Release Debug} |
| 17 | foreach i $conftypes { |
| 18 | if { [file executable "$TUT_PATH/$i/$TUT_NAME"] || [file executable "$TUT_PATH/$i/$TUT_NAME.exe"] } { |
| 19 | set TUT "$TUT_PATH/$i/$TUT_NAME" |
| 20 | break |
| 21 | } |
| 22 | } |
| 23 | if {![info exists TUT]} { |
| 24 | error "$TUT_NAME executable not found" |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 25 | } |
| 26 | |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 27 | # prompt of error message |
| 28 | set error_prompt ">>>" |
| 29 | # the beginning of error message |
| 30 | set error_head "$error_prompt Check-failed" |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 31 | |
| 32 | # detection on eof and timeout will be on every expect command |
| 33 | expect_after { |
| 34 | eof { |
| 35 | global error_head |
| 36 | error "$error_head unexpected termination" |
| 37 | } timeout { |
| 38 | global error_head |
| 39 | error "$error_head timeout" |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | # Run commands from command line |
| 44 | tcltest::loadTestedCommands |
| 45 | |
| 46 | # namespace of internal functions |
| 47 | namespace eval ly::private {} |
| 48 | |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 49 | # Send command 'cmd' to the process, then check output string by 'pattern'. |
| 50 | # Parameter cmd is a string of arguments. |
| 51 | # Parameter pattern is a regex or an exact string to match. If is not specified, only prompt assumed afterwards. |
| 52 | # It must not contain a prompt. There can be an '$' character at the end of the pattern, in which case the regex |
| 53 | # matches the characters before the prompt. |
| 54 | # Parameter 'opt' can contain: |
| 55 | # -ex has a similar meaning to the expect command. The 'pattern' parameter is used as a simple string |
| 56 | # for exact matching of the output. So 'pattern' is not a regular expression but some characters |
| 57 | # must still be escaped, eg ][. |
| 58 | proc ly_cmd {cmd {pattern ""} {opt ""}} { |
| 59 | global prompt |
| 60 | |
| 61 | send -- "${cmd}\r" |
| 62 | expect -- "${cmd}\r\n" |
| 63 | |
| 64 | if { $pattern eq "" } { |
| 65 | # command without output |
| 66 | expect ^$prompt |
| 67 | return |
| 68 | } |
| 69 | |
| 70 | # definition of an expression that matches failure |
| 71 | set failure_pattern "\r\n${prompt}$" |
| 72 | |
| 73 | if { $opt eq "" && [string index $pattern end] eq "$"} { |
| 74 | # check output by regular expression |
| 75 | # It was explicitly specified how the expression should end. |
| 76 | set pattern [string replace $pattern end end] |
| 77 | expect { |
| 78 | -re "${pattern}\r\n${prompt}$" {} |
| 79 | -re $failure_pattern { |
| 80 | error "unexpected output:\n$expect_out(buffer)" |
| 81 | } |
| 82 | } |
| 83 | } elseif { $opt eq "" } { |
| 84 | # check output by regular expression |
| 85 | expect { |
| 86 | -re "${pattern}.*\r\n${prompt}$" {} |
| 87 | -re $failure_pattern { |
| 88 | error "unexpected output:\n$expect_out(buffer)" |
| 89 | } |
| 90 | } |
| 91 | } elseif { $opt eq "-ex" } { |
| 92 | # check output by exact matching |
| 93 | expect { |
| 94 | -ex "${pattern}\r\n${prompt}" {} |
| 95 | -re $failure_pattern { |
| 96 | error "unexpected output:\n$expect_out(buffer)" |
| 97 | } |
| 98 | } |
| 99 | } else { |
| 100 | global error_head |
| 101 | error "$error_head unrecognized value of parameter 'opt'" |
| 102 | } |
| 103 | } |
| 104 | |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 105 | # Send command 'cmd' to the process, expect some header and then check output string by 'pattern'. |
| 106 | # This function is useful for checking an error that appears in the form of a header. |
| 107 | # Parameter header is the expected header on the output. |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 108 | # Parameter cmd is a string of arguments. |
| 109 | # Parameter pattern is a regex. It must not contain a prompt. |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 110 | proc ly_cmd_header {cmd header pattern} { |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 111 | global prompt |
| 112 | |
| 113 | send -- "${cmd}\r" |
| 114 | expect -- "${cmd}\r\n" |
| 115 | |
| 116 | expect { |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 117 | -re "$header .*${pattern}.*\r\n${prompt}$" {} |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 118 | -re "\r\n${prompt}$" { |
| 119 | error "unexpected output:\n$expect_out(buffer)" |
| 120 | } |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | # Whatever is written is sent, output is ignored and then another prompt is expected. |
| 125 | # Parameter cmd is optional and any output is ignored. |
| 126 | proc ly_ignore {{cmd ""}} { |
| 127 | global prompt |
| 128 | |
| 129 | send "${cmd}\r" |
| 130 | expect -re "$prompt$" |
| 131 | } |
| 132 | |
| 133 | # Send a completion request and check if the anchored regex output matches. |
| 134 | proc ly_completion {input output} { |
| 135 | global prompt |
| 136 | |
| 137 | send -- "${input}\t" |
| 138 | # expecting echoing input, output and 10 terminal control characters |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 139 | expect -re "^${input}\r${prompt}${output}.*\r.*$" |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 140 | } |
| 141 | |
| 142 | # Send a completion request and check if the anchored regex hint options match. |
| 143 | proc ly_hint {input prev_input hints} { |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 144 | global prompt |
| 145 | |
aPiecek | 266ca76 | 2023-03-22 15:04:59 +0100 | [diff] [blame] | 146 | set output {} |
| 147 | foreach i $hints { |
| 148 | # each element might have some number of spaces and CRLF around it |
| 149 | append output "${i} *(?:\\r\\n)?" |
| 150 | } |
| 151 | |
| 152 | send -- "${input}\t" |
| 153 | # expecting the hints, previous input from which the hints were generated |
| 154 | # and some number of terminal control characters |
aPiecek | 0ebc35b | 2023-06-22 14:11:58 +0200 | [diff] [blame] | 155 | expect -re "${output}\r${prompt}${prev_input}.*\r.*$" |
aPiecek | 6e5844c | 2023-05-22 11:42:09 +0200 | [diff] [blame] | 156 | } |