Ajoute created_by sur IssueIndexEntry/TicketSummaryDto + filtre createdBy (#5), et les use cases BulkUpdateIssueStatus/Priority + BulkDeleteIssues avec les DTO/outils MCP idea_ticket_bulk_* associés (#6). NON VERT : BulkDeleteIssues::execute référence BatchIssueResult::deleted(), constructeur pas encore ajouté à BatchIssueResult (seuls ok/err existent) -> `cargo check` échoue (E0599 dans application::issues::mod). Reste à DevBackend avant toute QA/merge. Branché sur feature/sdk-integration (dépend du commit #2 dans orchestrator/mcp/server.rs et tools.rs) ; à rebaser sur develop une fois feature/sdk-integration mergé. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
145 lines
3.6 KiB
Rust
145 lines
3.6 KiB
Rust
use std::str::FromStr;
|
|
|
|
use domain::{
|
|
AgentIssueRef, AgentIssueRole, Issue, IssueActor, IssueError, IssueId, IssueIndexEntry,
|
|
IssueLink, IssueLinkKind, IssueNumber, IssuePriority, IssueRef, IssueStatus, IssueVersion,
|
|
MarkdownDoc,
|
|
};
|
|
|
|
fn issue_number(n: u64) -> IssueNumber {
|
|
IssueNumber::new(n).unwrap()
|
|
}
|
|
|
|
fn issue() -> Issue {
|
|
Issue::new(
|
|
IssueId::new_random(),
|
|
issue_number(7),
|
|
"Fix boot reconcile",
|
|
MarkdownDoc::new("Description"),
|
|
IssueStatus::Open,
|
|
IssuePriority::Medium,
|
|
MarkdownDoc::new("Carnet"),
|
|
vec![IssueLink {
|
|
target: IssueRef::from(issue_number(8)),
|
|
kind: IssueLinkKind::RelatesTo,
|
|
}],
|
|
vec![AgentIssueRef {
|
|
agent_id: domain::AgentId::new_random(),
|
|
role: AgentIssueRole::Assigned,
|
|
}],
|
|
IssueActor::User,
|
|
1_000,
|
|
)
|
|
.unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn issue_ref_parses_and_formats_strict_hash_number() {
|
|
let reference = IssueRef::from_str("#42").unwrap();
|
|
|
|
assert_eq!(reference.number().get(), 42);
|
|
assert_eq!(reference.to_string(), "#42");
|
|
assert_eq!(
|
|
IssueRef::from_str("42"),
|
|
Err(IssueError::InvalidRef("42".into()))
|
|
);
|
|
assert_eq!(IssueRef::from_str("#0"), Err(IssueError::InvalidNumber));
|
|
assert_eq!(
|
|
IssueRef::from_str("#abc"),
|
|
Err(IssueError::InvalidRef("#abc".into()))
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_number_must_be_positive() {
|
|
assert_eq!(IssueNumber::new(0), Err(IssueError::InvalidNumber));
|
|
}
|
|
|
|
#[test]
|
|
fn issue_title_must_not_be_empty() {
|
|
let err = Issue::new(
|
|
IssueId::new_random(),
|
|
issue_number(1),
|
|
" ",
|
|
MarkdownDoc::new("Description"),
|
|
IssueStatus::Open,
|
|
IssuePriority::Medium,
|
|
MarkdownDoc::default(),
|
|
Vec::new(),
|
|
Vec::new(),
|
|
IssueActor::User,
|
|
1,
|
|
)
|
|
.unwrap_err();
|
|
|
|
assert_eq!(err, IssueError::EmptyTitle);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_rejects_self_link() {
|
|
let err = Issue::new(
|
|
IssueId::new_random(),
|
|
issue_number(9),
|
|
"Self link",
|
|
MarkdownDoc::new("Description"),
|
|
IssueStatus::Open,
|
|
IssuePriority::Medium,
|
|
MarkdownDoc::default(),
|
|
vec![IssueLink {
|
|
target: IssueRef::from(issue_number(9)),
|
|
kind: IssueLinkKind::Blocks,
|
|
}],
|
|
Vec::new(),
|
|
IssueActor::User,
|
|
1,
|
|
)
|
|
.unwrap_err();
|
|
|
|
assert_eq!(
|
|
err,
|
|
IssueError::SelfLink {
|
|
reference: IssueRef::from(issue_number(9))
|
|
}
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_mutation_increments_version_and_updates_actor_time() {
|
|
let issue = issue();
|
|
assert_eq!(issue.version, IssueVersion::INITIAL);
|
|
|
|
let updated = issue
|
|
.mutate(IssueActor::System, 2_000, |i| {
|
|
i.status = IssueStatus::InProgress;
|
|
})
|
|
.unwrap();
|
|
|
|
assert_eq!(updated.version.get(), 2);
|
|
assert_eq!(updated.status, IssueStatus::InProgress);
|
|
assert_eq!(updated.updated_by, IssueActor::System);
|
|
assert_eq!(updated.updated_at, 2_000);
|
|
}
|
|
|
|
#[test]
|
|
fn issue_index_entry_reuses_created_by_source_of_truth() {
|
|
let agent_id = domain::AgentId::new_random();
|
|
let issue = Issue::new(
|
|
IssueId::new_random(),
|
|
issue_number(11),
|
|
"Agent-created",
|
|
MarkdownDoc::new("Description"),
|
|
IssueStatus::Open,
|
|
IssuePriority::Medium,
|
|
MarkdownDoc::default(),
|
|
Vec::new(),
|
|
Vec::new(),
|
|
IssueActor::Agent { agent_id },
|
|
1,
|
|
)
|
|
.unwrap();
|
|
|
|
let row = IssueIndexEntry::from(&issue);
|
|
|
|
assert_eq!(row.created_by, IssueActor::Agent { agent_id });
|
|
}
|