phink_lib/cli/ui/
logger.rs

1use crate::{
2    cli::config::{
3        PFiles,
4        PhinkFiles,
5    },
6    cover::coverage::InputCoverage,
7    fuzzer::parser::OneInput,
8};
9use std::{
10    fs::{
11        File,
12        OpenOptions,
13    },
14    io,
15    io::{
16        BufReader,
17        BufWriter,
18        Read,
19        Write,
20    },
21    path::PathBuf,
22    time::{
23        SystemTime,
24        UNIX_EPOCH,
25    },
26};
27
28pub const LAST_SEED_FILENAME: &str = "last_seed.phink";
29
30pub struct LogWriter {
31    input: OneInput,
32    coverage: InputCoverage,
33}
34
35impl LogWriter {
36    pub fn new(input: OneInput, coverage: InputCoverage) -> Self {
37        LogWriter { input, coverage }
38    }
39
40    pub fn should_save() -> bool {
41        SystemTime::now()
42            .duration_since(UNIX_EPOCH)
43            .unwrap()
44            .as_secs()
45            % 2
46            == 0
47    }
48
49    pub fn save(&self, output: PathBuf) -> io::Result<()> {
50        let file = OpenOptions::new()
51            .create(true)
52            .write(true)
53            .truncate(true)
54            .open(PhinkFiles::new(output).path(PFiles::LastSeed))?;
55        let mut writer = BufWriter::new(file);
56
57        let input = &self.input;
58        writeln!(
59            writer,
60            "Got {} coverage size with {} message.s {:?}\nBytes: 0x{}\n",
61            self.coverage.coverage_len(),
62            input.messages.len(),
63            self.coverage.messages_coverage(),
64            hex::encode(&input.raw_binary)
65        )?;
66
67        for message in input.messages.iter() {
68            writeln!(writer, "{}", message.print())?;
69        }
70
71        writer.flush()?;
72        Ok(())
73    }
74}
75
76pub struct LogDisplayer {
77    output: PathBuf,
78}
79
80impl LogDisplayer {
81    pub fn new(output: PathBuf) -> Self {
82        Self { output }
83    }
84    pub fn load(&self) -> Option<String> {
85        let buf = PhinkFiles::new(self.output.clone()).path(PFiles::LastSeed);
86        let maybe_file = File::open(buf.clone());
87        if let Ok(file) = maybe_file {
88            return Some(Self::parse(file))
89        }
90        None
91    }
92
93    fn parse(file: File) -> String {
94        let mut contents = String::new();
95
96        BufReader::new(file)
97            .read_to_string(&mut contents)
98            .expect("Failed to read file");
99
100        contents
101    }
102}
103#[cfg(test)]
104mod tests {
105    use super::*;
106    #[test]
107    fn test_seed_displayer_load() {
108        let logger_display = LogDisplayer::new(PathBuf::from("tests/fixtures"));
109        let seeds = logger_display.load().unwrap();
110        assert!(seeds.contains("crash_with_invariant"));
111    }
112}