use crate::domain::model::decision_record::RecordLinks;
use crate::domain::model::record_ref::DecisionRecordRef;
use crate::domain::usecases::decision_record::DecisionRecordRepository;
pub fn list_links(
repo: &dyn DecisionRecordRepository,
id: &DecisionRecordRef,
) -> anyhow::Result<RecordLinks> {
let record = repo
.find_by_id(id)?
.ok_or_else(|| anyhow::anyhow!("record {id} not found"))?;
Ok(record.links)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::domain::usecases::decision_record::tests::{
adr, FakeDecisionRecordRepository, RecordFixture,
};
fn scenario() -> Scenario {
Scenario {
repo: FakeDecisionRecordRepository::with_records(vec![]),
}
}
struct Scenario {
repo: FakeDecisionRecordRepository,
}
impl Scenario {
fn given(mut self, fixture: RecordFixture) -> Self {
let raw = fixture
.id
.as_deref()
.expect("given() requires an explicit id — use .with_id()")
.to_string();
let numeric = DecisionRecordRef::new(&raw)
.unwrap_or_else(|_| panic!("given(): invalid id {raw:?}"));
self.repo.push_record(fixture.build(numeric));
self
}
fn when_list_links(self, id: &str) -> Outcome {
let id_ref = DecisionRecordRef::new(id)
.unwrap_or_else(|_| panic!("when_list_links: invalid id {id:?}"));
let result = list_links(&self.repo, &id_ref);
Outcome { result }
}
}
struct Outcome {
result: anyhow::Result<RecordLinks>,
}
impl Outcome {
fn then_link_count(self, expected: usize) -> Self {
let links = self.result.as_ref().expect("expected Ok, got Err");
assert_eq!(
links.len(),
expected,
"expected {expected} link(s), got {}",
links.len()
);
self
}
fn then_link_target(self, index: usize, expected: &str) -> Self {
let links = self.result.as_ref().expect("expected Ok, got Err");
assert_eq!(
links[index].target.as_str(),
expected,
"expected link[{index}].target = {expected:?}"
);
self
}
fn then_err_contains(self, substring: &str) {
let msg = self.result.expect_err("expected Err, got Ok").to_string();
assert!(
msg.contains(substring),
"expected error containing {substring:?}, got {msg:?}"
);
}
}
#[test]
fn listing_links_returns_the_links_of_a_record() {
scenario()
.given(
adr("Use Rust")
.with_id("ADR-0001")
.with_link("ADR-0001", "supersedes"),
)
.when_list_links("ADR-0001")
.then_link_count(1)
.then_link_target(0, "ADR-0001");
}
#[test]
fn listing_links_of_an_unknown_record_returns_an_error() {
scenario()
.when_list_links("ADR-0099")
.then_err_contains("not found");
}
#[test]
fn listing_links_returns_empty_when_the_record_has_none() {
scenario()
.given(adr("Use Rust").with_id("ADR-0001"))
.when_list_links("ADR-0001")
.then_link_count(0);
}
#[test]
fn listing_links_returns_the_correct_relationship() {
scenario()
.given(
adr("Use Rust")
.with_id("ADR-0001")
.with_link("ADR-0002", "amends"),
)
.when_list_links("ADR-0001")
.then_link_count(1)
.then_link_target(0, "ADR-0002");
}
}