|
1 | | -use std::fs; |
2 | | -use std::path::{Path, PathBuf}; |
3 | | -use std::process::Command; |
| 1 | +use std::path::Path; |
4 | 2 |
|
5 | 3 | use codeowners::runner::{self, RunConfig}; |
6 | 4 |
|
7 | | -fn copy_dir_recursive(from: &Path, to: &Path) { |
8 | | - fs::create_dir_all(to).expect("failed to create destination root"); |
9 | | - for entry in fs::read_dir(from).expect("failed to read source dir") { |
10 | | - let entry = entry.expect("failed to read dir entry"); |
11 | | - let file_type = entry.file_type().expect("failed to read file type"); |
12 | | - let src_path = entry.path(); |
13 | | - let dest_path = to.join(entry.file_name()); |
14 | | - if file_type.is_dir() { |
15 | | - copy_dir_recursive(&src_path, &dest_path); |
16 | | - } else if file_type.is_file() { |
17 | | - // Ensure parent exists then copy |
18 | | - if let Some(parent) = dest_path.parent() { |
19 | | - fs::create_dir_all(parent).expect("failed to create parent dir"); |
20 | | - } |
21 | | - fs::copy(&src_path, &dest_path).expect("failed to copy file"); |
22 | | - } |
23 | | - } |
24 | | -} |
25 | | - |
26 | | -fn init_git_repo(path: &Path) { |
27 | | - // Initialize a new git repository in the temp project |
28 | | - let status = Command::new("git") |
29 | | - .arg("init") |
30 | | - .current_dir(path) |
31 | | - .output() |
32 | | - .expect("failed to run git init"); |
33 | | - assert!( |
34 | | - status.status.success(), |
35 | | - "git init failed: {}", |
36 | | - String::from_utf8_lossy(&status.stderr) |
37 | | - ); |
| 5 | +mod common; |
| 6 | +use common::{assert_no_run_errors, build_run_config, is_file_staged, setup_fixture_repo}; |
38 | 7 |
|
39 | | - // Configure a dummy identity to appease git if commits ever happen; not strictly needed for staging |
40 | | - let _ = Command::new("git") |
41 | | - .arg("config") |
42 | | - .arg("user.email") |
43 | | - |
44 | | - .current_dir(path) |
45 | | - .output(); |
46 | | - let _ = Command::new("git") |
47 | | - .arg("config") |
48 | | - .arg("user.name") |
49 | | - .arg("Test User") |
50 | | - .current_dir(path) |
51 | | - .output(); |
| 8 | +#[test] |
| 9 | +fn test_generate_stages_codeowners() { |
| 10 | + run_and_check(runner::generate, true, true); |
52 | 11 | } |
53 | 12 |
|
54 | | -fn is_file_staged(repo_root: &Path, rel_path: &str) -> bool { |
55 | | - // Use git diff --name-only --cached to list staged files |
56 | | - let output = Command::new("git") |
57 | | - .arg("diff") |
58 | | - .arg("--name-only") |
59 | | - .arg("--cached") |
60 | | - .current_dir(repo_root) |
61 | | - .output() |
62 | | - .expect("failed to run git diff --cached"); |
63 | | - assert!( |
64 | | - output.status.success(), |
65 | | - "git diff failed: {}", |
66 | | - String::from_utf8_lossy(&output.stderr) |
67 | | - ); |
68 | | - let stdout = String::from_utf8_lossy(&output.stdout); |
69 | | - stdout.lines().any(|line| line.trim() == rel_path) |
| 13 | +#[test] |
| 14 | +fn test_generate_and_validate_stages_codeowners() { |
| 15 | + run_and_check(|rc, s| runner::generate_and_validate(rc, vec![], s), true, true); |
70 | 16 | } |
71 | 17 |
|
72 | | -fn build_run_config(project_root: &Path, codeowners_rel_path: &str) -> RunConfig { |
73 | | - let project_root = project_root.canonicalize().expect("failed to canonicalize project root"); |
74 | | - let codeowners_file_path = project_root.join(codeowners_rel_path); |
75 | | - let config_path = project_root.join("config/code_ownership.yml"); |
76 | | - RunConfig { |
77 | | - project_root, |
78 | | - codeowners_file_path, |
79 | | - config_path, |
80 | | - no_cache: true, |
81 | | - } |
| 18 | +#[test] |
| 19 | +fn test_generate_does_not_stage_codeowners() { |
| 20 | + run_and_check(runner::generate, false, false); |
82 | 21 | } |
83 | 22 |
|
84 | 23 | #[test] |
85 | | -fn test_generate_stages_codeowners() { |
86 | | - let temp_dir = tempfile::tempdir().expect("failed to create tempdir"); |
87 | | - let temp_root = temp_dir.path().to_path_buf(); |
88 | | - |
89 | | - // Copy the valid project fixture into a temporary git repo |
90 | | - let fixture_root = PathBuf::from("tests/fixtures/valid_project"); |
91 | | - copy_dir_recursive(&fixture_root, &temp_root); |
92 | | - init_git_repo(&temp_root); |
93 | | - |
94 | | - // Run generate with staging enabled, targeting the standard CODEOWNERS path |
95 | | - let run_config = build_run_config(&temp_root, ".github/CODEOWNERS"); |
96 | | - let result = runner::generate(&run_config, true); |
97 | | - assert!(result.io_errors.is_empty(), "io_errors: {:?}", result.io_errors); |
98 | | - assert!( |
99 | | - result.validation_errors.is_empty(), |
100 | | - "validation_errors: {:?}", |
101 | | - result.validation_errors |
102 | | - ); |
103 | | - |
104 | | - // Assert CODEOWNERS file exists and is staged |
105 | | - let rel_path = ".github/CODEOWNERS"; |
106 | | - assert!(run_config.codeowners_file_path.exists(), "CODEOWNERS file was not created"); |
107 | | - assert!(is_file_staged(&run_config.project_root, rel_path), "CODEOWNERS file was not staged"); |
| 24 | +fn test_generate_and_validate_does_not_stage_codeowners() { |
| 25 | + run_and_check(|rc, s| runner::generate_and_validate(rc, vec![], s), false, false); |
108 | 26 | } |
109 | 27 |
|
110 | | -#[test] |
111 | | -fn test_generate_and_validate_stages_codeowners() { |
112 | | - let temp_dir = tempfile::tempdir().expect("failed to create tempdir"); |
113 | | - let temp_root = temp_dir.path().to_path_buf(); |
| 28 | +const FIXTURE: &str = "tests/fixtures/valid_project"; |
| 29 | +const CODEOWNERS_REL: &str = ".github/CODEOWNERS"; |
114 | 30 |
|
115 | | - // Copy the valid project fixture into a temporary git repo |
116 | | - let fixture_root = PathBuf::from("tests/fixtures/valid_project"); |
117 | | - copy_dir_recursive(&fixture_root, &temp_root); |
118 | | - init_git_repo(&temp_root); |
| 31 | +fn run_and_check<F>(func: F, stage: bool, expected_staged: bool) |
| 32 | +where |
| 33 | + F: FnOnce(&RunConfig, bool) -> runner::RunResult, |
| 34 | +{ |
| 35 | + let temp_dir = setup_fixture_repo(Path::new(FIXTURE)); |
| 36 | + let run_config = build_run_config(temp_dir.path(), CODEOWNERS_REL); |
119 | 37 |
|
120 | | - // Run generate_and_validate with staging enabled |
121 | | - let run_config = build_run_config(&temp_root, ".github/CODEOWNERS"); |
122 | | - let result = runner::generate_and_validate(&run_config, vec![], true); |
123 | | - assert!(result.io_errors.is_empty(), "io_errors: {:?}", result.io_errors); |
124 | | - assert!( |
125 | | - result.validation_errors.is_empty(), |
126 | | - "validation_errors: {:?}", |
127 | | - result.validation_errors |
128 | | - ); |
| 38 | + let result = func(&run_config, stage); |
| 39 | + assert_no_run_errors(&result); |
129 | 40 |
|
130 | | - // Assert CODEOWNERS file exists and is staged |
131 | | - let rel_path = ".github/CODEOWNERS"; |
132 | 41 | assert!(run_config.codeowners_file_path.exists(), "CODEOWNERS file was not created"); |
133 | | - assert!(is_file_staged(&run_config.project_root, rel_path), "CODEOWNERS file was not staged"); |
| 42 | + let staged = is_file_staged(&run_config.project_root, CODEOWNERS_REL); |
| 43 | + assert_eq!(staged, expected_staged, "unexpected staged state for CODEOWNERS"); |
134 | 44 | } |
0 commit comments