1
use pretty_assertions::assert_eq;
2
use std::borrow::Cow;
3
use std::collections::BTreeSet;
4
use std::error::Error;
5
use std::fs;
6
use std::path::Path;
7
use std::path::PathBuf;
8
use std::process::Command;
9
use std::time::Instant;
10
use tests_integration::AcceptMode;
11
use tests_integration::golden_files::assert_no_redundant_expected_files;
12
use tests_integration::test_config::{round_expected_time, upsert_expected_time_config};
13

            
14
81
pub fn custom_test(test_dir: &str) -> Result<(), Box<dyn Error>> {
15
81
    let accept_mode = AcceptMode::from_env();
16
81
    let accept = accept_mode.accepts_outputs();
17
81
    let started_at = Instant::now();
18

            
19
    // Convert test directory to a PathBuf
20
81
    let test_path = PathBuf::from(test_dir);
21
81
    assert!(
22
81
        test_path.exists(),
23
        "Test directory not found: {test_path:?}"
24
    );
25

            
26
    // Get paths
27
81
    let script_path = test_path.join("run.sh");
28
81
    assert!(
29
81
        script_path.exists(),
30
        "Test script not found: {script_path:?}"
31
    );
32
81
    let expected_output_path = test_path.join("stdout.expected");
33
81
    let expected_error_path = test_path.join("stderr.expected");
34

            
35
    // Execute the test script in the correct directory
36
81
    let output = Command::new("sh")
37
81
        .arg("run.sh")
38
81
        .current_dir(&test_path)
39
81
        .output()?;
40

            
41
    // Convert captured output/error to string
42
81
    let actual_output = String::from_utf8_lossy(&output.stdout);
43
81
    let actual_error = String::from_utf8_lossy(&output.stderr);
44

            
45
81
    if accept {
46
        // Overwrite expected files
47
        update_file(expected_output_path, &actual_output)?;
48
        update_file(expected_error_path, &actual_error)?;
49
    } else {
50
        // Compare results
51
81
        let expected_output = if expected_output_path.exists() {
52
74
            fs::read_to_string(&expected_output_path)?
53
        } else {
54
7
            String::new()
55
        };
56
81
        let expected_error = if expected_error_path.exists() {
57
21
            fs::read_to_string(&expected_error_path)?
58
        } else {
59
60
            String::new()
60
        };
61

            
62
81
        assert_eq!(expected_error, actual_error, "Standard error mismatch");
63
81
        assert_eq!(expected_output, actual_output, "Standard output mismatch");
64
    }
65

            
66
81
    let allowed_expected_files = expected_custom_files_for_case(&actual_output, &actual_error);
67
81
    assert_no_redundant_expected_files(Path::new(&test_path), &allowed_expected_files, None)?;
68

            
69
81
    if accept_mode.records_expected_time() {
70
        let expected_time = round_expected_time(started_at.elapsed());
71
        upsert_expected_time_config(&test_path.join("config.toml"), expected_time)?;
72
81
    }
73

            
74
81
    Ok(())
75
81
}
76

            
77
fn update_file(
78
    expected_file_path: PathBuf,
79
    actual_output: &Cow<'_, str>,
80
) -> Result<(), Box<dyn Error>> {
81
    if expected_file_path.exists() {
82
        fs::remove_file(&expected_file_path)?;
83
    }
84
    if !actual_output.trim().is_empty() {
85
        fs::File::create(&expected_file_path)?;
86
        fs::write(&expected_file_path, actual_output.as_bytes())?;
87
    }
88
    Ok(())
89
}
90

            
91
/// Returns the expected snapshot files for the observed custom test output.
92
81
fn expected_custom_files_for_case(
93
81
    stdout: &Cow<'_, str>,
94
81
    stderr: &Cow<'_, str>,
95
81
) -> BTreeSet<String> {
96
81
    let mut expected_files = BTreeSet::new();
97
81
    if !stdout.trim().is_empty() {
98
74
        expected_files.insert("stdout.expected".to_string());
99
74
    }
100
81
    if !stderr.trim().is_empty() {
101
21
        expected_files.insert("stderr.expected".to_string());
102
60
    }
103
81
    expected_files
104
81
}
105

            
106
#[test]
107
1
fn assert_conjure_present() {
108
1
    conjure_cp_cli::find_conjure::conjure_executable().unwrap();
109
1
}
110

            
111
include!(concat!(env!("OUT_DIR"), "/gen_tests_custom.rs"));