From a020e6296d471a889ff634d3521824597cc2be44 Mon Sep 17 00:00:00 2001 From: Thomas Orozco Date: Mon, 17 Jan 2022 13:34:16 +0000 Subject: [PATCH] Read arguments from a script instead of stdin If a program under test reads stdin (e.g. by accident), then cram's current behavior can be a little confusing, since what will happen is that it'll omit running anything because the script has been read. For example, if your test file is ``` $ echo 123 123 $ cat > /dev/null $ echo 456 456 $ echo 789 789 ``` Then running it yields: ``` $ echo 123 123 $ cat > /dev/null $ echo 456 - 456 - $ echo 789 - 789 ``` This patch updates cram to pass the script via file instead, which makes this mistake harder to make. I've also updated one of the tests that was implicitly relying on this. --- cram/_test.py | 34 +++++++++++++++++++++++----------- examples/env.t | 1 + examples/stdin.t | 9 +++++++++ tests/debug.t | 4 +++- tests/test.t | 11 ++++++----- tests/xunit.t | 8 ++++++-- 6 files changed, 48 insertions(+), 19 deletions(-) create mode 100644 examples/stdin.t diff --git a/cram/_test.py b/cram/_test.py index 2cec870d..e7273316 100644 --- a/cram/_test.py +++ b/cram/_test.py @@ -1,6 +1,8 @@ """Utilities for running individual tests""" import itertools +import tempfile +import contextlib import os import re import time @@ -20,6 +22,14 @@ def _escape(s): return (_escapesub(lambda m: _escapemap[m.group(0)], s[:-1]) + b' (esc)\n') +@contextlib.contextmanager +def _maketestfile(script): + """Write test to a temporary file and yield the path""" + with tempfile.NamedTemporaryFile() as f: + f.write(b''.join(script)) + f.flush() + yield f.name + def test(lines, shell='/bin/sh', indent=2, testname=None, env=None, cleanenv=True, debug=False): r"""Run test lines and return input, output, and diff. @@ -103,22 +113,23 @@ def test(lines, shell='/bin/sh', indent=2, testname=None, env=None, env['TESTSHELL'] = shell[0] if debug: - stdin = [] + script = [] for line in lines: if not line.endswith(b'\n'): line += b'\n' if line.startswith(cmdline): - stdin.append(line[len(cmdline):]) + script.append(line[len(cmdline):]) elif line.startswith(conline): - stdin.append(line[len(conline):]) + script.append(line[len(conline):]) - execute(shell + ['-'], stdin=b''.join(stdin), env=env) + with _maketestfile(script) as f: + execute(shell + [f], env=env) return ([], [], []) after = {} refout, postout = [], [] i = pos = prepos = -1 - stdin = [] + script = [] for i, line in enumerate(lines): if not line.endswith(b'\n'): line += b'\n' @@ -127,17 +138,18 @@ def test(lines, shell='/bin/sh', indent=2, testname=None, env=None, after.setdefault(pos, []).append(line) prepos = pos pos = i - stdin.append(b'echo %s %d $?\n' % (salt, i)) - stdin.append(line[len(cmdline):]) + script.append(b'echo %s %d $?\n' % (salt, i)) + script.append(line[len(cmdline):]) elif line.startswith(conline): after.setdefault(prepos, []).append(line) - stdin.append(line[len(conline):]) + script.append(line[len(conline):]) elif not line.startswith(indent): after.setdefault(pos, []).append(line) - stdin.append(b'echo %s %d $?\n' % (salt, i + 1)) + script.append(b'echo %s %d $?\n' % (salt, i + 1)) - output, retcode = execute(shell + ['-'], stdin=b''.join(stdin), - stdout=PIPE, stderr=STDOUT, env=env) + with _maketestfile(script) as f: + output, retcode = execute(shell + [f], + stdout=PIPE, stderr=STDOUT, env=env) if retcode == 80: return (refout, None, []) diff --git a/examples/env.t b/examples/env.t index b774c898..292707a2 100644 --- a/examples/env.t +++ b/examples/env.t @@ -23,6 +23,7 @@ Check environment variables: fail.t missingeol.t skip.t + stdin.t test.t $ echo "$TESTFILE" env.t diff --git a/examples/stdin.t b/examples/stdin.t new file mode 100644 index 00000000..f185333f --- /dev/null +++ b/examples/stdin.t @@ -0,0 +1,9 @@ +Test that consumes stdin. Cram should not fail on this: + + $ echo 123 + 123 + $ cat > /dev/null + $ echo 456 + 456 + $ echo 789 + 789 diff --git a/tests/debug.t b/tests/debug.t index d1e6bf33..0b37a7d1 100644 --- a/tests/debug.t +++ b/tests/debug.t @@ -24,8 +24,10 @@ Debug mode: Debug mode with extra shell arguments: - $ cram --shell-opts='-s' -d debug.t + $ cram --shell-opts='-v' -d debug.t + echo hi hi + echo bye bye Test debug mode with set -x: diff --git a/tests/test.t b/tests/test.t index e1f74b12..dc79c94d 100644 --- a/tests/test.t +++ b/tests/test.t @@ -5,8 +5,8 @@ Set up cram alias and example tests: Run cram examples: $ cram -q examples examples/fail.t - .s.!.s. - # Ran 7 tests, 2 skipped, 1 failed. + .s.!.s.. + # Ran 8 tests, 2 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) @@ -16,8 +16,8 @@ Run cram examples: Run examples with bash: $ cram --shell=/bin/bash -q examples examples/fail.t - .s.!.s. - # Ran 7 tests, 2 skipped, 1 failed. + .s.!.s.. + # Ran 8 tests, 2 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) @@ -33,8 +33,9 @@ Verbose mode: examples/fail.t: failed examples/missingeol.t: passed examples/skip.t: skipped + examples/stdin.t: passed examples/test.t: passed - # Ran 7 tests, 2 skipped, 1 failed. + # Ran 8 tests, 2 skipped, 1 failed. [1] $ md5 examples/fail.t examples/fail.t.err .*\b0f598c2b7b8ca5bcb8880e492ff6b452\b.* (re) diff --git a/tests/xunit.t b/tests/xunit.t index 5b9a7cda..8ef86344 100644 --- a/tests/xunit.t +++ b/tests/xunit.t @@ -11,13 +11,14 @@ xUnit XML output: examples/fail.t: failed examples/missingeol.t: passed examples/skip.t: skipped + examples/stdin.t: passed examples/test.t: passed - # Ran 7 tests, 2 skipped, 1 failed. + # Ran 8 tests, 2 skipped, 1 failed. [1] $ cat cram.xml (re) + (re) (re)