use std::fs;
use std::path::{Path, PathBuf};
use crate::calibration::Calibration;
use crate::frame::TerminalFrame;
#[derive(Debug)]
#[must_use]
pub struct CaptureArtifact {
pub screenshot_path: Option<PathBuf>,
pub calibration: Option<Calibration>,
pub frame_text: String,
pub cols: u16,
pub rows: u16,
}
impl CaptureArtifact {
pub fn from_frame(frame: &TerminalFrame) -> Self {
Self {
screenshot_path: None,
calibration: None,
frame_text: frame.all_text(),
cols: frame.cols(),
rows: frame.rows(),
}
}
pub fn with_screenshot(mut self, path: PathBuf) -> Self {
self.screenshot_path = Some(path);
self
}
pub fn with_calibration(mut self, calibration: Calibration) -> Self {
self.calibration = Some(calibration);
self
}
}
pub struct ArtifactDir {
root: PathBuf,
}
impl ArtifactDir {
pub fn new(root: impl Into<PathBuf>) -> Result<Self, std::io::Error> {
let root = root.into();
fs::create_dir_all(&root)?;
Ok(Self { root })
}
pub fn root(&self) -> &Path {
&self.root
}
pub fn screenshot_path(&self, name: &str) -> PathBuf {
self.root.join(format!("{name}.png"))
}
pub fn overlay_path(&self, name: &str) -> PathBuf {
self.root.join(format!("{name}_overlay.png"))
}
pub fn frame_dump_path(&self, name: &str) -> PathBuf {
self.root.join(format!("{name}_frame.txt"))
}
pub fn tape_path(&self, name: &str) -> PathBuf {
self.root.join(format!("{name}.tape"))
}
pub fn save_frame_dump(
&self,
name: &str,
frame: &TerminalFrame,
) -> Result<PathBuf, std::io::Error> {
let path = self.frame_dump_path(name);
fs::write(&path, frame.all_text())?;
Ok(path)
}
pub fn save_artifact(
&self,
name: &str,
artifact: &CaptureArtifact,
) -> Result<(), std::io::Error> {
let frame_path = self.frame_dump_path(name);
fs::write(&frame_path, &artifact.frame_text)?;
if let Some(screenshot) = &artifact.screenshot_path
&& screenshot.exists()
{
let dest = self.screenshot_path(name);
fs::copy(screenshot, &dest)?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn artifact_dir_creates_directory() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let artifact_path = temp.path().join("artifacts");
let dir = ArtifactDir::new(&artifact_path).expect("failed to create artifact dir");
assert!(dir.root().exists());
}
#[test]
fn screenshot_path_uses_name() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let dir =
ArtifactDir::new(temp.path().join("artifacts")).expect("failed to create artifact dir");
let path = dir.screenshot_path("startup");
assert!(path.ends_with("startup.png"));
}
#[test]
fn save_frame_dump_writes_text() {
let temp = tempfile::TempDir::new().expect("failed to create temp dir");
let dir =
ArtifactDir::new(temp.path().join("artifacts")).expect("failed to create artifact dir");
let frame = TerminalFrame::new(80, 24, b"Hello World");
let path = dir
.save_frame_dump("test", &frame)
.expect("failed to save frame dump");
let content = fs::read_to_string(path).expect("failed to read frame dump");
assert!(content.contains("Hello World"));
}
#[test]
fn capture_artifact_from_frame_captures_text() {
let frame = TerminalFrame::new(80, 24, b"Test Content");
let artifact = CaptureArtifact::from_frame(&frame);
assert!(artifact.frame_text.contains("Test Content"));
assert_eq!(artifact.cols, 80);
assert_eq!(artifact.rows, 24);
assert!(artifact.screenshot_path.is_none());
}
}