use tedi::CloseState;
use v_fixtures::FixtureRenderer;
use crate::{
common::{
FixtureIssuesExt, TestContext,
are_you_sure::{UnsafePathExt, read_issue_file},
parse_virtual,
},
render_fixture,
};
#[tokio::test]
async fn test_comments_with_ids_sync_correctly() {
let ctx = TestContext::build_with_preexisting_state_unsafe("");
let vi = parse_virtual(
r#"- [ ] a <!-- @mock_user https://github.com/o/r/issues/1 -->
body text
<!-- @mock_user https://github.com/o/r/issues/1#issuecomment-12345 -->
This is my comment
"#,
);
let issue = ctx.consensus(&vi, None).await;
ctx.remote(&vi, None);
let out = ctx.open_issue(&issue).args(&["--force"]).run();
eprintln!("stdout: {}", out.stdout);
eprintln!("stderr: {}", out.stderr);
assert!(out.status.success(), "sync failed: {}", out.stderr);
}
#[tokio::test]
async fn test_nested_issues_preserved_through_sync() {
let ctx = TestContext::build_with_preexisting_state_unsafe("");
let vi = parse_virtual(
r#"- [ ] a <!-- @mock_user https://github.com/o/r/issues/1 -->
lorem ipsum
- [ ] b <!-- @mock_user https://github.com/o/r/issues/2 -->
nested body b
- [ ] c <!-- @mock_user https://github.com/o/r/issues/3 -->
nested body c
"#,
);
let issue = ctx.consensus(&vi, None).await;
ctx.remote(&vi, None);
let out = ctx.open_issue(&issue).run();
eprintln!("stdout: {}", out.stdout);
eprintln!("stderr: {}", out.stderr);
assert!(out.status.success(), "stderr: {}", out.stderr);
let path = ctx.resolve_issue_path(&issue);
let parent_dir = path.parent().unwrap();
let child_b_path = parent_dir.join("2_-_b.md");
let child_c_path = parent_dir.join("3_-_c.md");
let child_b_content = read_issue_file(&child_b_path);
let child_c_content = read_issue_file(&child_c_path);
assert!(child_b_content.contains("nested body b"), "nested issue b body lost");
assert!(child_c_content.contains("nested body c"), "nested issue c body lost");
}
#[tokio::test]
async fn test_blockers_preserved_through_sync() {
let ctx = TestContext::build_with_preexisting_state_unsafe("");
let vi = parse_virtual(
r#"- [ ] a <!-- @mock_user https://github.com/o/r/issues/1 -->
lorem ipsum
# Blockers
- first blocker
- second blocker
"#,
);
let issue = ctx.consensus(&vi, None).await;
ctx.remote(&vi, None);
let out = ctx.open_issue(&issue).run();
eprintln!("stdout: {}", out.stdout);
eprintln!("stderr: {}", out.stderr);
assert!(out.status.success(), "stderr: {}", out.stderr);
let path = ctx.resolve_issue_path(&issue);
let final_content = read_issue_file(&path);
assert!(final_content.contains("# Blockers"), "blockers section lost");
assert!(final_content.contains("first blocker"), "first blocker lost");
assert!(final_content.contains("second blocker"), "second blocker lost");
}
#[tokio::test]
async fn test_blockers_added_during_edit_preserved() {
let ctx = TestContext::build_with_preexisting_state_unsafe("");
let initial_vi = parse_virtual(
r#"- [ ] a <!-- @mock_user https://github.com/o/r/issues/1 -->
lorem ipsum
"#,
);
let initial_issue = ctx.consensus(&initial_vi, None).await;
ctx.remote(&initial_vi, None);
let edited_issue = parse_virtual(
r#"- [ ] a <!-- @mock_user https://github.com/o/r/issues/1 -->
lorem ipsum
# Blockers
- new blocker added
"#,
);
let out = ctx.open_issue(&initial_issue).edit(&edited_issue).run();
eprintln!("stdout: {}", out.stdout);
eprintln!("stderr: {}", out.stderr);
assert!(out.status.success(), "stderr: {}", out.stderr);
let path = ctx.resolve_issue_path(&initial_issue);
let final_content = read_issue_file(&path);
assert!(final_content.contains("# Blockers"), "blockers section not preserved");
assert!(final_content.contains("new blocker added"), "added blocker lost");
}
#[tokio::test]
async fn test_blockers_with_nesting_preserved() {
let ctx = TestContext::build_with_preexisting_state_unsafe("");
let vi = parse_virtual(
r#"- [ ] a <!-- @mock_user https://github.com/o/r/issues/1 -->
lorem ipsum
# Blockers
- phase 1
- task alpha
- task beta
- phase 2
- task gamma
"#,
);
let issue = ctx.consensus(&vi, None).await;
ctx.remote(&vi, None);
let out = ctx.open_issue(&issue).run();
eprintln!("stdout: {}", out.stdout);
eprintln!("stderr: {}", out.stderr);
assert!(out.status.success(), "stderr: {}", out.stderr);
let path = ctx.resolve_issue_path(&issue);
let final_content = read_issue_file(&path);
assert!(final_content.contains("phase 1"), "phase 1 lost");
assert!(final_content.contains("phase 2"), "phase 2 lost");
assert!(final_content.contains("task alpha"), "task alpha lost");
assert!(final_content.contains("task gamma"), "task gamma lost");
}
#[tokio::test]
async fn test_closing_nested_issue_creates_bak_file() {
let ctx = TestContext::build();
let initial_vi = parse_virtual(
r#"- [ ] a <!-- @mock_user https://github.com/o/r/issues/1 -->
lorem ipsum
- [ ] b <!-- @mock_user https://github.com/o/r/issues/2 -->
nested body content
"#,
);
let initial_issue = ctx.consensus(&initial_vi, None).await;
ctx.remote(&initial_vi, None);
let edited_issue = {
let mut initial = initial_issue.clone();
let (_, child) = initial.children.iter_mut().next().unwrap();
child.contents.state = CloseState::Closed;
initial
};
let out = ctx.open_issue(&initial_issue).edit(&edited_issue.into()).run();
assert!(out.status.success(), "stderr: {}", out.stderr);
insta::assert_snapshot!(render_fixture(FixtureRenderer::try_new(&ctx).unwrap().skip_meta(), &out), @"
//- /o/r/1_-_a/2_-_b.md.bak
- [x] b <!-- @mock_user https://github.com/o/r/issues/2 -->
nested body content
//- /o/r/1_-_a/__main__.md
- [ ] a <!-- @mock_user https://github.com/o/r/issues/1 -->
lorem ipsum
");
let path = ctx.resolve_issue_path(&initial_issue);
let closed_child_path = path.parent().unwrap().join("2_-_b.md.bak");
assert!(closed_child_path.exists(), "closed nested issue should have .bak file");
let child_content = read_issue_file(&closed_child_path);
assert!(child_content.contains("- [x] b"), "nested issue not marked closed");
assert!(child_content.contains("nested body content"), "child body should be preserved");
}