2018-10-30 09:07:40 -05:00
|
|
|
#!/usr/bin/env python3
|
2018-10-30 05:26:53 -05:00
|
|
|
'''
|
|
|
|
Test whether cargo-miri works properly.
|
|
|
|
Assumes the `MIRI_SYSROOT` env var to be set appropriately,
|
|
|
|
and the working directory to contain the cargo-miri-test project.
|
|
|
|
'''
|
|
|
|
|
2022-07-14 05:03:08 -05:00
|
|
|
import sys, subprocess, os, re, difflib
|
2018-10-30 05:26:53 -05:00
|
|
|
|
2020-03-22 03:04:10 -05:00
|
|
|
CGREEN = '\33[32m'
|
|
|
|
CBOLD = '\33[1m'
|
|
|
|
CEND = '\33[0m'
|
|
|
|
|
2018-12-18 14:49:38 -06:00
|
|
|
def fail(msg):
|
2019-06-29 06:33:47 -05:00
|
|
|
print("\nTEST FAIL: {}".format(msg))
|
2018-12-18 14:49:38 -06:00
|
|
|
sys.exit(1)
|
|
|
|
|
2021-02-27 05:24:58 -06:00
|
|
|
def cargo_miri(cmd, quiet = True):
|
|
|
|
args = ["cargo", "miri", cmd]
|
|
|
|
if quiet:
|
|
|
|
args += ["-q"]
|
2019-04-21 15:35:47 -05:00
|
|
|
if 'MIRI_TEST_TARGET' in os.environ:
|
|
|
|
args += ["--target", os.environ['MIRI_TEST_TARGET']]
|
|
|
|
return args
|
|
|
|
|
2021-01-12 15:16:48 -06:00
|
|
|
def normalize_stdout(str):
|
|
|
|
str = str.replace("src\\", "src/") # normalize paths across platforms
|
2022-07-23 12:28:44 -05:00
|
|
|
str = re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) # the time keeps changing, obviously
|
|
|
|
return str
|
|
|
|
|
|
|
|
def normalize_stderr(str):
|
2022-08-01 08:13:34 -05:00
|
|
|
str = re.sub("Preparing a sysroot for Miri \(target: [a-z0-9_-]+\)\.\.\. done\n", "", str) # remove leading cargo-miri setup output
|
2022-07-23 12:28:44 -05:00
|
|
|
return str
|
2021-01-12 15:16:48 -06:00
|
|
|
|
2022-07-14 05:03:08 -05:00
|
|
|
def check_output(actual, path, name):
|
|
|
|
expected = open(path).read()
|
|
|
|
if expected == actual:
|
|
|
|
return True
|
|
|
|
print(f"{path} did not match reference!")
|
|
|
|
print(f"--- BEGIN diff {name} ---")
|
|
|
|
for text in difflib.unified_diff(expected.split("\n"), actual.split("\n")):
|
|
|
|
print(text)
|
|
|
|
print(f"--- END diff {name} ---")
|
|
|
|
return False
|
|
|
|
|
2020-09-09 02:18:10 -05:00
|
|
|
def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}):
|
2020-09-12 06:57:49 -05:00
|
|
|
print("Testing {}...".format(name))
|
2018-10-30 05:26:53 -05:00
|
|
|
## Call `cargo miri`, capture all output
|
2020-09-09 01:58:29 -05:00
|
|
|
p_env = os.environ.copy()
|
|
|
|
p_env.update(env)
|
2018-10-30 05:26:53 -05:00
|
|
|
p = subprocess.Popen(
|
2018-11-27 08:06:51 -06:00
|
|
|
cmd,
|
2020-09-09 02:18:10 -05:00
|
|
|
stdin=subprocess.PIPE,
|
2018-10-30 05:26:53 -05:00
|
|
|
stdout=subprocess.PIPE,
|
2020-09-09 01:58:29 -05:00
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
env=p_env,
|
2018-10-30 05:26:53 -05:00
|
|
|
)
|
2020-09-09 02:18:10 -05:00
|
|
|
(stdout, stderr) = p.communicate(input=stdin)
|
2022-07-23 12:28:44 -05:00
|
|
|
stdout = normalize_stdout(stdout.decode("UTF-8"))
|
|
|
|
stderr = normalize_stderr(stderr.decode("UTF-8"))
|
2022-07-14 05:03:08 -05:00
|
|
|
|
|
|
|
stdout_matches = check_output(stdout, stdout_ref, "stdout")
|
|
|
|
stderr_matches = check_output(stderr, stderr_ref, "stderr")
|
|
|
|
|
|
|
|
if p.returncode == 0 and stdout_matches and stderr_matches:
|
2020-09-12 06:57:49 -05:00
|
|
|
# All good!
|
|
|
|
return
|
|
|
|
fail("exit code was {}".format(p.returncode))
|
2018-10-30 05:26:53 -05:00
|
|
|
|
2021-02-27 14:52:27 -06:00
|
|
|
def test_no_rebuild(name, cmd, env={}):
|
2021-02-27 05:24:58 -06:00
|
|
|
print("Testing {}...".format(name))
|
2021-02-27 14:52:27 -06:00
|
|
|
p_env = os.environ.copy()
|
|
|
|
p_env.update(env)
|
2021-02-27 05:24:58 -06:00
|
|
|
p = subprocess.Popen(
|
|
|
|
cmd,
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE,
|
2021-02-27 14:52:27 -06:00
|
|
|
env=p_env,
|
2021-02-27 05:24:58 -06:00
|
|
|
)
|
|
|
|
(stdout, stderr) = p.communicate()
|
|
|
|
stdout = stdout.decode("UTF-8")
|
|
|
|
stderr = stderr.decode("UTF-8")
|
|
|
|
if p.returncode != 0:
|
|
|
|
fail("rebuild failed");
|
2021-02-27 05:32:06 -06:00
|
|
|
# Also check for 'Running' as a sanity check.
|
|
|
|
if stderr.count(" Compiling ") > 0 or stderr.count(" Running ") == 0:
|
2021-02-27 05:24:58 -06:00
|
|
|
print("--- BEGIN stderr ---")
|
|
|
|
print(stderr, end="")
|
|
|
|
print("--- END stderr ---")
|
2021-02-27 05:32:06 -06:00
|
|
|
fail("Something was being rebuilt when it should not be (or we got no output)");
|
2021-02-27 05:24:58 -06:00
|
|
|
|
2018-11-27 08:06:51 -06:00
|
|
|
def test_cargo_miri_run():
|
2020-09-12 06:52:05 -05:00
|
|
|
test("`cargo miri run` (no isolation)",
|
2019-04-21 15:35:47 -05:00
|
|
|
cargo_miri("run"),
|
2020-12-21 04:29:49 -06:00
|
|
|
"run.default.stdout.ref", "run.default.stderr.ref",
|
2020-09-09 02:18:10 -05:00
|
|
|
stdin=b'12\n21\n',
|
2021-02-28 02:10:35 -06:00
|
|
|
env={
|
|
|
|
'MIRIFLAGS': "-Zmiri-disable-isolation",
|
|
|
|
'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence
|
|
|
|
},
|
2021-02-27 14:52:27 -06:00
|
|
|
)
|
|
|
|
# Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722)
|
2021-02-28 04:13:17 -06:00
|
|
|
test_no_rebuild("`cargo miri run` (no rebuild)",
|
2021-02-27 14:52:27 -06:00
|
|
|
cargo_miri("run", quiet=False) + ["--", ""],
|
2021-02-28 04:13:17 -06:00
|
|
|
env={'MIRITESTVAR': "wrongval"}, # changing the env var causes a rebuild (re-runs build.rs),
|
|
|
|
# so keep it set
|
2019-04-21 15:35:47 -05:00
|
|
|
)
|
2020-09-12 05:52:14 -05:00
|
|
|
test("`cargo miri run` (with arguments and target)",
|
2021-09-24 09:13:29 -05:00
|
|
|
cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"', r'he\\llo\"world'],
|
2020-12-21 04:29:49 -06:00
|
|
|
"run.args.stdout.ref", "run.args.stderr.ref",
|
2019-02-09 05:42:16 -06:00
|
|
|
)
|
2021-09-13 17:05:01 -05:00
|
|
|
test("`cargo miri r` (subcrate, no isolation)",
|
2021-09-11 11:00:59 -05:00
|
|
|
cargo_miri("r") + ["-p", "subcrate"],
|
|
|
|
"run.subcrate.stdout.ref", "run.subcrate.stderr.ref",
|
|
|
|
env={'MIRIFLAGS': "-Zmiri-disable-isolation"},
|
|
|
|
)
|
2021-06-23 13:35:08 -05:00
|
|
|
test("`cargo miri run` (custom target dir)",
|
|
|
|
# Attempt to confuse the argument parser.
|
|
|
|
cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"],
|
|
|
|
"run.args.stdout.ref", "run.custom-target-dir.stderr.ref",
|
|
|
|
)
|
2018-11-27 08:06:51 -06:00
|
|
|
|
2018-10-30 05:26:53 -05:00
|
|
|
def test_cargo_miri_test():
|
2020-09-11 11:20:41 -05:00
|
|
|
# rustdoc is not run on foreign targets
|
|
|
|
is_foreign = 'MIRI_TEST_TARGET' in os.environ
|
2021-01-12 15:16:48 -06:00
|
|
|
default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref"
|
|
|
|
filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref"
|
2020-09-11 11:20:41 -05:00
|
|
|
|
2022-06-27 10:16:27 -05:00
|
|
|
# macOS needs permissive provenance inside getrandom_1.
|
2020-09-12 05:52:14 -05:00
|
|
|
test("`cargo miri test`",
|
2020-09-09 01:58:29 -05:00
|
|
|
cargo_miri("test"),
|
2021-01-12 15:16:48 -06:00
|
|
|
default_ref, "test.stderr-empty.ref",
|
2022-06-26 22:00:54 -05:00
|
|
|
env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-seed=feed"},
|
2019-04-21 15:35:47 -05:00
|
|
|
)
|
2021-04-05 05:46:36 -05:00
|
|
|
test("`cargo miri test` (no isolation, no doctests)",
|
|
|
|
cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml`
|
|
|
|
"test.cross-target.stdout.ref", "test.stderr-empty.ref",
|
2022-06-26 22:00:54 -05:00
|
|
|
env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-disable-isolation"},
|
2020-09-12 06:52:05 -05:00
|
|
|
)
|
2020-09-12 05:52:14 -05:00
|
|
|
test("`cargo miri test` (with filter)",
|
2022-07-21 07:06:11 -05:00
|
|
|
cargo_miri("test") + ["--", "--format=pretty", "pl"],
|
2021-01-12 15:16:48 -06:00
|
|
|
filter_ref, "test.stderr-empty.ref",
|
2019-08-29 04:09:34 -05:00
|
|
|
)
|
2020-09-12 05:52:14 -05:00
|
|
|
test("`cargo miri test` (test target)",
|
2020-09-09 01:58:29 -05:00
|
|
|
cargo_miri("test") + ["--test", "test", "--", "--format=pretty"],
|
2020-12-21 04:29:49 -06:00
|
|
|
"test.test-target.stdout.ref", "test.stderr-empty.ref",
|
2022-06-26 22:00:54 -05:00
|
|
|
env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
|
2020-08-28 23:12:11 -05:00
|
|
|
)
|
2020-09-12 05:52:14 -05:00
|
|
|
test("`cargo miri test` (bin target)",
|
2020-09-09 01:58:29 -05:00
|
|
|
cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"],
|
2020-12-21 04:29:49 -06:00
|
|
|
"test.bin-target.stdout.ref", "test.stderr-empty.ref",
|
2020-09-12 06:52:05 -05:00
|
|
|
)
|
2021-09-11 11:00:59 -05:00
|
|
|
test("`cargo miri t` (subcrate, no isolation)",
|
|
|
|
cargo_miri("t") + ["-p", "subcrate"],
|
|
|
|
"test.subcrate.stdout.ref", "test.stderr-proc-macro.ref",
|
|
|
|
env={'MIRIFLAGS': "-Zmiri-disable-isolation"},
|
|
|
|
)
|
2021-05-26 17:40:47 -05:00
|
|
|
test("`cargo miri test` (subcrate, doctests)",
|
|
|
|
cargo_miri("test") + ["-p", "subcrate", "--doc"],
|
|
|
|
"test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref",
|
|
|
|
)
|
2021-06-23 13:35:08 -05:00
|
|
|
test("`cargo miri test` (custom target dir)",
|
|
|
|
cargo_miri("test") + ["--target-dir=custom-test"],
|
|
|
|
default_ref, "test.stderr-empty.ref",
|
2022-06-26 22:00:54 -05:00
|
|
|
env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
|
2021-06-23 13:35:08 -05:00
|
|
|
)
|
|
|
|
del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it
|
|
|
|
test("`cargo miri test` (config-cli)",
|
|
|
|
cargo_miri("test") + ["--config=build.target-dir=\"config-cli\"", "-Zunstable-options"],
|
|
|
|
default_ref, "test.stderr-empty.ref",
|
2022-06-26 22:00:54 -05:00
|
|
|
env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
|
2021-06-23 13:35:08 -05:00
|
|
|
)
|
2018-10-30 05:26:53 -05:00
|
|
|
|
2019-04-22 04:11:06 -05:00
|
|
|
os.chdir(os.path.dirname(os.path.realpath(__file__)))
|
2021-06-23 13:35:08 -05:00
|
|
|
os.environ["CARGO_TARGET_DIR"] = "target" # this affects the location of the target directory that we need to check
|
2020-09-12 07:24:56 -05:00
|
|
|
os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set
|
2021-04-05 06:18:59 -05:00
|
|
|
os.environ["RUST_TEST_THREADS"] = "1" # avoid non-deterministic output due to concurrent test runs
|
2019-04-22 04:11:06 -05:00
|
|
|
|
2020-03-22 03:04:10 -05:00
|
|
|
target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else ""
|
|
|
|
print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND)
|
|
|
|
|
2018-11-27 08:06:51 -06:00
|
|
|
test_cargo_miri_run()
|
2018-10-30 05:26:53 -05:00
|
|
|
test_cargo_miri_test()
|
2021-06-26 08:45:38 -05:00
|
|
|
# Ensure we did not create anything outside the expected target dir.
|
2021-06-23 13:35:08 -05:00
|
|
|
for target_dir in ["target", "custom-run", "custom-test", "config-cli"]:
|
|
|
|
if os.listdir(target_dir) != ["miri"]:
|
|
|
|
fail(f"`{target_dir}` contains unexpected files")
|
2021-06-26 08:45:38 -05:00
|
|
|
# Ensure something exists inside that target dir.
|
2021-06-23 13:35:08 -05:00
|
|
|
os.access(os.path.join(target_dir, "miri", "debug", "deps"), os.F_OK)
|
2019-04-22 04:11:06 -05:00
|
|
|
|
2019-06-29 06:33:47 -05:00
|
|
|
print("\nTEST SUCCESSFUL!")
|
2018-10-30 05:26:53 -05:00
|
|
|
sys.exit(0)
|