Skip to content

Commit 3965f88

Browse files
committed
test: Add more tests
1 parent 1ed7a42 commit 3965f88

File tree

5 files changed

+132
-8
lines changed

5 files changed

+132
-8
lines changed

css-inline/src/html/attributes.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ impl Class {
114114
if bloom_filter.might_have_class(name) {
115115
self.has_class_impl(name, case_sensitivity)
116116
} else {
117-
// Class is not in the Bloom filter, hence the this `class` value does not
117+
// Class is not in the Bloom filter, hence this `class` value does not
118118
// contain the given class
119119
false
120120
}
@@ -184,3 +184,20 @@ impl Attributes {
184184
self.find(&needle)
185185
}
186186
}
187+
188+
#[cfg(test)]
189+
mod tests {
190+
use super::Class;
191+
use selectors::attr::CaseSensitivity;
192+
use test_case::test_case;
193+
194+
#[test_case("a b")]
195+
#[test_case("a")]
196+
fn test_has_class(value: &str) {
197+
let class = Class::new(value.into());
198+
assert!(class.has_class(b"a", CaseSensitivity::CaseSensitive));
199+
assert!(class.has_class(b"A", CaseSensitivity::AsciiCaseInsensitive));
200+
assert!(!class.has_class(b"c", CaseSensitivity::CaseSensitive));
201+
assert!(!class.has_class(b"C", CaseSensitivity::AsciiCaseInsensitive));
202+
}
203+
}

css-inline/src/html/document.rs

+40
Original file line numberDiff line numberDiff line change
@@ -448,4 +448,44 @@ mod tests {
448448
let output = roundtrip(b"<html><head><title>Title of the document</title></head><body><!--TTT--></body></html>");
449449
assert_eq!(output, b"<html><head><title>Title of the document</title></head><body><!--TTT--></body></html>");
450450
}
451+
452+
#[test]
453+
fn test_debug() {
454+
let doc =
455+
Document::parse_with_options(b"<html><body></body></html>", 0, InliningMode::Document);
456+
assert_eq!(format!("{doc:?}"), "Document { nodes: [Node { parent: None, next_sibling: None, previous_sibling: None, first_child: None, last_child: None, data: Document }, Node { parent: None, next_sibling: None, previous_sibling: None, first_child: Some(NodeId(2)), last_child: Some(NodeId(2)), data: Document }, Node { parent: Some(NodeId(1)), next_sibling: None, previous_sibling: None, first_child: Some(NodeId(3)), last_child: Some(NodeId(4)), data: Element { element: ElementData { name: QualName { prefix: None, ns: Atom('http://www.w3.org/1999/xhtml' type=static), local: Atom('html' type=static) }, attributes: Attributes { attributes: [], class: None } }, inlining_ignored: false } }, Node { parent: Some(NodeId(2)), next_sibling: Some(NodeId(4)), previous_sibling: None, first_child: None, last_child: None, data: Element { element: ElementData { name: QualName { prefix: None, ns: Atom('http://www.w3.org/1999/xhtml' type=static), local: Atom('head' type=static) }, attributes: Attributes { attributes: [], class: None } }, inlining_ignored: false } }, Node { parent: Some(NodeId(2)), next_sibling: None, previous_sibling: Some(NodeId(3)), first_child: None, last_child: None, data: Element { element: ElementData { name: QualName { prefix: None, ns: Atom('http://www.w3.org/1999/xhtml' type=static), local: Atom('body' type=static) }, attributes: Attributes { attributes: [], class: None } }, inlining_ignored: false } }], styles: [], linked_stylesheets: [], .. }");
457+
}
458+
459+
#[test]
460+
fn test_edit_document() {
461+
let mut doc = Document::parse_with_options(
462+
b"<html><body><a></a><b></b></body></html>",
463+
0,
464+
InliningMode::Document,
465+
);
466+
let a_id = NodeId::new(5);
467+
assert_eq!(
468+
doc[a_id].as_element().expect("Element does not exist").name,
469+
QualName::new(None, ns!(html), local_name!("a"))
470+
);
471+
let b_id = NodeId::new(6);
472+
assert_eq!(
473+
doc[b_id].as_element().expect("Element does not exist").name,
474+
QualName::new(None, ns!(html), local_name!("b"))
475+
);
476+
// `a` is the previous sibling of `b`
477+
// `b` is the next sibling of `a`
478+
assert_eq!(doc[b_id].previous_sibling, Some(a_id));
479+
assert_eq!(doc[a_id].next_sibling, Some(b_id));
480+
// Detach `b`, so it has no previous sibling
481+
// And `a` has not next sibling
482+
doc.detach(b_id);
483+
assert_eq!(doc[b_id].previous_sibling, None);
484+
assert_eq!(doc[a_id].next_sibling, None);
485+
let head_id = NodeId::new(3);
486+
let body_id = NodeId::new(4);
487+
// Detach `head`, so previous sibling of `body` is empty
488+
doc.detach(head_id);
489+
assert_eq!(doc[body_id].next_sibling, None);
490+
}
451491
}

css-inline/src/html/serializer.rs

+22
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,28 @@ mod tests {
607607
assert_eq!(buffer, b"<!DOCTYPE html><html><head><title>&amp; &lt; &gt; &nbsp;</title></head><body></body></html>");
608608
}
609609

