group all tests into either passing or failing groups

This commit is contained in:
Sunshine 2020-05-23 03:49:04 -04:00
parent 3d678d80ee
commit 090d647390
No known key found for this signature in database
GPG key ID: B80CA68703CD8AB1
20 changed files with 2256 additions and 2143 deletions

View file

@ -1,9 +1,3 @@
use assert_cmd::prelude::*;
use std::env;
use std::io::Write;
use std::process::Command;
use tempfile::NamedTempFile;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -11,519 +5,527 @@ use tempfile::NamedTempFile;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_print_version() -> Result<(), Box<dyn std::error::Error>> { mod passing {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; use assert_cmd::prelude::*;
let out = cmd.arg("-V").output().unwrap(); use std::env;
use std::io::Write;
use std::process::Command;
use tempfile::NamedTempFile;
// STDOUT should contain program name and version #[test]
assert_eq!( fn print_version() -> Result<(), Box<dyn std::error::Error>> {
std::str::from_utf8(&out.stdout).unwrap(), let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
format!("{} {}\n", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")) let out = cmd.arg("-V").output().unwrap();
);
// STDERR should be empty // STDOUT should contain program name and version
assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
format!("{} {}\n", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"))
);
// The exit code should be 0 // STDERR should be empty
out.assert().code(0); assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), "");
Ok(()) // The exit code should be 0
} out.assert().code(0);
#[test] Ok(())
fn passing_bad_input_empty_target() -> Result<(), Box<dyn std::error::Error>> { }
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let out = cmd.arg("").output().unwrap();
// STDOUT should be empty #[test]
assert_eq!(std::str::from_utf8(&out.stdout).unwrap(), ""); fn bad_input_empty_target() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let out = cmd.arg("").output().unwrap();
// STDERR should contain error description // STDOUT should be empty
assert_eq!( assert_eq!(std::str::from_utf8(&out.stdout).unwrap(), "");
std::str::from_utf8(&out.stderr).unwrap(),
"No target specified\n"
);
// The exit code should be 1 // STDERR should contain error description
out.assert().code(1); assert_eq!(
std::str::from_utf8(&out.stderr).unwrap(),
"No target specified\n"
);
Ok(()) // The exit code should be 1
} out.assert().code(1);
#[test] Ok(())
fn passing_bad_input_data_url() -> Result<(), Box<dyn std::error::Error>> { }
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let out = cmd.arg("data:,Hello%2C%20World!").output().unwrap();
// STDOUT should contain HTML #[test]
assert_eq!(std::str::from_utf8(&out.stdout).unwrap(), ""); fn bad_input_data_url() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let out = cmd.arg("data:,Hello%2C%20World!").output().unwrap();
// STDERR should contain error description // STDOUT should contain HTML
assert_eq!( assert_eq!(std::str::from_utf8(&out.stdout).unwrap(), "");
std::str::from_utf8(&out.stderr).unwrap(),
"Unsupported data URL media type\n"
);
// The exit code should be 1 // STDERR should contain error description
out.assert().code(1); assert_eq!(
std::str::from_utf8(&out.stderr).unwrap(),
"Unsupported data URL media type\n"
);
Ok(()) // The exit code should be 1
} out.assert().code(1);
#[test] Ok(())
fn passing_isolate_data_url() -> Result<(), Box<dyn std::error::Error>> { }
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 #[test]
assert_eq!( fn isolate_data_url() -> Result<(), Box<dyn std::error::Error>> {
std::str::from_utf8(&out.stdout).unwrap(), let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
"<html><head>\ let out = cmd
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:;\"></meta>\ .arg("-M")
</head><body>Hello, World!</body></html>\n" .arg("-I")
); .arg("data:text/html,Hello%2C%20World!")
.output()
.unwrap();
// STDERR should be empty // STDOUT should contain isolated HTML
assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
"<html><head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:;\"></meta>\
</head><body>Hello, World!</body></html>\n"
);
// The exit code should be 0 // STDERR should be empty
out.assert().code(0); assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), "");
Ok(()) // The exit code should be 0
} out.assert().code(0);
#[test] Ok(())
fn passing_remove_css_from_data_url() -> Result<(), Box<dyn std::error::Error>> { }
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let out = cmd
.arg("-M")
.arg("-c")
.arg("data:text/html,<style>body{background-color:pink}</style>Hello")
.output()
.unwrap();
// STDOUT should contain HTML with no CSS #[test]
assert_eq!( fn remove_css_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
std::str::from_utf8(&out.stdout).unwrap(), let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
"<html><head>\ let out = cmd
<meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none';\"></meta>\ .arg("-M")
<style></style>\ .arg("-c")
</head><body>Hello</body></html>\n" .arg("data:text/html,<style>body{background-color:pink}</style>Hello")
); .output()
.unwrap();
// STDERR should be empty // STDOUT should contain HTML with no CSS
assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
"<html><head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none';\"></meta>\
<style></style>\
</head><body>Hello</body></html>\n"
);
// The exit code should be 0 // STDERR should be empty
out.assert().code(0); assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), "");
Ok(()) // The exit code should be 0
} out.assert().code(0);
#[test] Ok(())
fn passing_remove_frames_from_data_url() -> Result<(), Box<dyn std::error::Error>> { }
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let out = cmd
.arg("-M")
.arg("-f")
.arg("data:text/html,<iframe src=\"https://google.com\"></iframe>Hi")
.output()
.unwrap();
// STDOUT should contain HTML with no iframes #[test]
assert_eq!( fn remove_frames_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
std::str::from_utf8(&out.stdout).unwrap(), let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
"<html><head>\ let out = cmd
<meta http-equiv=\"Content-Security-Policy\" content=\"frame-src 'none';child-src 'none';\"></meta>\ .arg("-M")
</head><body><iframe src=\"\"></iframe>Hi</body></html>\n" .arg("-f")
); .arg("data:text/html,<iframe src=\"https://google.com\"></iframe>Hi")
.output()
.unwrap();
// STDERR should be empty // STDOUT should contain HTML with no iframes
assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
"<html><head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"frame-src 'none';child-src 'none';\"></meta>\
</head><body><iframe src=\"\"></iframe>Hi</body></html>\n"
);
// The exit code should be 0 // STDERR should be empty
out.assert().code(0); assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), "");
Ok(()) // The exit code should be 0
} out.assert().code(0);
#[test] Ok(())
fn passing_remove_images_from_data_url() -> Result<(), Box<dyn std::error::Error>> { }
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let out = cmd
.arg("-M")
.arg("-i")
.arg("data:text/html,<img src=\"https://google.com\"/>Hi")
.output()
.unwrap();
// STDOUT should contain HTML with no images #[test]
assert_eq!( fn remove_images_from_data_url() -> Result<(), Box<dyn std::error::Error>> {
std::str::from_utf8(&out.stdout).unwrap(), let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
format!( let out = cmd
.arg("-M")
.arg("-i")
.arg("data:text/html,<img src=\"https://google.com\"/>Hi")
.output()
.unwrap();
// STDOUT should contain HTML with no images
assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
format!(
"<html>\
<head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"img-src data:;\"></meta>\
</head>\
<body>\
<img src=\"{empty_image}\">\
Hi\
</body>\
</html>\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<dyn std::error::Error>> {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let out = cmd
.arg("-M")
.arg("-j")
.arg("data:text/html,<script>alert(2)</script>Hi")
.output()
.unwrap();
// STDOUT should contain HTML with no JS
assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
"<html>\ "<html>\
<head>\ <head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"img-src data:;\"></meta>\ <meta http-equiv=\"Content-Security-Policy\" content=\"script-src 'none';\"></meta>\
</head>\ <script></script></head>\
<body>\ <body>Hi</body>\
<img src=\"{empty_image}\">\ </html>\n"
Hi\ );
</body>\
</html>\n",
empty_image = empty_image!()
)
);
// STDERR should be empty // STDERR should be empty
assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), "");
// The exit code should be 0 // The exit code should be 0
out.assert().code(0); out.assert().code(0);
Ok(()) Ok(())
} }
#[test] #[test]
fn passing_remove_js_from_data_url() -> Result<(), Box<dyn std::error::Error>> { fn local_file_target_input() -> Result<(), Box<dyn std::error::Error>> {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?; let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let out = cmd let cwd_normalized: String =
.arg("-M") str!(env::current_dir().unwrap().to_str().unwrap()).replace("\\", "/");
.arg("-j") let out = cmd
.arg("data:text/html,<script>alert(2)</script>Hi") .arg("-M")
.output() .arg(if cfg!(windows) {
.unwrap(); "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 with no JS // STDOUT should contain HTML from the local file
assert_eq!( assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(), std::str::from_utf8(&out.stdout).unwrap(),
"<html>\
<head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"script-src 'none';\"></meta>\
<script></script></head>\
<body>Hi</body>\
</html>\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 passing_local_file_target_input() -> Result<(), Box<dyn std::error::Error>> {
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(),
"\
<!DOCTYPE html><html lang=\"en\"><head>\n \
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
<title>Local HTML file</title>\n \
<link rel=\"stylesheet\" type=\"text/css\" href=\"data:text/css;base64,Ym9keSB7CiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwOwogICAgY29sb3I6ICNmZmY7Cn0K\">\n \
<link rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
<img alt=\"\">\n \
<a href=\"file://local-file.html/\">Tricky href</a>\n \
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
<script src=\"data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==\"></script>\n\n\n\n\
</body></html>\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\ <!DOCTYPE html><html lang=\"en\"><head>\n \
{file}{cwd}/src/tests/data/basic/local-style.css\n\ <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
{file}{cwd}/src/tests/data/basic/local-script.js\n\ <title>Local HTML file</title>\n \
", <link rel=\"stylesheet\" type=\"text/css\" href=\"data:text/css;base64,Ym9keSB7CiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjMDAwOwogICAgY29sb3I6ICNmZmY7Cn0K\">\n \
file = file_url_protocol, <link rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
cwd = cwd_normalized <img alt=\"\">\n \
) <a href=\"file://local-file.html/\">Tricky href</a>\n \
); <a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
<script src=\"data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==\"></script>\n\n\n\n\
</body></html>\n\
"
);
// The exit code should be 0 // STDERR should contain list of retrieved file URLs
out.assert().code(0); assert_eq!(
std::str::from_utf8(&out.stderr).unwrap(),
Ok(())
}
#[test]
fn passing_local_file_target_input_absolute_target_path() -> Result<(), Box<dyn std::error::Error>>
{
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!( format!(
"{cwd}\\src\\tests\\data\\basic\\local-file.html", "\
cwd = cwd.to_str().unwrap() {file}{cwd}/src/tests/data/basic/local-file.html\n\
) {file}{cwd}/src/tests/data/basic/local-style.css\n\
} else { {file}{cwd}/src/tests/data/basic/local-script.js\n\
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!(
"\
<!DOCTYPE html><html lang=\"en\"><head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:; style-src 'none'; script-src 'none'; img-src data:;\"></meta>\n \
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
<title>Local HTML file</title>\n \
<link rel=\"stylesheet\" type=\"text/css\">\n \
<link rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
<img alt=\"\" src=\"{empty_image}\">\n \
<a href=\"file://local-file.html/\">Tricky href</a>\n \
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
<script></script>\n\n\n\n\
</body></html>\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 passing_local_file_url_target_input() -> Result<(), Box<dyn std::error::Error>> {
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, file = file_url_protocol,
cwd = cwd_normalized, cwd = cwd_normalized
) )
} else { );
// The exit code should be 0
out.assert().code(0);
Ok(())
}
#[test]
fn local_file_target_input_absolute_target_path() -> Result<(), Box<dyn std::error::Error>> {
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!( format!(
"{file}{cwd}/src/tests/data/basic/local-file.html", "\
file = file_url_protocol, <!DOCTYPE html><html lang=\"en\"><head>\
cwd = cwd_normalized, <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:; style-src 'none'; script-src 'none'; img-src data:;\"></meta>\n \
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
<title>Local HTML file</title>\n \
<link rel=\"stylesheet\" type=\"text/css\">\n \
<link rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
<img alt=\"\" src=\"{empty_image}\">\n \
<a href=\"file://local-file.html/\">Tricky href</a>\n \
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
<script></script>\n\n\n\n\
</body></html>\n\
",
empty_image = empty_image!()
) )
}) );
.output()
.unwrap();
// STDOUT should contain HTML from the local file // STDERR should contain only the target file
assert_eq!( assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(), std::str::from_utf8(&out.stderr).unwrap(),
format!(
"\
<!DOCTYPE html><html lang=\"en\"><head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none'; script-src 'none'; img-src data:;\"></meta>\n \
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
<title>Local HTML file</title>\n \
<link rel=\"stylesheet\" type=\"text/css\">\n \
<link rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
<img alt=\"\" src=\"{empty_image}\">\n \
<a href=\"file://local-file.html/\">Tricky href</a>\n \
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
<script></script>\n\n\n\n\
</body></html>\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!( format!(
"{file}{cwd}/src/tests/data/basic/local-file.html\n", "{file}{cwd}/src/tests/data/basic/local-file.html\n",
file = file_url_protocol, file = file_url_protocol,
cwd = cwd_normalized, cwd = cwd_normalized,
) )
} else { );
// The exit code should be 0
out.assert().code(0);
Ok(())
}
#[test]
fn local_file_url_target_input() -> Result<(), Box<dyn std::error::Error>> {
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!( format!(
"{file}{cwd}/src/tests/data/basic/local-file.html\n", "\
file = file_url_protocol, <!DOCTYPE html><html lang=\"en\"><head>\
cwd = cwd_normalized, <meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none'; script-src 'none'; img-src data:;\"></meta>\n \
<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n \
<title>Local HTML file</title>\n \
<link rel=\"stylesheet\" type=\"text/css\">\n \
<link rel=\"stylesheet\" type=\"text/css\">\n</head>\n\n<body>\n \
<img alt=\"\" src=\"{empty_image}\">\n \
<a href=\"file://local-file.html/\">Tricky href</a>\n \
<a href=\"https://github.com/Y2Z/monolith\">Remote URL</a>\n \
<script></script>\n\n\n\n\
</body></html>\n\
",
empty_image = empty_image!()
) )
} );
);
// The exit code should be 0 // STDERR should contain list of retrieved file URLs
out.assert().code(0); 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,
)
}
);
Ok(()) // The exit code should be 0
} out.assert().code(0);
#[test] Ok(())
fn passing_security_disallow_local_assets_within_data_url_targets( }
) -> Result<(), Box<dyn std::error::Error>> {
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 #[test]
assert_eq!( fn security_disallow_local_assets_within_data_url_targets(
std::str::from_utf8(&out.stdout).unwrap(), ) -> Result<(), Box<dyn std::error::Error>> {
"<html><head><script></script></head><body></body></html>\n" 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();
// STDERR should be empty // STDOUT should contain HTML with no JS in it
assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), ""); assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
"<html><head><script></script></head><body></body></html>\n"
);
// The exit code should be 0 // STDERR should be empty
out.assert().code(0); assert_eq!(std::str::from_utf8(&out.stderr).unwrap(), "");
Ok(()) // The exit code should be 0
} out.assert().code(0);
#[test] Ok(())
fn passing_embed_file_url_local_asset_within_style_attribute( }
) -> Result<(), Box<dyn std::error::Error>> {
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 version=\"1.1\" baseProfile=\"full\" width=\"300\" height=\"200\" xmlns=\"http://www.w3.org/2000/svg\">\
<rect width=\"100%\" height=\"100%\" fill=\"red\" />\
<circle cx=\"150\" cy=\"100\" r=\"80\" fill=\"green\" />\
<text x=\"150\" y=\"125\" font-size=\"60\" text-anchor=\"middle\" fill=\"white\">SVG</text>\
</svg>\n")?;
let mut file_html = NamedTempFile::new()?;
writeln!(
file_html,
"<div style='background-image: url(\"{file}{path}\")'></div>\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 #[test]
assert_eq!( fn embed_file_url_local_asset_within_style_attribute() -> Result<(), Box<dyn std::error::Error>>
std::str::from_utf8(&out.stdout).unwrap(), {
"<html><head></head><body><div style=\"background-image: url('data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJyZWQiIC8+PGNpcmNsZSBjeD0iMTUwIiBjeT0iMTAwIiByPSI4MCIgZmlsbD0iZ3JlZW4iIC8+PHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+PC9zdmc+Cgo=')\"></div>\n\n</body></html>\n" 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()?;
// STDERR should list temporary files that got retrieved writeln!(file_svg, "<svg version=\"1.1\" baseProfile=\"full\" width=\"300\" height=\"200\" xmlns=\"http://www.w3.org/2000/svg\">\
assert_eq!( <rect width=\"100%\" height=\"100%\" fill=\"red\" />\
std::str::from_utf8(&out.stderr).unwrap(), <circle cx=\"150\" cy=\"100\" r=\"80\" fill=\"green\" />\
format!( <text x=\"150\" y=\"125\" font-size=\"60\" text-anchor=\"middle\" fill=\"white\">SVG</text>\
"\ </svg>\n")?;
{file}{html_path}\n\ let mut file_html = NamedTempFile::new()?;
{file}{svg_path}\n\ writeln!(
", file_html,
"<div style='background-image: url(\"{file}{path}\")'></div>\n",
file = file_url_prefix, file = file_url_prefix,
html_path = str!(file_html.path().to_str().unwrap()).replace("\\", "/"), path = str!(file_svg.path().to_str().unwrap()).replace("\\", "/"),
svg_path = str!(file_svg.path().to_str().unwrap()).replace("\\", "/"), )?;
) let out = cmd.arg("-M").arg(file_html.path()).output().unwrap();
);
// The exit code should be 0 // STDOUT should contain HTML with date URL for background-image in it
out.assert().code(0); assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
"<html><head></head><body><div style=\"background-image: url('data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB3aWR0aD0iMzAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSJyZWQiIC8+PGNpcmNsZSBjeD0iMTUwIiBjeT0iMTAwIiByPSI4MCIgZmlsbD0iZ3JlZW4iIC8+PHRleHQgeD0iMTUwIiB5PSIxMjUiIGZvbnQtc2l6ZT0iNjAiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IndoaXRlIj5TVkc8L3RleHQ+PC9zdmc+Cgo=')\"></div>\n\n</body></html>\n"
);
Ok(()) // STDERR should list temporary files that got retrieved
} assert_eq!(
std::str::from_utf8(&out.stderr).unwrap(),
format!(
"\
{file}{html_path}\n\
{file}{svg_path}\n\
",
file = file_url_prefix,
html_path = str!(file_html.path().to_str().unwrap()).replace("\\", "/"),
svg_path = str!(file_svg.path().to_str().unwrap()).replace("\\", "/"),
)
);
#[test] // The exit code should be 0
fn passing_css_import_string() -> Result<(), Box<dyn std::error::Error>> { out.assert().code(0);
let file_url_prefix: &str = if cfg!(windows) { "file:///" } else { "file://" };
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let mut file_css = NamedTempFile::new()?;
writeln!(file_css, "body{{background-color:#000;color:#fff}}")?;
let mut file_html = NamedTempFile::new()?;
writeln!(
file_html,
"\
<style>\n\
@charset 'UTF-8';\n\
\n\
@import '{file}{css_path}';\n\
\n\
@import url({file}{css_path});\n\
\n\
@import url('{file}{css_path}')\n\
</style>\n\
",
file = file_url_prefix,
css_path = str!(file_css.path().to_str().unwrap()).replace("\\", "/"),
)?;
let out = cmd.arg("-M").arg(file_html.path()).output().unwrap();
// STDOUT should contain embedded CSS url()'s Ok(())
assert_eq!( }
std::str::from_utf8(&out.stdout).unwrap(),
"<html><head><style>\n@charset 'UTF-8';\n\n@import 'data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K';\n\n@import url('data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K');\n\n@import url('data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K')\n</style>\n\n</head><body></body></html>\n"
);
// STDERR should list temporary files that got retrieved #[test]
assert_eq!( fn css_import_string() -> Result<(), Box<dyn std::error::Error>> {
std::str::from_utf8(&out.stderr).unwrap(), let file_url_prefix: &str = if cfg!(windows) { "file:///" } else { "file://" };
format!( let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME"))?;
let mut file_css = NamedTempFile::new()?;
writeln!(file_css, "body{{background-color:#000;color:#fff}}")?;
let mut file_html = NamedTempFile::new()?;
writeln!(
file_html,
"\ "\
{file}{html_path}\n\ <style>\n\
{file}{css_path}\n\ @charset 'UTF-8';\n\
{file}{css_path}\n\ \n\
{file}{css_path}\n\ @import '{file}{css_path}';\n\
", \n\
@import url({file}{css_path});\n\
\n\
@import url('{file}{css_path}')\n\
</style>\n\
",
file = file_url_prefix, file = file_url_prefix,
html_path = str!(file_html.path().to_str().unwrap()).replace("\\", "/"),
css_path = str!(file_css.path().to_str().unwrap()).replace("\\", "/"), css_path = str!(file_css.path().to_str().unwrap()).replace("\\", "/"),
) )?;
); let out = cmd.arg("-M").arg(file_html.path()).output().unwrap();
// The exit code should be 0 // STDOUT should contain embedded CSS url()'s
out.assert().code(0); assert_eq!(
std::str::from_utf8(&out.stdout).unwrap(),
"<html><head><style>\n@charset 'UTF-8';\n\n@import 'data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K';\n\n@import url('data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K');\n\n@import url('data:text/css;base64,Ym9keXtiYWNrZ3JvdW5kLWNvbG9yOiMwMDA7Y29sb3I6I2ZmZn0K')\n</style>\n\n</head><body></body></html>\n"
);
Ok(()) // STDERR should list temporary files that got retrieved
assert_eq!(
std::str::from_utf8(&out.stderr).unwrap(),
format!(
"\
{file}{html_path}\n\
{file}{css_path}\n\
{file}{css_path}\n\
{file}{css_path}\n\
",
file = file_url_prefix,
html_path = str!(file_html.path().to_str().unwrap()).replace("\\", "/"),
css_path = str!(file_css.path().to_str().unwrap()).replace("\\", "/"),
)
);
// The exit code should be 0
out.assert().code(0);
Ok(())
}
} }

