3 Test whether cargo-miri works properly.
4 Assumes the `MIRI_SYSROOT` env var to be set appropriately,
5 and the working directory to contain the cargo-miri-test project.
8 import sys, subprocess, os, re
15 print("\nTEST FAIL: {}".format(msg))
18 def cargo_miri(cmd, quiet = True):
19 args = ["cargo", "miri", cmd]
22 if 'MIRI_TEST_TARGET' in os.environ:
23 args += ["--target", os.environ['MIRI_TEST_TARGET']]
26 def normalize_stdout(str):
27 str = str.replace("src\\", "src/") # normalize paths across platforms
28 return re.sub("finished in \d+\.\d\ds", "finished in $TIME", str)
30 def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}):
31 print("Testing {}...".format(name))
32 ## Call `cargo miri`, capture all output
33 p_env = os.environ.copy()
37 stdin=subprocess.PIPE,
38 stdout=subprocess.PIPE,
39 stderr=subprocess.PIPE,
42 (stdout, stderr) = p.communicate(input=stdin)
43 stdout = stdout.decode("UTF-8")
44 stderr = stderr.decode("UTF-8")
45 if p.returncode == 0 and normalize_stdout(stdout) == open(stdout_ref).read() and stderr == open(stderr_ref).read():
49 print("Test stdout or stderr did not match reference!")
50 print("--- BEGIN test stdout ---")
52 print("--- END test stdout ---")
53 print("--- BEGIN test stderr ---")
55 print("--- END test stderr ---")
56 fail("exit code was {}".format(p.returncode))
58 def test_no_rebuild(name, cmd, env={}):
59 print("Testing {}...".format(name))
60 p_env = os.environ.copy()
64 stdout=subprocess.PIPE,
65 stderr=subprocess.PIPE,
68 (stdout, stderr) = p.communicate()
69 stdout = stdout.decode("UTF-8")
70 stderr = stderr.decode("UTF-8")
72 fail("rebuild failed");
73 # Also check for 'Running' as a sanity check.
74 if stderr.count(" Compiling ") > 0 or stderr.count(" Running ") == 0:
75 print("--- BEGIN stderr ---")
77 print("--- END stderr ---")
78 fail("Something was being rebuilt when it should not be (or we got no output)");
80 def test_cargo_miri_run():
81 test("`cargo miri run` (no isolation)",
83 "run.default.stdout.ref", "run.default.stderr.ref",
86 'MIRIFLAGS': "-Zmiri-disable-isolation",
87 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence
90 # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722)
91 test_no_rebuild("`cargo miri run` (no rebuild)",
92 cargo_miri("run", quiet=False) + ["--", ""],
93 env={'MIRITESTVAR': "wrongval"}, # changing the env var causes a rebuild (re-runs build.rs),
96 test("`cargo miri run` (with arguments and target)",
97 cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"', r'he\\llo\"world'],
98 "run.args.stdout.ref", "run.args.stderr.ref",
100 test("`cargo miri r` (subcrate, no isolation)",
101 cargo_miri("r") + ["-p", "subcrate"],
102 "run.subcrate.stdout.ref", "run.subcrate.stderr.ref",
103 env={'MIRIFLAGS': "-Zmiri-disable-isolation"},
105 test("`cargo miri run` (custom target dir)",
106 # Attempt to confuse the argument parser.
107 cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"],
108 "run.args.stdout.ref", "run.custom-target-dir.stderr.ref",
111 def test_cargo_miri_test():
112 # rustdoc is not run on foreign targets
113 is_foreign = 'MIRI_TEST_TARGET' in os.environ
114 default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref"
115 filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref"
117 test("`cargo miri test`",
119 default_ref, "test.stderr-empty.ref",
120 env={'MIRIFLAGS': "-Zmiri-seed=feed"},
122 test("`cargo miri test` (no isolation, no doctests)",
123 cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml`
124 "test.cross-target.stdout.ref", "test.stderr-empty.ref",
125 env={'MIRIFLAGS': "-Zmiri-disable-isolation"},
127 test("`cargo miri test` (raw-ptr tracking)",
129 default_ref, "test.stderr-empty.ref",
130 env={'MIRIFLAGS': "-Zmiri-track-raw-pointers"},
132 test("`cargo miri test` (with filter)",
133 cargo_miri("test") + ["--", "--format=pretty", "le1"],
134 filter_ref, "test.stderr-empty.ref",
136 test("`cargo miri test` (test target)",
137 cargo_miri("test") + ["--test", "test", "--", "--format=pretty"],
138 "test.test-target.stdout.ref", "test.stderr-empty.ref",
140 test("`cargo miri test` (bin target)",
141 cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"],
142 "test.bin-target.stdout.ref", "test.stderr-empty.ref",
144 test("`cargo miri t` (subcrate, no isolation)",
145 cargo_miri("t") + ["-p", "subcrate"],
146 "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref",
147 env={'MIRIFLAGS': "-Zmiri-disable-isolation"},
149 test("`cargo miri test` (subcrate, doctests)",
150 cargo_miri("test") + ["-p", "subcrate", "--doc"],
151 "test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref",
153 test("`cargo miri test` (custom target dir)",
154 cargo_miri("test") + ["--target-dir=custom-test"],
155 default_ref, "test.stderr-empty.ref",
157 del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it
158 test("`cargo miri test` (config-cli)",
159 cargo_miri("test") + ["--config=build.target-dir=\"config-cli\"", "-Zunstable-options"],
160 default_ref, "test.stderr-empty.ref",
163 os.chdir(os.path.dirname(os.path.realpath(__file__)))
164 os.environ["CARGO_TARGET_DIR"] = "target" # this affects the location of the target directory that we need to check
165 os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set
166 os.environ["RUST_TEST_THREADS"] = "1" # avoid non-deterministic output due to concurrent test runs
168 target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else ""
169 print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND)
171 if not 'MIRI_SYSROOT' in os.environ:
172 # Make sure we got a working sysroot.
173 # (If the sysroot gets built later when output is compared, that leads to test failures.)
174 subprocess.run(cargo_miri("setup"), check=True)
175 test_cargo_miri_run()
176 test_cargo_miri_test()
177 # Ensure we did not create anything outside the expected target dir.
178 for target_dir in ["target", "custom-run", "custom-test", "config-cli"]:
179 if os.listdir(target_dir) != ["miri"]:
180 fail(f"`{target_dir}` contains unexpected files")
181 # Ensure something exists inside that target dir.
182 os.access(os.path.join(target_dir, "miri", "debug", "deps"), os.F_OK)
184 print("\nTEST SUCCESSFUL!")