Add project search in gitignored test

Kirill Bulatov created

Change summary

crates/project/src/project_tests.rs | 88 +++++++++++++++++++++++++++++++
crates/project/src/search.rs        | 28 ++++-----
crates/util/src/paths.rs            |  2 
3 files changed, 100 insertions(+), 18 deletions(-)

Detailed changes

crates/project/src/project_tests.rs 🔗

@@ -4050,6 +4050,94 @@ async fn test_search_with_exclusions_and_inclusions(cx: &mut gpui::TestAppContex
     );
 }
 
+#[gpui::test]
+async fn test_search_in_gitignored_dirs(cx: &mut gpui::TestAppContext) {
+    init_test(cx);
+
+    let fs = FakeFs::new(cx.background());
+    fs.insert_tree(
+        "/dir",
+        json!({
+            ".git": {},
+            ".gitignore": "**/target\n/node_modules\n",
+            "target": {
+                "index.txt": "index_key:index_value"
+            },
+            "node_modules": {
+                "eslint": {
+                    "index.ts": "const eslint_key = 'eslint value'",
+                    "package.json": r#"{ "some_key": "some value" }"#,
+                },
+                "prettier": {
+                    "index.ts": "const prettier_key = 'prettier value'",
+                    "package.json": r#"{ "other_key": "other value" }"#,
+                },
+            },
+            "package.json": r#"{ "main_key": "main value" }"#,
+        }),
+    )
+    .await;
+    let project = Project::test(fs.clone(), ["/dir".as_ref()], cx).await;
+
+    let query = "key";
+    assert_eq!(
+        search(
+            &project,
+            SearchQuery::text(query, false, false, false, Vec::new(), Vec::new()).unwrap(),
+            cx
+        )
+        .await
+        .unwrap(),
+        HashMap::from_iter([("package.json".to_string(), vec![8..11])]),
+        "Only one non-ignored file should have the query"
+    );
+
+    assert_eq!(
+        search(
+            &project,
+            SearchQuery::text(query, false, false, true, Vec::new(), Vec::new()).unwrap(),
+            cx
+        )
+        .await
+        .unwrap(),
+        HashMap::from_iter([
+            ("package.json".to_string(), vec![8..11]),
+            ("target/index.txt".to_string(), vec![6..9]),
+            (
+                "node_modules/prettier/package.json".to_string(),
+                vec![9..12]
+            ),
+            ("node_modules/prettier/index.ts".to_string(), vec![15..18]),
+            ("node_modules/eslint/index.ts".to_string(), vec![13..16]),
+            ("node_modules/eslint/package.json".to_string(), vec![8..11]),
+        ]),
+        "Unrestricted search with ignored directories should find every file with the query"
+    );
+
+    assert_eq!(
+        search(
+            &project,
+            SearchQuery::text(
+                query,
+                false,
+                false,
+                true,
+                vec![PathMatcher::new("node_modules/prettier/**").unwrap()],
+                vec![PathMatcher::new("*.ts").unwrap()],
+            )
+            .unwrap(),
+            cx
+        )
+        .await
+        .unwrap(),
+        HashMap::from_iter([(
+            "node_modules/prettier/package.json".to_string(),
+            vec![9..12]
+        )]),
+        "With search including ignored prettier directory and excluding TS files, only one file should be found"
+    );
+}
+
 #[test]
 fn test_glob_literal_prefix() {
     assert_eq!(glob_literal_prefix("**/*.js"), "");

crates/project/src/search.rs 🔗

@@ -372,28 +372,24 @@ impl SearchQuery {
         match file_path {
             Some(file_path) => {
                 let mut path = file_path.to_path_buf();
-                let mut matches;
                 loop {
-                    matches = !self
+                    if self
                         .files_to_exclude()
                         .iter()
                         .any(|exclude_glob| exclude_glob.is_match(&path))
-                        && (self.files_to_include().is_empty()
-                            || self
-                                .files_to_include()
-                                .iter()
-                                .any(|include_glob| include_glob.is_match(&path)));
-                    if matches || !path.pop() {
-                        break;
+                    {
+                        return false;
+                    } else if self.files_to_include().is_empty()
+                        || self
+                            .files_to_include()
+                            .iter()
+                            .any(|include_glob| include_glob.is_match(&path))
+                    {
+                        return true;
+                    } else if !path.pop() {
+                        return false;
                     }
                 }
-
-                let path_str = file_path.to_string_lossy();
-                if path_str.contains("node_modules") && path_str.contains("prettier") {
-                    dbg!(path_str, path, matches);
-                }
-
-                matches
             }
             None => self.files_to_include().is_empty(),
         }

crates/util/src/paths.rs 🔗

@@ -218,8 +218,6 @@ impl PathMatcher {
         })
     }
 
-    // TODO kb tests for matching
-    // TODO kb add an integration test on excluded file opening
     pub fn is_match<P: AsRef<Path>>(&self, other: P) -> bool {
         let other_path = other.as_ref();
         other_path.starts_with(&self.maybe_path)