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
use chrono_tz::Tz;
use crate::{Mactime2Application, Mactime2Writer};
use crate::bodyfile_sorter::*;

pub struct CsvOutput {
    src_zone: Tz, dst_zone: Tz
}

impl CsvOutput {
    pub fn new(src_zone: Tz, dst_zone: Tz) -> Self {
        Self {
            src_zone, dst_zone
        }
    }
}

impl Mactime2Writer for CsvOutput {
    fn fmt(&self, timestamp: &i64, entry: &ListEntry) -> String {
        let timestamp = Mactime2Application::format_date(*timestamp, &self.src_zone, &self.dst_zone);
        format!(
            "{},{},{},{},{},{},{},\"{}\"",
            timestamp,
            entry.line.get_size(),
            entry.flags,
            entry.line.get_mode(),
            entry.line.get_uid(),
            entry.line.get_gid(),
            entry.line.get_inode(),
            entry.line.get_name()
        )
    }
}

#[cfg(test)]
mod tests {
    use rand;
    use super::CsvOutput;
    use chrono::DateTime;
    use chrono_tz::TZ_VARIANTS;
    use chrono_tz::Tz;
    use std::sync::Arc;
    use bodyfile::Bodyfile3Line;
    use crate::bodyfile_sorter::{MACBFlags, ListEntry, Mactime2Writer};

    fn random_tz() -> Tz {
        let index = rand::random::<usize>() % TZ_VARIANTS.len();
        TZ_VARIANTS[index]
    }

    #[allow(non_snake_case)]
    #[test]
    fn test_correct_ts_UTC() {
        let output = CsvOutput::new(Tz::UTC, Tz::UTC);
        for _ in 1..10 {
            let unix_ts = rand::random::<u32>() as i64;
            let bf_line = Bodyfile3Line::new().with_crtime(unix_ts);
            let entry = ListEntry {
                flags: MACBFlags::B,
                line: Arc::new(bf_line)
            };

            let out_line = output.fmt(&unix_ts, &entry);
            let out_ts = out_line.split(',').into_iter().next().unwrap();
            let rfc3339 = DateTime::parse_from_rfc3339(out_ts).expect(out_ts);
            assert_eq!(unix_ts, rfc3339.timestamp(), "Timestamp {} converted to '{}' and back to {}", unix_ts, out_ts, rfc3339.timestamp());
        }
    }

    #[allow(non_snake_case)]
    #[test]
    fn test_correct_ts_random_tz() {
        for _ in 1..100 {
            let tz = random_tz();
            let output = CsvOutput::new(tz, tz);
            let unix_ts = rand::random::<u32>() as i64;
            let bf_line = Bodyfile3Line::new().with_crtime(unix_ts);
            let entry = ListEntry {
                flags: MACBFlags::B,
                line: Arc::new(bf_line)
            };

            let out_line = output.fmt(&unix_ts, &entry);
            let out_ts = out_line.split(',').into_iter().next().unwrap();
            let rfc3339 = DateTime::parse_from_rfc3339(out_ts).expect(out_ts);
            let offset = rfc3339.offset().local_minus_utc() as i64;
            let calculated_ts = rfc3339.timestamp() + offset;
            assert_eq!(unix_ts, calculated_ts, "Timestamp {} converted to '{}' and back to {} (offset was {}s)", unix_ts, out_ts, calculated_ts, offset);
        }
    }
}