1use crate::config::{Config, Format};
8use crate::formatter::{OutputFormat, SkipState};
9use crate::profiles::UserProfile;
10use crate::task_runner::TestRunResult;
11
12#[must_use]
14pub fn resolve_output_format(
15 config: &Config,
16 dl_result: &TestRunResult,
17 ul_result: &TestRunResult,
18 elapsed: std::time::Duration,
19) -> OutputFormat {
20 let profile = config
21 .profile()
22 .and_then(UserProfile::from_name)
23 .unwrap_or_default();
24 let theme = config.theme();
25
26 match config.format() {
28 Some(Format::Json) => OutputFormat::Json,
29 Some(Format::Jsonl) => OutputFormat::Jsonl,
30 Some(Format::Csv) => OutputFormat::Csv {
31 delimiter: config.csv_delimiter(),
32 header: config.csv_header(),
33 },
34 Some(Format::Minimal) => OutputFormat::Minimal { theme },
35 Some(Format::Simple) => OutputFormat::Simple { theme },
36 Some(Format::Compact) => OutputFormat::Compact {
37 dl_bytes: dl_result.total_bytes,
38 ul_bytes: ul_result.total_bytes,
39 dl_duration: dl_result.duration_secs,
40 ul_duration: ul_result.duration_secs,
41 elapsed,
42 profile,
43 theme,
44 },
45 Some(Format::Dashboard) => OutputFormat::Dashboard {
46 dl_mbps: dl_result.avg_bps / 1_000_000.0,
47 dl_peak_mbps: dl_result.peak_bps / 1_000_000.0,
48 dl_bytes: dl_result.total_bytes,
49 dl_duration: dl_result.duration_secs,
50 ul_mbps: ul_result.avg_bps / 1_000_000.0,
51 ul_peak_mbps: ul_result.peak_bps / 1_000_000.0,
52 ul_bytes: ul_result.total_bytes,
53 ul_duration: ul_result.duration_secs,
54 elapsed,
55 profile,
56 theme,
57 },
58 Some(Format::Detailed) => OutputFormat::Detailed {
59 dl_bytes: dl_result.total_bytes,
60 ul_bytes: ul_result.total_bytes,
61 dl_duration: dl_result.duration_secs,
62 ul_duration: ul_result.duration_secs,
63 skipped: SkipState {
64 download: config.no_download(),
65 upload: config.no_upload(),
66 },
67 elapsed,
68 profile,
69 minimal: config.minimal(),
70 theme,
71 },
72 None => {
73 OutputFormat::Detailed {
75 dl_bytes: dl_result.total_bytes,
76 ul_bytes: ul_result.total_bytes,
77 dl_duration: dl_result.duration_secs,
78 ul_duration: ul_result.duration_secs,
79 skipped: SkipState {
80 download: config.no_download(),
81 upload: config.no_upload(),
82 },
83 elapsed,
84 profile,
85 minimal: config.minimal(),
86 theme,
87 }
88 }
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use crate::config::{ConfigSource, OutputSource, TestSource};
96 use crate::task_runner::TestRunResult;
97
98 fn make_test_run(dl_bps: f64, dl_peak: f64, dl_bytes: u64, dl_dur: f64) -> TestRunResult {
100 TestRunResult {
101 avg_bps: dl_bps,
102 peak_bps: dl_peak,
103 total_bytes: dl_bytes,
104 duration_secs: dl_dur,
105 speed_samples: vec![dl_bps],
106 latency_under_load: None,
107 }
108 }
109
110 fn make_upload_run(bps: f64, peak: f64, bytes: u64, dur: f64) -> TestRunResult {
111 TestRunResult {
112 avg_bps: bps,
113 peak_bps: peak,
114 total_bytes: bytes,
115 duration_secs: dur,
116 speed_samples: vec![bps],
117 latency_under_load: None,
118 }
119 }
120
121 fn make_config(format: Option<Format>) -> Config {
122 let source = ConfigSource {
123 output: OutputSource {
124 format,
125 theme: String::from(if cfg!(windows) { "monochrome" } else { "dark" }),
126 ..Default::default()
127 },
128 ..Default::default()
129 };
130 Config::from_source(&source)
131 }
132
133 #[test]
134 fn test_resolve_output_format_json() {
135 let config = make_config(Some(Format::Json));
136 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
137 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
138
139 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(5));
140 assert!(matches!(result, OutputFormat::Json));
141 }
142
143 #[test]
144 fn test_resolve_output_format_jsonl() {
145 let config = make_config(Some(Format::Jsonl));
146 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
147 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
148
149 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(5));
150 assert!(matches!(result, OutputFormat::Jsonl));
151 }
152
153 #[test]
154 fn test_resolve_output_format_csv() {
155 let source = ConfigSource {
156 output: OutputSource {
157 format: Some(Format::Csv),
158 csv_delimiter: ';',
159 csv_header: Some(true),
160 ..Default::default()
161 },
162 ..Default::default()
163 };
164 let config = Config::from_source(&source);
165 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
166 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
167
168 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(5));
169 match result {
170 OutputFormat::Csv { delimiter, header } => {
171 assert_eq!(delimiter, ';');
172 assert!(header);
173 }
174 _ => panic!("Expected Csv format"),
175 }
176 }
177
178 #[test]
179 fn test_resolve_output_format_minimal() {
180 let config = make_config(Some(Format::Minimal));
181 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
182 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
183
184 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(5));
185 match result {
186 OutputFormat::Minimal { theme } => {
187 assert_eq!(
188 theme,
189 if cfg!(windows) {
190 crate::theme::Theme::Monochrome
191 } else {
192 crate::theme::Theme::Dark
193 }
194 );
195 }
196 _ => panic!("Expected Minimal format"),
197 }
198 }
199
200 #[test]
201 fn test_resolve_output_format_simple() {
202 let config = make_config(Some(Format::Simple));
203 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
204 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
205
206 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(5));
207 match result {
208 OutputFormat::Simple { theme } => {
209 assert_eq!(
210 theme,
211 if cfg!(windows) {
212 crate::theme::Theme::Monochrome
213 } else {
214 crate::theme::Theme::Dark
215 }
216 );
217 }
218 _ => panic!("Expected Simple format"),
219 }
220 }
221
222 #[test]
223 fn test_resolve_output_format_compact() {
224 let config = make_config(Some(Format::Compact));
225 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
226 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
227
228 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(5));
229 match result {
230 OutputFormat::Compact {
231 dl_bytes,
232 ul_bytes,
233 elapsed,
234 profile,
235 ..
236 } => {
237 assert_eq!(dl_bytes, 10_000_000);
238 assert_eq!(ul_bytes, 5_000_000);
239 assert_eq!(elapsed.as_secs(), 5);
240 assert_eq!(profile, UserProfile::PowerUser); }
242 _ => panic!("Expected Compact format"),
243 }
244 }
245
246 #[test]
247 fn test_resolve_output_format_dashboard() {
248 let config = make_config(Some(Format::Dashboard));
249 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
250 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
251
252 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(10));
253 match result {
254 OutputFormat::Dashboard {
255 dl_mbps,
256 dl_peak_mbps,
257 ul_mbps,
258 ul_peak_mbps,
259 elapsed,
260 ..
261 } => {
262 assert!((dl_mbps - 100.0).abs() < 0.01);
263 assert!((dl_peak_mbps - 120.0).abs() < 0.01);
264 assert!((ul_mbps - 50.0).abs() < 0.01);
265 assert!((ul_peak_mbps - 60.0).abs() < 0.01);
266 assert_eq!(elapsed.as_secs(), 10);
267 }
268 _ => panic!("Expected Dashboard format"),
269 }
270 }
271
272 #[test]
273 fn test_resolve_output_format_detailed() {
274 let config = make_config(Some(Format::Detailed));
275 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
276 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
277
278 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(8));
279 match result {
280 OutputFormat::Detailed {
281 dl_bytes,
282 ul_bytes,
283 elapsed,
284 skipped,
285 minimal,
286 ..
287 } => {
288 assert_eq!(dl_bytes, 10_000_000);
289 assert_eq!(ul_bytes, 5_000_000);
290 assert_eq!(elapsed.as_secs(), 8);
291 assert!(!skipped.download);
292 assert!(!skipped.upload);
293 assert!(!minimal);
294 }
295 _ => panic!("Expected Detailed format"),
296 }
297 }
298
299 #[test]
300 fn test_resolve_output_format_detailed_with_skipped() {
301 let source = ConfigSource {
302 test: TestSource {
303 no_download: Some(true),
304 no_upload: Some(true),
305 ..Default::default()
306 },
307 output: OutputSource {
308 format: Some(Format::Detailed),
309 minimal: Some(true),
310 theme: String::from("light"),
311 ..Default::default()
312 },
313 ..Default::default()
314 };
315 let config = Config::from_source(&source);
316 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
317 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
318
319 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(3));
320 match result {
321 OutputFormat::Detailed {
322 skipped,
323 minimal,
324 theme,
325 ..
326 } => {
327 assert!(skipped.download);
328 assert!(skipped.upload);
329 assert!(minimal);
330 assert_eq!(theme, crate::theme::Theme::Light);
331 }
332 _ => panic!("Expected Detailed format"),
333 }
334 }
335
336 #[test]
337 fn test_resolve_output_format_default_none() {
338 let source = ConfigSource {
340 output: OutputSource {
341 format: None,
342 ..Default::default()
343 },
344 ..Default::default()
345 };
346 let config = Config::from_source(&source);
347 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
348 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
349
350 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(5));
351 assert!(matches!(result, OutputFormat::Detailed { .. }));
352 }
353
354 #[test]
355 fn test_resolve_output_format_with_profile() {
356 let source = ConfigSource {
357 output: OutputSource {
358 format: Some(Format::Compact),
359 profile: Some(String::from("gamer")),
360 ..Default::default()
361 },
362 ..Default::default()
363 };
364 let config = Config::from_source(&source);
365 let dl = make_test_run(100_000_000.0, 120_000_000.0, 10_000_000, 2.0);
366 let ul = make_upload_run(50_000_000.0, 60_000_000.0, 5_000_000, 1.0);
367
368 let result = resolve_output_format(&config, &dl, &ul, std::time::Duration::from_secs(5));
369 match result {
370 OutputFormat::Compact { profile, .. } => {
371 assert_eq!(profile, UserProfile::Gamer);
372 }
373 _ => panic!("Expected Compact format"),
374 }
375 }
376}