| use std::path::Path; | |
| use std::process::{Command, ExitStatus}; | |
| fn run(dirname: &str) -> (ExitStatus, String, String) { | |
| let output = Command::new(env!("CARGO_BIN_EXE_linkchecker")) | |
| .current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).join("tests")) | |
| .arg(dirname) | |
| .output() | |
| .unwrap(); | |
| let stdout = String::from_utf8(output.stdout).unwrap(); | |
| let stderr = String::from_utf8(output.stderr).unwrap(); | |
| (output.status, stdout, stderr) | |
| } | |
| fn broken_test(dirname: &str, expected: &str) { | |
| let (status, stdout, stderr) = run(dirname); | |
| assert!(!status.success()); | |
| if !contains(expected, &stdout) { | |
| panic!( | |
| "stdout did not contain expected text: {}\n\ | |
| --- stdout:\n\ | |
| {}\n\ | |
| --- stderr:\n\ | |
| {}\n", | |
| expected, stdout, stderr | |
| ); | |
| } | |
| } | |
| fn contains(expected: &str, actual: &str) -> bool { | |
| // Normalize for Windows paths. | |
| let actual = actual.replace('\\', "/"); | |
| actual.lines().any(|mut line| { | |
| for (i, part) in expected.split("[..]").enumerate() { | |
| match line.find(part) { | |
| Some(j) => { | |
| if i == 0 && j != 0 { | |
| return false; | |
| } | |
| line = &line[j + part.len()..]; | |
| } | |
| None => return false, | |
| } | |
| } | |
| line.is_empty() || expected.ends_with("[..]") | |
| }) | |
| } | |
| fn valid_test(dirname: &str) { | |
| let (status, stdout, stderr) = run(dirname); | |
| if !status.success() { | |
| panic!( | |
| "test did not succeed as expected\n\ | |
| --- stdout:\n\ | |
| {}\n\ | |
| --- stderr:\n\ | |
| {}\n", | |
| stdout, stderr | |
| ); | |
| } | |
| } | |
| #[test] | |
| fn valid() { | |
| valid_test("valid/inner"); | |
| } | |
| #[test] | |
| fn basic_broken() { | |
| broken_test("basic_broken", "foo.html:3: broken link - `bar.html`"); | |
| } | |
| #[test] | |
| fn broken_fragment_local() { | |
| broken_test( | |
| "broken_fragment_local", | |
| "foo.html:3: broken link fragment `#somefrag` pointing to `foo.html`", | |
| ); | |
| } | |
| #[test] | |
| fn broken_fragment_remote() { | |
| broken_test( | |
| "broken_fragment_remote/inner", | |
| "foo.html:3: broken link fragment `#somefrag` pointing to \ | |
| `[..]/broken_fragment_remote/bar.html`", | |
| ); | |
| } | |
| #[test] | |
| fn broken_redir() { | |
| broken_test( | |
| "broken_redir", | |
| "foo.html:3: broken redirect from `redir-bad.html` to `sometarget`", | |
| ); | |
| } | |
| #[test] | |
| fn directory_link() { | |
| broken_test( | |
| "directory_link", | |
| "foo.html:3: directory link to `somedir` (directory links should use index.html instead)", | |
| ); | |
| } | |
| #[test] | |
| fn redirect_loop() { | |
| broken_test( | |
| "redirect_loop", | |
| "foo.html:3: redirect from `redir-bad.html` to `[..]redirect_loop/redir-bad.html` \ | |
| which is also a redirect (not supported)", | |
| ); | |
| } | |
| #[test] | |
| fn broken_intra_doc_link() { | |
| broken_test( | |
| "broken_intra_doc_link", | |
| "foo.html:3: broken intra-doc link - [<code>std::ffi::CString</code>]", | |
| ); | |
| } |