summaryrefslogtreecommitdiffstats
path: root/internals/src/encoder/trace.rs
diff options
context:
space:
mode:
Diffstat (limited to 'internals/src/encoder/trace.rs')
-rw-r--r--internals/src/encoder/trace.rs167
1 files changed, 167 insertions, 0 deletions
diff --git a/internals/src/encoder/trace.rs b/internals/src/encoder/trace.rs
new file mode 100644
index 0000000..20e3bcc
--- /dev/null
+++ b/internals/src/encoder/trace.rs
@@ -0,0 +1,167 @@
+/// If it is a test build the EncodingBuffer will
+/// have an additional `pub trace` field,
+/// which will contain a Vector of `Token`s
+/// generated when writing to the string buffer.
+///
+/// For example when calling `.write_utf8("hy")`
+/// following tokens will be added:
+/// `[NowUtf8, Text("hy")]`
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub enum TraceToken {
+ MarkFWS,
+ CRLF,
+ TruncateToCRLF,
+ Text(String),
+ NowChar,
+ NowStr,
+ NowAText,
+ NowUtf8,
+ NowCondText,
+ NowUnchecked,
+ NewSection,
+ End,
+ /// used to seperate a header from a body
+ ///
+ /// be aware that `Section::BodyPaylod` just
+ /// contains the Payload, so e.g. headers from
+ /// mime bodies or mime multipart body boundaries
+ /// still get written into the string buffer
+ BlankLine,
+ Body
+}
+
+pub fn simplify_trace_tokens<I: IntoIterator<Item=TraceToken>>(inp: I) -> Vec<TraceToken> {
+ use std::mem;
+ use self::TraceToken::*;
+ let iter = inp.into_iter()
+ .filter(|t| {
+ match *t {
+ NowChar |
+ NowStr |
+ NowAText |
+ NowUtf8 |
+ NowUnchecked |
+ NowCondText => false,
+ _ => true
+ }
+ });
+
+ let mut out = Vec::new();
+ let mut textbf = String::new();
+ let mut had_text = false;
+
+ for token in iter {
+ match token {
+ Text(str) => {
+ had_text = true;
+ textbf.push_str(&*str)
+ },
+ e => {
+ if had_text {
+ let text = mem::replace(&mut textbf, String::new());
+ out.push(Text(text));
+ had_text = false;
+ }
+ out.push(e);
+ }
+ }
+ }
+ if had_text {
+ out.push(Text(textbf))
+ }
+ out
+}
+
+#[macro_export]
+macro_rules! ec_test {
+ ( $(#[$attr:meta])* $name:ident, $inp:block => $mt:tt => [ $($tokens:tt)* ] ) => (
+
+ $(#[$attr])*
+ #[test]
+ fn $name() {
+ #![allow(unused_mut)]
+ use $crate::encoder::EncodingBuffer;
+ use std::mem;
+
+ let mail_type = {
+ let mt_str = stringify!($mt).to_lowercase();
+ match mt_str.as_str() {
+ "utf8" |
+ "internationalized"
+ => $crate::MailType::Internationalized,
+ "ascii"
+ => $crate::MailType::Ascii,
+ "mime8" |
+ "mime8bit" |
+ "mime8bitenabled"
+ => $crate::MailType::Mime8BitEnabled,
+ other => panic!( "invalid name for mail type: {}", other)
+ }
+ };
+
+ let mut encoder = EncodingBuffer::new(mail_type);
+ {
+ //REFACTOR(catch): use catch block once stable
+ let component = (|| -> Result<_, $crate::__FError> {
+ let component = $inp;
+ Ok(Box::new(component) as Box<$crate::encoder::EncodableInHeader>)
+ })().unwrap();
+
+ let mut handle = encoder.writer();
+ component.encode(&mut handle).unwrap();
+ // we do not want to finish writing as we might
+ // test just parts of headers
+ mem::forget(handle);
+ }
+ let mut expected: Vec<$crate::encoder::TraceToken> = Vec::new();
+ ec_test!{ __PRIV_TO_TOKEN_LIST expected $($tokens)* }
+ let got = $crate::encoder::simplify_trace_tokens(encoder.trace.into_iter());
+ assert_eq!(got, expected)
+ }
+ );
+
+ (__PRIV_TO_TOKEN_LIST $col:ident Text $e:expr) => (
+ $col.push($crate::encoder::TraceToken::Text({$e}.into()));
+ );
+ (__PRIV_TO_TOKEN_LIST $col:ident $token:ident) => (
+ $col.push($crate::encoder::TraceToken::$token);
+ );
+ (__PRIV_TO_TOKEN_LIST $col:ident Text $e:expr, $($other:tt)*) => ({
+ ec_test!{ __PRIV_TO_TOKEN_LIST $col Text $e }
+ ec_test!{ __PRIV_TO_TOKEN_LIST $col $($other)* }
+ });
+ (__PRIV_TO_TOKEN_LIST $col:ident $token:ident, $($other:tt)*) => (
+ ec_test!{ __PRIV_TO_TOKEN_LIST $col $token }
+ ec_test!{ __PRIV_TO_TOKEN_LIST $col $($other)* }
+ );
+ (__PRIV_TO_TOKEN_LIST $col:ident ) => ();
+ //conflict with nom due to it using a crate exposing compiler_error...
+// (__PRIV_TO_TOKEN_LIST $col:ident $($other:tt)*) => (
+// compiler_error!( concat!(
+// "syntax error in token list: ", stringify!($($other:tt)*)
+// ))
+// )
+}
+
+
+
+#[cfg(test)]
+mod test {
+ use soft_ascii_string::SoftAsciiStr;
+ use super::super::encodable::EncodeClosure;
+
+ ec_test!{ repreduces_all_tokens,
+ {
+ EncodeClosure::new(|writer| {
+ writer.write_utf8("hy-there")?;
+ writer.write_fws();
+ writer.write_str(SoftAsciiStr::from_unchecked("tshau-there"))?;
+ Ok(())
+ })
+ } => utf8 => [
+ Text "hy-there",
+ MarkFWS,
+ Text " tshau-there"
+ ]
+ }
+}