guix-scheme 0.1.0

Read, edit, and generate Guix Scheme files (channels.scm, system config.scm) from Rust
Documentation
//! Read/write coverage for a live guix-install-generated system.scm.

use guix_scheme::record::RecordViewMut;
use scheme_edit::{list, string_lit, sym, Document};

fn fixture() -> String {
    std::fs::read_to_string(concat!(
        env!("CARGO_MANIFEST_DIR"),
        "/../scheme-edit/tests/fixtures/system/live-panther.scm"
    ))
    .unwrap()
}

fn diff_lines(a: &str, b: &str) -> usize {
    a.lines().zip(b.lines()).filter(|(x, y)| x != y).count()
}

#[test]
fn roundtrips_byte_identical() {
    let src = fixture();
    let doc = Document::parse(&src).unwrap();
    assert_eq!(doc.to_string(), src);
}

#[test]
fn host_name_edit_is_single_line_diff() {
    let src = fixture();
    let mut doc = Document::parse(&src).unwrap();
    let os = doc
        .forms_mut()
        .find(|n| n.head_symbol() == Some("operating-system"))
        .unwrap();
    let mut v = RecordViewMut::new(os).unwrap();
    v.set_field("host-name", string_lit("renamed"));
    let out = doc.to_string();
    assert!(out.contains("(host-name \"renamed\")"));
    assert_eq!(diff_lines(&src, &out), 1);
}

#[test]
fn service_swap_preserves_everything_else() {
    let src = fixture();
    let mut doc = Document::parse(&src).unwrap();
    {
        let os = doc
            .forms_mut()
            .find(|n| n.head_symbol() == Some("operating-system"))
            .unwrap();
        let mut v = RecordViewMut::new(os).unwrap();
        let services = v.field_mut("services").unwrap();
        assert_eq!(services.head_symbol(), Some("append"));
        let list_idx = services
            .position_of(|n| n.head_symbol() == Some("list"))
            .unwrap();
        let inner = services.data_child_mut(list_idx).unwrap();
        let xfce = inner
            .position_of(|n| n.to_source().contains("xfce-desktop-service-type"))
            .unwrap();
        inner.replace_child(
            xfce,
            list(vec![sym("service"), sym("plasma-desktop-service-type")]),
        );
    }
    let out = doc.to_string();
    assert!(out.contains("(service plasma-desktop-service-type)"));
    assert!(!out.contains("xfce"));
    assert!(out.contains("(service openssh-service-type)"));
    assert!(out.contains("%os-desktop-services"));
    assert_eq!(diff_lines(&src, &out), 1);
}

#[test]
fn user_comment_edit_is_single_line_diff() {
    let src = fixture();
    let mut doc = Document::parse(&src).unwrap();
    {
        let os = doc
            .forms_mut()
            .find(|n| n.head_symbol() == Some("operating-system"))
            .unwrap();
        let mut v = RecordViewMut::new(os).unwrap();
        let users = v.field_mut("users").unwrap();
        assert_eq!(users.head_symbol(), Some("cons"));
        let ua_idx = users
            .position_of(|n| n.head_symbol() == Some("user-account"))
            .unwrap();
        let ua = users.data_child_mut(ua_idx).unwrap();
        let mut uv = RecordViewMut::new(ua).unwrap();
        uv.set_field("comment", string_lit("Panther User"));
    }
    let out = doc.to_string();
    assert!(out.contains("(comment \"Panther User\")"));
    assert!(out.contains("(supplementary-groups '(\"wheel\" \"audio\" \"video\"))"));
    assert_eq!(diff_lines(&src, &out), 1);
}