610+
#[test]
611+
fn test_untouched_style() {
612+
let doc = Document::parse_with_options(
613+
b"<html><body><p style=\"color:blue;\"></p></body></html>",
614+
0,
615+
InliningMode::Document,
616+
);
617+
let mut buffer = Vec::new();
618+
doc.serialize(
619+
&mut buffer,
620+
IndexMap::default(),
621+
false,
622+
false,
623+
InliningMode::Document,
624+
)
625+
.expect("Should not fail");
626+
assert_eq!(
627+
buffer,
628+
b"<html><head></head><body><p style=\"color:blue;\"></p></body></html>"
629+
);
630+
}
631+
610632
#[test]
611633
fn test_attributes() {
612634
let doc = Document::parse_with_options(

css-inline/src/resolver.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ pub trait StylesheetResolver: Send + Sync {
1717

1818
#[cfg(not(feature = "http"))]
1919
{
20-
Err(InlineError::IO(std::io::Error::new(
20+
Err(std::io::Error::new(
2121
ErrorKind::Unsupported,
2222
"Loading external URLs requires the `http` feature",
23-
)))
23+
)
24+
.into())
2425
}
2526
} else {
2627
#[cfg(feature = "file")]
@@ -29,10 +30,11 @@ pub trait StylesheetResolver: Send + Sync {
2930
}
3031
#[cfg(not(feature = "file"))]
3132
{
32-
Err(InlineError::IO(std::io::Error::new(
33+
Err(std::io::Error::new(
3334
ErrorKind::Unsupported,
3435
"Loading local files requires the `file` feature",
35-
)))
36+
)
37+
.into())
3638
}
3739
}
3840
}
@@ -64,7 +66,7 @@ pub trait StylesheetResolver: Send + Sync {
6466
}
6567
/// Return the "Unsupported" kind of error.
6668
fn unsupported(&self, reason: &str) -> InlineError {
67-
InlineError::IO(std::io::Error::new(ErrorKind::Unsupported, reason))
69+
std::io::Error::new(ErrorKind::Unsupported, reason).into()
6870
}
6971
}
7072

css-inline/tests/test_inlining.rs

+45-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::{error::Error, sync::Arc};
2+
13
#[macro_use]
24
mod utils;
35

@@ -32,10 +34,12 @@ fn assert_http(inlined: Result<String, css_inline::InlineError>, expected: &str)
3234
}
3335
#[cfg(not(feature = "http"))]
3436
{
37+
let error = inlined.expect_err("Should fail");
3538
assert_eq!(
36-
inlined.expect_err("Should fail").to_string(),
39+
error.to_string(),
3740
"Loading external URLs requires the `http` feature"
3841
);
42+
assert!(error.source().is_some());
3943
}
4044
}
4145

@@ -617,10 +621,12 @@ fn missing_stylesheet() {
617621
let inlined = inline(html);
618622
#[cfg(feature = "file")]
619623
{
624+
let error = inlined.expect_err("Should be an error");
620625
assert_eq!(
621-
inlined.expect_err("Should be an error").to_string(),
626+
error.to_string(),
622627
"Missing stylesheet file: tests/missing.css"
623628
);
629+
assert!(error.source().is_none());
624630
}
625631
#[cfg(not(feature = "file"))]
626632
{
@@ -698,6 +704,7 @@ fn remote_network_stylesheet_invalid_url() {
698704
#[cfg(not(feature = "http"))]
699705
let expected = "Loading external URLs requires the `http` feature";
700706
assert_eq!(error.to_string(), expected);
707+
assert!(error.source().is_some());
701708
}
702709

703710
#[test]
@@ -1001,6 +1008,42 @@ fn test_disable_cache() {
10011008
assert_eq!(debug, "CSSInliner { options: InlineOptions { inline_style_tags: true, keep_style_tags: false, keep_link_tags: false, base_url: None, load_remote_stylesheets: true, cache: None, extra_css: None, preallocate_node_capacity: 32, .. } }");
10021009
}
10031010

1011+
#[test]
1012+
fn test_resolver_without_implementation() {
1013+
let html = r#"
1014+
<html>
1015+
<head>
1016+
<link href="http://127.0.0.1:1234/external.css" rel="stylesheet">
1017+
</head>
1018+
</html>"#;
1019+
1020+
#[derive(Debug, Default)]
1021+
pub struct CustomStylesheetResolver;
1022+
1023+
impl css_inline::StylesheetResolver for CustomStylesheetResolver {}
1024+
1025+
let inliner = CSSInliner::options()
1026+
.resolver(Arc::new(CustomStylesheetResolver))
1027+
.build();
1028+
1029+
let error = inliner.inline(html).expect_err("Should fail");
1030+
#[cfg(feature = "http")]
1031+
{
1032+
assert_eq!(
1033+
error.to_string(),
1034+
"Loading external URLs is not supported: http://127.0.0.1:1234/external.css"
1035+
);
1036+
}
1037+
#[cfg(not(feature = "http"))]
1038+
{
1039+
assert_eq!(
1040+
error.to_string(),
1041+
"Loading external URLs requires the `http` feature"
1042+
);
1043+
}
1044+
assert!(error.source().is_some());
1045+
}
1046+
10041047
const FRAGMENT: &str = r#"<main>
10051048
<h1>Hello</h1>
10061049
<section>

0 commit comments

Comments
 (0)