summaryrefslogtreecommitdiffstats
path: root/tests/tool_i.tcl
blob: d0f3d4b1fdb10c4883ebbaadd48d4ff96e94f77b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# @brief Common functions and variables for Tool Under Test (TUT).
#
# The script requires variables:
# TUT_PATH - Assumed absolute path to the directory in which the TUT is located.
# TUT_NAME - TUT name (without path).
#
# The script sets the variables:
# TUT - The path (including the name) of the executable TUT.
# error_prompt - Delimiter on error.
# error_head - Header on error.

package require Expect

# Complete the path for Tool Under Test (TUT). For example, on Windows, TUT can be located in the Debug or Release
# subdirectory. Note that Release build takes precedence over Debug.
set conftypes {{} Release Debug}
foreach i $conftypes {
    if { [file executable "$TUT_PATH/$i/$TUT_NAME"] || [file executable "$TUT_PATH/$i/$TUT_NAME.exe"] } {
        set TUT "$TUT_PATH/$i/$TUT_NAME"
        break
    }
}
if {![info exists TUT]} {
    error "$TUT_NAME executable not found"
}

# prompt of error message
set error_prompt ">>>"
# the beginning of error message
set error_head "$error_prompt Check-failed"

# detection on eof and timeout will be on every expect command
expect_after {
    eof {
        global error_head
        error "$error_head unexpected termination"
    } timeout {
        global error_head
        error "$error_head timeout"
    }
}

# Run commands from command line
tcltest::loadTestedCommands

# namespace of internal functions
namespace eval ly::private {}

# Send command 'cmd' to the process, then check output string by 'pattern'.
# Parameter cmd is a string of arguments.
# Parameter pattern is a regex or an exact string to match. If is not specified, only prompt assumed afterwards.
# It must not contain a prompt. There can be an '$' character at the end of the pattern, in which case the regex
# matches the characters before the prompt.
# Parameter 'opt' can contain:
#   -ex     has a similar meaning to the expect command. The 'pattern' parameter is used as a simple string
#           for exact matching of the output. So 'pattern' is not a regular expression but some characters
#           must still be escaped, eg ][.
proc ly_cmd {cmd {pattern ""} {opt ""}} {
    global prompt

    send -- "${cmd}\r"
    expect -- "${cmd}\r\n"

    if { $pattern eq "" } {
        # command without output
        expect ^$prompt
        return
    }

    # definition of an expression that matches failure
    set failure_pattern "\r\n${prompt}$"

    if { $opt eq "" && [string index $pattern end] eq "$"} {
        # check output by regular expression
        # It was explicitly specified how the expression should end.
        set pattern [string replace $pattern end end]
        expect {
            -re "${pattern}\r\n${prompt}$" {}
            -re $failure_pattern {
                error "unexpected output:\n$expect_out(buffer)"
            }
        }
    } elseif { $opt eq "" } {
        # check output by regular expression
        expect {
            -re "${pattern}.*\r\n${prompt}$" {}
            -re $failure_pattern {
                error "unexpected output:\n$expect_out(buffer)"
            }
        }
    } elseif { $opt eq "-ex" } {
        # check output by exact matching
        expect {
            -ex "${pattern}\r\n${prompt}" {}
            -re $failure_pattern {
                error "unexpected output:\n$expect_out(buffer)"
            }
        }
    } else {
        global error_head
        error "$error_head unrecognized value of parameter 'opt'"
    }
}

# Send command 'cmd' to the process, expect some header and then check output string by 'pattern'.
# This function is useful for checking an error that appears in the form of a header.
# Parameter header is the expected header on the output.
# Parameter cmd is a string of arguments.
# Parameter pattern is a regex. It must not contain a prompt.
proc ly_cmd_header {cmd header pattern} {
    global prompt

    send -- "${cmd}\r"
    expect -- "${cmd}\r\n"

    expect {
        -re "$header .*${pattern}.*\r\n${prompt}$" {}
        -re "\r\n${prompt}$" {
            error "unexpected output:\n$expect_out(buffer)"
        }
    }
}

# Whatever is written is sent, output is ignored and then another prompt is expected.
# Parameter cmd is optional and any output is ignored.
proc ly_ignore {{cmd ""}} {
    global prompt

    send "${cmd}\r"
    expect -re "$prompt$"
}

# Send a completion request and check if the anchored regex output matches.
proc ly_completion {input output} {
    global prompt

    send -- "${input}\t"
    # expecting echoing input, output and 10 terminal control characters
    expect -re "^${input}\r${prompt}${output}.*\r.*$"
}

# Send a completion request and check if the anchored regex hint options match.
proc ly_hint {input prev_input hints} {
    global prompt

    set output {}
    foreach i $hints {
        # each element might have some number of spaces and CRLF around it
        append output "${i} *(?:\\r\\n)?"
    }

    send -- "${input}\t"
    # expecting the hints, previous input from which the hints were generated
    # and some number of terminal control characters
    expect -re "${output}\r${prompt}${prev_input}.*\r.*$"
}