1#[cfg(test)]
8mod test {
9 use std::{
10 env::{self, current_dir, set_current_dir},
11 fs,
12 process::Command,
13 };
14
15 use tempfile::{TempDir, tempdir};
16
17 use crate::{cli::LinesChangedOnly, rest_client::RestClient};
18 use git_bot_feedback::FileFilter;
19
20 const TEST_REPO_URL: &str = "https://github.com/cpp-linter/cpp-linter";
21
22 fn clone_repo(sha: Option<&str>, path: &str, patch_path: Option<&str>) {
24 let ok = Command::new("git")
25 .args(["clone", TEST_REPO_URL, path])
26 .status()
27 .expect("Failed to clone repo");
28 if !ok.success() {
29 panic!("Failed to clone repo");
30 }
31 if let Some(sha) = sha {
32 let ok = Command::new("git")
33 .args(["-c", "advice.detachedHead=false", "checkout", sha])
34 .current_dir(path)
35 .status()
36 .expect("Failed to checkout commit");
37 if !ok.success() {
38 panic!("Failed to checkout commit");
39 }
40 }
41 if let Some(patch) = patch_path {
42 let canonical_patch_path = fs::canonicalize(patch).unwrap();
43 let patch_path = canonical_patch_path
44 .to_str()
45 .unwrap()
46 .trim_start_matches("\\\\?\\");
48 let ok = Command::new("git")
49 .args(["apply", "--index", patch_path])
50 .current_dir(path)
51 .status()
52 .expect("Failed to apply patch and stage its changes");
53 if !ok.success() {
54 panic!("Failed to apply patch and stage its changes");
55 }
56 let ok = Command::new("git")
57 .args(["status", "-s"])
58 .current_dir(path)
59 .status()
60 .expect("Failed to get git status after applying patch");
61 if !ok.success() {
62 panic!("Failed to get git status after applying patch");
63 }
64 }
65 }
66
67 fn get_temp_dir() -> TempDir {
68 let tmp = tempdir().unwrap();
69 println!("Using temp folder at {:?}", tmp.path());
70 tmp
71 }
72
73 async fn checkout_cpp_linter_py_repo(
74 sha: &str,
75 extensions: &[&str],
76 tmp: &TempDir,
77 patch_path: Option<&str>,
78 ignore_staged: bool,
79 ) -> Vec<crate::common_fs::FileObj> {
80 clone_repo(
81 Some(sha),
82 tmp.path().as_os_str().to_str().unwrap(),
83 patch_path,
84 );
85 unsafe {
87 env::set_var("GITHUB_ACTIONS", "false");
88 env::set_var("CI", "false");
89 }
90 let rest_api_client = RestClient::new().unwrap();
91 let file_filter = FileFilter::new(&["target"], extensions, None);
92 set_current_dir(tmp).unwrap();
93 let base_diff = if ignore_staged {
94 Some("HEAD".to_string())
95 } else {
96 None
97 };
98 rest_api_client
99 .get_list_of_changed_files(
100 &file_filter,
101 &LinesChangedOnly::Off.into(),
102 &base_diff,
103 ignore_staged,
104 )
105 .await
106 .unwrap()
107 }
108
109 #[tokio::test]
110 async fn with_no_changed_sources() {
111 let sha = "0c236809891000b16952576dc34de082d7a40bf3";
113 let cur_dir = current_dir().unwrap();
114 let tmp = get_temp_dir();
115 let extensions = ["cpp", "hpp"];
116 let files = checkout_cpp_linter_py_repo(sha, &extensions, &tmp, None, false).await;
117 println!("files = {:?}", files);
118 assert!(files.is_empty());
119 set_current_dir(cur_dir).unwrap(); drop(tmp); }
122
123 #[tokio::test]
124 async fn with_changed_sources() {
125 let sha = "950ff0b690e1903797c303c5fc8d9f3b52f1d3c5";
127 let cur_dir = current_dir().unwrap();
128 let tmp = get_temp_dir();
129 let extensions = ["cpp", "hpp"];
130 let files = checkout_cpp_linter_py_repo(sha, &extensions, &tmp, None, false).await;
131 println!("files = {:?}", files);
132 assert!(files.len() >= 2);
133 for file in files {
134 assert!(
135 extensions.contains(
136 &file
137 .name
138 .extension()
139 .unwrap()
140 .to_string_lossy()
141 .to_string()
142 .as_str()
143 )
144 );
145 }
146 set_current_dir(cur_dir).unwrap(); drop(tmp); }
149
150 #[tokio::test]
151 async fn with_staged_changed_sources() {
152 let sha = "0c236809891000b16952576dc34de082d7a40bf3";
154 let cur_dir = current_dir().unwrap();
155 let tmp = get_temp_dir();
156 let extensions = ["cpp", "hpp"];
157 let files = checkout_cpp_linter_py_repo(
158 sha,
159 &extensions,
160 &tmp,
161 Some("tests/git_status_test_assets/cpp-linter/cpp-linter/test_git_lib.patch"),
162 false,
163 )
164 .await;
165 println!("files = {:?}", files);
166 assert!(!files.is_empty());
167 for file in files {
168 assert!(
169 extensions.contains(
170 &file
171 .name
172 .extension()
173 .unwrap()
174 .to_string_lossy()
175 .to_string()
176 .as_str()
177 )
178 );
179 }
180 set_current_dir(cur_dir).unwrap(); drop(tmp); }
183
184 #[tokio::test]
185 async fn with_ignored_staged_changes() {
186 let sha = "0c236809891000b16952576dc34de082d7a40bf3";
188 let cur_dir = current_dir().unwrap();
189 let tmp = get_temp_dir();
190 let extensions = ["cpp", "hpp"];
191 let files = checkout_cpp_linter_py_repo(
192 sha,
193 &extensions,
194 &tmp,
195 Some("tests/git_status_test_assets/cpp-linter/cpp-linter/test_git_lib.patch"),
196 true,
197 )
198 .await;
199 eprintln!("files: {files:?}");
200 assert!(files.is_empty());
201 set_current_dir(cur_dir).unwrap(); drop(tmp); }
204}