@@ -63,74 +63,6 @@ def stop_process__hack(name):
63
63
send_signal (name , signal .SIGSTOP )
64
64
65
65
66
- class InteractiveTest (object ):
67
- """Define a test case for the interactive shell.
68
-
69
- This is implemented as a context-manager wrapper around
70
- pexpect.spawn, use like this:
71
-
72
- with InteractiveTest("Describe the test") as osh:
73
- osh.sendline(...)
74
- osh.expect(...)
75
- ...
76
- """
77
-
78
- def __init__ (self , description , program = SHELL ):
79
- self .program = program
80
- self .shell = None
81
- self .description = description
82
-
83
- def __enter__ (self ):
84
- if 0 :
85
- if DEBUG :
86
- print (self .description )
87
- else :
88
- print (self .description , end = '' )
89
-
90
- #env = dict(os.environ)
91
- #env['PS1'] = 'test$ '
92
- env = None
93
-
94
- sh_argv = ['--rcfile' , '/dev/null' ]
95
-
96
- # Why the heck is --norc different from --rcfile /dev/null in bash??? This
97
- # makes it so the prompt of the parent shell doesn't leak. Very annoying.
98
- if self .program == 'bash' :
99
- sh_argv .append ('--norc' )
100
- #print(sh_argv)
101
-
102
- # Python 3: encoding required
103
- self .shell = pexpect .spawn (
104
- self .program , sh_argv , env = env , encoding = 'utf-8' ,
105
- timeout = TIMEOUT )
106
-
107
- # suppress output when DEBUG is not set.
108
- if DEBUG :
109
- self .shell .logfile = sys .stdout
110
-
111
- # generally don't want local echo, it gets confusing fast.
112
- self .shell .setecho (False )
113
- return self .shell
114
-
115
- def __exit__ (self , t , v , tb ):
116
- global g_failures
117
- self .shell .close ()
118
-
119
- if not DEBUG :
120
- # show result of test
121
- if tb :
122
- g_failures += 1
123
- print ("... Fail" )
124
- else :
125
- print ("... OK" )
126
- # Allow other tests to keep running
127
- return True
128
- else :
129
- # Fail fast when in debug mode.
130
- pass
131
-
132
-
133
-
134
66
CASES = []
135
67
136
68
def register (skip_shells = None ):
@@ -142,10 +74,62 @@ def decorator(func):
142
74
return func
143
75
return decorator
144
76
77
+ #
78
+ # Test Cases
79
+ #
80
+ # TODO:
81
+ # - Fold code from demo/
82
+ # - bug-858-trap.sh
83
+ # - sigwinch-bug.sh
84
+ # - signal-during-read.sh -- actually 5 kinds of read
85
+ # - Fill out this TEST MATRIX.
86
+ #
87
+ # A. Which shell? osh, bash, dash, etc.
88
+ #
89
+ # B. What mode is it in?
90
+ #
91
+ # 1. Interactive (stdin is a terminal)
92
+ # 2. Non-interactive
93
+ #
94
+ # C. What is the main thread of the shell doing?
95
+ #
96
+ # 1. waiting for external process: sleep 1
97
+ # 2. wait builtin: sleep 5 & wait
98
+ # variants: wait -n: this matters when testing exit code
99
+ # 3. read builtin read
100
+ # variants: FIVE kinds, read -d, read -n, etc.
101
+ # 4. computation, e.g. fibonacci with $(( a + b ))
102
+ #
103
+ # if interactive:
104
+ # 5. keyboard input from terminal with select()
105
+ #
106
+ # Another way to categorize the main loop:
107
+ # 1. running script code
108
+ # 2. running trap code
109
+ # 3. running TAB completion plugin code
110
+ #
111
+ # D. What is it interrupted by?
112
+ #
113
+ # 1. SIGINT
114
+ # 2. SIGTSTP
115
+ # 3. SIGWINCH
116
+ # 4. SIGUSR1 -- doesn't this quit?
117
+ #
118
+ # if interactive:
119
+ # 1. SIGINT Ctrl-C from terminal (relies on signal distribution to child?)
120
+ # 2. SIGTSTP Ctrl-Z from terminal
121
+ #
122
+ # E. What is the signal state?
123
+ #
124
+ # 1. no trap handlers installed
125
+ # 2. trap 'echo X' SIGWINCH
126
+ # 3. trap 'echo X' SIGINT ?
127
+
145
128
146
129
# TODO: Make this pass in OSH
147
- @register (skip_shells = ['osh' ])
148
- def a (sh ):
130
+ #@register(skip_shells=['osh'])
131
+ @register ()
132
+ def t0 (sh ):
149
133
'wait builtin then SIGWINCH (issue 1067)'
150
134
151
135
sh .sendline ('sleep 1 &' )
@@ -163,7 +147,7 @@ def a(sh):
163
147
164
148
165
149
@register ()
166
- def b (sh ):
150
+ def t1 (sh ):
167
151
'Ctrl-C during external command'
168
152
169
153
sh .sendline ('sleep 5' )
@@ -178,7 +162,7 @@ def b(sh):
178
162
179
163
180
164
@register ()
181
- def c (sh ):
165
+ def t2 (sh ):
182
166
'Ctrl-C during read builtin'
183
167
184
168
sh .sendline ('read' )
@@ -194,7 +178,7 @@ def c(sh):
194
178
195
179
# TODO: fix on OSH
196
180
@register (skip_shells = ['osh' ])
197
- def d (sh ):
181
+ def t3 (sh ):
198
182
'Ctrl-C during wait builtin'
199
183
200
184
sh .sendline ('sleep 5 &' )
@@ -211,7 +195,7 @@ def d(sh):
211
195
212
196
213
197
@register ()
214
- def e (sh ):
198
+ def t4 (sh ):
215
199
'Ctrl-C during pipeline'
216
200
sh .sendline ('sleep 5 | cat' )
217
201
@@ -224,9 +208,8 @@ def e(sh):
224
208
sh .expect ('status=130' )
225
209
226
210
227
- # TODO: make it work on OSH
228
211
@register (skip_shells = ['osh' ])
229
- def f (sh ):
212
+ def t5 (sh ):
230
213
'Ctrl-C during Command Sub (issue 467)'
231
214
sh .sendline ('`sleep 5`' )
232
215
@@ -241,7 +224,7 @@ def f(sh):
241
224
242
225
243
226
@register (skip_shells = ['bash' ])
244
- def g (sh ):
227
+ def t6 (sh ):
245
228
'fg twice should not result in fatal error (issue 1004)'
246
229
sh .expect (r'.*\$ ' )
247
230
sh .sendline ("cat" )
@@ -260,7 +243,7 @@ def g(sh):
260
243
261
244
262
245
@register (skip_shells = ['bash' ])
263
- def h (sh ):
246
+ def t7 (sh ):
264
247
'Test resuming a killed process'
265
248
sh .expect (r'.*\$ ' )
266
249
sh .sendline ("cat" )
@@ -276,7 +259,7 @@ def h(sh):
276
259
277
260
278
261
@register (skip_shells = ['bash' ])
279
- def j (sh ):
262
+ def t8 (sh ):
280
263
'Call fg after process exits (issue 721)'
281
264
282
265
sh .expect (r".*\$" )
@@ -312,6 +295,7 @@ def WriteHeader(self, sh_labels):
312
295
class Result (object ):
313
296
SKIP = 1
314
297
OK = 2
298
+ FAIL = 3
315
299
316
300
317
301
def RunCases (cases , case_predicate , shell_pairs , results ):
@@ -333,11 +317,40 @@ def RunCases(cases, case_predicate, shell_pairs, results):
333
317
result_row .append (Result .SKIP )
334
318
continue
335
319
336
- with InteractiveTest (desc , program = shell_path ) as sh :
320
+ env = None
321
+ sh_argv = ['--rcfile' , '/dev/null' ]
322
+
323
+ # Why the heck is --norc different from --rcfile /dev/null in bash??? This
324
+ # makes it so the prompt of the parent shell doesn't leak. Very annoying.
325
+ if shell_label == 'bash' :
326
+ sh_argv .append ('--norc' )
327
+ #print(sh_argv)
328
+
329
+ # Python 3: encoding required
330
+ sh = pexpect .spawn (
331
+ shell_path , sh_argv , env = env , encoding = 'utf-8' , timeout = TIMEOUT )
332
+
333
+ # suppress output when DEBUG is not set.
334
+ if DEBUG :
335
+ sh .logfile = sys .stdout
336
+
337
+ # Generally don't want local echo, it gets confusing fast.
338
+ sh .setecho (False )
339
+
340
+ ok = True
341
+ try :
337
342
func (sh )
343
+ except Exception as e :
344
+ import traceback
345
+ print (e )
346
+ result_row .append (Result .FAIL )
347
+ ok = False
338
348
339
- # TODO: Failing will raise an exception and we won't print anything?
340
- result_row .append (Result .OK )
349
+ finally :
350
+ sh .close ()
351
+
352
+ if ok :
353
+ result_row .append (Result .OK )
341
354
342
355
result_row .append (desc )
343
356
results .append (result_row )
@@ -362,6 +375,8 @@ def PrintResults(shell_pairs, results):
362
375
for cell in row [1 :- 1 ]:
363
376
if cell == Result .SKIP :
364
377
f .write ('SKIP\t ' )
378
+ elif cell == Result .FAIL :
379
+ f .write ('%sFAIL%s\t ' % (ansi .BOLD + ansi .RED , ansi .RESET ))
365
380
elif cell == Result .OK :
366
381
f .write ('%sok%s\t ' % (ansi .BOLD + ansi .GREEN , ansi .RESET ))
367
382
else :
@@ -376,6 +391,12 @@ def main(argv):
376
391
o = spec_lib .Options ()
377
392
opts , argv = o .parse_args (argv )
378
393
394
+ # List test cases and return
395
+ if opts .do_list :
396
+ for i , (desc , _ , _ ) in enumerate (CASES ):
397
+ print ('%d\t %s' % (i , desc ))
398
+ return
399
+
379
400
shells = argv [1 :]
380
401
shell_pairs = spec_lib .MakeShellPairs (shells )
381
402
0 commit comments