diff --git a/src/tests/cli/basic.rs b/src/tests/cli/basic.rs index 629d938..be22213 100644 --- a/src/tests/cli/basic.rs +++ b/src/tests/cli/basic.rs @@ -10,7 +10,7 @@ mod passing { use assert_cmd::prelude::*; use std::env; use std::io::Write; - use std::process::Command; + use std::process::{Command, Stdio}; use tempfile::NamedTempFile; #[test] @@ -34,473 +34,25 @@ mod passing { } #[test] - fn bad_input_empty_target() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd.arg("").output().unwrap(); - - // STDOUT should be empty - assert_eq!(std::str::from_utf8(&out.stdout).unwrap(), ""); - - // STDERR should contain error description - assert_eq!( - std::str::from_utf8(&out.stderr).unwrap(), - "No target specified\n" - ); - - // The exit code should be 1 - out.assert().code(1); - - Ok(()) - } - - #[test] - fn bad_input_data_url() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd.arg("data:,Hello%2C%20World!").output().unwrap(); - - // STDOUT should contain HTML - assert_eq!(std::str::from_utf8(&out.stdout).unwrap(), ""); - - // STDERR should contain error description - assert_eq!( - std::str::from_utf8(&out.stderr).unwrap(), - "Unsupported data URL media type\n" - ); - - // The exit code should be 1 - out.assert().code(1); - - Ok(()) - } - - #[test] - fn isolate_data_url() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd - .arg("-M") - .arg("-I") - .arg("data:text/html,Hello%2C%20World!") - .output() - .unwrap(); - - // STDOUT should contain isolated HTML - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - "\ - \ - Hello, World!\n" - ); - - // STDERR should be empty - assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); - - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn remove_css_from_data_url() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd - .arg("-M") - .arg("-c") - .arg("data:text/html,Hello") - .output() - .unwrap(); - - // STDOUT should contain HTML with no CSS - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - "\ - \ - \ - Hello\n" - ); - - // STDERR should be empty - assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); - - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn remove_fonts_from_data_url() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd - .arg("-M") - .arg("-F") - .arg("data:text/html,Hi") - .output() - .unwrap(); - - // STDOUT should contain HTML with no web fonts - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - "\ - \ - \ - Hi\n" - ); - - // STDERR should be empty - assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); - - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn remove_frames_from_data_url() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd - .arg("-M") - .arg("-f") - .arg("data:text/html,Hi") - .output() - .unwrap(); - - // STDOUT should contain HTML with no iframes - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - "\ - \ - Hi\n" - ); - - // STDERR should be empty - assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); - - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn remove_images_from_data_url() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd - .arg("-M") - .arg("-i") - .arg("data:text/html,Hi") - .output() - .unwrap(); - - // STDOUT should contain HTML with no images - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - format!( - "\ - \ - \ - \ - \ - \ - Hi\ - \ - \n", - empty_image = empty_image!() - ) - ); - - // STDERR should be empty - assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); - - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn remove_js_from_data_url() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd - .arg("-M") - .arg("-j") - .arg("data:text/html,Hi") - .output() - .unwrap(); - - // STDOUT should contain HTML with no JS - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - "\ - \ - \ - \ - Hi\ - \n" - ); - - // STDERR should be empty - assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); - - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn local_file_target_input() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let cwd_normalized: String = - str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/"); - let out = cmd - .arg("-M") - .arg(if cfg!(windows) { - "src\\tests\\data\\basic\\local-file.html" - } else { - "src/tests/data/basic/local-file.html" - }) - .output() + fn stdin_target_input() -> Result<(), Box> { + let mut echo = Command::new("echo") + .arg("Hello from STDIN") + .stdout(Stdio::piped()) + .spawn() .unwrap(); - let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" }; - - // STDOUT should contain HTML from the local file - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - "\ - \n \ - \n \ - Local HTML file\n \ - \n \ - \n\n\n\n \ - \"\"\n \ - Tricky href\n \ - Remote URL\n \ - \n\n\n\n\ - \n\ - " - ); - - // STDERR should contain list of retrieved file URLs - assert_eq!( - std::str::from_utf8(&out.stderr).unwrap(), - format!( - "\ - {file}{cwd}/src/tests/data/basic/local-file.html\n \ - {file}{cwd}/src/tests/data/basic/local-style.css\n \ - {file}{cwd}/src/tests/data/basic/local-script.js\n\ - ", - file = file_url_protocol, - cwd = cwd_normalized - ) - ); + let echo_out = echo.stdout.take().unwrap(); + echo.wait().unwrap(); - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn local_file_target_input_absolute_target_path() -> Result<(), Box> { - let cwd = env::current_dir().unwrap(); - let cwd_normalized: String = - str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/"); let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd - .arg("-M") - .arg("-jciI") - .arg(if cfg!(windows) { - format!( - "{cwd}\\src\\tests\\data\\basic\\local-file.html", - cwd = cwd.to_str().unwrap() - ) - } else { - format!( - "{cwd}/src/tests/data/basic/local-file.html", - cwd = cwd.to_str().unwrap() - ) - }) - .output() - .unwrap(); - let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" }; + cmd.stdin(echo_out); + let out = cmd.arg("-M").arg("-").output().unwrap(); - // STDOUT should contain HTML from the local file + // STDOUT should contain HTML from STDIN assert_eq!( std::str::from_utf8(&out.stdout).unwrap(), - format!( - "\ - \ - \n \ - \n \ - Local HTML file\n \ - \n \ - \n\n\n\n \ - \"\"\n \ - Tricky href\n \ - Remote URL\n \ - \n\n\n\n\ - \n\ - ", - empty_image = empty_image!() - ) + "Hello from STDIN\n\n" ); - // STDERR should contain only the target file - assert_eq!( - std::str::from_utf8(&out.stderr).unwrap(), - format!( - "{file}{cwd}/src/tests/data/basic/local-file.html\n", - file = file_url_protocol, - cwd = cwd_normalized, - ) - ); - - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn local_file_url_target_input() -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let cwd_normalized: String = - str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/"); - let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" }; - let out = cmd - .arg("-M") - .arg("-cji") - .arg(if cfg!(windows) { - format!( - "{file}{cwd}/src/tests/data/basic/local-file.html", - file = file_url_protocol, - cwd = cwd_normalized, - ) - } else { - format!( - "{file}{cwd}/src/tests/data/basic/local-file.html", - file = file_url_protocol, - cwd = cwd_normalized, - ) - }) - .output() - .unwrap(); - - // STDOUT should contain HTML from the local file - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - format!( - "\ - \ - \n \ - \n \ - Local HTML file\n \ - \n \ - \n\n\n\n \ - \"\"\n \ - Tricky href\n \ - Remote URL\n \ - \n\n\n\n\ - \n\ - ", - empty_image = empty_image!() - ) - ); - - // STDERR should contain list of retrieved file URLs - assert_eq!( - std::str::from_utf8(&out.stderr).unwrap(), - if cfg!(windows) { - format!( - "{file}{cwd}/src/tests/data/basic/local-file.html\n", - file = file_url_protocol, - cwd = cwd_normalized, - ) - } else { - format!( - "{file}{cwd}/src/tests/data/basic/local-file.html\n", - file = file_url_protocol, - cwd = cwd_normalized, - ) - } - ); - - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn security_disallow_local_assets_within_data_url_targets( - ) -> Result<(), Box> { - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let out = cmd - .arg("-M") - .arg("data:text/html,%3Cscript%20src=\"src/tests/data/basic/local-script.js\"%3E%3C/script%3E") - .output() - .unwrap(); - - // STDOUT should contain HTML with no JS in it - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - "\n" - ); - - // STDERR should be empty - assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); - - // The exit code should be 0 - out.assert().code(0); - - Ok(()) - } - - #[test] - fn embed_file_url_local_asset_within_style_attribute() -> Result<(), Box> - { - let file_url_prefix: &str = if cfg!(windows) { "file:///" } else { "file://" }; - let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; - let mut file_svg = NamedTempFile::new()?; - writeln!(file_svg, "\ - \ - \ - SVG\ - \n")?; - let mut file_html = NamedTempFile::new()?; - writeln!( - file_html, - "
\n", - file = file_url_prefix, - path = str!(file_svg.path().to_str().unwrap()).replace("\\", "/"), - )?; - let out = cmd.arg("-M").arg(file_html.path()).output().unwrap(); - - // STDOUT should contain HTML with date URL for background-image in it - assert_eq!( - std::str::from_utf8(&out.stdout).unwrap(), - "
\ + Hello, World!\n" + ); + + // STDERR should be empty + assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } + + #[test] + fn remove_css_from_data_url() -> Result<(), Box> { + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let out = cmd + .arg("-M") + .arg("-c") + .arg("data:text/html,Hello") + .output() + .unwrap(); + + // STDOUT should contain HTML with no CSS + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + "\ + \ + \ + Hello\n" + ); + + // STDERR should be empty + assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } + + #[test] + fn remove_fonts_from_data_url() -> Result<(), Box> { + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let out = cmd + .arg("-M") + .arg("-F") + .arg("data:text/html,Hi") + .output() + .unwrap(); + + // STDOUT should contain HTML with no web fonts + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + "\ + \ + \ + Hi\n" + ); + + // STDERR should be empty + assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } + + #[test] + fn remove_frames_from_data_url() -> Result<(), Box> { + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let out = cmd + .arg("-M") + .arg("-f") + .arg("data:text/html,Hi") + .output() + .unwrap(); + + // STDOUT should contain HTML with no iframes + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + "\ + \ + Hi\n" + ); + + // STDERR should be empty + assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } + + #[test] + fn remove_images_from_data_url() -> Result<(), Box> { + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let out = cmd + .arg("-M") + .arg("-i") + .arg("data:text/html,Hi") + .output() + .unwrap(); + + // STDOUT should contain HTML with no images + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + format!( + "\ + \ + \ + \ + \ + \ + Hi\ + \ + \n", + empty_image = empty_image!() + ) + ); + + // STDERR should be empty + assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } + + #[test] + fn remove_js_from_data_url() -> Result<(), Box> { + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let out = cmd + .arg("-M") + .arg("-j") + .arg("data:text/html,Hi") + .output() + .unwrap(); + + // STDOUT should contain HTML with no JS + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + "\ + \ + \ + \ + Hi\ + \n" + ); + + // STDERR should be empty + assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } + + #[test] + fn security_disallow_local_assets_within_data_url_targets( + ) -> Result<(), Box> { + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let out = cmd + .arg("-M") + .arg("data:text/html,%3Cscript%20src=\"src/tests/data/basic/local-script.js\"%3E%3C/script%3E") + .output() + .unwrap(); + + // STDOUT should contain HTML with no JS in it + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + "\n" + ); + + // STDERR should be empty + assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } +} diff --git a/src/tests/cli/local_files.rs b/src/tests/cli/local_files.rs new file mode 100644 index 0000000..86cf09c --- /dev/null +++ b/src/tests/cli/local_files.rs @@ -0,0 +1,245 @@ +// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ +// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ +// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ +// ██╔═══╝ ██╔══██║╚════██║╚════██║██║██║╚██╗██║██║ ██║ +// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ +// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ + +#[cfg(test)] +mod passing { + use assert_cmd::prelude::*; + use std::env; + use std::io::Write; + use std::process::Command; + use tempfile::NamedTempFile; + + #[test] + fn local_file_target_input() -> Result<(), Box> { + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let cwd_normalized: String = + str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/"); + let out = cmd + .arg("-M") + .arg(if cfg!(windows) { + "src\\tests\\data\\basic\\local-file.html" + } else { + "src/tests/data/basic/local-file.html" + }) + .output() + .unwrap(); + let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" }; + + // STDOUT should contain HTML from the local file + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + "\ + \n \ + \n \ + Local HTML file\n \ + \n \ + \n\n\n\n \ + \"\"\n \ + Tricky href\n \ + Remote URL\n \ + \n\n\n\n\ + \n\ + " + ); + + // STDERR should contain list of retrieved file URLs + assert_eq!( + std::str::from_utf8(&out.stderr).unwrap(), + format!( + "\ + {file}{cwd}/src/tests/data/basic/local-file.html\n \ + {file}{cwd}/src/tests/data/basic/local-style.css\n \ + {file}{cwd}/src/tests/data/basic/local-script.js\n\ + ", + file = file_url_protocol, + cwd = cwd_normalized + ) + ); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } + + #[test] + fn local_file_target_input_absolute_target_path() -> Result<(), Box> { + let cwd = env::current_dir().unwrap(); + let cwd_normalized: String = + str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/"); + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let out = cmd + .arg("-M") + .arg("-jciI") + .arg(if cfg!(windows) { + format!( + "{cwd}\\src\\tests\\data\\basic\\local-file.html", + cwd = cwd.to_str().unwrap() + ) + } else { + format!( + "{cwd}/src/tests/data/basic/local-file.html", + cwd = cwd.to_str().unwrap() + ) + }) + .output() + .unwrap(); + let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" }; + + // STDOUT should contain HTML from the local file + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + format!( + "\ + \ + \n \ + \n \ + Local HTML file\n \ + \n \ + \n\n\n\n \ + \"\"\n \ + Tricky href\n \ + Remote URL\n \ + \n\n\n\n\ + \n\ + ", + empty_image = empty_image!() + ) + ); + + // STDERR should contain only the target file + assert_eq!( + std::str::from_utf8(&out.stderr).unwrap(), + format!( + "{file}{cwd}/src/tests/data/basic/local-file.html\n", + file = file_url_protocol, + cwd = cwd_normalized, + ) + ); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } + + #[test] + fn local_file_url_target_input() -> Result<(), Box> { + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let cwd_normalized: String = + str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/"); + let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" }; + let out = cmd + .arg("-M") + .arg("-cji") + .arg(if cfg!(windows) { + format!( + "{file}{cwd}/src/tests/data/basic/local-file.html", + file = file_url_protocol, + cwd = cwd_normalized, + ) + } else { + format!( + "{file}{cwd}/src/tests/data/basic/local-file.html", + file = file_url_protocol, + cwd = cwd_normalized, + ) + }) + .output() + .unwrap(); + + // STDOUT should contain HTML from the local file + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + format!( + "\ + \ + \n \ + \n \ + Local HTML file\n \ + \n \ + \n\n\n\n \ + \"\"\n \ + Tricky href\n \ + Remote URL\n \ + \n\n\n\n\ + \n\ + ", + empty_image = empty_image!() + ) + ); + + // STDERR should contain list of retrieved file URLs + assert_eq!( + std::str::from_utf8(&out.stderr).unwrap(), + if cfg!(windows) { + format!( + "{file}{cwd}/src/tests/data/basic/local-file.html\n", + file = file_url_protocol, + cwd = cwd_normalized, + ) + } else { + format!( + "{file}{cwd}/src/tests/data/basic/local-file.html\n", + file = file_url_protocol, + cwd = cwd_normalized, + ) + } + ); + + // The exit code should be 0 + out.assert().code(0); + + Ok(()) + } + + #[test] + fn embed_file_url_local_asset_within_style_attribute() -> Result<(), Box> + { + let file_url_prefix: &str = if cfg!(windows) { "file:///" } else { "file://" }; + let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; + let mut file_svg = NamedTempFile::new()?; + writeln!(file_svg, "\ + \ + \ + SVG\ + \n")?; + let mut file_html = NamedTempFile::new()?; + writeln!( + file_html, + "
\n", + file = file_url_prefix, + path = str!(file_svg.path().to_str().unwrap()).replace("\\", "/"), + )?; + let out = cmd.arg("-M").arg(file_html.path()).output().unwrap(); + + // STDOUT should contain HTML with date URL for background-image in it + assert_eq!( + std::str::from_utf8(&out.stdout).unwrap(), + "