624 lines
20 KiB
Rust
624 lines
20 KiB
Rust
fn eval_with_cfg(src: &'static [u8], expected: &'static [u8], cfg: &super::Cfg) {
|
|
let mut code = src.to_vec();
|
|
let min = super::minify(&mut code, cfg);
|
|
assert_eq!(
|
|
std::str::from_utf8(&min).unwrap(),
|
|
std::str::from_utf8(expected).unwrap(),
|
|
);
|
|
}
|
|
|
|
fn eval(src: &'static [u8], expected: &'static [u8]) {
|
|
eval_with_cfg(src, expected, &super::Cfg::new());
|
|
}
|
|
|
|
fn eval_with_keep_html_head(src: &'static [u8], expected: &'static [u8]) -> () {
|
|
let mut cfg = super::Cfg::new();
|
|
cfg.keep_html_and_head_opening_tags = true;
|
|
eval_with_cfg(src, expected, &cfg);
|
|
}
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
fn eval_with_js_min(src: &'static [u8], expected: &'static [u8]) -> () {
|
|
let mut cfg = super::Cfg::new();
|
|
cfg.minify_js = true;
|
|
eval_with_cfg(src, expected, &cfg);
|
|
}
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
fn eval_with_css_min(src: &'static [u8], expected: &'static [u8]) -> () {
|
|
let mut cfg = super::Cfg::new();
|
|
cfg.minify_css = true;
|
|
eval_with_cfg(src, expected, &cfg);
|
|
}
|
|
|
|
#[test]
|
|
fn test_collapse_whitespace() {
|
|
eval(b"<a> \n  </a>", b"<a> </a>");
|
|
// Tag names should be case insensitive.
|
|
eval(b"<A> \n  </a>", b"<a> </a>");
|
|
eval(b"<a> \n  </A>", b"<a> </a>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_collapse_and_trim_whitespace() {
|
|
eval(b"<label> \n  </label>", b"<label></label>");
|
|
eval(b"<label> \n a </label>", b"<label>a</label>");
|
|
eval(b"<label> \n a b </label>", b"<label>a b</label>");
|
|
// Tag names should be case insensitive.
|
|
eval(b"<lAbEL> \n a b </LABel>", b"<label>a b</label>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_collapse_destroy_whole_and_trim_whitespace() {
|
|
eval(b"<ul> \n  </ul>", b"<ul></ul>");
|
|
eval(b"<ul> \n a </ul>", b"<ul>a</ul>");
|
|
eval(b"<ul> \n a b </ul>", b"<ul>a b</ul>");
|
|
eval(
|
|
b"<ul> \n a<pre></pre> <pre></pre>b </ul>",
|
|
b"<ul>a<pre></pre><pre></pre>b</ul>",
|
|
);
|
|
// Tag names should be case insensitive.
|
|
eval(b"<uL> \n a b </UL>", b"<ul>a b</ul>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_no_whitespace_minification() {
|
|
eval(b"<pre> \n  \t </pre>", b"<pre> \n \t </pre>");
|
|
eval(
|
|
b"<textarea> \n  \t </textarea>",
|
|
b"<textarea> \n \t </textarea>",
|
|
);
|
|
// Tag names should be case insensitive.
|
|
eval(b"<pRe> \n  \t </PRE>", b"<pre> \n \t </pre>");
|
|
eval(
|
|
b"<pre> <span> 1 2 </span> </pre>",
|
|
b"<pre> <span> 1 2 </span> </pre>",
|
|
);
|
|
eval(
|
|
b"<pre> <span> 1 <pre>\n</pre> 2 </span> </pre>",
|
|
b"<pre> <span> 1 <pre>\n</pre> 2 </span> </pre>",
|
|
);
|
|
eval(
|
|
b"<div> <pre> <span> 1 <pre>\n</pre> 2 </span> </pre> </div>",
|
|
b"<div><pre> <span> 1 <pre>\n</pre> 2 </span> </pre></div>",
|
|
);
|
|
eval(
|
|
br#"<pre><code>fn main() {
|
|
println!("Hello, world!");
|
|
<span>loop {
|
|
println!("Hello, world!");
|
|
}</span>
|
|
}
|
|
</code></pre>"#,
|
|
br#"<pre><code>fn main() {
|
|
println!("Hello, world!");
|
|
<span>loop {
|
|
println!("Hello, world!");
|
|
}</span>
|
|
}
|
|
</code></pre>"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parsing_extra_head_tag() {
|
|
// Extra `<head>` in `<label>` should be dropped, so whitespace around `<head>` should be joined and therefore trimmed due to `<label>` whitespace rules.
|
|
eval_with_keep_html_head(
|
|
b"<html><head><meta><head><link><head><body><label> <pre> </pre> <head> </label>",
|
|
b"<html><head><meta><link><body><label><pre> </pre></label>",
|
|
);
|
|
// Same as above except it's a `</head>`, which should get reinterpreted as a `<head>`.
|
|
eval_with_keep_html_head(
|
|
b"<html><head><meta><head><link><head><body><label> <pre> </pre> </head> </label>",
|
|
b"<html><head><meta><link><body><label><pre> </pre></label>",
|
|
);
|
|
// `<head>` gets implicitly closed by `<body>`, so any following `</head>` should be ignored. (They should be anyway, since `</head>` would not be a valid closing tag.)
|
|
eval_with_keep_html_head(
|
|
b"<html><head><body><label> </head> </label>",
|
|
b"<html><head><body><label></label>",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parsing_omitted_closing_tag() {
|
|
eval_with_keep_html_head(b"<html>", b"<html>");
|
|
eval_with_keep_html_head(b" <html>\n", b"<html>");
|
|
eval_with_keep_html_head(b" <!doctype html> <html>\n", b"<!doctype html><html>");
|
|
eval_with_keep_html_head(
|
|
b"<!doctype html><html><div> <p>Foo</div></html>",
|
|
b"<!doctype html><html><div><p>Foo</div>",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_self_closing_svg_tag_whitespace_removal() {
|
|
eval(b"<svg><path d=a /></svg>", b"<svg><path d=a /></svg>");
|
|
eval(b"<svg><path d=a/ /></svg>", b"<svg><path d=a/ /></svg>");
|
|
eval(b"<svg><path d=\"a/\" /></svg>", b"<svg><path d=a/ /></svg>");
|
|
eval(b"<svg><path d=\"a/\"/></svg>", b"<svg><path d=a/ /></svg>");
|
|
eval(b"<svg><path d='a/' /></svg>", b"<svg><path d=a/ /></svg>");
|
|
eval(b"<svg><path d='a/'/></svg>", b"<svg><path d=a/ /></svg>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_parsing_with_omitted_tags() {
|
|
eval_with_keep_html_head(b"<ul><li>1<li>2<li>3</ul>", b"<ul><li>1<li>2<li>3</ul>");
|
|
eval_with_keep_html_head(b"<rt>", b"<rt>");
|
|
eval_with_keep_html_head(b"<rt><rp>1</rp><div></div>", b"<rt><rp>1</rp><div></div>");
|
|
eval_with_keep_html_head(b"<div><rt></div>", b"<div><rt></div>");
|
|
eval_with_keep_html_head(b"<html><head><body>", b"<html><head><body>");
|
|
eval_with_keep_html_head(b"<html><head><body>", b"<html><head><body>");
|
|
// Tag names should be case insensitive.
|
|
eval_with_keep_html_head(b"<rt>", b"<rt>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_unmatched_closing_tag() {
|
|
eval_with_keep_html_head(b"Hello</p>Goodbye", b"Hello<p>Goodbye");
|
|
eval_with_keep_html_head(b"Hello<br></br>Goodbye", b"Hello<br>Goodbye");
|
|
eval_with_keep_html_head(b"<div>Hello</p>Goodbye", b"<div>Hello<p>Goodbye");
|
|
eval_with_keep_html_head(b"<ul><li>a</p>", b"<ul><li>a<p>");
|
|
eval_with_keep_html_head(b"<ul><li><rt>a</p>", b"<ul><li><rt>a<p>");
|
|
eval_with_keep_html_head(
|
|
b"<html><head><body><ul><li><rt>a</p>",
|
|
b"<html><head><body><ul><li><rt>a<p>",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_removal_of_html_and_head_opening_tags() {
|
|
// Even though `<head>` is dropped, it's still parsed, so its content is still subject to `<head>` whitespace minification rules.
|
|
eval(
|
|
b"<!DOCTYPE html><html><head> <meta> <body>",
|
|
b"<!DOCTYPE html><meta><body>",
|
|
);
|
|
// The tag should not be dropped if it has attributes.
|
|
eval(
|
|
b"<!DOCTYPE html><html lang=en><head> <meta> <body>",
|
|
b"<!DOCTYPE html><html lang=en><meta><body>",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_removal_of_optional_tags() {
|
|
eval_with_keep_html_head(
|
|
b"<ul><li>1</li><li>2</li><li>3</li></ul>",
|
|
b"<ul><li>1<li>2<li>3</ul>",
|
|
);
|
|
eval_with_keep_html_head(b"<rt></rt>", b"<rt>");
|
|
eval_with_keep_html_head(
|
|
b"<rt></rt><rp>1</rp><div></div>",
|
|
b"<rt><rp>1</rp><div></div>",
|
|
);
|
|
eval_with_keep_html_head(b"<div><rt></rt></div>", b"<div><rt></div>");
|
|
eval_with_keep_html_head(
|
|
br#"
|
|
<html>
|
|
<head>
|
|
</head>
|
|
|
|
<body>
|
|
</body>
|
|
</html>
|
|
"#,
|
|
b"<html><head><body>",
|
|
);
|
|
// Tag names should be case insensitive.
|
|
eval_with_keep_html_head(b"<RT></rt>", b"<rt>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_removal_of_optional_closing_p_tag() {
|
|
eval(b"<p></p><address></address>", b"<p><address></address>");
|
|
eval(b"<p></p>", b"<p>");
|
|
eval(b"<map><p></p></map>", b"<map><p></p></map>");
|
|
eval(
|
|
b"<map><p></p><address></address></map>",
|
|
b"<map><p><address></address></map>",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_attr_double_quoted_value_minification() {
|
|
eval(b"<a b=\" hello \"></a>", b"<a b=\" hello \"></a>");
|
|
eval(b"<a b=' hello '></a>", b"<a b=\" hello \"></a>");
|
|
eval(br#"<a b="/>aaaa"></a>"#, br#"<a b="/>aaaa"></a>"#);
|
|
eval(br#"<a b="</a>a"></a>"#, br#"<a b="</a>a"></a>"#);
|
|
eval(b"<a b= hello ></a>", b"<a b=\" hello \"></a>");
|
|
eval(b"<a b= hello ></a>", b"<a b=\" hello \"></a>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_attr_single_quoted_value_minification() {
|
|
eval(b"<a b=\""hello\"></a>", b"<a b='\"hello'></a>");
|
|
eval(b"<a b='\"hello'></a>", b"<a b='\"hello'></a>");
|
|
eval(b"<a b='/>a'></a>", b"<a b=\"/>a\"></a>");
|
|
eval(
|
|
b"<a b= he"llo ></a>",
|
|
b"<a b=' he\"llo '></a>",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_attr_unquoted_value_minification() {
|
|
eval(b"<a b==></a>", b"<a b==></a>");
|
|
eval(b"<a b=`'\"<<==/`/></a>", b"<a b=`'\"<<==/`/></a>");
|
|
eval(b"<a b=\"hello\"></a>", b"<a b=hello></a>");
|
|
eval(b"<a b='hello'></a>", b"<a b=hello></a>");
|
|
eval(b"<a b=/>></a>", br#"<a b="/>"></a>"#);
|
|
eval(b"<a b=/><a></a>", br#"<a b="/><a"></a>"#);
|
|
eval(b"<a b=hello></a>", b"<a b=hello></a>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_attr_whatwg_unquoted_value_minification() {
|
|
let mut cfg = super::Cfg::new();
|
|
cfg.ensure_spec_compliant_unquoted_attribute_values = true;
|
|
eval_with_cfg(b"<a b==></a>", br#"<a b="="></a>"#, &cfg);
|
|
eval_with_cfg(
|
|
br#"<a b=`'"<<==/`/></a>"#,
|
|
br#"<a b="`'"<<==/`/"></a>"#,
|
|
&cfg,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_class_attr_value_minification() {
|
|
eval(b"<a class= c></a>", b"<a class=c></a>");
|
|
eval(
|
|
b"<a class= c  d ></a>",
|
|
b"<a class=\"c d\"></a>",
|
|
);
|
|
eval(b"<a class=    ></a>", b"<a></a>");
|
|
eval(b"<a class=\" c\n \n \"></a>", b"<a class=c></a>");
|
|
eval(b"<a class=\" c\n \nd \"></a>", b"<a class=\"c d\"></a>");
|
|
eval(b"<a class=\" \n \n \"></a>", b"<a></a>");
|
|
eval(b"<a class=' c\n \n '></a>", b"<a class=c></a>");
|
|
eval(b"<a class=' c\n \nd '></a>", b"<a class=\"c d\"></a>");
|
|
eval(b"<a class=' \n \n '></a>", b"<a></a>");
|
|
// Attribute names should be case insensitive.
|
|
eval(b"<a CLasS=' \n \n '></a>", b"<a></a>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_d_attr_value_minification() {
|
|
eval(b"<svg><path d= c /></svg>", b"<svg><path d=c /></svg>");
|
|
eval(
|
|
b"<svg><path d= c  d  /></svg>",
|
|
b"<svg><path d=\"c d\"/></svg>",
|
|
);
|
|
eval(
|
|
b"<svg><path d=     /></svg>",
|
|
b"<svg><path/></svg>",
|
|
);
|
|
eval(
|
|
b"<svg><path d=\" c\n \n \" /></svg>",
|
|
b"<svg><path d=c /></svg>",
|
|
);
|
|
eval(
|
|
b"<svg><path d=\" c\n \nd \" /></svg>",
|
|
b"<svg><path d=\"c d\"/></svg>",
|
|
);
|
|
eval(
|
|
b"<svg><path d=\" \n \n \" /></svg>",
|
|
b"<svg><path/></svg>",
|
|
);
|
|
eval(
|
|
b"<svg><path d=' c\n \n ' /></svg>",
|
|
b"<svg><path d=c /></svg>",
|
|
);
|
|
eval(
|
|
b"<svg><path d=' c\n \nd ' /></svg>",
|
|
b"<svg><path d=\"c d\"/></svg>",
|
|
);
|
|
eval(b"<svg><path d=' \n \n ' /></svg>", b"<svg><path/></svg>");
|
|
// Attribute names should be case insensitive.
|
|
eval(b"<svg><path D=' \n \n ' /></svg>", b"<svg><path/></svg>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_boolean_attr_value_removal() {
|
|
eval(b"<div hidden=\"true\"></div>", b"<div hidden></div>");
|
|
eval(b"<div hidden=\"false\"></div>", b"<div hidden></div>");
|
|
eval(b"<div hidden=\"1\"></div>", b"<div hidden></div>");
|
|
eval(b"<div hidden=\"0\"></div>", b"<div hidden></div>");
|
|
eval(b"<div hidden=\"abc\"></div>", b"<div hidden></div>");
|
|
eval(b"<div hidden=\"\"></div>", b"<div hidden></div>");
|
|
eval(b"<div hidden></div>", b"<div hidden></div>");
|
|
// Attribute names should be case insensitive.
|
|
eval(b"<div HIDden=\"true\"></div>", b"<div hidden></div>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_empty_attr_removal() {
|
|
eval(b"<div lang=\" \"></div>", b"<div lang=\" \"></div>");
|
|
eval(b"<div lang=\"\"></div>", b"<div></div>");
|
|
eval(b"<div lang=''></div>", b"<div></div>");
|
|
eval(b"<div lang=></div>", b"<div></div>");
|
|
eval(b"<div lang></div>", b"<div></div>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_default_attr_value_removal() {
|
|
eval(b"<a target=\"_self\"></a>", b"<a></a>");
|
|
eval(b"<a target='_self'></a>", b"<a></a>");
|
|
eval(b"<a target=_self></a>", b"<a></a>");
|
|
// Attribute names should be case insensitive.
|
|
eval(b"<a taRGET='_self'></a>", b"<a></a>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_script_type_attr_value_removal() {
|
|
eval(
|
|
b"<script type=\"application/ecmascript\"></script>",
|
|
b"<script></script>",
|
|
);
|
|
eval(
|
|
b"<script type=\"application/javascript\"></script>",
|
|
b"<script></script>",
|
|
);
|
|
eval(
|
|
b"<script type=\"text/jscript\"></script>",
|
|
b"<script></script>",
|
|
);
|
|
eval(
|
|
b"<script type=\"text/plain\"></script>",
|
|
b"<script type=text/plain></script>",
|
|
);
|
|
// Tag and attribute names should be case insensitive.
|
|
eval(
|
|
b"<SCRipt TYPE=\"application/ecmascript\"></SCrIPT>",
|
|
b"<script></script>",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_empty_attr_value_removal() {
|
|
eval(b"<div a=\" \"></div>", b"<div a=\" \"></div>");
|
|
eval(b"<div a=\"\"></div>", b"<div a></div>");
|
|
eval(b"<div a=''></div>", b"<div a></div>");
|
|
eval(b"<div a=></div>", b"<div a></div>");
|
|
eval(b"<div a></div>", b"<div a></div>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_space_between_attrs_minification() {
|
|
eval(
|
|
b"<div a=\" \" b=\" \"></div>",
|
|
b"<div a=\" \"b=\" \"></div>",
|
|
);
|
|
eval(b"<div a=' ' b=\" \"></div>", b"<div a=\" \"b=\" \"></div>");
|
|
eval(
|
|
b"<div a=  b=\" \"></div>",
|
|
b"<div a=\" \"b=\" \"></div>",
|
|
);
|
|
eval(b"<div a=\"1\" b=\" \"></div>", b"<div a=1 b=\" \"></div>");
|
|
eval(b"<div a='1' b=\" \"></div>", b"<div a=1 b=\" \"></div>");
|
|
eval(b"<div a=\"a\"b=\"b\"></div>", b"<div a=a b=b></div>");
|
|
}
|
|
|
|
#[test]
|
|
fn test_hexadecimal_entity_decoding() {
|
|
eval(b".", b".");
|
|
eval(b"/", b"/");
|
|
eval(b"/", b"/");
|
|
eval(b"�", b"\0");
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"ᅑ", b"\xe1\x85\x91");
|
|
eval(b"�", b"\xef\xbf\xbd");
|
|
eval(
|
|
b"�",
|
|
b"\xef\xbf\xbd",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_decimal_entity_decoding() {
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"0", b"0");
|
|
eval(b"ᅑ", b"\xe1\x85\x91");
|
|
eval(b"�", b"\xef\xbf\xbd");
|
|
eval(
|
|
b"�",
|
|
b"\xef\xbf\xbd",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_named_entity_decoding() {
|
|
eval(b">", b">");
|
|
eval(b">", b">");
|
|
eval(b"&", b"&");
|
|
eval(b"&", b"&");
|
|
eval(b"&xxxyyyzzz", b"&xxxyyyzzz");
|
|
eval(b"&ere", b"&ere");
|
|
eval(b"They & Co.", b"They & Co.");
|
|
eval(b"if (this && that)", b"if (this && that)");
|
|
// These entities decode to longer UTF-8 sequences, so we keep them encoded.
|
|
eval(b"≪⃒", b"≪⃒");
|
|
eval(b"≪⃒abc", b"≪⃒abc");
|
|
eval(b"≫⃒", b"≫⃒");
|
|
|
|
// Named entities not ending with ';' in attr values are not decoded if immediately
|
|
// followed by an alphanumeric or `=` character. (See parser for more details.)
|
|
eval(
|
|
br#"<a href="exam ple?>a=5"></a>"#,
|
|
br#"<a href="exam ple?>a=5"></a>"#,
|
|
);
|
|
eval(
|
|
br#"<a href="exam ple?>=5"></a>"#,
|
|
br#"<a href="exam ple?>=5"></a>"#,
|
|
);
|
|
eval(
|
|
br#"<a href="exam ple?>~5"></a>"#,
|
|
br#"<a href="exam ple?>~5"></a>"#,
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_unintentional_entity_prevention() {
|
|
eval(b"&amp", b"&amp");
|
|
eval(b"&amp;", b"&amp;");
|
|
eval(b"&amp", b"&amp");
|
|
eval(b"&amp;", b"&amp;");
|
|
eval(b"&amp;", b"&amp;");
|
|
eval(b"&amp;", b"&amp;");
|
|
eval(b"&amp", b"&amp");
|
|
eval(b"&amp", b"&amp");
|
|
eval(b"&amp;", b"&amp;");
|
|
eval(b"&amp;", b"&amp;");
|
|
eval(b"&amp;", b"&amp;");
|
|
eval(b"&amp;", b"&amp;");
|
|
|
|
eval(b"&lt", b"&lt");
|
|
eval(b"&lt", b"&lt");
|
|
eval(b"&lt;", b"&lt;");
|
|
eval(b"&lt;", b"&lt;");
|
|
eval(b"&lt", b"&lt");
|
|
eval(b"&lt;", b"&lt;");
|
|
|
|
eval(b"&am&amp", b"&am&amp");
|
|
eval(b"&am&amp;", b"&am&amp;");
|
|
|
|
eval(b"&≪⃒", b"&≪⃒");
|
|
eval(b"&am≪⃒", b"&am≪⃒");
|
|
eval(b"&am≪⃒a", b"&am≪⃒a");
|
|
eval(b"&am&nLt", b"&am&nLt");
|
|
}
|
|
|
|
#[test]
|
|
fn test_left_chevron_in_content() {
|
|
eval(b"<pre><</pre>", b"<pre><</pre>");
|
|
eval(b"<pre>< </pre>", b"<pre>< </pre>");
|
|
eval(b"<pre> < </pre>", b"<pre> < </pre>");
|
|
|
|
eval(b"<pre> <a </pre>", b"<pre> <a </pre>");
|
|
eval(b"<pre> <a </pre>", b"<pre> <a </pre>");
|
|
eval(b"<pre> <a </pre>", b"<pre> <a </pre>");
|
|
eval(b"<pre> <a </pre>", b"<pre> <a </pre>");
|
|
|
|
eval(b"<pre> <? </pre>", b"<pre> <? </pre>");
|
|
eval(b"<pre> <? </pre>", b"<pre> <? </pre>");
|
|
eval(b"<pre> <? </pre>", b"<pre> <? </pre>");
|
|
eval(b"<pre> <? </pre>", b"<pre> <? </pre>");
|
|
|
|
eval(b"<pre> </ </pre>", b"<pre> </ </pre>");
|
|
eval(b"<pre> <! </pre>", b"<pre> <! </pre>");
|
|
|
|
eval(b"<", b"<");
|
|
eval(b"<", b"<");
|
|
eval(b"<;", b"<;");
|
|
eval(b"<;", b"<;");
|
|
eval(b"<;", b"<;");
|
|
eval(b"<", b"<");
|
|
eval(b"<", b"<");
|
|
eval(b"<;", b"<;");
|
|
eval(b"<;", b"<;");
|
|
eval(b"<;", b"<;");
|
|
|
|
eval(b"<a", b"<a");
|
|
eval(b"<a", b"<a");
|
|
eval(b"<a;", b"<a;");
|
|
eval(b"<a;", b"<a;");
|
|
eval(b"<a;", b"<a;");
|
|
eval(b"<a;;", b"<a;;");
|
|
|
|
eval(b"<!", b"<!");
|
|
eval(b"<&", b"<&");
|
|
eval(b"</", b"</");
|
|
eval(b"<?", b"<?");
|
|
eval(b"<@", b"<@");
|
|
}
|
|
|
|
#[test]
|
|
fn test_comments_removal() {
|
|
eval(
|
|
b"<pre>a <!-- akd--sj\n <!-- \t\0f--ajk--df->lafj --> b</pre>",
|
|
b"<pre>a b</pre>",
|
|
);
|
|
eval(b"&a<!-- akd--sj\n <!-- \t\0f--ajk--df->lafj -->mp", b"&");
|
|
eval(
|
|
b"<script><!-- akd--sj\n <!-- \t\0f--ajk--df->lafj --></script>",
|
|
b"<script><!-- akd--sj\n <!-- \t\0f--ajk--df->lafj --></script>",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_processing_instructions() {
|
|
eval(b"<?php hello??? >> ?>", b"<?php hello??? >> ?>");
|
|
eval(b"av<?xml 1.0 ?>g", b"av<?xml 1.0 ?>g");
|
|
}
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
#[test]
|
|
fn test_js_minification() {
|
|
eval_with_js_min(b"<script>let a = 1;</script>", b"<script>let a=1;</script>");
|
|
eval_with_js_min(
|
|
br#"
|
|
<script>let a = 1;</script>
|
|
<script>let b = 2;</script>
|
|
"#,
|
|
b"<script>let a=1;</script><script>let b=2;</script>",
|
|
);
|
|
eval_with_js_min(
|
|
b"<scRIPt type=text/plain> alert(1.00000); </scripT>",
|
|
b"<script type=text/plain> alert(1.00000); </script>",
|
|
);
|
|
eval_with_js_min(
|
|
br#"
|
|
<script>
|
|
// This is a comment.
|
|
let a = 1;
|
|
</script>
|
|
"#,
|
|
b"<script>let a=1;</script>",
|
|
);
|
|
}
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
#[test]
|
|
fn test_js_minification_unintentional_closing_tag() {
|
|
eval_with_js_min(
|
|
br#"<script>let a = "</" + "script>";</script>"#,
|
|
br#"<script>let a="<\/script>";</script>"#,
|
|
);
|
|
eval_with_js_min(
|
|
br#"<script>let a = "</S" + "cRiPT>";</script>"#,
|
|
br#"<script>let a="<\/ScRiPT>";</script>"#,
|
|
);
|
|
eval_with_js_min(
|
|
br#"<script>let a = "\u003c/script>";</script>"#,
|
|
br#"<script>let a="<\/script>";</script>"#,
|
|
);
|
|
eval_with_js_min(
|
|
br#"<script>let a = "\u003c/scrIPt>";</script>"#,
|
|
br#"<script>let a="<\/scrIPt>";</script>"#,
|
|
);
|
|
}
|
|
|
|
#[cfg(feature = "js-esbuild")]
|
|
#[test]
|
|
fn test_css_minification() {
|
|
// `<style>` contents.
|
|
eval_with_css_min(
|
|
b"<style>div { color: yellow }</style>",
|
|
b"<style>div{color:#ff0}</style>",
|
|
);
|
|
// `style` attributes.
|
|
eval_with_css_min(
|
|
br#"<div style="color: yellow;"></div>"#,
|
|
br#"<div style=color:#ff0></div>"#,
|
|
);
|
|
// `style` attributes are removed if fully minified away.
|
|
eval_with_css_min(br#"<div style=" /* */ "></div>"#, br#"<div></div>"#);
|
|
}
|