153 lines
4.9 KiB
Rust
153 lines
4.9 KiB
Rust
//! When sync began (M5c spec, section 5): the ledger's first line, `began`, once; a ledger read
|
|
//! back that does not start with it, or has a second, is damaged; and conclusions matched by their
|
|
//! peer as well as their workspace and text. Do not edit.
|
|
|
|
#[path = "support/ledger.rs"]
|
|
mod ledger;
|
|
#[path = "support/tmp.rs"]
|
|
mod tmp;
|
|
|
|
use ledger::{
|
|
Home, TIME, began, began_line, conclude, decided, edit, line, sent, time, to_trusted, turn,
|
|
};
|
|
use memoryd::honcho::ledger::{Action, Ledger, LedgerError, Workspace};
|
|
|
|
const POINTER: &str = "; see docs/runbook.md#honcho-ledger-damaged";
|
|
|
|
#[test]
|
|
fn the_began_line() {
|
|
assert_eq!(
|
|
serde_json::to_string(&began()).unwrap(),
|
|
format!(r#"{{"type":"began","time":"{TIME}"}}"#)
|
|
);
|
|
assert_eq!(
|
|
began_line(),
|
|
format!("{{\"type\":\"began\",\"time\":\"{TIME}\"}}\n")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn began_is_kept_and_read_back() {
|
|
let home = Home::new("began-kept");
|
|
let fresh = home.open();
|
|
assert_eq!(fresh.began(), None);
|
|
let mut ledger = home.begun();
|
|
assert_eq!(ledger.began(), Some(time()));
|
|
ledger
|
|
.append(decided(&turn("chat-1", 1), to_trusted("kyle")))
|
|
.unwrap();
|
|
assert_eq!(home.text().lines().next(), Some(began_line().trim_end()));
|
|
let again = home.open();
|
|
assert_eq!(again.began(), Some(time()));
|
|
assert_eq!(again.counts().decided, 1, "began is no item");
|
|
}
|
|
|
|
#[test]
|
|
fn began_only_first_and_once() {
|
|
let home = Home::new("began-once");
|
|
let mut ledger = home.begun();
|
|
let err = ledger.append(began()).unwrap_err();
|
|
assert!(matches!(err, LedgerError::BeganNotFirst), "{err:?}");
|
|
assert_eq!(err.to_string(), "sync began, but not on the first line");
|
|
let home = Home::new("began-late");
|
|
let mut ledger = home.open();
|
|
ledger
|
|
.append(decided(&turn("chat-1", 1), to_trusted("kyle")))
|
|
.unwrap();
|
|
assert!(matches!(
|
|
ledger.append(began()),
|
|
Err(LedgerError::BeganNotFirst)
|
|
));
|
|
}
|
|
|
|
/// `open`'s error for `text`: its line and its display.
|
|
fn damaged(tag: &str, text: &str) -> (usize, String, Home) {
|
|
let home = Home::new(tag);
|
|
home.write(text);
|
|
let err = Ledger::open(&home.path).unwrap_err();
|
|
let shown = err.to_string();
|
|
match err {
|
|
LedgerError::Damaged { line, .. } => (line, shown, home),
|
|
other => panic!("not Damaged: {other:?}"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn a_ledger_that_does_not_start_with_began_is_damaged() {
|
|
let first = line(&decided(&turn("chat-1", 1), to_trusted("kyle")));
|
|
let (number, shown, home) = damaged("began-missing", &first);
|
|
assert_eq!(number, 1);
|
|
assert_eq!(
|
|
shown,
|
|
format!(
|
|
"{}:1: the first line is not when sync began{POINTER}",
|
|
home.path.display()
|
|
)
|
|
);
|
|
let twice = format!("{}{first}{}", began_line(), began_line());
|
|
let (number, shown, home) = damaged("began-twice", &twice);
|
|
assert_eq!(number, 3);
|
|
assert_eq!(
|
|
shown,
|
|
format!(
|
|
"{}:3: sync began, but not on the first line{POINTER}",
|
|
home.path.display()
|
|
)
|
|
);
|
|
// An empty ledger has no line to be wrong: it is empty.
|
|
let home = Home::new("began-empty");
|
|
home.write("");
|
|
assert_eq!(home.open().began(), None);
|
|
}
|
|
|
|
fn unconclude_about(peer: &str, text: &str) -> Action {
|
|
Action::Unconclude {
|
|
workspace: Workspace::Trusted,
|
|
peer: peer.to_string(),
|
|
text: text.to_string(),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn a_conclusion_is_found_by_its_peer_too() {
|
|
let home = Home::new("began-peer");
|
|
let mut ledger = home.begun();
|
|
let (owner, agent, undo) = (edit("e1", 0), edit("e2", 0), edit("e3", 0));
|
|
ledger
|
|
.append(decided(&owner, conclude(Workspace::Trusted, "Uses tabs.")))
|
|
.unwrap();
|
|
let mut about_agent = conclude(Workspace::Trusted, "Uses tabs.");
|
|
if let Action::Conclude { peer, .. } = &mut about_agent {
|
|
*peer = "boxmaker0".to_string();
|
|
}
|
|
ledger.append(decided(&agent, about_agent)).unwrap();
|
|
ledger.append(sent(&owner, &["c-owner"])).unwrap();
|
|
ledger.append(sent(&agent, &["c-agent"])).unwrap();
|
|
assert_eq!(
|
|
ledger.conclusion(Workspace::Trusted, "kyle", "Uses tabs."),
|
|
Some((owner.clone(), "c-owner".to_string()))
|
|
);
|
|
assert_eq!(
|
|
ledger.conclusion(Workspace::Trusted, "boxmaker0", "Uses tabs."),
|
|
Some((agent.clone(), "c-agent".to_string()))
|
|
);
|
|
// The owner's is undone: the agent's stays.
|
|
ledger
|
|
.append(decided(&undo, unconclude_about("kyle", "Uses tabs.")))
|
|
.unwrap();
|
|
ledger.append(sent(&undo, &["c-owner"])).unwrap();
|
|
assert_eq!(
|
|
ledger.conclusion(Workspace::Trusted, "kyle", "Uses tabs."),
|
|
None
|
|
);
|
|
assert_eq!(
|
|
ledger.conclusion(Workspace::Trusted, "boxmaker0", "Uses tabs."),
|
|
Some((agent, "c-agent".to_string()))
|
|
);
|
|
let again = home.open();
|
|
assert_eq!(
|
|
again.conclusion(Workspace::Trusted, "kyle", "Uses tabs."),
|
|
None
|
|
);
|
|
}
|