use std::{fmt::Display, path::PathBuf};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
use super::{Commit, NonZeroOid, Repo, RepoError};
pub const TEST_SUCCESS_EXIT_CODE: i32 = 0;
pub const TEST_INDETERMINATE_EXIT_CODE: i32 = 125;
pub const TEST_ABORT_EXIT_CODE: i32 = 127;
pub fn make_test_command_slug(command: String) -> String {
command.replace(['/', ' ', '\n'], "__")
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SerializedNonZeroOid(pub NonZeroOid);
impl Serialize for SerializedNonZeroOid {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.0.to_string())
}
}
impl<'de> Deserialize<'de> for SerializedNonZeroOid {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let s = String::deserialize(deserializer)?;
let oid: NonZeroOid = s.parse().map_err(|_| {
de::Error::invalid_value(de::Unexpected::Str(&s), &"a valid non-zero OID")
})?;
Ok(SerializedNonZeroOid(oid))
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum TestCommand {
String(String),
Args(Vec<String>),
}
impl Display for TestCommand {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
TestCommand::String(s) => write!(f, "{s}"),
TestCommand::Args(args) => {
for (i, arg) in args.iter().enumerate() {
if i > 0 {
write!(f, " ")?;
}
write!(f, "{}", shell_words::quote(arg))?;
}
Ok(())
}
}
}
}
#[derive(Debug, Serialize, Deserialize)]
#[allow(missing_docs)]
pub struct SerializedTestResult {
pub command: TestCommand,
pub exit_code: i32,
pub head_commit_oid: Option<SerializedNonZeroOid>,
pub snapshot_tree_oid: Option<SerializedNonZeroOid>,
#[serde(default)]
pub interactive: bool,
}
fn get_test_dir(repo: &Repo) -> Result<PathBuf, RepoError> {
Ok(repo.get_branchless_dir()?.join("test"))
}
pub fn get_test_tree_dir(repo: &Repo, commit: &Commit) -> Result<PathBuf, RepoError> {
Ok(get_test_dir(repo)?.join(commit.get_tree_oid().to_string()))
}
pub fn get_test_locks_dir(repo: &Repo) -> Result<PathBuf, RepoError> {
Ok(get_test_dir(repo)?.join("locks"))
}
pub fn get_test_worktrees_dir(repo: &Repo) -> Result<PathBuf, RepoError> {
Ok(get_test_dir(repo)?.join("worktrees"))
}
pub fn get_latest_test_command_path(repo: &Repo) -> Result<PathBuf, RepoError> {
Ok(get_test_dir(repo)?.join("latest-command"))
}