OXYGENHUB
# 98a0fb9f0948 spectra / tests / cli_project.rs
3.8 KiB · Rust · last changed Spectra stands alone: its own identities, signatures and CBOR; projects of any kind of work (#26, #27) 1 day ago source blame history raw
1
//! Projects from the command line (spec §23.1): any kind of work, with or
2
//! without a folder that Spectra never reads; links drawn by the owner; an
3
//! agent needs a registered project.
4
5
use spectra_core::keys::KeyPair;
6
use std::path::Path;
7
use std::process::{Command, Output};
8
9
fn hermetic(dir: &Path) -> Command {
10
    let mut c = Command::new(env!("CARGO_BIN_EXE_spectra"));
11
    c.env("SPECTRA_DATA", dir.join("data"))
12
        .env("SPECTRA_HOME", dir.join("owner"))
13
        .env("HOME", dir)
14
        .env("XDG_DATA_HOME", dir.join("xdg"))
15
        .env("NO_COLOR", "1");
16
    c
17
}
18
19
fn run(dir: &Path, args: &[&str]) -> Output {
20
    hermetic(dir).args(args).output().unwrap()
21
}
22
23
fn text(o: &Output) -> String {
24
    format!("{}{}", String::from_utf8_lossy(&o.stdout), String::from_utf8_lossy(&o.stderr))
25
}
26
27
fn setup() -> tempfile::TempDir {
28
    let dir = tempfile::tempdir().unwrap();
29
    KeyPair::create_home(&dir.path().join("owner"), "Andy McCall", "").unwrap();
30
    assert!(run(dir.path(), &["init"]).status.success());
31
    dir
32
}
33
34
fn projects(d: &Path) -> serde_json::Value {
35
    serde_json::from_slice(&run(d, &["project", "list", "--json"]).stdout).unwrap()
36
}
37
38
#[test]
39
fn any_work_is_a_project_and_the_owner_links_them() {
40
    let dir = setup();
41
    let d = dir.path();
42
    // A book being restructured: a folder of chapters, and an index with none.
43
    std::fs::create_dir_all(d.join("Manuscript")).unwrap();
44
    std::fs::write(d.join("Manuscript/.oxymodules"), "this is not read").unwrap();
45
    let o = run(d, &["project", "add", d.join("Manuscript").to_str().unwrap(), "-d", "the book, chapter by chapter"]);
46
    assert!(o.status.success(), "{}", text(&o));
47
    let o = run(d, &["project", "add", "index", "-d", "the index and cross-references", "--url", "https://example.org/index"]);
48
    assert!(o.status.success(), "{}", text(&o));
49
    let o = run(d, &["project", "link", "index", "--depends-on", "manuscript"]);
50
    assert!(o.status.success(), "{}", text(&o));
51
52
    let list = projects(d);
53
    let book = list.as_array().unwrap().iter().find(|p| p["name"] == "manuscript").unwrap();
54
    let index = list.as_array().unwrap().iter().find(|p| p["name"] == "index").unwrap();
55
    assert_eq!(book["description"], "the book, chapter by chapter");
56
    assert!(book["path"].as_str().unwrap().ends_with("Manuscript"));
57
    assert!(index["path"].is_null(), "no folder");
58
    assert_eq!(index["url"], "https://example.org/index");
59
    assert_eq!(index["depends_on"], serde_json::json!(["manuscript"]));
60
    assert_eq!(book["depended_on_by"], serde_json::json!(["index"]));
61
62
    assert!(run(d, &["project", "link", "index", "--depends-on", "manuscript", "--remove"]).status.success());
63
    assert_eq!(projects(d)[0]["depends_on"], serde_json::json!([]));
64
    assert!(!run(d, &["project", "link", "index", "--depends-on", "nowhere"]).status.success());
65
    assert!(run(d, &["admin", "check"]).status.success());
66
    assert!(run(d, &["admin", "verify"]).status.success());
67
}
68
69
#[test]
70
fn a_project_is_registered_once_and_an_agent_needs_one() {
71
    let dir = setup();
72
    let d = dir.path();
73
    std::fs::create_dir_all(d.join("oxygen")).unwrap();
74
    assert!(run(d, &["project", "add", d.join("oxygen").to_str().unwrap()]).status.success());
75
    let again = run(d, &["project", "add", d.join("oxygen").to_str().unwrap(), "--name", "other"]);
76
    assert!(!again.status.success() && text(&again).contains("already a project"), "{}", text(&again));
77
    assert!(!run(d, &["project", "add", "Not A Name"]).status.success());
78
    let o = run(
79
        d,
80
        &["agent", "add", "kimi", "--kind", "kimi-code", "--project", "nowhere", "--home", d.join("kimi").to_str().unwrap(), "--yes"],
81
    );
82
    assert!(!o.status.success() && text(&o).contains("no project named nowhere"), "{}", text(&o));
83
    assert!(!d.join("kimi").exists(), "no key is made for an agent that cannot be added");
84
}