huskies: merge 895
This commit is contained in:
@@ -682,3 +682,257 @@ fn snippet_skips_leading_empty_lines() {
|
||||
let result = first_non_empty_snippet(text, 120);
|
||||
assert_eq!(result, "actual error here");
|
||||
}
|
||||
|
||||
// -- AC1: blocked items appear in-place, not in a separate "Blocked" section --
|
||||
|
||||
#[test]
|
||||
fn blocked_item_appears_in_in_progress_not_separate_section() {
|
||||
use tempfile::TempDir;
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
let items = vec![make_item(
|
||||
"42_story_blocked",
|
||||
"Blocked Story",
|
||||
Stage::Blocked {
|
||||
reason: "retry limit exceeded".to_string(),
|
||||
},
|
||||
)];
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let output = build_status_from_items(tmp.path(), &agents, &items);
|
||||
|
||||
// Must NOT appear under a separate "Blocked" section.
|
||||
assert!(
|
||||
!output.contains("**Blocked**"),
|
||||
"output must not have a separate Blocked section: {output}"
|
||||
);
|
||||
|
||||
// Must appear under "In Progress".
|
||||
let in_progress_pos = output
|
||||
.find("**In Progress**")
|
||||
.expect("In Progress section must exist");
|
||||
let qa_pos = output.find("**QA**").expect("QA section must exist");
|
||||
let story_pos = output
|
||||
.find("42 [story]")
|
||||
.expect("story must appear in output");
|
||||
|
||||
assert!(
|
||||
story_pos > in_progress_pos && story_pos < qa_pos,
|
||||
"blocked story should be in In Progress section: in_progress={in_progress_pos} story={story_pos} qa={qa_pos}\n{output}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blocked_item_shows_red_dot_in_in_progress_section() {
|
||||
use tempfile::TempDir;
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
let items = vec![make_item(
|
||||
"50_story_blocked_dot",
|
||||
"Blocked With Dot",
|
||||
Stage::Blocked {
|
||||
reason: "too many failures".to_string(),
|
||||
},
|
||||
)];
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let output = build_status_from_items(tmp.path(), &agents, &items);
|
||||
|
||||
assert!(
|
||||
output.contains("\u{1F534} "), // 🔴
|
||||
"blocked story should show red circle emoji: {output}"
|
||||
);
|
||||
}
|
||||
|
||||
// -- AC2: stage counts include blocked items --
|
||||
|
||||
#[test]
|
||||
fn in_progress_count_includes_blocked_items() {
|
||||
use tempfile::TempDir;
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
let items = vec![
|
||||
make_item("10_story_coding", "Coding Story", Stage::Coding),
|
||||
make_item(
|
||||
"11_story_blocked",
|
||||
"Blocked Story",
|
||||
Stage::Blocked {
|
||||
reason: "failed".to_string(),
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let output = build_status_from_items(tmp.path(), &agents, &items);
|
||||
|
||||
// "In Progress" header should show count of 2 (one coding + one blocked).
|
||||
assert!(
|
||||
output.contains("**In Progress** (2)"),
|
||||
"In Progress count should include blocked items: {output}"
|
||||
);
|
||||
}
|
||||
|
||||
// -- AC4: frozen items appear in-place, with ❄️ indicator --
|
||||
|
||||
#[test]
|
||||
fn frozen_coding_item_appears_in_in_progress_section() {
|
||||
use tempfile::TempDir;
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
let items = vec![make_item(
|
||||
"60_story_frozen",
|
||||
"Frozen Coding Story",
|
||||
Stage::Frozen {
|
||||
resume_to: Box::new(Stage::Coding),
|
||||
},
|
||||
)];
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let output = build_status_from_items(tmp.path(), &agents, &items);
|
||||
|
||||
let in_progress_pos = output
|
||||
.find("**In Progress**")
|
||||
.expect("In Progress section must exist");
|
||||
let qa_pos = output.find("**QA**").expect("QA section must exist");
|
||||
let story_pos = output
|
||||
.find("60 [story]")
|
||||
.expect("story must appear in output");
|
||||
|
||||
assert!(
|
||||
story_pos > in_progress_pos && story_pos < qa_pos,
|
||||
"frozen-coding story should appear in In Progress: in_progress={in_progress_pos} story={story_pos} qa={qa_pos}\n{output}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frozen_qa_item_appears_in_qa_section() {
|
||||
use tempfile::TempDir;
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
let items = vec![make_item(
|
||||
"70_story_frozen_qa",
|
||||
"Frozen QA Story",
|
||||
Stage::Frozen {
|
||||
resume_to: Box::new(Stage::Qa),
|
||||
},
|
||||
)];
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let output = build_status_from_items(tmp.path(), &agents, &items);
|
||||
|
||||
let qa_pos = output.find("**QA**").expect("QA section must exist");
|
||||
let merge_pos = output.find("**Merge**").expect("Merge section must exist");
|
||||
let story_pos = output
|
||||
.find("70 [story]")
|
||||
.expect("story must appear in output");
|
||||
|
||||
assert!(
|
||||
story_pos > qa_pos && story_pos < merge_pos,
|
||||
"frozen-QA story should appear in QA section: qa={qa_pos} story={story_pos} merge={merge_pos}\n{output}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frozen_item_shows_snowflake_indicator() {
|
||||
use tempfile::TempDir;
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
let items = vec![make_item(
|
||||
"80_story_frozen_flake",
|
||||
"Frozen Flake Story",
|
||||
Stage::Frozen {
|
||||
resume_to: Box::new(Stage::Coding),
|
||||
},
|
||||
)];
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let output = build_status_from_items(tmp.path(), &agents, &items);
|
||||
|
||||
assert!(
|
||||
output.contains("\u{2744}\u{FE0F}"), // ❄️
|
||||
"frozen story should show snowflake prefix: {output}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frozen_and_blocked_use_distinct_indicators() {
|
||||
use tempfile::TempDir;
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
let items = vec![
|
||||
make_item(
|
||||
"90_story_blocked_ind",
|
||||
"Blocked Story",
|
||||
Stage::Blocked {
|
||||
reason: "failed".to_string(),
|
||||
},
|
||||
),
|
||||
make_item(
|
||||
"91_story_frozen_ind",
|
||||
"Frozen Story",
|
||||
Stage::Frozen {
|
||||
resume_to: Box::new(Stage::Coding),
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let output = build_status_from_items(tmp.path(), &agents, &items);
|
||||
|
||||
assert!(
|
||||
output.contains("\u{1F534} "), // 🔴 for blocked
|
||||
"blocked story should show red dot: {output}"
|
||||
);
|
||||
assert!(
|
||||
output.contains("\u{2744}\u{FE0F}"), // ❄️ for frozen
|
||||
"frozen story should show snowflake: {output}"
|
||||
);
|
||||
}
|
||||
|
||||
// -- merge-failure items appear in Merge section --
|
||||
|
||||
#[test]
|
||||
fn merge_failure_item_appears_in_merge_section_not_blocked() {
|
||||
use crate::pipeline_state::BranchName;
|
||||
use tempfile::TempDir;
|
||||
let tmp = TempDir::new().unwrap();
|
||||
|
||||
let items = vec![make_item(
|
||||
"100_story_merge_fail",
|
||||
"Merge Failure Story",
|
||||
Stage::MergeFailure {
|
||||
reason: "conflict in lib.rs".to_string(),
|
||||
feature_branch: BranchName("feature/100".to_string()),
|
||||
commits_ahead: std::num::NonZeroU32::new(1).unwrap(),
|
||||
},
|
||||
)];
|
||||
|
||||
let agents = AgentPool::new_test(3000);
|
||||
let output = build_status_from_items(tmp.path(), &agents, &items);
|
||||
|
||||
// Must not be in a separate "Blocked" section.
|
||||
assert!(
|
||||
!output.contains("**Blocked**"),
|
||||
"output must not have a separate Blocked section: {output}"
|
||||
);
|
||||
|
||||
let merge_pos = output.find("**Merge**").expect("Merge section must exist");
|
||||
let done_pos = output.find("**Done**").expect("Done section must exist");
|
||||
let story_pos = output
|
||||
.find("100 [story]")
|
||||
.expect("story must appear in output");
|
||||
|
||||
assert!(
|
||||
story_pos > merge_pos && story_pos < done_pos,
|
||||
"merge-failure story should appear in Merge section: merge={merge_pos} story={story_pos} done={done_pos}\n{output}"
|
||||
);
|
||||
|
||||
assert!(
|
||||
output.contains("\u{26D4}"), // ⛔
|
||||
"merge failure should show stop sign: {output}"
|
||||
);
|
||||
assert!(
|
||||
output.contains("conflict in lib.rs"),
|
||||
"merge failure reason should be shown: {output}"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user