mirror of
https://github.com/fish-shell/fish-shell.git
synced 2026-06-07 18:21:16 -03:00
Update littlecheck
From commit b1369a52c24336da2d2d6d5dc6707a7834065d43 This adds the "REQUIRES" directive that allows specifying preconditions for tests, which allows us to add tests that don't have to run on all systems. Now, I don't want to just make all tests specific to an OS or something, but e.g. a `git` test would be a honkin' great idea, and we can't ask everyone to have `git`!
This commit is contained in:
@@ -25,6 +25,7 @@ COMMENT_RE = r"^(?:[^#].*)?#\s*"
|
||||
|
||||
# A regex showing how to run the file.
|
||||
RUN_RE = re.compile(COMMENT_RE + r"RUN:\s+(.*)\n")
|
||||
REQUIRES_RE = re.compile(COMMENT_RE + r"REQUIRES:\s+(.*)\n")
|
||||
|
||||
# A regex capturing lines that should be checked against stdout.
|
||||
CHECK_STDOUT_RE = re.compile(COMMENT_RE + r"CHECK:\s+(.*)\n")
|
||||
@@ -32,6 +33,7 @@ CHECK_STDOUT_RE = re.compile(COMMENT_RE + r"CHECK:\s+(.*)\n")
|
||||
# A regex capturing lines that should be checked against stderr.
|
||||
CHECK_STDERR_RE = re.compile(COMMENT_RE + r"CHECKERR:\s+(.*)\n")
|
||||
|
||||
SKIP = object()
|
||||
|
||||
class Config(object):
|
||||
def __init__(self):
|
||||
@@ -357,6 +359,20 @@ def perform_substitution(input_str, subs):
|
||||
return re.sub(r"%(%|[a-zA-Z0-9_-]+)", subber, input_str)
|
||||
|
||||
|
||||
def runproc(cmd):
|
||||
""" Wrapper around subprocess.Popen to save typing """
|
||||
PIPE = subprocess.PIPE
|
||||
proc = subprocess.Popen(
|
||||
cmd,
|
||||
stdin=PIPE,
|
||||
stdout=PIPE,
|
||||
stderr=PIPE,
|
||||
shell=True,
|
||||
close_fds=True, # For Python 2.6 as shipped on RHEL 6
|
||||
)
|
||||
return proc
|
||||
|
||||
|
||||
class TestRun(object):
|
||||
def __init__(self, name, runcmd, checker, subs, config):
|
||||
self.name = name
|
||||
@@ -442,14 +458,7 @@ class TestRun(object):
|
||||
PIPE = subprocess.PIPE
|
||||
if self.config.verbose:
|
||||
print(self.subbed_command)
|
||||
proc = subprocess.Popen(
|
||||
self.subbed_command,
|
||||
stdin=PIPE,
|
||||
stdout=PIPE,
|
||||
stderr=PIPE,
|
||||
shell=True,
|
||||
close_fds=True, # For Python 2.6 as shipped on RHEL 6
|
||||
)
|
||||
proc = runproc(self.subbed_command)
|
||||
stdout, stderr = proc.communicate()
|
||||
# HACK: This is quite cheesy: POSIX specifies that sh should return 127 for a missing command.
|
||||
# Technically it's also possible to return it in other conditions.
|
||||
@@ -457,6 +466,13 @@ class TestRun(object):
|
||||
status = proc.returncode
|
||||
if status == 127:
|
||||
raise CheckerError("Command could not be found: " + self.subbed_command)
|
||||
if status == 126:
|
||||
raise CheckerError("Command is not executable: " + self.subbed_command)
|
||||
|
||||
# If a test returns 125, we skip it and don't even attempt to compare output.
|
||||
# This is similar to what `git bisect run` does.
|
||||
if status == 125:
|
||||
return SKIP
|
||||
|
||||
outlines = [
|
||||
Line(text, idx + 1, "stdout")
|
||||
@@ -575,6 +591,8 @@ class Checker(object):
|
||||
else:
|
||||
raise CheckerError("No runlines ('# RUN') found")
|
||||
|
||||
self.requirecmds = [RunCmd.parse(sl) for sl in group1s(REQUIRES_RE)]
|
||||
|
||||
# Find check cmds.
|
||||
self.outchecks = [
|
||||
CheckCmd.parse(sl, "CHECK") for sl in group1s(CHECK_STDOUT_RE)
|
||||
@@ -589,6 +607,19 @@ def check_file(input_file, name, subs, config, failure_handler):
|
||||
success = True
|
||||
lines = Line.readfile(input_file, name)
|
||||
checker = Checker(name, lines)
|
||||
|
||||
# Run all the REQUIRES lines first,
|
||||
# if any of them fail it's a SKIP
|
||||
for reqcmd in checker.requirecmds:
|
||||
proc = runproc(
|
||||
perform_substitution(reqcmd.args, subs)
|
||||
)
|
||||
stdout, stderr = proc.communicate()
|
||||
status = proc.returncode
|
||||
if proc.returncode > 0:
|
||||
return SKIP
|
||||
|
||||
# Only then run the RUN lines.
|
||||
for runcmd in checker.runcmds:
|
||||
failure = TestRun(name, runcmd, checker, subs, config).run()
|
||||
if failure:
|
||||
@@ -668,14 +699,20 @@ def main():
|
||||
subs = def_subs.copy()
|
||||
subs["s"] = path
|
||||
starttime = datetime.datetime.now()
|
||||
if not check_path(path, subs, config, TestFailure.print_message):
|
||||
ret = check_path(path, subs, config, TestFailure.print_message)
|
||||
if not ret:
|
||||
failure_count += 1
|
||||
elif config.progress:
|
||||
endtime = datetime.datetime.now()
|
||||
duration_ms = round((endtime - starttime).total_seconds() * 1000)
|
||||
reason = "ok"
|
||||
color = "{GREEN}"
|
||||
if ret is SKIP:
|
||||
reason = "SKIPPED"
|
||||
color = "{BLUE}"
|
||||
print(
|
||||
"{GREEN}ok{RESET} ({duration} ms)".format(
|
||||
duration=duration_ms, **fields
|
||||
(color + "{reason}{RESET} ({duration} ms)").format(
|
||||
duration=duration_ms, reason=reason, **fields
|
||||
)
|
||||
)
|
||||
sys.exit(failure_count)
|
||||
|
||||
Reference in New Issue
Block a user