blob: 6264b24b18b9d066d908875f14345b95bc019682 [file] [log] [blame]
aPiecek266ca762023-03-22 15:04:59 +01001package require Expect
2
3source [expr {[info exists ::env(TESTS_DIR)] ? "$env(TESTS_DIR)/common.tcl" : "../common.tcl"}]
4
5# set the timeout to 1 second
6set timeout 1
7# prompt of yanglint
8set prompt "> "
9# turn off dialog between expect and yanglint
10log_user 0
aPiecek7621b1f2023-03-23 15:34:24 +010011# setting some large terminal width
12stty columns 720
aPiecek266ca762023-03-22 15:04:59 +010013
14variable ly_setup {
15 spawn $::env(YANGLINT)
16 ly_skip_warnings
aPiecek7621b1f2023-03-23 15:34:24 +010017 # Searchpath is set, so modules can be loaded via the 'load' command.
18 ly_cmd "searchpath $::env(YANG_MODULES_DIR)"
aPiecek266ca762023-03-22 15:04:59 +010019}
20
21variable ly_cleanup {
22 ly_exit
23}
24
25# detection on eof and timeout will be on every expect command
26expect_after {
27 eof {
28 global error_head
29 error "$error_head unexpected termination"
30 } timeout {
31 global error_head
32 error "$error_head timeout"
33 }
34}
35
36# Run commands from command line
37tcltest::loadTestedCommands
38
39# namespace of internal functions
40namespace eval ly::private {}
41
42# Skip no dir and/or no history warnings and prompt.
43proc ly_skip_warnings {} {
44 global prompt
45 expect -re "(YANGLINT.*)*$prompt" {}
46}
47
48# Send command 'cmd' to the process, then check output string by 'pattern'.
49# Parameter cmd is a string of arguments.
50# Parameter pattern is a regex or an exact string to match. If is not specified, only prompt assumed afterwards.
51# It must not contain a prompt. There can be an '$' character at the end of the pattern, in which case the regex
52# matches the characters before the prompt.
53# Parameter 'opt' can contain:
54# -ex has a similar meaning to the expect command. The 'pattern' parameter is used as a simple string
55# for exact matching of the output. So 'pattern' is not a regular expression but some characters
56# must still be escaped, eg ][.
57proc ly_cmd {cmd {pattern ""} {opt ""}} {
58 global prompt
59
60 send -- "${cmd}\r"
61 expect -- "${cmd}\r\n"
62
63 if { $pattern eq "" } {
64 # command without output
65 expect ^$prompt
66 return
67 }
68
69 # definition of an expression that matches failure
70 set failure_pattern "\r\n${prompt}$"
71
72 if { $opt eq "" && [string index $pattern end] eq "$"} {
73 # check output by regular expression
74 # It was explicitly specified how the expression should end.
75 set pattern [string replace $pattern end end]
76 expect {
77 -re "${pattern}\r\n${prompt}$" {}
78 -re $failure_pattern {
79 error "unexpected output:\n$expect_out(buffer)"
80 }
81 }
82 } elseif { $opt eq "" } {
83 # check output by regular expression
84 expect {
85 -re "${pattern}.*\r\n${prompt}$" {}
86 -re $failure_pattern {
87 error "unexpected output:\n$expect_out(buffer)"
88 }
89 }
90 } elseif { $opt eq "-ex" } {
91 # check output by exact matching
92 expect {
93 -ex "${pattern}\r\n${prompt}" {}
94 -re $failure_pattern {
95 error "unexpected output:\n$expect_out(buffer)"
96 }
97 }
98 } else {
99 global error_head
100 error "$error_head unrecognized value of parameter 'opt'"
101 }
102}
103
104# Send command 'cmd' to the process, expect error header and then check output string by 'pattern'.
105# Parameter cmd is a string of arguments.
106# Parameter pattern is a regex. It must not contain a prompt.
107proc ly_cmd_err {cmd pattern} {
108 global prompt
109
110 send -- "${cmd}\r"
111 expect -- "${cmd}\r\n"
112
113 expect {
114 -re "YANGLINT\\\[E\\\]: .*${pattern}.*\r\n${prompt}$" {}
115 -re "libyang\\\[\[0-9]+\\\]: .*${pattern}.*\r\n${prompt}$" {}
116 -re "\r\n${prompt}$" {
117 error "unexpected output:\n$expect_out(buffer)"
118 }
119 }
120}
121
122# Send command 'cmd' to the process, expect warning header and then check output string by 'pattern'.
123# Parameter cmd is a string of arguments.
124# Parameter pattern is a regex. It must not contain a prompt.
125proc ly_cmd_wrn {cmd pattern} {
126 global prompt
127
128 send -- "${cmd}\r"
129 expect -- "${cmd}\r\n"
130
131 expect {
132 -re "YANGLINT\\\[W\\\]: .*${pattern}.*\r\n${prompt}$" {}
133 -re "\r\n${prompt}$" {
134 error "unexpected output:\n$expect_out(buffer)"
135 }
136 }
137}
138
139# Whatever is written is sent, output is ignored and then another prompt is expected.
140# Parameter cmd is optional and any output is ignored.
141proc ly_ignore {{cmd ""}} {
142 global prompt
143
144 send "${cmd}\r"
145 expect -re "$prompt$"
146}
147
148# Send a completion request and check if the anchored regex output matches.
149proc ly_completion {input output} {
150 global prompt
151
152 send -- "${input}\t"
153 # expecting echoing input, output and 10 terminal control characters
154 expect -re "^${input}\r> ${output}.*\r.*$"
155}
156
157# Send a completion request and check if the anchored regex hint options match.
158proc ly_hint {input prev_input hints} {
159 set output {}
160 foreach i $hints {
161 # each element might have some number of spaces and CRLF around it
162 append output "${i} *(?:\\r\\n)?"
163 }
164
165 send -- "${input}\t"
166 # expecting the hints, previous input from which the hints were generated
167 # and some number of terminal control characters
aPiecek15cc4cf2023-04-17 15:23:21 +0200168 expect -re "${output}\r> ${prev_input}.*\r.*$"
aPiecek266ca762023-03-22 15:04:59 +0100169}
170
171# Send 'exit' and wait for eof.
172proc ly_exit {} {
173 send "exit\r"
174 expect eof
175}
aPiecek6e5844c2023-05-22 11:42:09 +0200176
177# Check if yanglint supports the specified command.
178# Parameter cmd is a command to be found.
179# Return true if command is found otherwise false.
180proc ly_cmd_exists {cmd} {
181 global prompt
182 set rc true
183 spawn $::env(YANGLINT)
184 ly_skip_warnings
185
186 send -- "help\r"
187 expect -- "help\r\n"
188
189 set failure_pattern "\r\n${prompt}$"
190 expect {
191 -re "${cmd}.*\r\n${prompt}$" {}
192 -re $failure_pattern {
193 set rc false
194 }
195 }
196
197 ly_exit
198 return $rc
199}