//! Integration tests for gpu-trace-perf snapshot

use std::sync::Arc;

use crate::GpuTracePerfRun;
use tempfile::TempDir;

#[allow(unused)]
pub fn single_trace_snapshot(filename: &str) {
    let mut run = GpuTracePerfRun::new();
    let output = run.setup_snapshot();
    run.add_trace(filename);
    run.snapshot_output(&format!("snapshot_{filename}"));
}

#[test]
pub fn snapshot_no_traces() {
    let mut run = GpuTracePerfRun::new();
    run.setup_snapshot();

    run.snapshot_output("snapshot_no_traces");
}

fn snapshot_baseline(name: &str, traces: &[&str]) -> Arc<TempDir> {
    let mut run = GpuTracePerfRun::new();
    let baseline = run.setup_snapshot();
    for trace in traces {
        run.add_trace(trace);
    }
    run.snapshot_output(&format!("snapshot_baseline_{name}"));

    baseline
}

fn snapshot_compare(name: &str, traces: &[&str], baseline: Arc<TempDir>) -> Arc<TempDir> {
    let mut run = GpuTracePerfRun::new();
    let compare = run.setup_snapshot();
    run.arg("--baseline");
    run.path_arg(baseline.path());
    for trace in traces {
        run.add_trace(trace);
    }
    run.snapshot_output(&format!("snapshot_{name}"));

    compare
}

fn single_trace_pass(trace: &str) {
    let baseline = snapshot_baseline(trace, &[trace]);
    let compare = snapshot_compare(trace, &[trace], baseline);

    crate::check_html_links(compare.path());
}

#[test]
pub fn snapshot_mock_trace_pass() {
    single_trace_pass("glxgears.mock-trace");
}

#[test]
pub fn snapshot_mock_trace_fail() {
    let baseline = snapshot_baseline("mock_trace_fail", &["glxgears.mock-trace"]);

    let mut run = GpuTracePerfRun::new();
    let compare = run.setup_snapshot();
    run.add_trace("glxgears.mock-trace");
    run.arg("--baseline");
    run.path_arg(baseline.path());
    run.env("MOCK_BREAK_RENDERING", "true");

    run.snapshot_output("snapshot_mock_trace_fail");

    crate::check_html_links(compare.path());
}

#[test]
pub fn snapshot_mock_trace_timeout() {
    let baseline = snapshot_baseline("snapshot_mock_trace_timeout", &["glxgears.mock-trace"]);

    let mut run = GpuTracePerfRun::new();
    let compare = run.setup_snapshot();
    run.arg("--timeout");
    run.arg("1");
    run.add_trace("glxgears.mock-trace");
    run.arg("--baseline");
    run.path_arg(baseline.path());
    run.env("MOCK_TIMEOUT", "1");

    run.snapshot_output("snapshot_mock_trace_timeout");

    crate::check_html_links(compare.path());
}

#[test]
pub fn snapshot_mock_trace_flake() {
    let baseline = snapshot_baseline("snapshot_mock_trace_flake", &["glxgears.mock-trace"]);

    let mut run = GpuTracePerfRun::new();
    let compare = run.setup_snapshot();
    run.add_trace("glxgears.mock-trace");
    run.arg("--baseline");
    run.path_arg(baseline.path());
    run.env("MOCK_FLAKE_RENDERING", "true");

    run.snapshot_output("snapshot_mock_trace_flake");

    crate::check_html_links(compare.path());
}

#[test]
#[cfg(feature = "testgfxr")]
pub fn snapshot_gfxr_pass() {
    single_trace_pass("vkcube-10-frames.gfxr");
}

#[test]
#[cfg(feature = "testrdc")]
pub fn snapshot_renderdoc_pass() {
    single_trace_pass("vkcube.rdc");
}

#[test]
#[cfg(feature = "testangle")]
pub fn snapshot_angle_pass() {
    single_trace_pass("angle_trace_tests/google_maps");
}

#[test]
#[cfg(feature = "testapitrace")]
pub fn snapshot_apitrace_pass() {
    single_trace_pass("glmark2-pulsar.trace");
}

#[test]
#[cfg(feature = "testapitrace")]
pub fn snapshot_apitrace_fail() {
    let baseline = snapshot_baseline("snapshot_apitrace_fail", &["glmark2-pulsar.trace"]);

    let mut run = GpuTracePerfRun::new();
    let compare = run.setup_snapshot();
    run.add_trace("glmark2-pulsar.trace");
    run.arg("--baseline");
    run.path_arg(baseline.path());
    run.env("MESA_SHADER_READ_PATH", "src/test_data/pulsar-override/");

    run.snapshot_output("snapshot_apitrace_fail");

    crate::check_html_links(compare.path());
}

#[test]
pub fn snapshot_toml_output() {
    let mut run = GpuTracePerfRun::new();
    let output = run.setup_snapshot();
    run.add_trace("glxgears.mock-trace");

    let result = run.run();

    let toml_path = output.path().join("traces.toml");

    assert!(
        result.status.success(),
        "Did not return success:\nstdout: {}\nstderr: {}\n",
        result.stdout,
        result.stderr
    );

    let config = gpu_trace_perf::traces_config::TracesConfig::load(&toml_path)
        .expect("loading generated TOML");

    assert_eq!(config.traces_db.download_url, "");
    assert_eq!(config.traces.len(), 1);

    let trace = &config.traces[0];
    assert_eq!(trace.path, "src/test_data/glxgears.mock-trace");

    let device = trace
        .device("device-name")
        .expect("finding device-name entry");
    assert_eq!(device.checksum.len(), 64, "SHA-256 hex should be 64 chars");
}

#[test]
#[cfg(feature = "testapitrace")]
pub fn apitrace_file_not_found() {
    single_trace_snapshot("typoed.trace");
}

/// This is now disabled, because it prints a backtrace I haven't figured out
/// how to filter.  Maybe if we make a better file that produces an apitrace
/// error we can reenable it.
#[allow(dead_code)]
#[cfg(feature = "testapitrace")]
pub fn apitrace_corrupted_file() {
    single_trace_snapshot("corrupted.trace");
}
