memoryd: sync begins when Honcho is turned on, and conclusions are matched by peer
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
//! 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
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user