11
11
import optparse
12
12
import os
13
13
import pexpect
14
+ import re
14
15
import signal
15
16
import sys
16
17
@@ -49,12 +50,13 @@ def stop_process__hack(name, sig_num=signal.SIGSTOP):
49
50
CASES = []
50
51
51
52
52
- def register (skip_shells = None , not_impl_shells = None ):
53
+ def register (skip_shells = None , not_impl_shells = None , needs_dimensions = False ):
53
54
skip_shells = skip_shells or []
54
55
not_impl_shells = not_impl_shells or []
55
56
56
57
def decorator (func ):
57
- CASES .append ((func .__doc__ , func , skip_shells , not_impl_shells ))
58
+ CASES .append ((func .__doc__ , func , skip_shells , not_impl_shells ,
59
+ needs_dimensions ))
58
60
return func
59
61
60
62
return decorator
@@ -67,6 +69,40 @@ class Result(object):
67
69
FAIL = 4
68
70
69
71
72
+ class TerminalDimensionEnvVars :
73
+ """
74
+ Context manager for setting and unsetting LINES and COLUMNS environment variables.
75
+ """
76
+
77
+ def __init__ (self , lines : int , columns : int ):
78
+ self .lines = lines
79
+ self .columns = columns
80
+ self .original_lines = None
81
+ self .original_columns = None
82
+
83
+ def __enter__ (self ):
84
+ # Save original values
85
+ self .original_lines = os .environ .get ('LINES' )
86
+ self .original_columns = os .environ .get ('COLUMNS' )
87
+
88
+ # Set new values
89
+ os .environ ['LINES' ] = str (self .lines )
90
+ os .environ ['COLUMNS' ] = str (self .columns )
91
+ return self
92
+
93
+ def __exit__ (self , exc_type , exc_val , exc_tb ):
94
+ # Restore original values
95
+ if self .original_lines is None :
96
+ del os .environ ['LINES' ]
97
+ else :
98
+ os .environ ['LINES' ] = self .original_lines
99
+
100
+ if self .original_columns is None :
101
+ del os .environ ['COLUMNS' ]
102
+ else :
103
+ os .environ ['COLUMNS' ] = self .original_columns
104
+
105
+
70
106
class TestRunner (object ):
71
107
72
108
def __init__ (self , num_retries , pexpect_timeout , verbose , num_lines ,
@@ -77,7 +113,7 @@ def __init__(self, num_retries, pexpect_timeout, verbose, num_lines,
77
113
self .num_lines = num_lines
78
114
self .num_columns = num_columns
79
115
80
- def RunOnce (self , shell_path , shell_label , func ):
116
+ def RunOnce (self , shell_path , shell_label , func , test_params = {} ):
81
117
sh_argv = []
82
118
if shell_label in ('bash' , 'osh' ):
83
119
sh_argv .extend (['--rcfile' , '/dev/null' ])
@@ -87,57 +123,44 @@ def RunOnce(self, shell_path, shell_label, func):
87
123
sh_argv .append ('--norc' )
88
124
#print(sh_argv)
89
125
90
- # Set LINES and COLUMNS in case a program needs them (like pyte tests)
91
- # Setting the dimensions kw param to spawn() is not sufficient
92
- original_lines = os .environ .get ('LINES' )
93
- original_columns = os .environ .get ('COLUMNS' )
94
- os .environ ['LINES' ] = str (self .num_lines )
95
- os .environ ['COLUMNS' ] = str (self .num_columns )
126
+ # Python 3: encoding required
127
+ sh = pexpect .spawn (
128
+ shell_path ,
129
+ sh_argv ,
130
+ encoding = "utf-8" ,
131
+ dimensions = (self .num_lines , self .num_columns ),
132
+ # Generally don't want local echo of input, it gets confusing fast.
133
+ echo = False ,
134
+ timeout = self .pexpect_timeout ,
135
+ )
96
136
97
- try :
98
- # Python 3: encoding required
99
- sh = pexpect .spawn (
100
- shell_path ,
101
- sh_argv ,
102
- encoding = "utf-8" ,
103
- dimensions = (self .num_lines , self .num_columns ),
104
- # Generally don't want local echo of input, it gets confusing fast.
105
- echo = False ,
106
- timeout = self .pexpect_timeout ,
107
- )
108
-
109
- sh .shell_label = shell_label # for tests to use
110
-
111
- if self .verbose :
112
- sh .logfile = sys .stdout
113
-
114
- ok = True
115
- try :
116
- func (sh )
117
- except Exception as e :
118
- import traceback
119
- traceback .print_exc (file = sys .stderr )
120
- return Result .FAIL
121
- ok = False
137
+ sh .shell_label = shell_label # for tests to use
122
138
123
- finally :
124
- sh . close ()
139
+ if self . verbose :
140
+ sh . logfile = sys . stdout
125
141
126
- if ok :
127
- return Result .OK
142
+ ok = True
143
+ try :
144
+ # Support tests that need extra params (like dimensions), without
145
+ # impacting existing tests
146
+ if len (test_params ) > 0 :
147
+ func (sh , test_params )
148
+ else :
149
+ func (sh )
150
+ except Exception :
151
+ import traceback
152
+ traceback .print_exc (file = sys .stderr )
153
+ return Result .FAIL
154
+ ok = False
128
155
129
156
finally :
130
- if original_lines is None :
131
- del os .environ ['LINES' ]
132
- else :
133
- os .environ ['LINES' ] = original_lines
134
- if original_columns is None :
135
- del os .environ ['COLUMNS' ]
136
- else :
137
- os .environ ['COLUMNS' ] = original_columns
157
+ sh .close ()
138
158
139
- def RunCase (self , shell_path , shell_label , func ):
140
- result = self .RunOnce (shell_path , shell_label , func )
159
+ if ok :
160
+ return Result .OK
161
+
162
+ def RunCase (self , shell_path , shell_label , func , test_params = {}):
163
+ result = self .RunOnce (shell_path , shell_label , func , test_params )
141
164
142
165
if result == Result .OK :
143
166
return result , - 1 # short circuit for speed
@@ -148,7 +171,8 @@ def RunCase(self, shell_path, shell_label, func):
148
171
log ('\t FAILED first time: Retrying 4 times' )
149
172
for i in range (self .num_retries ):
150
173
log ('\t Retry %d of %d' , i + 1 , self .num_retries )
151
- result = self .RunOnce (shell_path , shell_label , func )
174
+ result = self .RunOnce (shell_path , shell_label , func ,
175
+ test_params )
152
176
if result == Result .OK :
153
177
num_success += 1
154
178
else :
@@ -164,13 +188,18 @@ def RunCase(self, shell_path, shell_label, func):
164
188
165
189
def RunCases (self , cases , case_predicate , shell_pairs , result_table ,
166
190
flaky ):
167
- for case_num , (desc , func , skip_shells ,
168
- not_impl_shells ) in enumerate (cases ):
191
+ for case_num , (desc , func , skip_shells , not_impl_shells ,
192
+ needs_dimensions ) in enumerate (cases ):
169
193
if not case_predicate (case_num , desc ):
170
194
continue
171
195
172
196
result_row = [case_num ]
173
197
198
+ test_params = {}
199
+ if needs_dimensions :
200
+ test_params ['num_lines' ] = self .num_lines
201
+ test_params ['num_columns' ] = self .num_columns
202
+
174
203
for shell_label , shell_path in shell_pairs :
175
204
skip_str = ''
176
205
if shell_label in skip_shells :
@@ -195,7 +224,8 @@ def RunCases(self, cases, case_predicate, shell_pairs, result_table,
195
224
flaky [case_num , shell_label ] = - 1
196
225
continue
197
226
198
- result , retries = self .RunCase (shell_path , shell_label , func )
227
+ result , retries = self .RunCase (shell_path , shell_label , func ,
228
+ test_params )
199
229
flaky [case_num , shell_label ] = retries
200
230
201
231
result_row .append (result )
@@ -360,7 +390,7 @@ def main(argv):
360
390
361
391
# List test cases and return
362
392
if opts .do_list :
363
- for i , (desc , _ , _ , _ ) in enumerate (CASES ):
393
+ for i , (desc , * _ ) in enumerate (CASES ):
364
394
print ('%d\t %s' % (i , desc ))
365
395
return
366
396
0 commit comments