use guix_scheme::{validate_syntax, OperatingSystemView, OperatingSystemViewMut};
use scheme_edit::Document;
const CONFIG: &str = "\
(operating-system
(host-name \"x\")
(timezone \"UTC\")
(locale \"en_US.utf8\")
(file-systems
(cons* (file-system
(mount-point \"/boot\")
(device \"/dev/sda1\")
(type \"vfat\"))
%base-file-systems))
(services (list (service foo-service-type))))
";
fn os_form(doc: &Document) -> &scheme_edit::Node {
doc.forms().next().unwrap()
}
fn os_form_mut(doc: &mut Document) -> &mut scheme_edit::Node {
doc.forms_mut().next().unwrap()
}
#[test]
fn reads_string_fields_and_presence() {
let doc = Document::parse(CONFIG).unwrap();
let view = OperatingSystemView::new(os_form(&doc)).unwrap();
assert_eq!(view.host_name().as_deref(), Some("x"));
assert_eq!(view.timezone().as_deref(), Some("UTC"));
assert_eq!(view.locale().as_deref(), Some("en_US.utf8"));
assert!(view.field("services").is_some());
assert!(view.has_field("file-systems"));
assert!(!view.has_field("mapped-devices"));
}
#[test]
fn new_rejects_non_os_form() {
let doc = Document::parse("(list 1 2)").unwrap();
assert!(OperatingSystemView::new(os_form(&doc)).is_none());
}
#[test]
fn add_file_system_into_cons_star_preserves_tail_and_existing() {
let mut doc = Document::parse(CONFIG).unwrap();
{
let mut view = OperatingSystemViewMut::new(os_form_mut(&mut doc)).unwrap();
view.add_file_system(
"(file-system (mount-point \"/\") (device \"/dev/sda2\") (type \"ext4\"))",
)
.unwrap();
}
let out = doc.to_string();
assert!(out.contains("(mount-point \"/\")"), "new fs missing: {out}");
assert!(
out.contains("(mount-point \"/boot\")"),
"old fs lost: {out}"
);
assert!(out.contains("%base-file-systems"), "tail lost: {out}");
assert!(Document::parse(&out).is_ok(), "does not reparse: {out}");
}
#[test]
fn add_file_system_when_absent_creates_cons_star() {
let mut doc = Document::parse("(operating-system (host-name \"h\"))").unwrap();
{
let mut view = OperatingSystemViewMut::new(os_form_mut(&mut doc)).unwrap();
view.add_file_system("(file-system (mount-point \"/\") (device \"root\") (type \"ext4\"))")
.unwrap();
}
let out = doc.to_string();
assert!(out.contains("(file-systems"), "field not created: {out}");
assert!(out.contains("cons*"), "not a cons* shape: {out}");
assert!(out.contains("%base-file-systems"), "no base tail: {out}");
assert!(Document::parse(&out).is_ok());
}
#[test]
fn add_mapped_device_when_absent_creates_list() {
let mut doc = Document::parse("(operating-system (host-name \"h\"))").unwrap();
{
let mut view = OperatingSystemViewMut::new(os_form_mut(&mut doc)).unwrap();
view.add_mapped_device(
"(mapped-device (source \"my-root\") (target \"root\") (type luks-device-mapping))",
)
.unwrap();
}
let out = doc.to_string();
assert!(out.contains("(mapped-devices"), "field not created: {out}");
assert!(out.contains("(list"), "not a list shape: {out}");
assert!(out.contains("(source \"my-root\")"));
assert!(Document::parse(&out).is_ok());
}
#[test]
fn add_file_system_rejects_wrong_datum() {
let mut doc = Document::parse(CONFIG).unwrap();
let mut view = OperatingSystemViewMut::new(os_form_mut(&mut doc)).unwrap();
assert!(view
.add_file_system("(mapped-device (source \"x\"))")
.is_err());
assert!(view.add_file_system("(unclosed").is_err());
}
#[test]
fn set_field_creates_and_replaces() {
let mut doc = Document::parse("(operating-system (host-name \"h\"))").unwrap();
{
let mut view = OperatingSystemViewMut::new(os_form_mut(&mut doc)).unwrap();
view.set_field("timezone", "\"Europe/Berlin\"").unwrap();
view.set_field("host-name", "\"renamed\"").unwrap();
}
let view_doc = doc.to_string();
let reparsed = Document::parse(&view_doc).unwrap();
let view = OperatingSystemView::new(os_form(&reparsed)).unwrap();
assert_eq!(view.timezone().as_deref(), Some("Europe/Berlin"));
assert_eq!(view.host_name().as_deref(), Some("renamed"));
}
#[test]
fn enterprise_merge_injects_disk_layout() {
let mut doc =
Document::parse("(operating-system\n (inherit %os-base)\n (host-name \"ent\"))").unwrap();
{
let mut view = OperatingSystemViewMut::new(os_form_mut(&mut doc)).unwrap();
view.add_file_system(
"(file-system (mount-point \"/\") (device \"/dev/sda2\") (type \"ext4\"))",
)
.unwrap();
view.add_mapped_device(
"(mapped-device (source \"crypt\") (target \"root\") (type luks-device-mapping))",
)
.unwrap();
}
let out = doc.to_string();
assert!(out.contains("(inherit %os-base)"), "inherit lost: {out}");
assert!(out.contains("(file-systems"), "no file-systems: {out}");
assert!(out.contains("(mapped-devices"), "no mapped-devices: {out}");
assert!(Document::parse(&out).is_ok(), "does not reparse: {out}");
let reparsed = Document::parse(&out).unwrap();
let view = OperatingSystemView::new(os_form(&reparsed)).unwrap();
assert!(view.has_field("file-systems"));
assert!(view.has_field("mapped-devices"));
assert_eq!(view.host_name().as_deref(), Some("ent"));
}
#[test]
fn read_only_view_is_byte_identical() {
let doc = Document::parse(CONFIG).unwrap();
let _view = OperatingSystemView::new(os_form(&doc)).unwrap();
assert_eq!(doc.to_string(), CONFIG);
}
#[test]
fn validate_syntax_accepts_and_rejects() {
assert!(validate_syntax("(a b)").is_ok());
assert!(validate_syntax("(unclosed").is_err());
}