1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
#![cfg(feature = "spans")]
use std::{include_str, ops::Range};
use codespan_reporting::{
self,
diagnostic::{Diagnostic, Label},
files::SimpleFiles,
term::{self, termcolor::Buffer},
};
use html5tokenizer::{
error::Error, BufferQueue, Tag, Token, TokenSink, TokenSinkResult, Tokenizer, TokenizerOpts,
};
#[derive(Default)]
struct TagSink {
tags: Vec<Tag>,
errors: Vec<(Error, Range<usize>)>,
}
impl TokenSink for TagSink {
fn process_token(&mut self, token: Token, _line_number: u64) -> TokenSinkResult {
if let Token::TagToken(tag) = token {
self.tags.push(tag);
} else if let Token::ParseError { error, span } = token {
self.errors.push((error, span));
}
TokenSinkResult::Continue
}
}
#[test]
fn test() {
let sink = TagSink::default();
let mut input = BufferQueue::new();
let text = include_str!("files/test.html");
input.push_back(text.to_string());
let mut tok = Tokenizer::new(sink, TokenizerOpts::default());
let _ = tok.feed(&mut input);
let mut files = SimpleFiles::new();
let file_id = files.add("test.html", text);
let mut labels = Vec::new();
let tags = tok.sink.tags;
for tag in &tags[..2] {
labels.push(
Label::primary(file_id, tag.name_span.clone()).with_message(format!("{:?}", tag.kind)),
);
}
labels.push(
Label::primary(file_id, tags[2].attrs[0].name_span.clone()).with_message("attribute name"),
);
labels.push(
Label::primary(file_id, tags[2].attrs[0].value_span.clone())
.with_message("attribute value"),
);
labels.push(
Label::primary(file_id, tags[4].attrs[0].value_span.clone())
.with_message("in single quotes"),
);
labels.push(
Label::primary(file_id, tags[4].attrs[1].value_span.clone())
.with_message("in double quotes"),
);
for (error, span) in tok.sink.errors {
labels.push(Label::primary(file_id, span).with_message(format!("{}", error)));
}
let diagnostic = Diagnostic::note().with_labels(labels);
let mut writer = Buffer::no_color();
let config = codespan_reporting::term::Config::default();
term::emit(&mut writer, &config, &files, &diagnostic).unwrap();
let actual = remove_trailing_spaces(std::str::from_utf8(writer.as_slice()).unwrap());
let expected = include_str!("files/test.out");
if actual != expected {
println!(
"EXPECTED:\n{banner}\n{expected}{banner}\n\nACTUAL OUTPUT:\n{banner}\n{actual}{banner}",
banner = "-".repeat(30),
expected = expected,
actual = actual
);
panic!("failed");
}
}
fn remove_trailing_spaces(text: &str) -> String {
text.lines()
.map(|l| l.trim_end())
.collect::<Vec<_>>()
.join("\n")
}
|