1use crate::args::Args;
2use crate::time;
3
4use crossterm::style::Stylize;
5use std::borrow::{Borrow, Cow};
6
7#[derive(Debug)]
8pub struct Modifier<'a> {
9 pub dates: bool,
10 pub loglevels: bool,
11 pub colors: bool,
12 pub prefix: &'a str,
13 pub suffix: &'a str,
14 pub prefix_err: Option<&'a str>,
15 pub suffix_err: Option<&'a str>,
16}
17
18impl<'a> From<&'a Args> for Modifier<'a> {
19 fn from(args: &'a Args) -> Self {
20 Modifier {
21 dates: args.with_dates,
22 loglevels: args.with_dates,
23 colors: args.with_colors,
24 prefix: &args.prefix,
25 suffix: &args.suffix,
26 prefix_err: args.prefix_err.as_deref(),
27 suffix_err: args.suffix_err.as_deref(),
28 }
29 }
30}
31
32#[derive(Debug, Eq, PartialEq, Clone, Copy)]
33pub enum Output {
34 StdOut,
35 StdErr,
36}
37
38pub fn add_modifier_to_line(line: &str, output: Output, modifier: &Modifier) -> String {
39 let prefix = match output {
40 Output::StdOut => modifier.prefix,
41 Output::StdErr => modifier.prefix_err.unwrap_or(modifier.prefix),
42 };
43
44 let suffix = match output {
45 Output::StdOut => modifier.suffix,
46 Output::StdErr => modifier.suffix_err.unwrap_or(modifier.suffix),
47 };
48
49 let date = if modifier.dates {
50 let d = format!("{}", time::now().format("[%Y-%m-%d %H:%M:%S%.3f] "));
51 Cow::Owned(if modifier.colors {
52 format!("{}", d.grey())
53 } else {
54 d
55 })
56 } else {
57 Cow::Borrowed("")
58 };
59
60 let loglevel = if modifier.loglevels {
61 match (output, modifier.colors) {
62 (Output::StdOut, true) => Cow::Owned(format!("{}", "[INFO] ".green())),
63 (Output::StdOut, false) => Cow::Borrowed("[INFO] "),
64 (Output::StdErr, true) => Cow::Owned(format!("{}", "[ERR] ".red())),
65 (Output::StdErr, false) => Cow::Borrowed("[ERR] "),
66 }
67 } else {
68 Cow::Borrowed("")
69 };
70
71 prefix.to_string() + date.borrow() + loglevel.borrow() + line + suffix
72}
73
74#[cfg(test)]
75mod test {
76 use super::*;
77 use chrono::TimeZone;
78
79 #[test]
80 fn null_modifier_does_nothing() {
81 let modifier = Modifier {
82 dates: false,
83 loglevels: false,
84 colors: false,
85 prefix: "",
86 suffix: "",
87 prefix_err: None,
88 suffix_err: None,
89 };
90
91 for output in [Output::StdOut, Output::StdErr] {
92 assert_eq!(
93 add_modifier_to_line("hogehoge", output, &modifier),
94 "hogehoge"
95 );
96 }
97 }
98
99 #[test]
100 fn prefix_and_suffix() {
101 let modifier = Modifier {
102 dates: false,
103 loglevels: false,
104 colors: false,
105 prefix: "prefix",
106 suffix: "suffix",
107 prefix_err: Some("prefix-err"),
108 suffix_err: Some("suffix-err"),
109 };
110
111 assert_eq!(
112 add_modifier_to_line("hoge", Output::StdOut, &modifier),
113 "prefixhogesuffix"
114 );
115 assert_eq!(
116 add_modifier_to_line("hoge", Output::StdErr, &modifier),
117 "prefix-errhogesuffix-err"
118 );
119 }
120
121 #[test]
122 fn prefix_err_and_suffix_err_defaults_to_prefix_and_suffix() {
123 let modifier = Modifier {
124 dates: false,
125 loglevels: false,
126 colors: false,
127 prefix: "prefix",
128 suffix: "suffix",
129 prefix_err: None,
130 suffix_err: None,
131 };
132
133 assert_eq!(
134 add_modifier_to_line("hoge", Output::StdErr, &modifier),
135 "prefixhogesuffix"
136 );
137 }
138
139 #[test]
140 fn loglevels() {
141 let modifier = Modifier {
142 dates: false,
143 loglevels: true,
144 colors: false,
145 prefix: "",
146 suffix: "",
147 prefix_err: None,
148 suffix_err: None,
149 };
150
151 assert_eq!(
152 add_modifier_to_line("hoge", Output::StdOut, &modifier),
153 "[INFO] hoge"
154 );
155 assert_eq!(
156 add_modifier_to_line("hoge", Output::StdErr, &modifier),
157 "[ERR] hoge"
158 );
159 }
160
161 #[test]
162 fn prefix_dates_loglevels_come_in_order() {
163 let dt: chrono::NaiveDateTime = "2022-09-02T10:11:12".parse().unwrap();
164 let ldt = chrono::Local.from_local_datetime(&dt).unwrap();
165 time::mock_time::set_mock_time(ldt);
166
167 let modifier = Modifier {
168 dates: true,
169 loglevels: true,
170 colors: false,
171 prefix: "prefix",
172 suffix: "",
173 prefix_err: Some("prefix"),
174 suffix_err: None,
175 };
176
177 assert_eq!(
178 add_modifier_to_line("hoge", Output::StdOut, &modifier),
179 "prefix[2022-09-02 10:11:12.000] [INFO] hoge"
180 );
181 assert_eq!(
182 add_modifier_to_line("hoge", Output::StdErr, &modifier),
183 "prefix[2022-09-02 10:11:12.000] [ERR] hoge"
184 );
185 }
186}