use std::path::PathBuf;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SessionMode {
Default,
Test,
}
impl SessionMode {
pub fn parse(raw: Option<&str>) -> Result<Self, String> {
match raw {
None | Some("default") => Ok(SessionMode::Default),
Some("test") => Ok(SessionMode::Test),
Some(other) => Err(format!(
"alc_session_new: unknown mode '{other}' (allowed: \"default\" | \"test\")"
)),
}
}
pub fn as_str(&self) -> &'static str {
match self {
SessionMode::Default => "default",
SessionMode::Test => "test",
}
}
}
#[derive(Debug, Clone)]
pub struct AlcSession {
pub session_id: String,
pub project_root: Option<PathBuf>,
pub mode: SessionMode,
}
impl AlcSession {
pub fn new(project_root: Option<PathBuf>, mode: SessionMode) -> Self {
Self {
session_id: gen_session_id(),
project_root,
mode,
}
}
}
fn gen_session_id() -> String {
let ms = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.map(|d| d.as_millis())
.unwrap_or(0);
format!("alc-sess-{ms}")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mode_parse_accepts_default_and_test() {
assert_eq!(SessionMode::parse(None).unwrap(), SessionMode::Default);
assert_eq!(
SessionMode::parse(Some("default")).unwrap(),
SessionMode::Default
);
assert_eq!(SessionMode::parse(Some("test")).unwrap(), SessionMode::Test);
}
#[test]
fn mode_parse_rejects_unknown_with_typed_error() {
let err = SessionMode::parse(Some("sandbox")).unwrap_err();
assert!(err.contains("unknown mode 'sandbox'"));
assert!(err.contains("\"default\""));
assert!(err.contains("\"test\""));
}
#[test]
fn mode_as_str_round_trips_with_parse() {
for mode in [SessionMode::Default, SessionMode::Test] {
let parsed = SessionMode::parse(Some(mode.as_str())).unwrap();
assert_eq!(parsed, mode);
}
}
#[test]
fn session_id_has_alc_sess_prefix_and_grows_monotonically() {
let s1 = AlcSession::new(None, SessionMode::Default);
std::thread::sleep(std::time::Duration::from_millis(2));
let s2 = AlcSession::new(None, SessionMode::Default);
assert!(s1.session_id.starts_with("alc-sess-"));
assert!(s2.session_id.starts_with("alc-sess-"));
assert_ne!(s1.session_id, s2.session_id);
}
#[test]
fn session_records_project_root_and_mode() {
let pr = std::path::PathBuf::from("/tmp/example");
let s = AlcSession::new(Some(pr.clone()), SessionMode::Test);
assert_eq!(s.project_root.as_deref(), Some(pr.as_path()));
assert_eq!(s.mode, SessionMode::Test);
}
}