vfa_tui/models/
workspace.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Deserialize, Serialize)]
7pub struct WorkspaceEntry {
8 pub path: String,
10 pub name: Option<String>,
12 pub team: Option<String>,
14 pub tags: Option<Vec<String>>,
16 pub policy_overrides: Option<toml::Value>,
18}
19
20#[derive(Debug, Clone)]
22pub struct ResolvedWorkspace {
23 pub canonical_path: std::path::PathBuf,
25 pub name: String,
27 pub team: Option<String>,
29 pub tags: Vec<String>,
31 pub status: WorkspaceStatus,
33}
34
35#[derive(Debug, Clone, PartialEq)]
37pub enum WorkspaceStatus {
38 Available,
40 Unavailable(String),
42 Scanning,
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn workspace_entry_round_trip() {
52 let entry = WorkspaceEntry {
53 path: "$HOME/repos/payment-service".to_string(),
54 name: Some("payment-service".to_string()),
55 team: Some("payments".to_string()),
56 tags: Some(vec!["production".to_string(), "pci".to_string()]),
57 policy_overrides: None,
58 };
59
60 let json = serde_json::to_string(&entry).expect("serialize");
61 let decoded: WorkspaceEntry = serde_json::from_str(&json).expect("deserialize");
62
63 assert_eq!(decoded.path, entry.path);
64 assert_eq!(decoded.name, entry.name);
65 assert_eq!(decoded.team, entry.team);
66 assert_eq!(decoded.tags, entry.tags);
67 }
68
69 #[test]
70 fn workspace_entry_minimal_fields() {
71 let json = r#"{"path": "/home/user/foo"}"#;
72 let entry: WorkspaceEntry = serde_json::from_str(json).expect("deserialize");
73 assert_eq!(entry.path, "/home/user/foo");
74 assert!(entry.name.is_none());
75 assert!(entry.team.is_none());
76 assert!(entry.tags.is_none());
77 assert!(entry.policy_overrides.is_none());
78 }
79
80 #[test]
81 fn workspace_status_equality() {
82 assert_eq!(WorkspaceStatus::Available, WorkspaceStatus::Available);
83 assert_eq!(
84 WorkspaceStatus::Unavailable("no such path".to_string()),
85 WorkspaceStatus::Unavailable("no such path".to_string()),
86 );
87 assert_ne!(WorkspaceStatus::Available, WorkspaceStatus::Scanning);
88 }
89
90 #[test]
91 fn resolved_workspace_debug_clone() {
92 let rw = ResolvedWorkspace {
93 canonical_path: std::path::PathBuf::from("/home/user/foo"),
94 name: "foo".to_string(),
95 team: None,
96 tags: vec![],
97 status: WorkspaceStatus::Available,
98 };
99 let cloned = rw.clone();
100 assert_eq!(cloned.name, "foo");
101 let _ = format!("{:?}", rw);
103 }
104}