OILS / test / spec_lib.py View on Github | oilshell.org

225 lines, 163 significant
1"""
2spec_lib.py
3
4Shared between sh_spec.py (Python 2) and spec/stateful/harness.py (Python 3)!
5"""
6from __future__ import print_function
7
8import os
9import re
10import sys
11
12
13def log(msg, *args):
14 # type: (str, *Any) -> None
15 if args:
16 msg = msg % args
17 print(msg, file=sys.stderr)
18
19
20# Note that devtools/release.sh spec-all runs with bin/osh and $DIR/_bin/osh,
21# which should NOT match
22
23OSH_CPP_RE = re.compile(r'_bin/\w+-\w+(-sh)?/osh') # e.g. $PWD/_bin/cxx-dbg/osh
24YSH_CPP_RE = re.compile(r'_bin/\w+-\w+(-sh)?/ysh') # e.g. $PWD/_bin/cxx-dbg/ysh
25OIL_CPP_RE = re.compile(r'_bin/\w+-\w+(-sh)?/oil')
26
27def MakeShellPairs(shells):
28 shell_pairs = []
29
30 saw_osh = False
31 saw_ysh = False
32 saw_oil = False
33
34 for path in shells:
35 name, _ = os.path.splitext(path)
36 label = os.path.basename(name)
37
38 if label == 'osh':
39 # change the second 'osh' to 'osh_ALT' so it's distinct
40 if saw_osh:
41 if OSH_CPP_RE.search(path):
42 label = 'osh-cpp'
43 else:
44 label = 'osh_ALT'
45 saw_osh = True
46
47 elif label == 'ysh':
48 if saw_ysh:
49 if YSH_CPP_RE.search(path):
50 label = 'ysh-cpp'
51 else:
52 label = 'ysh_ALT'
53
54 saw_ysh = True
55
56 elif label == 'oil': # TODO: remove this
57 if saw_oil:
58 if OIL_CPP_RE.search(path):
59 label = 'oil-cpp'
60 else:
61 label = 'oil_ALT'
62
63 saw_oil = True
64
65 shell_pairs.append((label, path))
66 return shell_pairs
67
68
69RANGE_RE = re.compile('(\d+) \s* - \s* (\d+)', re.VERBOSE)
70
71
72def ParseRange(range_str):
73 try:
74 d = int(range_str)
75 return d, d # singleton range
76 except ValueError:
77 m = RANGE_RE.match(range_str)
78 if not m:
79 raise RuntimeError('Invalid range %r' % range_str)
80 b, e = m.groups()
81 return int(b), int(e)
82
83
84class RangePredicate(object):
85 """Zero-based indexing, inclusive ranges."""
86
87 def __init__(self, begin, end):
88 self.begin = begin
89 self.end = end
90
91 def __call__(self, i, case):
92 return self.begin <= i <= self.end
93
94
95class RegexPredicate(object):
96 """Filter by name."""
97
98 def __init__(self, desc_re):
99 self.desc_re = desc_re
100
101 def __call__(self, i, case):
102 return bool(self.desc_re.search(case['desc']))
103
104
105
106def DefineCommon(p):
107 """Flags shared between sh_spec.py and stateful/harness.py."""
108 p.add_option(
109 '-v', '--verbose', dest='verbose', action='store_true', default=False,
110 help='Show details about test failures')
111 p.add_option(
112 '-r', '--range', dest='range', default=None,
113 help='Execute only a given test range, e.g. 5-10, 5-, -10, or 5')
114 p.add_option(
115 '--regex', dest='regex', default=None,
116 help='Execute only tests whose description matches a given regex '
117 '(case-insensitive)')
118 p.add_option(
119 '--list', dest='do_list', action='store_true', default=None,
120 help='Just list tests')
121 p.add_option(
122 '--oils-failures-allowed', dest='oils_failures_allowed', type='int',
123 default=0, help="Allow this number of Oils failures")
124
125 # Select what shells to run
126 p.add_option(
127 '--oils-bin-dir', dest='oils_bin_dir', default=None,
128 help="Directory that osh and ysh live in")
129 p.add_option(
130 '--oils-cpp-bin-dir', dest='oils_cpp_bin_dir', default=None,
131 help="Directory that native C++ osh and ysh live in")
132 p.add_option(
133 '--ovm-bin-dir', dest='ovm_bin_dir', default=None,
134 help="Directory of the legacy OVM/CPython build")
135 p.add_option(
136 '--compare-shells', dest='compare_shells', action='store_true',
137 help="Compare against shells specified at the top of each file")
138
139
140def DefineStateful(p):
141 p.add_option(
142 '--num-retries', dest='num_retries',
143 type='int', default=4,
144 help='Number of retries (for spec/stateful only)')
145 p.add_option(
146 '--pexpect-timeout', dest='pexpect_timeout',
147 type='float', default=1.0,
148 help='In seconds')
149 p.add_option(
150 '--results-file', dest='results_file', default=None,
151 help='Write table of results to this file. Default is stdout.')
152
153
154def DefineShSpec(p):
155 p.add_option(
156 '-d', '--details', dest='details', action='store_true', default=False,
157 help='Show details even for successful cases (requires -v)')
158 p.add_option(
159 '-t', '--trace', dest='trace', action='store_true', default=False,
160 help='trace execution of shells to diagnose hangs')
161
162 # Execution modes
163 p.add_option(
164 '-p', '--print', dest='do_print', action='store_true', default=None,
165 help="Print test code, but don't run it")
166 p.add_option(
167 '--print-spec-suite', dest='print_spec_suite', action='store_true', default=None,
168 help="Print suite this file belongs to")
169 p.add_option(
170 '--print-table', dest='print_table', action='store_true', default=None,
171 help="Print table of test files")
172 p.add_option(
173 '--print-tagged', dest='print_tagged',
174 help="Print spec files tagged with a certain string")
175
176 # Output control
177 p.add_option(
178 '--format', dest='format', choices=['ansi', 'html'],
179 default='ansi', help="Output format (default 'ansi')")
180 p.add_option(
181 '--stats-file', dest='stats_file', default=None,
182 help="File to write stats to")
183 p.add_option(
184 '--tsv-output', dest='tsv_output', default=None,
185 help="Write a TSV log to this file. Subsumes --stats-file.")
186 p.add_option(
187 '--stats-template', dest='stats_template', default='',
188 help="Python format string for stats")
189
190 p.add_option(
191 '--path-env', dest='path_env', default='',
192 help="The full PATH, for finding binaries used in tests.")
193 p.add_option(
194 '--tmp-env', dest='tmp_env', default='',
195 help="A temporary directory that the tests can use.")
196
197 # Notes:
198 # - utf-8 is the Ubuntu default
199 # - this flag has limited usefulness. It may be better to simply export LANG=
200 # in this test case itself.
201 p.add_option(
202 '--lang-env', dest='lang_env', default='en_US.UTF-8',
203 help="The LANG= setting, which affects various libc functions.")
204 p.add_option(
205 '--env-pair', dest='env_pair', default=[], action='append',
206 help='A key=value pair to add to the environment')
207
208 p.add_option(
209 '--timeout', dest='timeout', default='',
210 help="Prefix shell invocation with 'timeout N'")
211 p.add_option(
212 '--timeout-bin', dest='timeout_bin', default=None,
213 help="Use the smoosh timeout binary at this location.")
214
215 p.add_option(
216 '--posix', dest='posix', default=False, action='store_true',
217 help='Pass -o posix to the shell (when applicable)')
218
219 p.add_option(
220 '--sh-env-var-name', dest='sh_env_var_name', default='SH',
221 help="Set this environment variable to the path of the shell")
222
223 p.add_option(
224 '--pyann-out-dir', dest='pyann_out_dir', default=None,
225 help='Run OSH with PYANN_OUT=$dir/$case_num.json')