View file

@ -1,8 +1,3 @@
use reqwest::blocking::Client;
use std::collections::HashMap;
use crate::css;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -10,308 +5,315 @@ use crate::css;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_empty_input() { mod passing {
let cache = &mut HashMap::new(); use crate::css;
let client = Client::new(); use reqwest::blocking::Client;
use std::collections::HashMap;
assert_eq!( #[test]
css::embed_css(cache, &client, "", "", false, false, false,), fn empty_input() {
"" let cache = &mut HashMap::new();
); let client = Client::new();
}
assert_eq!(
#[test] css::embed_css(cache, &client, "", "", false, false, false,),
fn passing_style_exclude_unquoted_images() { ""
let cache = &mut HashMap::new(); );
let client = Client::new(); }
const STYLE: &str = "/* border: none;*/\ #[test]
background-image: url(https://somewhere.com/bg.png); \ fn style_exclude_unquoted_images() {
list-style: url(/assets/images/bullet.svg);\ let cache = &mut HashMap::new();
width:99.998%; \ let client = Client::new();
margin-top: -20px; \
line-height: -1; \ const STYLE: &str = "/* border: none;*/\
height: calc(100vh - 10pt)"; background-image: url(https://somewhere.com/bg.png); \
list-style: url(/assets/images/bullet.svg);\
assert_eq!( width:99.998%; \
css::embed_css( margin-top: -20px; \
cache, line-height: -1; \
&client, height: calc(100vh - 10pt)";
"https://doesntmatter.local/",
&STYLE, assert_eq!(
false, css::embed_css(
true, cache,
true, &client,
), "https://doesntmatter.local/",
format!( &STYLE,
"/* border: none;*/\ false,
background-image: url('{empty_image}'); \ true,
list-style: url('{empty_image}');\ true,
width:99.998%; \ ),
margin-top: -20px; \ format!(
line-height: -1; \ "/* border: none;*/\
height: calc(100vh - 10pt)", background-image: url('{empty_image}'); \
empty_image = empty_image!() list-style: url('{empty_image}');\
) width:99.998%; \
); margin-top: -20px; \
} line-height: -1; \
height: calc(100vh - 10pt)",
#[test] empty_image = empty_image!()
fn passing_style_exclude_single_quoted_images() { )
let cache = &mut HashMap::new(); );
let client = Client::new(); }
const STYLE: &str = "/* border: none;*/\ #[test]
background-image: url('https://somewhere.com/bg.png'); \ fn style_exclude_single_quoted_images() {
list-style: url('/assets/images/bullet.svg');\ let cache = &mut HashMap::new();
width:99.998%; \ let client = Client::new();
margin-top: -20px; \
line-height: -1; \ const STYLE: &str = "/* border: none;*/\
height: calc(100vh - 10pt)"; background-image: url('https://somewhere.com/bg.png'); \
list-style: url('/assets/images/bullet.svg');\
assert_eq!( width:99.998%; \
css::embed_css(cache, &client, "", &STYLE, false, true, true,), margin-top: -20px; \
format!( line-height: -1; \
"/* border: none;*/\ height: calc(100vh - 10pt)";
background-image: url('{empty_image}'); \
list-style: url('{empty_image}');\ assert_eq!(
width:99.998%; \ css::embed_css(cache, &client, "", &STYLE, false, true, true,),
margin-top: -20px; \ format!(
line-height: -1; \ "/* border: none;*/\
height: calc(100vh - 10pt)", background-image: url('{empty_image}'); \
empty_image = empty_image!() list-style: url('{empty_image}');\
) width:99.998%; \
); margin-top: -20px; \
} line-height: -1; \
height: calc(100vh - 10pt)",
#[test] empty_image = empty_image!()
fn passing_style_block() { )
let cache = &mut HashMap::new(); );
let client = Client::new(); }
const CSS: &str = "\ #[test]
#id.class-name:not(:nth-child(3n+0)) {\n \ fn style_block() {
// border: none;\n \ let cache = &mut HashMap::new();
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=');\n\ let client = Client::new();
}\n\
\n\ const CSS: &str = "\
html > body {}"; #id.class-name:not(:nth-child(3n+0)) {\n \
// border: none;\n \
assert_eq!( background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=');\n\
css::embed_css(cache, &client, "file:///", &CSS, false, false, true,), }\n\
CSS \n\
); html > body {}";
}
assert_eq!(
#[test] css::embed_css(cache, &client, "file:///", &CSS, false, false, true,),
fn passing_attribute_selectors() { CSS
let cache = &mut HashMap::new(); );
let client = Client::new(); }
const CSS: &str = "\ #[test]
[data-value] { fn attribute_selectors() {
/* Attribute exists */ let cache = &mut HashMap::new();
} let client = Client::new();
[data-value='foo'] { const CSS: &str = "\
/* Attribute has this exact value */ [data-value] {
} /* Attribute exists */
}
[data-value*='foo'] {
/* Attribute value contains this value somewhere in it */ [data-value='foo'] {
} /* Attribute has this exact value */
}
[data-value~='foo'] {
/* Attribute has this value in a space-separated list somewhere */ [data-value*='foo'] {
} /* Attribute value contains this value somewhere in it */
}
[data-value^='foo'] {
/* Attribute value starts with this */ [data-value~='foo'] {
} /* Attribute has this value in a space-separated list somewhere */
}
[data-value|='foo'] {
/* Attribute value starts with this in a dash-separated list */ [data-value^='foo'] {
} /* Attribute value starts with this */
}
[data-value$='foo'] {
/* Attribute value ends with this */ [data-value|='foo'] {
} /* Attribute value starts with this in a dash-separated list */
"; }
assert_eq!( [data-value$='foo'] {
css::embed_css(cache, &client, "", &CSS, false, false, false,), /* Attribute value ends with this */
CSS }
); ";
}
assert_eq!(
#[test] css::embed_css(cache, &client, "", &CSS, false, false, false,),
fn passing_import_string() { CSS
let cache = &mut HashMap::new(); );
let client = Client::new(); }
const CSS: &str = "\ #[test]
@charset 'UTF-8';\n\ fn import_string() {
\n\ let cache = &mut HashMap::new();
@import 'data:text/css,html{background-color:%23000}';\n\ let client = Client::new();
\n\
@import url('data:text/css,html{color:%23fff}')\n\ const CSS: &str = "\
"; @charset 'UTF-8';\n\
\n\
assert_eq!( @import 'data:text/css,html{background-color:%23000}';\n\
css::embed_css( \n\
cache, @import url('data:text/css,html{color:%23fff}')\n\
&client, ";
"https://doesntmatter.local/",
&CSS, assert_eq!(
false, css::embed_css(
false, cache,
true, &client,
), "https://doesntmatter.local/",
"\ &CSS,
@charset 'UTF-8';\n\ false,
\n\ false,
@import 'data:text/css;base64,aHRtbHtiYWNrZ3JvdW5kLWNvbG9yOiMwMDB9';\n\ true,
\n\ ),
@import url('data:text/css;base64,aHRtbHtjb2xvcjojZmZmfQ==')\n\ "\
" @charset 'UTF-8';\n\
); \n\
} @import 'data:text/css;base64,aHRtbHtiYWNrZ3JvdW5kLWNvbG9yOiMwMDB9';\n\
\n\
#[test] @import url('data:text/css;base64,aHRtbHtjb2xvcjojZmZmfQ==')\n\
fn passing_hash_urls() { "
let cache = &mut HashMap::new(); );
let client = Client::new(); }
const CSS: &str = "\ #[test]
body {\n \ fn hash_urls() {
behavior: url(#default#something);\n\ let cache = &mut HashMap::new();
}\n\ let client = Client::new();
\n\
.scissorHalf {\n \ const CSS: &str = "\
offset-path: url(#somePath);\n\ body {\n \
}\n\ behavior: url(#default#something);\n\
"; }\n\
\n\
assert_eq!( .scissorHalf {\n \
css::embed_css( offset-path: url(#somePath);\n\
cache, }\n\
&client, ";
"https://doesntmatter.local/",
&CSS, assert_eq!(
false, css::embed_css(
false, cache,
true, &client,
), "https://doesntmatter.local/",
CSS &CSS,
); false,
} false,
true,
#[test] ),
fn passing_transform_percentages_and_degrees() { CSS
let cache = &mut HashMap::new(); );
let client = Client::new(); }
const CSS: &str = "\ #[test]
div {\n \ fn transform_percentages_and_degrees() {
transform: translate(-50%, -50%) rotate(-45deg);\n\ let cache = &mut HashMap::new();
transform: translate(50%, 50%) rotate(45deg);\n\ let client = Client::new();
transform: translate(+50%, +50%) rotate(+45deg);\n\
}\n\ const CSS: &str = "\
"; div {\n \
transform: translate(-50%, -50%) rotate(-45deg);\n\
assert_eq!( transform: translate(50%, 50%) rotate(45deg);\n\
css::embed_css( transform: translate(+50%, +50%) rotate(+45deg);\n\
cache, }\n\
&client, ";
"https://doesntmatter.local/",
&CSS, assert_eq!(
false, css::embed_css(
false, cache,
true, &client,
), "https://doesntmatter.local/",
CSS &CSS,
); false,
} false,
true,
#[test] ),
fn passing_unusual_indents() { CSS
let cache = &mut HashMap::new(); );
let client = Client::new(); }
const CSS: &str = "\ #[test]
.is\\:good:hover {\n \ fn unusual_indents() {
color: green\n\ let cache = &mut HashMap::new();
}\n\ let client = Client::new();
\n\
#\\~\\!\\@\\$\\%\\^\\&\\*\\(\\)\\+\\=\\,\\.\\/\\\\\\'\\\"\\;\\:\\?\\>\\<\\[\\]\\{\\}\\|\\`\\# {\n \ const CSS: &str = "\
color: black\n\ .is\\:good:hover {\n \
}\n\ color: green\n\
"; }\n\
\n\
assert_eq!( #\\~\\!\\@\\$\\%\\^\\&\\*\\(\\)\\+\\=\\,\\.\\/\\\\\\'\\\"\\;\\:\\?\\>\\<\\[\\]\\{\\}\\|\\`\\# {\n \
css::embed_css( color: black\n\
cache, }\n\
&client, ";
"https://doesntmatter.local/",
&CSS, assert_eq!(
false, css::embed_css(
false, cache,
true, &client,
), "https://doesntmatter.local/",
CSS &CSS,
); false,
} false,
true,
#[test] ),
fn passing_exclude_fonts() { CSS
let cache = &mut HashMap::new(); );
let client = Client::new(); }
const CSS: &str = "\ #[test]
@font-face {\n \ fn exclude_fonts() {
font-family: 'My Font';\n \ let cache = &mut HashMap::new();
src: url(my_font.woff);\n\ let client = Client::new();
}\n\
\n\ const CSS: &str = "\
#identifier {\n \ @font-face {\n \
font-family: 'My Font' Arial\n\ font-family: 'My Font';\n \
}\n\ src: url(my_font.woff);\n\
\n\ }\n\
@font-face {\n \ \n\
font-family: 'My Font';\n \ #identifier {\n \
src: url(my_font.woff);\n\ font-family: 'My Font' Arial\n\
}\n\ }\n\
\n\ \n\
div {\n \ @font-face {\n \
font-family: 'My Font' Verdana\n\ font-family: 'My Font';\n \
}\n\ src: url(my_font.woff);\n\
"; }\n\
\n\
const CSS_OUT: &str = " \ div {\n \
\n\ font-family: 'My Font' Verdana\n\
\n\ }\n\
#identifier {\n \ ";
font-family: 'My Font' Arial\n\
}\n\ const CSS_OUT: &str = " \
\n \ \n\
\n\ \n\
\n\ #identifier {\n \
div {\n \ font-family: 'My Font' Arial\n\
font-family: 'My Font' Verdana\n\ }\n\
}\n\ \n \
"; \n\
\n\
assert_eq!( div {\n \
css::embed_css( font-family: 'My Font' Verdana\n\
cache, }\n\
&client, ";
"https://doesntmatter.local/",
&CSS, assert_eq!(
true, css::embed_css(
false, cache,
true, &client,
), "https://doesntmatter.local/",
CSS_OUT &CSS,
); true,
false,
true,
),
CSS_OUT
);
}
} }

View file

@ -1,5 +1,3 @@
use crate::css;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,44 +5,49 @@ use crate::css;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_empty_input_single_quotes() { mod passing {
assert_eq!(css::enquote(str!(""), false), "''"); use crate::css;
}
#[test] #[test]
fn passing_empty_input_double_quotes() { fn empty_input_single_quotes() {
assert_eq!(css::enquote(str!(""), true), "\"\""); assert_eq!(css::enquote(str!(""), false), "''");
} }
#[test] #[test]
fn passing_apostrophes_single_quotes() { fn empty_input_double_quotes() {
assert_eq!( assert_eq!(css::enquote(str!(""), true), "\"\"");
css::enquote(str!("It's a lovely day, don't you think?"), false), }
"'It\\'s a lovely day, don\\'t you think?'"
);
}
#[test] #[test]
fn passing_apostrophes_double_quotes() { fn apostrophes_single_quotes() {
assert_eq!( assert_eq!(
css::enquote(str!("It's a lovely day, don't you think?"), true), css::enquote(str!("It's a lovely day, don't you think?"), false),
"\"It's a lovely day, don't you think?\"" "'It\\'s a lovely day, don\\'t you think?'"
); );
} }
#[test] #[test]
fn passing_feet_and_inches_single_quotes() { fn apostrophes_double_quotes() {
assert_eq!( assert_eq!(
css::enquote(str!("5'2\", 6'5\""), false), css::enquote(str!("It's a lovely day, don't you think?"), true),
"'5\\'2\", 6\\'5\"'" "\"It's a lovely day, don't you think?\""
); );
} }
#[test] #[test]
fn passing_feet_and_inches_double_quotes() { fn feet_and_inches_single_quotes() {
assert_eq!( assert_eq!(
css::enquote(str!("5'2\", 6'5\""), true), css::enquote(str!("5'2\", 6'5\""), false),
"\"5'2\\\", 6'5\\\"\"" "'5\\'2\", 6\\'5\"'"
); );
}
#[test]
fn feet_and_inches_double_quotes() {
assert_eq!(
css::enquote(str!("5'2\", 6'5\""), true),
"\"5'2\\\", 6'5\\\"\""
);
}
} }

View file

@ -1,6 +1,3 @@
use crate::html;
use html5ever::rcdom::{Handle, NodeData};
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -8,42 +5,48 @@ use html5ever::rcdom::{Handle, NodeData};
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn get_node_name() { mod passing {
let html = "<!doctype html><html><HEAD></HEAD><body><div><P></P></div></body></html>"; use crate::html;
let dom = html::html_to_dom(&html); use html5ever::rcdom::{Handle, NodeData};
let mut count = 0;
fn test_walk(node: &Handle, i: &mut i8) { #[test]
*i += 1; fn get_node_name() {
let html = "<!doctype html><html><HEAD></HEAD><body><div><P></P></div></body></html>";
let dom = html::html_to_dom(&html);
let mut count = 0;
match &node.data { fn test_walk(node: &Handle, i: &mut i8) {
NodeData::Document => { *i += 1;
for child in node.children.borrow().iter() {
test_walk(child, &mut *i);
}
}
NodeData::Element { ref name, .. } => {
let node_name = name.local.as_ref().to_string();
let parent = html::get_parent_node(node);
let parent_node_name = html::get_node_name(&parent);
if node_name == "head" || node_name == "body" {
assert_eq!(parent_node_name, Some("html"));
} else if node_name == "div" {
assert_eq!(parent_node_name, Some("body"));
} else if node_name == "p" {
assert_eq!(parent_node_name, Some("div"));
}
for child in node.children.borrow().iter() { match &node.data {
test_walk(child, &mut *i); NodeData::Document => {
for child in node.children.borrow().iter() {
test_walk(child, &mut *i);
}
} }
} NodeData::Element { ref name, .. } => {
_ => (), let node_name = name.local.as_ref().to_string();
}; let parent = html::get_parent_node(node);
let parent_node_name = html::get_node_name(&parent);
if node_name == "head" || node_name == "body" {
assert_eq!(parent_node_name, Some("html"));
} else if node_name == "div" {
assert_eq!(parent_node_name, Some("body"));
} else if node_name == "p" {
assert_eq!(parent_node_name, Some("div"));
}
for child in node.children.borrow().iter() {
test_walk(child, &mut *i);
}
}
_ => (),
};
}
test_walk(&dom.document, &mut count);
assert_eq!(count, 7);
} }
test_walk(&dom.document, &mut count);
assert_eq!(count, 7);
} }

View file

@ -1,5 +1,3 @@
use crate::html;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,29 +5,34 @@ use crate::html;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_icon() { mod passing {
assert!(html::is_icon("icon")); use crate::html;
}
#[test] #[test]
fn passing_shortcut_icon_capitalized() { fn icon() {
assert!(html::is_icon("Shortcut Icon")); assert!(html::is_icon("icon"));
} }
#[test] #[test]
fn passing_icon_uppercase() { fn shortcut_icon_capitalized() {
assert!(html::is_icon("ICON")); assert!(html::is_icon("Shortcut Icon"));
} }
#[test] #[test]
fn passing_mask_icon() { fn icon_uppercase() {
assert!(html::is_icon("mask-icon")); assert!(html::is_icon("ICON"));
} }
#[test] #[test]
fn passing_fluid_icon() { fn mask_icon() {
assert!(html::is_icon("fluid-icon")); assert!(html::is_icon("mask-icon"));
}
#[test]
fn fluid_icon() {
assert!(html::is_icon("fluid-icon"));
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -39,12 +42,17 @@ fn passing_fluid_icon() {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_stylesheet() { mod failing {
assert!(!html::is_icon("stylesheet")); use crate::html;
}
#[test] #[test]
fn failing_empty_string() { fn stylesheet() {
assert!(!html::is_icon("")); assert!(!html::is_icon("stylesheet"));
}
#[test]
fn empty_string() {
assert!(!html::is_icon(""));
}
} }

View file

@ -1,5 +1,3 @@
use crate::html;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,182 +5,187 @@ use crate::html;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_div_as_root_element() { mod passing {
let html = "<div><script src=\"some.js\"></script></div>"; use crate::html;
let dom = html::html_to_dom(&html);
let opt_no_css: bool = false; #[test]
let opt_no_frames: bool = false; fn div_as_root_element() {
let opt_no_js: bool = false; let html = "<div><script src=\"some.js\"></script></div>";
let opt_no_images: bool = false; let dom = html::html_to_dom(&html);
let opt_isolate: bool = false;
assert_eq!( let opt_no_css: bool = false;
html::stringify_document( let opt_no_frames: bool = false;
&dom.document, let opt_no_js: bool = false;
opt_no_css, let opt_no_images: bool = false;
opt_no_frames, let opt_isolate: bool = false;
opt_no_js,
opt_no_images,
opt_isolate,
),
"<html><head></head><body><div><script src=\"some.js\"></script></div></body></html>"
);
}
#[test] assert_eq!(
fn passing_full_page_with_no_html_head_or_body() { html::stringify_document(
let html = "<title>Isolated document</title>\ &dom.document,
<link rel=\"something\" href=\"some.css\" />\ opt_no_css,
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\ opt_no_frames,
<div><script src=\"some.js\"></script></div>"; opt_no_js,
let dom = html::html_to_dom(&html); opt_no_images,
opt_isolate,
),
"<html><head></head><body><div><script src=\"some.js\"></script></div></body></html>"
);
}
let opt_no_css: bool = false; #[test]
let opt_no_frames: bool = false; fn full_page_with_no_html_head_or_body() {
let opt_no_js: bool = false; let html = "<title>Isolated document</title>\
let opt_no_images: bool = false; <link rel=\"something\" href=\"some.css\" />\
let opt_isolate: bool = true; <meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
<div><script src=\"some.js\"></script></div>";
assert_eq!( let dom = html::html_to_dom(&html);
html::stringify_document(
&dom.document, let opt_no_css: bool = false;
opt_no_css, let opt_no_frames: bool = false;
opt_no_frames, let opt_no_js: bool = false;
opt_no_js, let opt_no_images: bool = false;
opt_no_images, let opt_isolate: bool = true;
opt_isolate,
), assert_eq!(
"<html>\ html::stringify_document(
<head>\ &dom.document,
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:;\"></meta>\ opt_no_css,
<title>Isolated document</title>\ opt_no_frames,
<link rel=\"something\" href=\"some.css\">\ opt_no_js,
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\ opt_no_images,
</head>\ opt_isolate,
<body>\ ),
<div>\ "<html>\
<script src=\"some.js\"></script>\ <head>\
</div>\ <meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:;\"></meta>\
</body>\ <title>Isolated document</title>\
</html>" <link rel=\"something\" href=\"some.css\">\
);
}
#[test]
fn passing_doctype_and_the_rest_no_html_head_or_body() {
let html = "<!doctype html>\
<title>Unstyled document</title>\
<link rel=\"stylesheet\" href=\"main.css\"/>\
<div style=\"display: none;\"></div>";
let dom = html::html_to_dom(&html);
let opt_no_css: bool = true;
let opt_no_frames: bool = false;
let opt_no_js: bool = false;
let opt_no_images: bool = false;
let opt_isolate: bool = false;
assert_eq!(
html::stringify_document(
&dom.document,
opt_no_css,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_isolate,
),
"<!DOCTYPE html>\
<html>\
<head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none';\"></meta>\
<title>Unstyled document</title>\
<link rel=\"stylesheet\" href=\"main.css\">\
</head>\
<body><div style=\"display: none;\"></div></body>\
</html>"
);
}
#[test]
fn passing_doctype_and_the_rest_no_html_head_or_body_forbid_frames() {
let html = "<!doctype html>\
<title>Frameless document</title>\
<link rel=\"something\"/>\
<div><script src=\"some.js\"></script></div>";
let dom = html::html_to_dom(&html);
let opt_no_css: bool = false;
let opt_no_frames: bool = true;
let opt_no_js: bool = false;
let opt_no_images: bool = false;
let opt_isolate: bool = false;
assert_eq!(
html::stringify_document(
&dom.document,
opt_no_css,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_isolate,
),
"<!DOCTYPE html>\
<html>\
<head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"frame-src 'none';child-src 'none';\"></meta>\
<title>Frameless document</title>\
<link rel=\"something\">\
</head>\
<body><div><script src=\"some.js\"></script></div></body>\
</html>"
);
}
#[test]
fn passing_doctype_and_the_rest_all_forbidden() {
let html = "<!doctype html>\
<title>no-frame no-css no-js no-image isolated document</title>\
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
<link rel=\"stylesheet\" href=\"some.css\">\
<div>\
<script src=\"some.js\"></script>\
<img style=\"width: 100%;\" src=\"some.png\" />\
<iframe src=\"some.html\"></iframe>\
</div>";
let dom = html::html_to_dom(&html);
let opt_isolate: bool = true;
let opt_no_css: bool = true;
let opt_no_frames: bool = true;
let opt_no_js: bool = true;
let opt_no_images: bool = true;
assert_eq!(
html::stringify_document(
&dom.document,
opt_no_css,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_isolate,
),
"<!DOCTYPE html>\
<html>\
<head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:; style-src 'none'; frame-src 'none';child-src 'none'; script-src 'none'; img-src data:;\"></meta>\
<title>no-frame no-css no-js no-image isolated document</title>\
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\ <meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
<link rel=\"stylesheet\" href=\"some.css\">\
</head>\ </head>\
<body>\ <body>\
<div>\ <div>\
<script src=\"some.js\"></script>\ <script src=\"some.js\"></script>\
<img style=\"width: 100%;\" src=\"some.png\">\
<iframe src=\"some.html\"></iframe>\
</div>\ </div>\
</body>\ </body>\
</html>" </html>"
); );
}
#[test]
fn doctype_and_the_rest_no_html_head_or_body() {
let html = "<!doctype html>\
<title>Unstyled document</title>\
<link rel=\"stylesheet\" href=\"main.css\"/>\
<div style=\"display: none;\"></div>";
let dom = html::html_to_dom(&html);
let opt_no_css: bool = true;
let opt_no_frames: bool = false;
let opt_no_js: bool = false;
let opt_no_images: bool = false;
let opt_isolate: bool = false;
assert_eq!(
html::stringify_document(
&dom.document,
opt_no_css,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_isolate,
),
"<!DOCTYPE html>\
<html>\
<head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"style-src 'none';\"></meta>\
<title>Unstyled document</title>\
<link rel=\"stylesheet\" href=\"main.css\">\
</head>\
<body><div style=\"display: none;\"></div></body>\
</html>"
);
}
#[test]
fn doctype_and_the_rest_no_html_head_or_body_forbid_frames() {
let html = "<!doctype html>\
<title>Frameless document</title>\
<link rel=\"something\"/>\
<div><script src=\"some.js\"></script></div>";
let dom = html::html_to_dom(&html);
let opt_no_css: bool = false;
let opt_no_frames: bool = true;
let opt_no_js: bool = false;
let opt_no_images: bool = false;
let opt_isolate: bool = false;
assert_eq!(
html::stringify_document(
&dom.document,
opt_no_css,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_isolate,
),
"<!DOCTYPE html>\
<html>\
<head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"frame-src 'none';child-src 'none';\"></meta>\
<title>Frameless document</title>\
<link rel=\"something\">\
</head>\
<body><div><script src=\"some.js\"></script></div></body>\
</html>"
);
}
#[test]
fn doctype_and_the_rest_all_forbidden() {
let html = "<!doctype html>\
<title>no-frame no-css no-js no-image isolated document</title>\
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
<link rel=\"stylesheet\" href=\"some.css\">\
<div>\
<script src=\"some.js\"></script>\
<img style=\"width: 100%;\" src=\"some.png\" />\
<iframe src=\"some.html\"></iframe>\
</div>";
let dom = html::html_to_dom(&html);
let opt_isolate: bool = true;
let opt_no_css: bool = true;
let opt_no_frames: bool = true;
let opt_no_js: bool = true;
let opt_no_images: bool = true;
assert_eq!(
html::stringify_document(
&dom.document,
opt_no_css,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_isolate,
),
"<!DOCTYPE html>\
<html>\
<head>\
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'unsafe-inline' data:; style-src 'none'; frame-src 'none';child-src 'none'; script-src 'none'; img-src data:;\"></meta>\
<title>no-frame no-css no-js no-image isolated document</title>\
<meta http-equiv=\"Content-Security-Policy\" content=\"default-src https:\">\
<link rel=\"stylesheet\" href=\"some.css\">\
</head>\
<body>\
<div>\
<script src=\"some.js\"></script>\
<img style=\"width: 100%;\" src=\"some.png\">\
<iframe src=\"some.html\"></iframe>\
</div>\
</body>\
</html>"
);
}
} }

View file

@ -1,8 +1,3 @@
use crate::html;
use html5ever::serialize::{serialize, SerializeOpts};
use reqwest::blocking::Client;
use std::collections::HashMap;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -10,410 +5,419 @@ use std::collections::HashMap;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_basic() { mod passing {
let cache = &mut HashMap::new(); use crate::html;
use html5ever::serialize::{serialize, SerializeOpts};
use reqwest::blocking::Client;
use std::collections::HashMap;
let html = "<div><P></P></div>"; #[test]
let dom = html::html_to_dom(&html); fn basic() {
let url = "http://localhost"; let cache = &mut HashMap::new();
let opt_no_css: bool = false; let html = "<div><P></P></div>";
let opt_no_fonts: bool = false; let dom = html::html_to_dom(&html);
let opt_no_frames: bool = false; let url = "http://localhost";
let opt_no_js: bool = false;
let opt_no_images: bool = false;
let opt_silent = true;
let client = Client::new(); let opt_no_css: bool = false;
let opt_no_fonts: bool = false;
let opt_no_frames: bool = false;
let opt_no_js: bool = false;
let opt_no_images: bool = false;
let opt_silent = true;
html::walk_and_embed_assets( let client = Client::new();
cache,
&client,
&url,
&dom.document,
opt_no_css,
opt_no_fonts,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
let mut buf: Vec<u8> = Vec::new(); html::walk_and_embed_assets(
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap(); cache,
&client,
&url,
&dom.document,
opt_no_css,
opt_no_fonts,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
assert_eq!( let mut buf: Vec<u8> = Vec::new();
buf.iter().map(|&c| c as char).collect::<String>(), serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
"<html><head></head><body><div><p></p></div></body></html>"
);
}
#[test] assert_eq!(
fn passing_ensure_no_recursive_iframe() { buf.iter().map(|&c| c as char).collect::<String>(),
let html = "<div><P></P><iframe src=\"\"></iframe></div>"; "<html><head></head><body><div><p></p></div></body></html>"
let dom = html::html_to_dom(&html); );
let url = "http://localhost"; }
let cache = &mut HashMap::new();
let opt_no_css: bool = false; #[test]
let opt_no_fonts: bool = false; fn ensure_no_recursive_iframe() {
let opt_no_frames: bool = false; let html = "<div><P></P><iframe src=\"\"></iframe></div>";
let opt_no_js: bool = false; let dom = html::html_to_dom(&html);
let opt_no_images: bool = false; let url = "http://localhost";
let opt_silent = true; let cache = &mut HashMap::new();
let client = Client::new(); let opt_no_css: bool = false;
let opt_no_fonts: bool = false;
let opt_no_frames: bool = false;
let opt_no_js: bool = false;
let opt_no_images: bool = false;
let opt_silent = true;
html::walk_and_embed_assets( let client = Client::new();
cache,
&client,
&url,
&dom.document,
opt_no_css,
opt_no_fonts,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
let mut buf: Vec<u8> = Vec::new(); html::walk_and_embed_assets(
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap(); cache,
&client,
&url,
&dom.document,
opt_no_css,
opt_no_fonts,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
assert_eq!( let mut buf: Vec<u8> = Vec::new();
buf.iter().map(|&c| c as char).collect::<String>(), serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
"<html><head></head><body><div><p></p><iframe src=\"\"></iframe></div></body></html>"
);
}
#[test] assert_eq!(
fn passing_ensure_no_recursive_frame() { buf.iter().map(|&c| c as char).collect::<String>(),
let html = "<frameset><frame src=\"\"></frameset>"; "<html><head></head><body><div><p></p><iframe src=\"\"></iframe></div></body></html>"
let dom = html::html_to_dom(&html); );
let url = "http://localhost"; }
let cache = &mut HashMap::new();
let opt_no_css: bool = false; #[test]
let opt_no_fonts: bool = false; fn ensure_no_recursive_frame() {
let opt_no_frames: bool = false; let html = "<frameset><frame src=\"\"></frameset>";
let opt_no_js: bool = false; let dom = html::html_to_dom(&html);
let opt_no_images: bool = false; let url = "http://localhost";
let opt_silent = true; let cache = &mut HashMap::new();
let client = Client::new(); let opt_no_css: bool = false;
let opt_no_fonts: bool = false;
let opt_no_frames: bool = false;
let opt_no_js: bool = false;
let opt_no_images: bool = false;
let opt_silent = true;
html::walk_and_embed_assets( let client = Client::new();
cache,
&client,
&url,
&dom.document,
opt_no_css,
opt_no_fonts,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
let mut buf: Vec<u8> = Vec::new(); html::walk_and_embed_assets(
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap(); cache,
&client,
&url,
&dom.document,
opt_no_css,
opt_no_fonts,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
assert_eq!( let mut buf: Vec<u8> = Vec::new();
buf.iter().map(|&c| c as char).collect::<String>(), serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
"<html><head></head><frameset><frame src=\"\"></frameset></html>"
);
}
#[test] assert_eq!(
fn passing_no_css() { buf.iter().map(|&c| c as char).collect::<String>(),
let html = "<link rel=\"stylesheet\" href=\"main.css\">\ "<html><head></head><frameset><frame src=\"\"></frameset></html>"
<style>html{background-color: #000;}</style>\ );
<div style=\"display: none;\"></div>"; }
let dom = html::html_to_dom(&html);
let url = "http://localhost";
let cache = &mut HashMap::new();
let opt_no_css: bool = true; #[test]
let opt_no_fonts: bool = false; fn no_css() {
let opt_no_frames: bool = false; let html = "<link rel=\"stylesheet\" href=\"main.css\">\
let opt_no_js: bool = false; <style>html{background-color: #000;}</style>\
let opt_no_images: bool = false; <div style=\"display: none;\"></div>";
let opt_silent = true; let dom = html::html_to_dom(&html);
let client = Client::new(); let url = "http://localhost";
let cache = &mut HashMap::new();
html::walk_and_embed_assets( let opt_no_css: bool = true;
cache, let opt_no_fonts: bool = false;
&client, let opt_no_frames: bool = false;
&url, let opt_no_js: bool = false;
&dom.document, let opt_no_images: bool = false;
opt_no_css, let opt_silent = true;
opt_no_fonts, let client = Client::new();
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
let mut buf: Vec<u8> = Vec::new(); html::walk_and_embed_assets(
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap(); cache,
&client,
&url,
&dom.document,
opt_no_css,
opt_no_fonts,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
assert_eq!( let mut buf: Vec<u8> = Vec::new();
buf.iter().map(|&c| c as char).collect::<String>(), serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
"<html>\
<head>\
<link rel=\"stylesheet\">\
<style></style>\
</head>\
<body>\
<div></div>\
</body>\
</html>"
);
}
#[test] assert_eq!(
fn passing_no_images() { buf.iter().map(|&c| c as char).collect::<String>(),
let html = "<link rel=\"icon\" href=\"favicon.ico\">\
<div><img src=\"http://localhost/assets/mono_lisa.png\" /></div>";
let dom = html::html_to_dom(&html);
let url = "http://localhost";
let cache = &mut HashMap::new();
let opt_no_css: bool = false;
let opt_no_fonts: bool = false;
let opt_no_frames: bool = false;
let opt_no_js: bool = false;
let opt_no_images: bool = true;
let opt_silent = true;
let client = Client::new();
html::walk_and_embed_assets(
cache,
&client,
&url,
&dom.document,
opt_no_css,
opt_no_fonts,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
let mut buf: Vec<u8> = Vec::new();
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
assert_eq!(
buf.iter().map(|&c| c as char).collect::<String>(),
format!(
"<html>\ "<html>\
<head>\ <head>\
<link rel=\"icon\">\ <link rel=\"stylesheet\">\
</head>\ <style></style>\
<body>\ </head>\
<div>\ <body>\
<img src=\"{empty_image}\">\ <div></div>\
</div>\ </body>\
</body>\ </html>"
</html>", );
empty_image = empty_image!() }
)
); #[test]
} fn no_images() {
let html = "<link rel=\"icon\" href=\"favicon.ico\">\
#[test] <div><img src=\"http://localhost/assets/mono_lisa.png\" /></div>";
fn passing_no_body_background_images() { let dom = html::html_to_dom(&html);
let html = "<body background=\"no/such/image.png\" background=\"no/such/image2.png\"></body>"; let url = "http://localhost";
let dom = html::html_to_dom(&html); let cache = &mut HashMap::new();
let url = "http://localhost";
let cache = &mut HashMap::new(); let opt_no_css: bool = false;
let opt_no_fonts: bool = false;
let opt_no_css: bool = false; let opt_no_frames: bool = false;
let opt_no_fonts: bool = false; let opt_no_js: bool = false;
let opt_no_frames: bool = false; let opt_no_images: bool = true;
let opt_no_js: bool = false; let opt_silent = true;
let opt_no_images: bool = true;
let opt_silent = true; let client = Client::new();
let client = Client::new(); html::walk_and_embed_assets(
cache,
html::walk_and_embed_assets( &client,
cache, &url,
&client, &dom.document,
&url, opt_no_css,
&dom.document, opt_no_fonts,
opt_no_css, opt_no_frames,
opt_no_fonts, opt_no_js,
opt_no_frames, opt_no_images,
opt_no_js, opt_silent,
opt_no_images, );
opt_silent,
); let mut buf: Vec<u8> = Vec::new();
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
let mut buf: Vec<u8> = Vec::new();
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap(); assert_eq!(
buf.iter().map(|&c| c as char).collect::<String>(),
assert_eq!( format!(
buf.iter().map(|&c| c as char).collect::<String>(), "<html>\
"<html><head></head><body></body></html>" <head>\
); <link rel=\"icon\">\
} </head>\
<body>\
#[test] <div>\
fn passing_no_frames() { <img src=\"{empty_image}\">\
let html = "<frameset><frame src=\"http://trackbook.com\"></frameset>"; </div>\
let dom = html::html_to_dom(&html); </body>\
let url = "http://localhost"; </html>",
let cache = &mut HashMap::new(); empty_image = empty_image!()
)
let opt_no_css: bool = false; );
let opt_no_fonts: bool = false; }
let opt_no_frames: bool = true;
let opt_no_js: bool = false; #[test]
let opt_no_images: bool = false; fn no_body_background_images() {
let opt_silent = true; let html =
let client = Client::new(); "<body background=\"no/such/image.png\" background=\"no/such/image2.png\"></body>";
let dom = html::html_to_dom(&html);
html::walk_and_embed_assets( let url = "http://localhost";
cache, let cache = &mut HashMap::new();
&client,
&url, let opt_no_css: bool = false;
&dom.document, let opt_no_fonts: bool = false;
opt_no_css, let opt_no_frames: bool = false;
opt_no_fonts, let opt_no_js: bool = false;
opt_no_frames, let opt_no_images: bool = true;
opt_no_js, let opt_silent = true;
opt_no_images,
opt_silent, let client = Client::new();
);
html::walk_and_embed_assets(
let mut buf: Vec<u8> = Vec::new(); cache,
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap(); &client,
&url,
assert_eq!( &dom.document,
buf.iter().map(|&c| c as char).collect::<String>(), opt_no_css,
"<html><head></head><frameset><frame src=\"\"></frameset></html>" opt_no_fonts,
); opt_no_frames,
} opt_no_js,
opt_no_images,
#[test] opt_silent,
fn passing_no_iframes() { );
let html = "<iframe src=\"http://trackbook.com\"></iframe>";
let dom = html::html_to_dom(&html); let mut buf: Vec<u8> = Vec::new();
let url = "http://localhost"; serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
let cache = &mut HashMap::new();
assert_eq!(
let opt_no_css: bool = false; buf.iter().map(|&c| c as char).collect::<String>(),
let opt_no_fonts: bool = false; "<html><head></head><body></body></html>"
let opt_no_frames: bool = true; );
let opt_no_js: bool = false; }
let opt_no_images: bool = false;
let opt_silent = true; #[test]
let client = Client::new(); fn no_frames() {
let html = "<frameset><frame src=\"http://trackbook.com\"></frameset>";
html::walk_and_embed_assets( let dom = html::html_to_dom(&html);
cache, let url = "http://localhost";
&client, let cache = &mut HashMap::new();
&url,
&dom.document, let opt_no_css: bool = false;
opt_no_css, let opt_no_fonts: bool = false;
opt_no_fonts, let opt_no_frames: bool = true;
opt_no_frames, let opt_no_js: bool = false;
opt_no_js, let opt_no_images: bool = false;
opt_no_images, let opt_silent = true;
opt_silent, let client = Client::new();
);
html::walk_and_embed_assets(
let mut buf: Vec<u8> = Vec::new(); cache,
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap(); &client,
&url,
assert_eq!( &dom.document,
buf.iter().map(|&c| c as char).collect::<String>(), opt_no_css,
"<html><head></head><body><iframe src=\"\"></iframe></body></html>" opt_no_fonts,
); opt_no_frames,
} opt_no_js,
opt_no_images,
#[test] opt_silent,
fn passing_no_js() { );
let html = "<div onClick=\"void(0)\">\
<script src=\"http://localhost/assets/some.js\"></script>\ let mut buf: Vec<u8> = Vec::new();
<script>alert(1)</script>\ serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
</div>";
let dom = html::html_to_dom(&html); assert_eq!(
let url = "http://localhost"; buf.iter().map(|&c| c as char).collect::<String>(),
let cache = &mut HashMap::new(); "<html><head></head><frameset><frame src=\"\"></frameset></html>"
);
let opt_no_css: bool = false; }
let opt_no_fonts: bool = false;
let opt_no_frames: bool = false; #[test]
let opt_no_js: bool = true; fn no_iframes() {
let opt_no_images: bool = false; let html = "<iframe src=\"http://trackbook.com\"></iframe>";
let opt_silent = true; let dom = html::html_to_dom(&html);
let url = "http://localhost";
let client = Client::new(); let cache = &mut HashMap::new();
html::walk_and_embed_assets( let opt_no_css: bool = false;
cache, let opt_no_fonts: bool = false;
&client, let opt_no_frames: bool = true;
&url, let opt_no_js: bool = false;
&dom.document, let opt_no_images: bool = false;
opt_no_css, let opt_silent = true;
opt_no_fonts, let client = Client::new();
opt_no_frames,
opt_no_js, html::walk_and_embed_assets(
opt_no_images, cache,
opt_silent, &client,
); &url,
&dom.document,
let mut buf: Vec<u8> = Vec::new(); opt_no_css,
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap(); opt_no_fonts,
opt_no_frames,
assert_eq!( opt_no_js,
buf.iter().map(|&c| c as char).collect::<String>(), opt_no_images,
"<html><head></head><body><div><script></script>\ opt_silent,
<script></script></div></body></html>" );
);
} let mut buf: Vec<u8> = Vec::new();
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
#[test]
fn passing_with_no_integrity() { assert_eq!(
let html = "<title>No integrity</title>\ buf.iter().map(|&c| c as char).collect::<String>(),
<link integrity=\"sha384-...\" rel=\"something\"/>\ "<html><head></head><body><iframe src=\"\"></iframe></body></html>"
<script integrity=\"sha384-...\" src=\"some.js\"></script>"; );
let dom = html::html_to_dom(&html); }
let url = "http://localhost";
let cache = &mut HashMap::new(); #[test]
let client = Client::new(); fn no_js() {
let opt_no_css: bool = true; let html = "<div onClick=\"void(0)\">\
let opt_no_fonts: bool = false; <script src=\"http://localhost/assets/some.js\"></script>\
let opt_no_frames: bool = true; <script>alert(1)</script>\
let opt_no_js: bool = true; </div>";
let opt_no_images: bool = true; let dom = html::html_to_dom(&html);
let opt_silent = true; let url = "http://localhost";
let cache = &mut HashMap::new();
html::walk_and_embed_assets(
cache, let opt_no_css: bool = false;
&client, let opt_no_fonts: bool = false;
&url, let opt_no_frames: bool = false;
&dom.document, let opt_no_js: bool = true;
opt_no_css, let opt_no_images: bool = false;
opt_no_fonts, let opt_silent = true;
opt_no_frames,
opt_no_js, let client = Client::new();
opt_no_images,
opt_silent, html::walk_and_embed_assets(
); cache,
&client,
let mut buf: Vec<u8> = Vec::new(); &url,
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap(); &dom.document,
opt_no_css,
assert_eq!( opt_no_fonts,
buf.iter().map(|&c| c as char).collect::<String>(), opt_no_frames,
"<html>\ opt_no_js,
<head><title>No integrity</title><link rel=\"something\"><script></script></head>\ opt_no_images,
<body></body>\ opt_silent,
</html>" );
);
let mut buf: Vec<u8> = Vec::new();
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
assert_eq!(
buf.iter().map(|&c| c as char).collect::<String>(),
"<html><head></head><body><div><script></script>\
<script></script></div></body></html>"
);
}
#[test]
fn with_no_integrity() {
let html = "<title>No integrity</title>\
<link integrity=\"sha384-...\" rel=\"something\"/>\
<script integrity=\"sha384-...\" src=\"some.js\"></script>";
let dom = html::html_to_dom(&html);
let url = "http://localhost";
let cache = &mut HashMap::new();
let client = Client::new();
let opt_no_css: bool = true;
let opt_no_fonts: bool = false;
let opt_no_frames: bool = true;
let opt_no_js: bool = true;
let opt_no_images: bool = true;
let opt_silent = true;
html::walk_and_embed_assets(
cache,
&client,
&url,
&dom.document,
opt_no_css,
opt_no_fonts,
opt_no_frames,
opt_no_js,
opt_no_images,
opt_silent,
);
let mut buf: Vec<u8> = Vec::new();
serialize(&mut buf, &dom.document, SerializeOpts::default()).unwrap();
assert_eq!(
buf.iter().map(|&c| c as char).collect::<String>(),
"<html>\
<head><title>No integrity</title><link rel=\"something\"><script></script></head>\
<body></body>\
</html>"
);
}
} }

View file

@ -1,5 +1,3 @@
use crate::js;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,19 +5,24 @@ use crate::js;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_onblur_camelcase() { mod passing {
assert!(js::attr_is_event_handler("onBlur")); use crate::js;
}
#[test] #[test]
fn passing_onclick_lowercase() { fn onblur_camelcase() {
assert!(js::attr_is_event_handler("onclick")); assert!(js::attr_is_event_handler("onBlur"));
} }
#[test] #[test]
fn passing_onclick_camelcase() { fn onclick_lowercase() {
assert!(js::attr_is_event_handler("onClick")); assert!(js::attr_is_event_handler("onclick"));
}
#[test]
fn onclick_camelcase() {
assert!(js::attr_is_event_handler("onClick"));
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -29,17 +32,22 @@ fn passing_onclick_camelcase() {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_href() { mod failing {
assert!(!js::attr_is_event_handler("href")); use crate::js;
}
#[test] #[test]
fn failing_empty_string() { fn href() {
assert!(!js::attr_is_event_handler("")); assert!(!js::attr_is_event_handler("href"));
} }
#[test] #[test]
fn failing_class() { fn empty_string() {
assert!(!js::attr_is_event_handler("class")); assert!(!js::attr_is_event_handler(""));
}
#[test]
fn class() {
assert!(!js::attr_is_event_handler("class"));
}
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,42 +5,47 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_removes_fragment() { mod passing {
assert_eq!( use crate::utils;
utils::clean_url("https://somewhere.com/font.eot#iefix"),
"https://somewhere.com/font.eot"
);
}
#[test] #[test]
fn passing_removes_empty_fragment() { fn removes_fragment() {
assert_eq!( assert_eq!(
utils::clean_url("https://somewhere.com/font.eot#"), utils::clean_url("https://somewhere.com/font.eot#iefix"),
"https://somewhere.com/font.eot" "https://somewhere.com/font.eot"
); );
} }
#[test] #[test]
fn passing_removes_empty_query_and_empty_fragment() { fn removes_empty_fragment() {
assert_eq!( assert_eq!(
utils::clean_url("https://somewhere.com/font.eot?#"), utils::clean_url("https://somewhere.com/font.eot#"),
"https://somewhere.com/font.eot" "https://somewhere.com/font.eot"
); );
} }
#[test] #[test]
fn passing_removes_empty_query_amp_and_empty_fragment() { fn removes_empty_query_and_empty_fragment() {
assert_eq!( assert_eq!(
utils::clean_url("https://somewhere.com/font.eot?a=b&#"), utils::clean_url("https://somewhere.com/font.eot?#"),
"https://somewhere.com/font.eot?a=b" "https://somewhere.com/font.eot"
); );
} }
#[test] #[test]
fn passing_keeps_credentials() { fn removes_empty_query_amp_and_empty_fragment() {
assert_eq!( assert_eq!(
utils::clean_url("https://cookie:monster@gibson.internet/"), utils::clean_url("https://somewhere.com/font.eot?a=b&#"),
"https://cookie:monster@gibson.internet/" "https://somewhere.com/font.eot?a=b"
); );
}
#[test]
fn keeps_credentials() {
assert_eq!(
utils::clean_url("https://cookie:monster@gibson.internet/"),
"https://cookie:monster@gibson.internet/"
);
}
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,22 +5,27 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_encode_string_with_specific_media_type() { mod passing {
let mime = "application/javascript"; use crate::utils;
let data = "var word = 'hello';\nalert(word);\n";
let data_url = utils::data_to_data_url(mime, data.as_bytes(), "", "");
assert_eq!( #[test]
&data_url, fn encode_string_with_specific_media_type() {
"data:application/javascript;base64,dmFyIHdvcmQgPSAnaGVsbG8nOwphbGVydCh3b3JkKTsK" let mime = "application/javascript";
); let data = "var word = 'hello';\nalert(word);\n";
} let data_url = utils::data_to_data_url(mime, data.as_bytes(), "", "");
#[test] assert_eq!(
fn passing_encode_append_fragment() { &data_url,
let data = "<svg></svg>\n"; "data:application/javascript;base64,dmFyIHdvcmQgPSAnaGVsbG8nOwphbGVydCh3b3JkKTsK"
let data_url = utils::data_to_data_url("text/css", data.as_bytes(), "", "fragment"); );
}
assert_eq!(&data_url, "data:text/css;base64,PHN2Zz48L3N2Zz4K#fragment");
#[test]
fn encode_append_fragment() {
let data = "<svg></svg>\n";
let data_url = utils::data_to_data_url("text/css", data.as_bytes(), "", "fragment");
assert_eq!(&data_url, "data:text/css;base64,PHN2Zz48L3N2Zz4K#fragment");
}
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,76 +5,82 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_parse_text_html_base64() { mod passing {
let (media_type, data) = utils::data_url_to_data("data:text/html;base64,V29yayBleHBhbmRzIHNvIGFzIHRvIGZpbGwgdGhlIHRpbWUgYXZhaWxhYmxlIGZvciBpdHMgY29tcGxldGlvbg=="); use crate::utils;
assert_eq!(media_type, "text/html"); #[test]
assert_eq!( fn parse_text_html_base64() {
String::from_utf8_lossy(&data), let (media_type, data) = utils::data_url_to_data("data:text/html;base64,V29yayBleHBhbmRzIHNvIGFzIHRvIGZpbGwgdGhlIHRpbWUgYXZhaWxhYmxlIGZvciBpdHMgY29tcGxldGlvbg==");
"Work expands so as to fill the time available for its completion"
);
}
#[test] assert_eq!(media_type, "text/html");
fn passing_parse_text_html_utf8() { assert_eq!(
let (media_type, data) = utils::data_url_to_data( String::from_utf8_lossy(&data),
"data:text/html;utf8,Work expands so as to fill the time available for its completion", "Work expands so as to fill the time available for its completion"
); );
}
assert_eq!(media_type, "text/html"); #[test]
assert_eq!( fn parse_text_html_utf8() {
String::from_utf8_lossy(&data), let (media_type, data) = utils::data_url_to_data(
"Work expands so as to fill the time available for its completion" "data:text/html;utf8,Work expands so as to fill the time available for its completion",
); );
}
#[test] assert_eq!(media_type, "text/html");
fn passing_parse_text_html_plaintext() { assert_eq!(
let (media_type, data) = utils::data_url_to_data( String::from_utf8_lossy(&data),
"data:text/html,Work expands so as to fill the time available for its completion", "Work expands so as to fill the time available for its completion"
); );
}
assert_eq!(media_type, "text/html"); #[test]
assert_eq!( fn parse_text_html_plaintext() {
String::from_utf8_lossy(&data), let (media_type, data) = utils::data_url_to_data(
"Work expands so as to fill the time available for its completion" "data:text/html,Work expands so as to fill the time available for its completion",
); );
}
#[test] assert_eq!(media_type, "text/html");
fn passing_parse_text_html_charset_utf_8_between_two_whitespaces() { assert_eq!(
let (media_type, data) = utils::data_url_to_data(" data:text/html;charset=utf-8,Work expands so as to fill the time available for its completion "); String::from_utf8_lossy(&data),
"Work expands so as to fill the time available for its completion"
);
}
assert_eq!(media_type, "text/html"); #[test]
assert_eq!( fn parse_text_html_charset_utf_8_between_two_whitespaces() {
String::from_utf8_lossy(&data), let (media_type, data) = utils::data_url_to_data(" data:text/html;charset=utf-8,Work expands so as to fill the time available for its completion ");
"Work expands so as to fill the time available for its completion"
);
}
#[test] assert_eq!(media_type, "text/html");
fn passing_parse_text_css_url_encoded() { assert_eq!(
let (media_type, data) = utils::data_url_to_data("data:text/css,div{background-color:%23000}"); String::from_utf8_lossy(&data),
"Work expands so as to fill the time available for its completion"
);
}
assert_eq!(media_type, "text/css"); #[test]
assert_eq!(String::from_utf8_lossy(&data), "div{background-color:#000}"); fn parse_text_css_url_encoded() {
} let (media_type, data) =
utils::data_url_to_data("data:text/css,div{background-color:%23000}");
#[test] assert_eq!(media_type, "text/css");
fn passing_parse_no_media_type_base64() { assert_eq!(String::from_utf8_lossy(&data), "div{background-color:#000}");
let (media_type, data) = utils::data_url_to_data("data:;base64,dGVzdA=="); }
assert_eq!(media_type, ""); #[test]
assert_eq!(String::from_utf8_lossy(&data), "test"); fn parse_no_media_type_base64() {
} let (media_type, data) = utils::data_url_to_data("data:;base64,dGVzdA==");
#[test] assert_eq!(media_type, "");
fn passing_parse_no_media_type_no_encoding() { assert_eq!(String::from_utf8_lossy(&data), "test");
let (media_type, data) = utils::data_url_to_data("data:;,test%20test"); }
assert_eq!(media_type, ""); #[test]
assert_eq!(String::from_utf8_lossy(&data), "test test"); fn parse_no_media_type_no_encoding() {
let (media_type, data) = utils::data_url_to_data("data:;,test%20test");
assert_eq!(media_type, "");
assert_eq!(String::from_utf8_lossy(&data), "test test");
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -86,10 +90,15 @@ fn passing_parse_no_media_type_no_encoding() {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_just_word_data() { mod failing {
let (media_type, data) = utils::data_url_to_data("data"); use crate::utils;
assert_eq!(media_type, ""); #[test]
assert_eq!(String::from_utf8_lossy(&data), ""); fn just_word_data() {
let (media_type, data) = utils::data_url_to_data("data");
assert_eq!(media_type, "");
assert_eq!(String::from_utf8_lossy(&data), "");
}
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,131 +5,136 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_image_gif87() { mod passing {
assert_eq!(utils::detect_media_type(b"GIF87a", ""), "image/gif"); use crate::utils;
}
#[test] #[test]
fn passing_image_gif89() { fn image_gif87() {
assert_eq!(utils::detect_media_type(b"GIF89a", ""), "image/gif"); assert_eq!(utils::detect_media_type(b"GIF87a", ""), "image/gif");
} }
#[test] #[test]
fn passing_image_jpeg() { fn image_gif89() {
assert_eq!(utils::detect_media_type(b"\xFF\xD8\xFF", ""), "image/jpeg"); assert_eq!(utils::detect_media_type(b"GIF89a", ""), "image/gif");
} }
#[test] #[test]
fn passing_image_png() { fn image_jpeg() {
assert_eq!( assert_eq!(utils::detect_media_type(b"\xFF\xD8\xFF", ""), "image/jpeg");
utils::detect_media_type(b"\x89PNG\x0D\x0A\x1A\x0A", ""), }
"image/png"
);
}
#[test] #[test]
fn passing_image_svg() { fn image_png() {
assert_eq!(utils::detect_media_type(b"<svg ", ""), "image/svg+xml"); assert_eq!(
} utils::detect_media_type(b"\x89PNG\x0D\x0A\x1A\x0A", ""),
"image/png"
);
}
#[test] #[test]
fn passing_image_webp() { fn image_svg() {
assert_eq!( assert_eq!(utils::detect_media_type(b"<svg ", ""), "image/svg+xml");
utils::detect_media_type(b"RIFF....WEBPVP8 ", ""), }
"image/webp"
);
}
#[test] #[test]
fn passing_image_icon() { fn image_webp() {
assert_eq!( assert_eq!(
utils::detect_media_type(b"\x00\x00\x01\x00", ""), utils::detect_media_type(b"RIFF....WEBPVP8 ", ""),
"image/x-icon" "image/webp"
); );
} }
#[test] #[test]
fn passing_image_svg_filename() { fn image_icon() {
assert_eq!( assert_eq!(
utils::detect_media_type(b"<?xml ", "local-file.svg"), utils::detect_media_type(b"\x00\x00\x01\x00", ""),
"image/svg+xml" "image/x-icon"
); );
} }
#[test] #[test]
fn passing_image_svg_url_uppercase() { fn image_svg_filename() {
assert_eq!( assert_eq!(
utils::detect_media_type(b"", "https://some-site.com/images/local-file.SVG"), utils::detect_media_type(b"<?xml ", "local-file.svg"),
"image/svg+xml" "image/svg+xml"
); );
} }
#[test] #[test]
fn passing_audio_mpeg() { fn image_svg_url_uppercase() {
assert_eq!(utils::detect_media_type(b"ID3", ""), "audio/mpeg"); assert_eq!(
} utils::detect_media_type(b"", "https://some-site.com/images/local-file.SVG"),
"image/svg+xml"
);
}
#[test] #[test]
fn passing_audio_mpeg_2() { fn audio_mpeg() {
assert_eq!(utils::detect_media_type(b"\xFF\x0E", ""), "audio/mpeg"); assert_eq!(utils::detect_media_type(b"ID3", ""), "audio/mpeg");
} }
#[test] #[test]
fn passing_audio_mpeg_3() { fn audio_mpeg_2() {
assert_eq!(utils::detect_media_type(b"\xFF\x0F", ""), "audio/mpeg"); assert_eq!(utils::detect_media_type(b"\xFF\x0E", ""), "audio/mpeg");
} }
#[test] #[test]
fn passing_audio_ogg() { fn audio_mpeg_3() {
assert_eq!(utils::detect_media_type(b"OggS", ""), "audio/ogg"); assert_eq!(utils::detect_media_type(b"\xFF\x0F", ""), "audio/mpeg");
} }
#[test] #[test]
fn passing_audio_wav() { fn audio_ogg() {
assert_eq!( assert_eq!(utils::detect_media_type(b"OggS", ""), "audio/ogg");
utils::detect_media_type(b"RIFF....WAVEfmt ", ""), }
"audio/wav"
);
}
#[test] #[test]
fn passing_audio_flac() { fn audio_wav() {
assert_eq!(utils::detect_media_type(b"fLaC", ""), "audio/x-flac"); assert_eq!(
} utils::detect_media_type(b"RIFF....WAVEfmt ", ""),
"audio/wav"
);
}
#[test] #[test]
fn passing_video_avi() { fn audio_flac() {
assert_eq!( assert_eq!(utils::detect_media_type(b"fLaC", ""), "audio/x-flac");
utils::detect_media_type(b"RIFF....AVI LIST", ""), }
"video/avi"
);
}
#[test] #[test]
fn passing_video_mp4() { fn video_avi() {
assert_eq!(utils::detect_media_type(b"....ftyp", ""), "video/mp4"); assert_eq!(
} utils::detect_media_type(b"RIFF....AVI LIST", ""),
"video/avi"
);
}
#[test] #[test]
fn passing_video_mpeg() { fn video_mp4() {
assert_eq!( assert_eq!(utils::detect_media_type(b"....ftyp", ""), "video/mp4");
utils::detect_media_type(b"\x00\x00\x01\x0B", ""), }
"video/mpeg"
);
}
#[test] #[test]
fn passing_video_quicktime() { fn video_mpeg() {
assert_eq!(utils::detect_media_type(b"....moov", ""), "video/quicktime"); assert_eq!(
} utils::detect_media_type(b"\x00\x00\x01\x0B", ""),
"video/mpeg"
);
}
#[test] #[test]
fn passing_video_webm() { fn video_quicktime() {
assert_eq!( assert_eq!(utils::detect_media_type(b"....moov", ""), "video/quicktime");
utils::detect_media_type(b"\x1A\x45\xDF\xA3", ""), }
"video/webm"
); #[test]
fn video_webm() {
assert_eq!(
utils::detect_media_type(b"\x1A\x45\xDF\xA3", ""),
"video/webm"
);
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -141,7 +144,12 @@ fn passing_video_webm() {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_unknown_media_type() { mod failing {
assert_eq!(utils::detect_media_type(b"abcdef0123456789", ""), ""); use crate::utils;
#[test]
fn unknown_media_type() {
assert_eq!(utils::detect_media_type(b"abcdef0123456789", ""), "");
}
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,32 +5,37 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_remove_protocl_and_fragment() { mod passing {
if cfg!(windows) { use crate::utils;
assert_eq!(
utils::file_url_to_fs_path("file:///C:/documents/some-path/some-file.svg#fragment"),
"C:\\documents\\some-path\\some-file.svg"
);
} else {
assert_eq!(
utils::file_url_to_fs_path("file:///tmp/some-path/some-file.svg#fragment"),
"/tmp/some-path/some-file.svg"
);
}
}
#[test] #[test]
fn passing_decodes_urls() { fn remove_protocl_and_fragment() {
if cfg!(windows) { if cfg!(windows) {
assert_eq!( assert_eq!(
utils::file_url_to_fs_path("file:///C:/Documents%20and%20Settings/some-file.html"), utils::file_url_to_fs_path("file:///C:/documents/some-path/some-file.svg#fragment"),
"C:\\Documents and Settings\\some-file.html" "C:\\documents\\some-path\\some-file.svg"
); );
} else { } else {
assert_eq!( assert_eq!(
utils::file_url_to_fs_path("file:///home/user/My%20Documents"), utils::file_url_to_fs_path("file:///tmp/some-path/some-file.svg#fragment"),
"/home/user/My Documents" "/tmp/some-path/some-file.svg"
); );
}
}
#[test]
fn decodes_urls() {
if cfg!(windows) {
assert_eq!(
utils::file_url_to_fs_path("file:///C:/Documents%20and%20Settings/some-file.html"),
"C:\\Documents and Settings\\some-file.html"
);
} else {
assert_eq!(
utils::file_url_to_fs_path("file:///home/user/My%20Documents"),
"/home/user/My Documents"
);
}
} }
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,17 +5,22 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_data_url() { mod passing {
assert_eq!( use crate::utils;
utils::get_url_fragment(
"data:image/svg+xml;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h#test"
),
"test"
);
}
#[test] #[test]
fn passing_https_empty() { fn data_url() {
assert_eq!(utils::get_url_fragment("https://kernel.org#"), ""); assert_eq!(
utils::get_url_fragment(
"data:image/svg+xml;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h#test"
),
"test"
);
}
#[test]
fn https_empty() {
assert_eq!(utils::get_url_fragment("https://kernel.org#"), "");
}
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,18 +5,23 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_data_url_text_html() { mod passing {
assert!(utils::is_data_url( use crate::utils;
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
));
}
#[test] #[test]
fn passing_data_url_no_media_type() { fn data_url_text_html() {
assert!(utils::is_data_url( assert!(utils::is_data_url(
"data:;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h" "data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
)); ));
}
#[test]
fn data_url_no_media_type() {
assert!(utils::is_data_url(
"data:;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
));
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -28,17 +31,22 @@ fn passing_data_url_no_media_type() {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_https_url() { mod failing {
assert!(!utils::is_data_url("https://kernel.org")); use crate::utils;
}
#[test] #[test]
fn failing_no_protocol_url() { fn https_url() {
assert!(!utils::is_data_url("//kernel.org")); assert!(!utils::is_data_url("https://kernel.org"));
} }
#[test] #[test]
fn failing_empty_string() { fn no_protocol_url() {
assert!(!utils::is_data_url("")); assert!(!utils::is_data_url("//kernel.org"));
}
#[test]
fn empty_string() {
assert!(!utils::is_data_url(""));
}
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,32 +5,37 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_unix_file_url() { mod passing {
assert!(utils::is_file_url( use crate::utils;
"file:///home/user/Websites/my-website/index.html"
));
}
#[test] #[test]
fn passing_windows_file_url() { fn unix_file_url() {
assert!(utils::is_file_url( assert!(utils::is_file_url(
"file:///C:/Documents%20and%20Settings/user/Websites/my-website/assets/images/logo.png" "file:///home/user/Websites/my-website/index.html"
)); ));
} }
#[test] #[test]
fn passing_unix_url_with_backslashes() { fn windows_file_url() {
assert!(utils::is_file_url( assert!(utils::is_file_url(
"file:\\\\\\home\\user\\Websites\\my-website\\index.html" "file:///C:/Documents%20and%20Settings/user/Websites/my-website/assets/images/logo.png"
)); ));
} }
#[test] #[test]
fn passing_windows_file_url_with_backslashes() { fn unix_url_with_backslashes() {
assert!(utils::is_file_url( assert!(utils::is_file_url(
"file:\\\\\\C:\\Documents%20and%20Settings\\user\\Websites\\my-website\\assets\\images\\logo.png" "file:\\\\\\home\\user\\Websites\\my-website\\index.html"
)); ));
}
#[test]
fn windows_file_url_with_backslashes() {
assert!(utils::is_file_url(
"file:\\\\\\C:\\Documents%20and%20Settings\\user\\Websites\\my-website\\assets\\images\\logo.png"
));
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -42,34 +45,39 @@ fn passing_windows_file_url_with_backslashes() {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_url_with_no_protocl() { mod failing {
assert!(!utils::is_file_url("//kernel.org")); use crate::utils;
}
#[test] #[test]
fn failing_dot_slash_filename() { fn url_with_no_protocl() {
assert!(!utils::is_file_url("./index.html")); assert!(!utils::is_file_url("//kernel.org"));
} }
#[test] #[test]
fn failing_just_filename() { fn dot_slash_filename() {
assert!(!utils::is_file_url("some-local-page.htm")); assert!(!utils::is_file_url("./index.html"));
} }
#[test] #[test]
fn failing_https_ip_port_url() { fn just_filename() {
assert!(!utils::is_file_url("https://1.2.3.4:80/www/index.html")); assert!(!utils::is_file_url("some-local-page.htm"));
} }
#[test] #[test]
fn failing_data_url() { fn https_ip_port_url() {
assert!(!utils::is_file_url( assert!(!utils::is_file_url("https://1.2.3.4:80/www/index.html"));
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h" }
));
}
#[test] #[test]
fn failing_just_word_file() { fn data_url() {
assert!(!utils::is_file_url("file")); assert!(!utils::is_file_url(
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
));
}
#[test]
fn just_word_file() {
assert!(!utils::is_file_url("file"));
}
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,19 +5,24 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_http_url() { mod passing {
assert!(utils::is_http_url("http://kernel.org")); use crate::utils;
}
#[test] #[test]
fn passing_https_url() { fn http_url() {
assert!(utils::is_http_url("https://www.rust-lang.org/")); assert!(utils::is_http_url("http://kernel.org"));
} }
#[test] #[test]
fn passing_http_url_with_backslashes() { fn https_url() {
assert!(utils::is_http_url("http:\\\\freebsd.org\\")); assert!(utils::is_http_url("https://www.rust-lang.org/"));
}
#[test]
fn http_url_with_backslashes() {
assert!(utils::is_http_url("http:\\\\freebsd.org\\"));
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -29,29 +32,34 @@ fn passing_http_url_with_backslashes() {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_url_with_no_protocol() { mod failing {
assert!(!utils::is_http_url("//kernel.org")); use crate::utils;
}
#[test] #[test]
fn failing_dot_slash_filename() { fn url_with_no_protocol() {
assert!(!utils::is_http_url("./index.html")); assert!(!utils::is_http_url("//kernel.org"));
} }
#[test] #[test]
fn failing_just_filename() { fn dot_slash_filename() {
assert!(!utils::is_http_url("some-local-page.htm")); assert!(!utils::is_http_url("./index.html"));
} }
#[test] #[test]
fn failing_https_ip_port_url() { fn just_filename() {
assert!(!utils::is_http_url("ftp://1.2.3.4/www/index.html")); assert!(!utils::is_http_url("some-local-page.htm"));
} }
#[test] #[test]
fn failing_data_url() { fn https_ip_port_url() {
assert!(!utils::is_http_url( assert!(!utils::is_http_url("ftp://1.2.3.4/www/index.html"));
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h" }
));
#[test]
fn data_url() {
assert!(!utils::is_http_url(
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h"
));
}
} }

View file

@ -1,7 +1,3 @@
use url::ParseError;
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -9,203 +5,210 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_from_https_to_level_up_relative() -> Result<(), ParseError> { mod passing {
let resolved_url = utils::resolve_url("https://www.kernel.org", "../category/signatures.html")?; use crate::utils;
use url::ParseError;
assert_eq!( #[test]
resolved_url.as_str(), fn from_https_to_level_up_relative() -> Result<(), ParseError> {
"https://www.kernel.org/category/signatures.html" let resolved_url =
); utils::resolve_url("https://www.kernel.org", "../category/signatures.html")?;
Ok(()) assert_eq!(
} resolved_url.as_str(),
"https://www.kernel.org/category/signatures.html"
);
#[test] Ok(())
fn passing_from_just_filename_to_full_https_url() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"saved_page.htm",
"https://www.kernel.org/category/signatures.html",
)?;
assert_eq!( #[test]
resolved_url.as_str(), fn from_just_filename_to_full_https_url() -> Result<(), ParseError> {
"https://www.kernel.org/category/signatures.html" let resolved_url = utils::resolve_url(
); "saved_page.htm",
"https://www.kernel.org/category/signatures.html",
)?;
Ok(()) assert_eq!(
} resolved_url.as_str(),
"https://www.kernel.org/category/signatures.html"
);
#[test] Ok(())
fn passing_from_https_url_to_url_with_no_protocol() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"https://www.kernel.org",
"//www.kernel.org/theme/images/logos/tux.png",
)?;
assert_eq!( #[test]
resolved_url.as_str(), fn from_https_url_to_url_with_no_protocol() -> Result<(), ParseError> {
"https://www.kernel.org/theme/images/logos/tux.png" let resolved_url = utils::resolve_url(
); "https://www.kernel.org",
"//www.kernel.org/theme/images/logos/tux.png",
)?;
Ok(()) assert_eq!(
} resolved_url.as_str(),
"https://www.kernel.org/theme/images/logos/tux.png"
);
#[test] Ok(())
fn passing_from_https_url_to_url_with_no_protocol_and_on_different_hostname( }
) -> Result<(), ParseError> {
let resolved_url = utils::resolve_url(
"https://www.kernel.org",
"//another-host.org/theme/images/logos/tux.png",
)?;
assert_eq!( #[test]
resolved_url.as_str(), fn from_https_url_to_url_with_no_protocol_and_on_different_hostname() -> Result<(), ParseError>
"https://another-host.org/theme/images/logos/tux.png" {
); let resolved_url = utils::resolve_url(
"https://www.kernel.org",
"//another-host.org/theme/images/logos/tux.png",
)?;
Ok(()) assert_eq!(
} resolved_url.as_str(),
"https://another-host.org/theme/images/logos/tux.png"
);
#[test] Ok(())
fn passing_from_https_url_to_relative_root_path() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"https://www.kernel.org/category/signatures.html",
"/theme/images/logos/tux.png",
)?;
assert_eq!( #[test]
resolved_url.as_str(), fn from_https_url_to_relative_root_path() -> Result<(), ParseError> {
"https://www.kernel.org/theme/images/logos/tux.png" let resolved_url = utils::resolve_url(
); "https://www.kernel.org/category/signatures.html",
"/theme/images/logos/tux.png",
)?;
Ok(()) assert_eq!(
} resolved_url.as_str(),
"https://www.kernel.org/theme/images/logos/tux.png"
);
#[test] Ok(())
fn passing_from_https_to_just_filename() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"https://www.w3schools.com/html/html_iframe.asp",
"default.asp",
)?;
assert_eq!( #[test]
resolved_url.as_str(), fn from_https_to_just_filename() -> Result<(), ParseError> {
"https://www.w3schools.com/html/default.asp" let resolved_url = utils::resolve_url(
); "https://www.w3schools.com/html/html_iframe.asp",
"default.asp",
)?;
Ok(()) assert_eq!(
} resolved_url.as_str(),
"https://www.w3schools.com/html/default.asp"
);
#[test] Ok(())
fn passing_from_data_url_to_https() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
"https://www.kernel.org/category/signatures.html",
)?;
assert_eq!( #[test]
resolved_url.as_str(), fn from_data_url_to_https() -> Result<(), ParseError> {
"https://www.kernel.org/category/signatures.html" let resolved_url = utils::resolve_url(
); "data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
"https://www.kernel.org/category/signatures.html",
)?;
Ok(()) assert_eq!(
} resolved_url.as_str(),
"https://www.kernel.org/category/signatures.html"
);
#[test] Ok(())
fn passing_from_data_url_to_data_url() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
"data:text/html;base64,PGEgaHJlZj0iaW5kZXguaHRtbCI+SG9tZTwvYT4K",
)?;
assert_eq!( #[test]
resolved_url.as_str(), fn from_data_url_to_data_url() -> Result<(), ParseError> {
"data:text/html;base64,PGEgaHJlZj0iaW5kZXguaHRtbCI+SG9tZTwvYT4K" let resolved_url = utils::resolve_url(
); "data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
"data:text/html;base64,PGEgaHJlZj0iaW5kZXguaHRtbCI+SG9tZTwvYT4K",
)?;
Ok(()) assert_eq!(
} resolved_url.as_str(),
"data:text/html;base64,PGEgaHJlZj0iaW5kZXguaHRtbCI+SG9tZTwvYT4K"
);
#[test] Ok(())
fn passing_from_file_url_to_relative_path() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"file:///home/user/Websites/my-website/index.html",
"assets/images/logo.png",
)
.unwrap_or(str!());
assert_eq!( #[test]
resolved_url.as_str(), fn from_file_url_to_relative_path() -> Result<(), ParseError> {
"file:///home/user/Websites/my-website/assets/images/logo.png" let resolved_url = utils::resolve_url(
); "file:///home/user/Websites/my-website/index.html",
"assets/images/logo.png",
)
.unwrap_or(str!());
Ok(()) assert_eq!(
} resolved_url.as_str(),
"file:///home/user/Websites/my-website/assets/images/logo.png"
);
#[test] Ok(())
fn passing_from_file_url_to_relative_path_with_backslashes() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"file:\\\\\\home\\user\\Websites\\my-website\\index.html",
"assets\\images\\logo.png",
)
.unwrap_or(str!());
assert_eq!( #[test]
resolved_url.as_str(), fn from_file_url_to_relative_path_with_backslashes() -> Result<(), ParseError> {
"file:///home/user/Websites/my-website/assets/images/logo.png" let resolved_url = utils::resolve_url(
); "file:\\\\\\home\\user\\Websites\\my-website\\index.html",
"assets\\images\\logo.png",
)
.unwrap_or(str!());
Ok(()) assert_eq!(
} resolved_url.as_str(),
"file:///home/user/Websites/my-website/assets/images/logo.png"
);
#[test] Ok(())
fn passing_from_data_url_to_file_url() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
"file:///etc/passwd",
)
.unwrap_or(str!());
assert_eq!(resolved_url.as_str(), "file:///etc/passwd"); #[test]
fn from_data_url_to_file_url() -> Result<(), ParseError> {
let resolved_url = utils::resolve_url(
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
"file:///etc/passwd",
)
.unwrap_or(str!());
Ok(()) assert_eq!(resolved_url.as_str(), "file:///etc/passwd");
}
#[test] Ok(())
fn passing_preserve_fragment() -> Result<(), ParseError> { }
let resolved_url = utils::resolve_url(
"http://doesnt-matter.local/",
"css/fonts/fontmarvelous.svg#fontmarvelous",
)
.unwrap_or(str!());
assert_eq!( #[test]
resolved_url.as_str(), fn preserve_fragment() -> Result<(), ParseError> {
"http://doesnt-matter.local/css/fonts/fontmarvelous.svg#fontmarvelous" let resolved_url = utils::resolve_url(
); "http://doesnt-matter.local/",
"css/fonts/fontmarvelous.svg#fontmarvelous",
)
.unwrap_or(str!());
Ok(()) assert_eq!(
} resolved_url.as_str(),
"http://doesnt-matter.local/css/fonts/fontmarvelous.svg#fontmarvelous"
);
#[test] Ok(())
fn passing_resolve_from_file_url_to_file_url() -> Result<(), ParseError> { }
let resolved_url = if cfg!(windows) {
utils::resolve_url("file:///c:/index.html", "file:///c:/image.png").unwrap_or(str!())
} else {
utils::resolve_url("file:///tmp/index.html", "file:///tmp/image.png").unwrap_or(str!())
};
assert_eq!( #[test]
resolved_url.as_str(), fn resolve_from_file_url_to_file_url() -> Result<(), ParseError> {
if cfg!(windows) { let resolved_url = if cfg!(windows) {
"file:///c:/image.png" utils::resolve_url("file:///c:/index.html", "file:///c:/image.png").unwrap_or(str!())
} else { } else {
"file:///tmp/image.png" utils::resolve_url("file:///tmp/index.html", "file:///tmp/image.png").unwrap_or(str!())
} };
);
Ok(()) assert_eq!(
resolved_url.as_str(),
if cfg!(windows) {
"file:///c:/image.png"
} else {
"file:///tmp/image.png"
}
);
Ok(())
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -215,15 +218,21 @@ fn passing_resolve_from_file_url_to_file_url() -> Result<(), ParseError> {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_from_data_url_to_url_with_no_protocol() -> Result<(), ParseError> { mod failing {
let resolved_url = utils::resolve_url( use crate::utils;
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h", use url::ParseError;
"//www.w3schools.com/html/html_iframe.asp",
)
.unwrap_or(str!());
assert_eq!(resolved_url.as_str(), ""); #[test]
fn from_data_url_to_url_with_no_protocol() -> Result<(), ParseError> {
let resolved_url = utils::resolve_url(
"data:text/html;base64,V2VsY29tZSBUbyBUaGUgUGFydHksIDxiPlBhbDwvYj4h",
"//www.w3schools.com/html/html_iframe.asp",
)
.unwrap_or(str!());
Ok(()) assert_eq!(resolved_url.as_str(), "");
Ok(())
}
} }

View file

@ -1,8 +1,3 @@
use crate::utils;
use reqwest::blocking::Client;
use std::collections::HashMap;
use std::env;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -10,66 +5,74 @@ use std::env;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_read_data_url() { mod passing {
let cache = &mut HashMap::new(); use crate::utils;
let client = Client::new(); use reqwest::blocking::Client;
use std::collections::HashMap;
use std::env;
// If both source and target are data URLs, #[test]
// ensure the result contains target data URL fn read_data_url() {
let (data, final_url, media_type) = utils::retrieve_asset( let cache = &mut HashMap::new();
cache, let client = Client::new();
&client,
"data:text/html;base64,c291cmNl",
"data:text/html;base64,dGFyZ2V0",
false,
)
.unwrap();
assert_eq!(
utils::data_to_data_url(&media_type, &data, &final_url, ""),
utils::data_to_data_url("text/html", "target".as_bytes(), "", "")
);
assert_eq!(
final_url,
utils::data_to_data_url("text/html", "target".as_bytes(), "", "")
);
assert_eq!(&media_type, "text/html");
}
#[test] // If both source and target are data URLs,
fn passing_read_local_file_with_file_url_parent() { // ensure the result contains target data URL
let cache = &mut HashMap::new(); let (data, final_url, media_type) = utils::retrieve_asset(
let client = Client::new(); cache,
&client,
let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" }; "data:text/html;base64,c291cmNl",
"data:text/html;base64,dGFyZ2V0",
// Inclusion of local assets from local sources should be allowed false,
let cwd = env::current_dir().unwrap();
let (data, final_url, _media_type) = utils::retrieve_asset(
cache,
&client,
&format!(
"{file}{cwd}/src/tests/data/basic/local-file.html",
file = file_url_protocol,
cwd = cwd.to_str().unwrap()
),
&format!(
"{file}{cwd}/src/tests/data/basic/local-script.js",
file = file_url_protocol,
cwd = cwd.to_str().unwrap()
),
false,
)
.unwrap();
assert_eq!(utils::data_to_data_url("application/javascript", &data, &final_url, ""), "data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==");
assert_eq!(
&final_url,
&format!(
"{file}{cwd}/src/tests/data/basic/local-script.js",
file = file_url_protocol,
cwd = cwd.to_str().unwrap()
) )
); .unwrap();
assert_eq!(
utils::data_to_data_url(&media_type, &data, &final_url, ""),
utils::data_to_data_url("text/html", "target".as_bytes(), "", "")
);
assert_eq!(
final_url,
utils::data_to_data_url("text/html", "target".as_bytes(), "", "")
);
assert_eq!(&media_type, "text/html");
}
#[test]
fn read_local_file_with_file_url_parent() {
let cache = &mut HashMap::new();
let client = Client::new();
let file_url_protocol: &str = if cfg!(windows) { "file:///" } else { "file://" };
// Inclusion of local assets from local sources should be allowed
let cwd = env::current_dir().unwrap();
let (data, final_url, _media_type) = utils::retrieve_asset(
cache,
&client,
&format!(
"{file}{cwd}/src/tests/data/basic/local-file.html",
file = file_url_protocol,
cwd = cwd.to_str().unwrap()
),
&format!(
"{file}{cwd}/src/tests/data/basic/local-script.js",
file = file_url_protocol,
cwd = cwd.to_str().unwrap()
),
false,
)
.unwrap();
assert_eq!(utils::data_to_data_url("application/javascript", &data, &final_url, ""), "data:application/javascript;base64,ZG9jdW1lbnQuYm9keS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSAiZ3JlZW4iOwpkb2N1bWVudC5ib2R5LnN0eWxlLmNvbG9yID0gInJlZCI7Cg==");
assert_eq!(
&final_url,
&format!(
"{file}{cwd}/src/tests/data/basic/local-script.js",
file = file_url_protocol,
cwd = cwd.to_str().unwrap()
)
);
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -79,46 +82,53 @@ fn passing_read_local_file_with_file_url_parent() {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_read_local_file_with_data_url_parent() { mod failing {
let cache = &mut HashMap::new(); use crate::utils;
let client = Client::new(); use reqwest::blocking::Client;
use std::collections::HashMap;
// Inclusion of local assets from data URL sources should not be allowed #[test]
match utils::retrieve_asset( fn read_local_file_with_data_url_parent() {
cache, let cache = &mut HashMap::new();
&client, let client = Client::new();
"data:text/html;base64,SoUrCe",
"file:///etc/passwd", // Inclusion of local assets from data URL sources should not be allowed
false, match utils::retrieve_asset(
) { cache,
Ok((..)) => { &client,
assert!(false); "data:text/html;base64,SoUrCe",
"file:///etc/passwd",
false,
) {
Ok((..)) => {
assert!(false);
}
Err(_) => {
assert!(true);
}
} }
Err(_) => { }
assert!(true);
} #[test]
} fn read_local_file_with_https_parent() {
} let cache = &mut HashMap::new();
let client = Client::new();
#[test]
fn failing_read_local_file_with_https_parent() { // Inclusion of local assets from remote sources should not be allowed
let cache = &mut HashMap::new(); match utils::retrieve_asset(
let client = Client::new(); cache,
&client,
// Inclusion of local assets from remote sources should not be allowed "https://kernel.org/",
match utils::retrieve_asset( "file:///etc/passwd",
cache, false,
&client, ) {
"https://kernel.org/", Ok((..)) => {
"file:///etc/passwd", assert!(false);
false, }
) { Err(_) => {
Ok((..)) => { assert!(true);
assert!(false); }
}
Err(_) => {
assert!(true);
} }
} }
} }

View file

@ -1,5 +1,3 @@
use crate::utils;
// ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗ // ██████╗ █████╗ ███████╗███████╗██╗███╗ ██╗ ██████╗
// ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝ // ██╔══██╗██╔══██╗██╔════╝██╔════╝██║████╗ ██║██╔════╝
// ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗ // ██████╔╝███████║███████╗███████╗██║██╔██╗ ██║██║ ███╗
@ -7,50 +5,55 @@ use crate::utils;
// ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║███████║███████║██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚══════╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn passing_mailto() { mod passing {
assert!(utils::url_has_protocol( use crate::utils;
"mailto:somebody@somewhere.com?subject=hello"
));
}
#[test] #[test]
fn passing_tel() { fn mailto() {
assert!(utils::url_has_protocol("tel:5551234567")); assert!(utils::url_has_protocol(
} "mailto:somebody@somewhere.com?subject=hello"
));
}
#[test] #[test]
fn passing_ftp_no_slashes() { fn tel() {
assert!(utils::url_has_protocol("ftp:some-ftp-server.com")); assert!(utils::url_has_protocol("tel:5551234567"));
} }
#[test] #[test]
fn passing_ftp_with_credentials() { fn ftp_no_slashes() {
assert!(utils::url_has_protocol( assert!(utils::url_has_protocol("ftp:some-ftp-server.com"));
"ftp://user:password@some-ftp-server.com" }
));
}
#[test] #[test]
fn passing_javascript() { fn ftp_with_credentials() {
assert!(utils::url_has_protocol("javascript:void(0)")); assert!(utils::url_has_protocol(
} "ftp://user:password@some-ftp-server.com"
));
}
#[test] #[test]
fn passing_http() { fn javascript() {
assert!(utils::url_has_protocol("http://news.ycombinator.com")); assert!(utils::url_has_protocol("javascript:void(0)"));
} }
#[test] #[test]
fn passing_https() { fn http() {
assert!(utils::url_has_protocol("https://github.com")); assert!(utils::url_has_protocol("http://news.ycombinator.com"));
} }
#[test] #[test]
fn passing_mailto_uppercase() { fn https() {
assert!(utils::url_has_protocol( assert!(utils::url_has_protocol("https://github.com"));
"MAILTO:somebody@somewhere.com?subject=hello" }
));
#[test]
fn mailto_uppercase() {
assert!(utils::url_has_protocol(
"MAILTO:somebody@somewhere.com?subject=hello"
));
}
} }
// ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗ // ███████╗ █████╗ ██╗██╗ ██╗███╗ ██╗ ██████╗
@ -60,24 +63,29 @@ fn passing_mailto_uppercase() {
// ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝ // ██║ ██║ ██║██║███████╗██║██║ ╚████║╚██████╔╝
// ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝ // ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚═╝╚═╝ ╚═══╝ ╚═════╝
#[test] #[cfg(test)]
fn failing_url_with_no_protocol() { mod failing {
assert!(!utils::url_has_protocol( use crate::utils;
"//some-hostname.com/some-file.html"
));
}
#[test] #[test]
fn failing_relative_path() { fn url_with_no_protocol() {
assert!(!utils::url_has_protocol("some-hostname.com/some-file.html")); assert!(!utils::url_has_protocol(
} "//some-hostname.com/some-file.html"
));
}
#[test] #[test]
fn failing_relative_to_root_path() { fn relative_path() {
assert!(!utils::url_has_protocol("/some-file.html")); assert!(!utils::url_has_protocol("some-hostname.com/some-file.html"));
} }
#[test] #[test]
fn failing_empty_string() { fn relative_to_root_path() {
assert!(!utils::url_has_protocol("")); assert!(!utils::url_has_protocol("/some-file.html"));
}
#[test]
fn empty_string() {
assert!(!utils::url_has_protocol(""));
}
} }