use gitea_pr_review::gitea::dto::*; use gitea_pr_review::normalize::normalize_bundle; #[test] fn normalize_groups_replies_and_sorts_threads_by_time() { let bundle = PullBundleDto { pull: PullDto { number: 42, title: "Fix parser".into(), state: "open".into(), body: Some("desc".into()), user: UserDto { login: "alice".into(), }, base: PullBranchDto { ref_name: "main".into(), }, head: PullBranchDto { ref_name: "feature/x".into(), }, created_at: "2026-04-08T10:00:00Z".into(), updated_at: "2026-04-08T11:00:00Z".into(), merged_at: None, additions: Some(99), deletions: Some(33), changed_files: Some(7), }, reviews: vec![ ReviewDto { id: 8, state: "APPROVED".into(), user: UserDto { login: "carol".into(), }, submitted_at: Some("2026-04-08T13:00:00Z".into()), }, ReviewDto { id: 7, state: "COMMENT".into(), user: UserDto { login: "bob".into(), }, submitted_at: Some("2026-04-08T12:00:00Z".into()), }, ], comments: vec![ ReviewCommentDto { id: 2, body: "reply".into(), created_at: "2026-04-08T12:02:00Z".into(), updated_at: Some("2026-04-08T12:03:00Z".into()), user: UserDto { login: "bob".into(), }, path: Some("src/main.rs".into()), line: Some(10), pull_request_review_id: Some(7), original_position: Some(10), position: Some(10), commit_id: Some("abc123".into()), original_commit_id: Some("abc123".into()), diff_hunk: Some("@@ -1 +1 @@".into()), }, ReviewCommentDto { id: 1, body: "root".into(), created_at: "2026-04-08T12:01:00Z".into(), updated_at: Some("2026-04-08T12:02:00Z".into()), user: UserDto { login: "bob".into(), }, path: Some("src/main.rs".into()), line: Some(10), pull_request_review_id: Some(7), original_position: Some(10), position: Some(10), commit_id: Some("abc123".into()), original_commit_id: Some("abc123".into()), diff_hunk: Some("@@ -1 +1 @@".into()), }, ReviewCommentDto { id: 3, body: "other thread".into(), created_at: "2026-04-08T11:59:00Z".into(), updated_at: None, user: UserDto { login: "dave".into(), }, path: Some("src/lib.rs".into()), line: Some(22), pull_request_review_id: Some(8), original_position: Some(22), position: Some(22), commit_id: Some("def456".into()), original_commit_id: Some("def456".into()), diff_hunk: Some("@@ -2 +2 @@".into()), }, ], commits: vec![ CommitDto { sha: "bbbbbbbccccccc".into(), commit: RepoCommitDto { message: "fix: later commit\n\nbody".into(), author: Some(CommitUserDto { name: "Bob".into(), date: "2026-04-08T12:30:00Z".into(), }), }, }, CommitDto { sha: "aaaaaaabbbbbbb".into(), commit: RepoCommitDto { message: "feat: earlier commit".into(), author: Some(CommitUserDto { name: "Alice".into(), date: "2026-04-08T11:30:00Z".into(), }), }, }, ], files: vec![ ChangedFileDto { filename: "src/main.rs".into(), additions: 5, deletions: 1, changes: Some(6), status: Some("modified".into()), previous_filename: None, }, ChangedFileDto { filename: "src/lib.rs".into(), additions: 3, deletions: 2, changes: Some(5), status: Some("modified".into()), previous_filename: None, }, ], }; let doc = normalize_bundle("org/repo", bundle); assert_eq!(doc.meta.repo, "org/repo"); assert_eq!(doc.meta.pr_index, 42); assert_eq!(doc.meta.base_branch, "main"); assert_eq!(doc.meta.head_branch, "feature/x"); assert_eq!(doc.commits.len(), 2); assert_eq!(doc.commits[0].title, "feat: earlier commit"); assert_eq!(doc.commits[0].author, "Alice"); assert_eq!(doc.commits[1].title, "fix: later commit"); assert_eq!(doc.reviews.len(), 2); assert_eq!(doc.reviews[0].id, 7); assert_eq!(doc.reviews[1].id, 8); assert_eq!(doc.diff_stat.files_changed, 2); assert_eq!(doc.diff_stat.additions, 8); assert_eq!(doc.diff_stat.deletions, 3); assert_eq!(doc.diff_stat.files[0].path, "src/main.rs"); assert_eq!(doc.diff_stat.files[1].path, "src/lib.rs"); assert_eq!(doc.threads.len(), 2); assert_eq!(doc.threads[0].root_comment.id, 3); assert_eq!(doc.threads[0].file_path.as_deref(), Some("src/lib.rs")); assert_eq!(doc.threads[0].line, Some(22)); assert_eq!(doc.threads[1].root_comment.id, 1); assert_eq!(doc.threads[1].replies.len(), 1); assert_eq!(doc.threads[1].replies[0].id, 2); assert_eq!(doc.threads[1].file_path.as_deref(), Some("src/main.rs")); assert_eq!(doc.threads[1].line, Some(10)); }