2021-08-09 09:11:24 -04:00
use std ::str ::from_utf8 ;
use crate ::cfg ::Cfg ;
use crate ::minify ;
pub fn eval_with_cfg ( src : & 'static [ u8 ] , expected : & 'static [ u8 ] , cfg : & Cfg ) {
let min = minify ( & src , cfg ) ;
assert_eq! ( from_utf8 ( & min ) . unwrap ( ) , from_utf8 ( expected ) . unwrap ( ) , ) ;
}
#[ cfg(feature = " js-esbuild " ) ]
pub fn eval_with_js_min ( src : & 'static [ u8 ] , expected : & 'static [ u8 ] ) -> ( ) {
let mut cfg = Cfg ::new ( ) ;
cfg . minify_js = true ;
eval_with_cfg ( src , expected , & cfg ) ;
}
#[ cfg(feature = " js-esbuild " ) ]
pub fn eval_with_css_min ( src : & 'static [ u8 ] , expected : & 'static [ u8 ] ) -> ( ) {
let mut cfg = Cfg ::new ( ) ;
cfg . minify_css = true ;
eval_with_cfg ( src , expected , & cfg ) ;
}
pub fn eval ( src : & 'static [ u8 ] , expected : & 'static [ u8 ] ) {
let mut cfg = Cfg ::new ( ) ;
// Most common tests assume the following minifications aren't done.
cfg . keep_html_and_head_opening_tags = true ;
eval_with_cfg ( src , expected , & cfg ) ;
}
fn eval_without_keep_html_head ( src : & 'static [ u8 ] , expected : & 'static [ u8 ] ) -> ( ) {
eval_with_cfg ( src , expected , & Cfg ::new ( ) ) ;
}
2021-08-09 12:56:48 -04:00
#[ test ]
fn test_minification_of_doctype ( ) {
eval ( b " <!DOCTYPE html><html> " , b " <!doctypehtml><html> " ) ;
eval (
b " <!DOCTYPE html SYSTEM 'about:legacy-compat'><html> " ,
b " <!doctypehtml SYSTEM 'about:legacy-compat'><html> " ,
) ;
}
2021-08-09 09:11:24 -04:00
#[ 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 (
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 (
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 (
b " <html><head><body><label> </head> </label> " ,
b " <html><head><body><label></label> " ,
) ;
}
#[ 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_without_keep_html_head (
b " <!DOCTYPE html><html><head> <meta> <body> " ,
2021-08-09 12:56:48 -04:00
b " <!doctypehtml><meta><body> " ,
2021-08-09 09:11:24 -04:00
) ;
// The tag should not be dropped if it has attributes.
eval_without_keep_html_head (
b " <!DOCTYPE html><html lang=en><head> <meta> <body> " ,
2021-08-09 12:56:48 -04:00
b " <!doctypehtml><html lang=en><meta><body> " ,
2021-08-09 09:11:24 -04:00
) ;
// The tag should be dropped if it has no attributes after minification.
eval_without_keep_html_head (
b " <!DOCTYPE html><html style=' '><head> <meta> <body> " ,
2021-08-09 12:56:48 -04:00
b " <!doctypehtml><meta><body> " ,
2021-08-09 09:11:24 -04:00
) ;
}
#[ test ]
fn test_unmatched_closing_tag ( ) {
eval ( b " Hello</p>Goodbye " , b " Hello<p>Goodbye " ) ;
eval ( b " Hello<br></br>Goodbye " , b " Hello<br>Goodbye " ) ;
eval ( b " <div>Hello</p>Goodbye " , b " <div>Hello<p>Goodbye " ) ;
eval ( b " <ul><li>a</p> " , b " <ul><li>a<p> " ) ;
eval ( b " <ul><li><rt>a</p> " , b " <ul><li><rt>a<p> " ) ;
eval (
b " <html><head><body><ul><li><rt>a</p> " ,
b " <html><head><body><ul><li><rt>a<p> " ,
) ;
}
#[ test ]
// NOTE: Keep inputs in sync with onepass variant. Outputs are different as main variant reorders attributes.
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 b= \" \" a=1></div> " ) ;
eval ( b " <div a='1' b= \" \" ></div> " , b " <div b= \" \" a=1></div> " ) ;
eval ( b " <div a= \" a \" b= \" b \" ></div> " , b " <div a=a b=b></div> " ) ;
}
#[ test ]
fn test_attr_whatwg_unquoted_value_minification ( ) {
let mut cfg = 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 ,
) ;
}
2021-08-09 12:56:48 -04:00
#[ test ]
fn test_viewport_attr_minification ( ) {
eval (
b " <meta name=viewport content='width=device-width, initial-scale=1'> " ,
b " <meta content=width=device-width,initial-scale=1 name=viewport> " ,
) ;
}
2021-08-09 09:11:24 -04:00
#[ cfg(feature = " js-esbuild " ) ]
#[ test ]
fn test_style_attr_minification ( ) {
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>"# ) ;
}