use anyhow::Result;
use git_iris::config::Config;
use git_iris::context::ChangeType;
use git_iris::git::GitRepo;
use git_iris::types::MarkdownPullRequest;
use std::sync::Arc;
use tempfile::TempDir;
#[path = "test_utils.rs"]
mod test_utils;
use test_utils::{MockDataBuilder, setup_git_repo_with_commits};
fn create_mock_generated_pr() -> MarkdownPullRequest {
MockDataBuilder::generated_pull_request()
}
fn setup_test_repo_with_commits_arc() -> Result<(TempDir, Arc<GitRepo>)> {
let (temp_dir, git_repo) = setup_git_repo_with_commits()?;
Ok((temp_dir, Arc::new(git_repo)))
}
#[test]
fn test_format_pull_request() {
let pr = create_mock_generated_pr();
let formatted = pr.format();
assert!(!formatted.is_empty());
let raw = pr.raw_content();
assert!(raw.contains("# Add JWT authentication with user registration"));
assert!(raw.contains("## Summary"));
assert!(raw.contains("## Description"));
assert!(raw.contains("## Commits"));
assert!(raw.contains("abc1234"));
assert!(raw.contains("def5678"));
assert!(raw.contains("## Breaking Changes"));
assert!(raw.contains("## Testing"));
assert!(raw.contains("## Notes"));
}
#[test]
fn test_format_pull_request_minimal() {
let pr = MarkdownPullRequest {
content: r"# Fix bug in user authentication
## Summary
Fixes a critical bug in the authentication flow.
## Description
This PR fixes an issue where users couldn't log in properly.
## Commits
- `abc1234`: Fix authentication bug
"
.to_string(),
};
let raw = pr.raw_content();
assert!(raw.contains("# Fix bug in user authentication"));
assert!(raw.contains("## Summary"));
assert!(raw.contains("## Description"));
assert!(raw.contains("## Commits"));
assert!(raw.contains("abc1234"));
assert!(!raw.contains("## Breaking Changes"));
assert!(!raw.contains("## Testing"));
assert!(!raw.contains("## Notes"));
}
#[tokio::test]
async fn test_git_repo_get_commits_for_pr() -> Result<()> {
let (temp_dir, git_repo) = setup_test_repo_with_commits_arc()?;
let repo = git2::Repository::open(temp_dir.path())?;
let mut revwalk = repo.revwalk()?;
revwalk.push_head()?;
let commits: Vec<_> = revwalk.collect::<std::result::Result<Vec<_>, _>>()?;
if commits.len() >= 2 {
let from_commit = repo.find_commit(commits[1])?; let to_commit = repo.find_commit(commits[0])?;
let commit_messages = git_repo
.get_commits_for_pr(&from_commit.id().to_string(), &to_commit.id().to_string())?;
assert!(!commit_messages.is_empty());
assert!(commit_messages[0].contains("Add main function"));
}
Ok(())
}
#[tokio::test]
async fn test_git_repo_get_commit_range_files() -> Result<()> {
let (temp_dir, git_repo) = setup_test_repo_with_commits_arc()?;
let repo = git2::Repository::open(temp_dir.path())?;
let mut revwalk = repo.revwalk()?;
revwalk.push_head()?;
let commits: Vec<_> = revwalk.collect::<std::result::Result<Vec<_>, _>>()?;
if commits.len() >= 2 {
let from_commit = repo.find_commit(commits[1])?; let to_commit = repo.find_commit(commits[0])?;
let files = git_repo
.get_commit_range_files(&from_commit.id().to_string(), &to_commit.id().to_string())?;
assert!(!files.is_empty());
assert!(files.iter().any(|f| f.path == "src/main.rs"));
assert!(
files
.iter()
.any(|f| matches!(f.change_type, ChangeType::Added))
);
}
Ok(())
}
#[tokio::test]
async fn test_git_repo_pr_methods() -> Result<()> {
let (temp_dir, git_repo) = setup_test_repo_with_commits_arc()?;
let repo = git2::Repository::open(temp_dir.path())?;
let mut revwalk = repo.revwalk()?;
revwalk.push_head()?;
let commits: Vec<_> = revwalk.collect::<std::result::Result<Vec<_>, _>>()?;
if commits.len() >= 2 {
let from_commit = repo.find_commit(commits[1])?;
let to_commit = repo.find_commit(commits[0])?;
let from_id = from_commit.id().to_string();
let to_id = to_commit.id().to_string();
let commit_messages = git_repo.get_commits_for_pr(&from_id, &to_id)?;
assert!(!commit_messages.is_empty());
let files = git_repo.get_commit_range_files(&from_id, &to_id)?;
assert!(!files.is_empty());
let context =
git_repo.get_git_info_for_commit_range(&Config::default(), &from_id, &to_id)?;
assert!(context.branch.contains(".."));
assert!(!context.staged_files.is_empty());
}
Ok(())
}
#[test]
fn test_format_pull_request_with_unicode() {
let pr = MarkdownPullRequest {
content: r"# ๐ Add deployment automation
## Summary
Implements automated deployment with emojis ๐
## Description
This PR adds deployment automation:
โข Feature 1
โข Feature 2 โ
## Commits
- `abc1234`: Add ๐ง configuration
## Breaking Changes
- โ ๏ธ Configuration format changed
## Testing
Test with ๐งช test suite
## Notes
Deployment requires ๐ secrets
"
.to_string(),
};
let raw = pr.raw_content();
assert!(raw.contains("๐ Add deployment automation"));
assert!(raw.contains("๐"));
assert!(raw.contains("โ
"));
assert!(raw.contains("๐ง"));
assert!(raw.contains("โ ๏ธ"));
assert!(raw.contains("๐งช"));
assert!(raw.contains("๐"));
}
#[cfg(test)]
mod commitish_tests {
fn is_likely_commit_hash(reference: &str) -> bool {
reference.len() >= 7 && reference.chars().all(|c| c.is_ascii_hexdigit())
}
fn is_commitish_syntax(reference: &str) -> bool {
reference.contains('~') || reference.contains('^') || reference.starts_with('@')
}
fn is_likely_commit_hash_or_commitish(reference: &str) -> bool {
if reference.len() >= 7 && reference.chars().all(|c| c.is_ascii_hexdigit()) {
return true;
}
is_commitish_syntax(reference)
}
#[test]
fn test_commit_hash_detection() {
assert!(is_likely_commit_hash("abcdef1234567"));
assert!(is_likely_commit_hash("1234567"));
assert!(!is_likely_commit_hash("abc123")); assert!(!is_likely_commit_hash("abcdefg1234567")); assert!(!is_likely_commit_hash("HEAD~2"));
assert!(!is_likely_commit_hash("main"));
}
#[test]
fn test_commitish_syntax_detection() {
assert!(is_commitish_syntax("HEAD~2"));
assert!(is_commitish_syntax("main~1"));
assert!(is_commitish_syntax("origin/main~3"));
assert!(is_commitish_syntax("HEAD^"));
assert!(is_commitish_syntax("HEAD^^"));
assert!(is_commitish_syntax("main^2"));
assert!(is_commitish_syntax("@"));
assert!(is_commitish_syntax("@~3"));
assert!(is_commitish_syntax("@^"));
assert!(is_commitish_syntax("HEAD~2^"));
assert!(!is_commitish_syntax("main"));
assert!(!is_commitish_syntax("feature-branch"));
assert!(!is_commitish_syntax("abcdef1234567"));
}
#[test]
fn test_combined_detection() {
assert!(is_likely_commit_hash_or_commitish("abcdef1234567"));
assert!(is_likely_commit_hash_or_commitish("1234567"));
assert!(is_likely_commit_hash_or_commitish("HEAD~2"));
assert!(is_likely_commit_hash_or_commitish("HEAD^"));
assert!(is_likely_commit_hash_or_commitish("@~3"));
assert!(is_likely_commit_hash_or_commitish("main~1"));
assert!(!is_likely_commit_hash_or_commitish("main"));
assert!(!is_likely_commit_hash_or_commitish("feature-branch"));
assert!(!is_likely_commit_hash_or_commitish("origin/main"));
}
}