1
use std::fs::File;
2
use std::path::Path;
3
use std::path::PathBuf;
4

            
5
use log::info;
6
use merc_utilities::MercError;
7

            
8
/// A utility for dumping files, mostly used for testing and debugging
9
///
10
/// # Details
11
///
12
/// The given name is used to create a dedicated directory for the output files,
13
/// this is especially useful for files dumped from (random) tests.
14
///
15
/// Uses the `MERC_DUMP=1` environment variable to enable or disable dumping files
16
/// to disk, to avoid unnecessary writes during normal runs. In combination with
17
/// `MERC_SEED` we can reproduce specific tests cases for random runs.
18
pub struct DumpFiles {
19
    // None when dumping is disabled.
20
    directory: Option<PathBuf>,
21
}
22

            
23
impl DumpFiles {
24
    /// Creates a new `DumpFiles` instance with the given directory as output.
25
16800
    pub fn new(directory: &str) -> Self {
26
16800
        if let Ok(dump_dir) = std::env::var("MERC_DUMP") {
27
            // Check if the directory is an absolute path
28
            if !Path::new(dump_dir.as_str()).is_absolute() {
29
                panic!("MERC_DUMP must be an absolute path, because tests write relative to their source file.");
30
            }
31

            
32
            Self {
33
                directory: Some(Path::new(&dump_dir).join(directory)),
34
            }
35
        } else {
36
            // Dumping disabled.
37
16800
            Self { directory: None }
38
        }
39
16800
    }
40

            
41
    /// Dumps a file with the given filename suffix by calling the provided function
42
    /// to write the contents.
43
3100
    pub fn dump<F>(&mut self, filename: &str, mut write: F) -> Result<(), MercError>
44
3100
    where
45
3100
        F: FnMut(&mut File) -> Result<(), MercError>,
46
    {
47
3100
        if let Some(directory) = &self.directory {
48
            // Ensure the dump directory exists.
49
            let _ = std::fs::create_dir_all(directory);
50

            
51
            let path = Path::new(&directory).join(filename);
52
            let mut file = File::create(&path)?;
53
            write(&mut file)?;
54

            
55
            info!("Dumped file: {}", path.to_string_lossy());
56
        } else {
57
3100
            info!("No MERC_DUMP set, skipping dump: {}", filename);
58
        }
59
3100
        Ok(())
60
3100
    }
61
}