use starbase_utils::glob::*;
mod globset {
use super::*;
#[test]
fn doesnt_match_when_empty() {
let list: Vec<String> = vec![];
let set = GlobSet::new(&list).unwrap();
assert!(!set.matches("file.ts"));
let list: Vec<&str> = vec![];
let set = GlobSet::new(list).unwrap();
assert!(!set.matches("file.ts"));
}
#[test]
fn matches_explicit() {
let set = GlobSet::new(["source"]).unwrap();
assert!(set.matches("source"));
assert!(!set.matches("source.ts"));
}
#[test]
fn matches_exprs() {
let set = GlobSet::new(["files/*.ts"]).unwrap();
assert!(set.matches("files/index.ts"));
assert!(set.matches("files/test.ts"));
assert!(!set.matches("index.ts"));
assert!(!set.matches("files/index.js"));
assert!(!set.matches("files/dir/index.ts"));
}
#[test]
fn matches_rel_start() {
let set = GlobSet::new(["./source"]).unwrap();
assert!(set.matches("source"));
assert!(!set.matches("source.ts"));
}
#[test]
fn doesnt_match_negations() {
let set = GlobSet::new(["files/*", "!**/*.ts"]).unwrap();
assert!(set.matches("files/test.js"));
assert!(set.matches("files/test.go"));
assert!(!set.matches("files/test.ts"));
}
#[test]
fn doesnt_match_negations_using_split() {
let set = GlobSet::new_split(["files/*"], ["**/*.ts"]).unwrap();
assert!(set.matches("files/test.js"));
assert!(set.matches("files/test.go"));
assert!(!set.matches("files/test.ts"));
}
#[test]
fn doesnt_match_global_negations() {
let set = GlobSet::new(["**/*"]).unwrap();
assert!(set.matches("files/test.js"));
assert!(!set.matches(".git/cache"));
assert!(!set.matches("files/.git/cache"));
assert!(!set.matches(".DS_Store"));
assert!(!set.matches("files/.DS_Store"));
}
#[test]
fn only_negates_root_node_modules() {
let set = GlobSet::new(["**/*"]).unwrap();
assert!(!set.matches("node_modules/foo.js"));
assert!(!set.matches("node_modules/sub/foo.js"));
assert!(set.matches("packages/foo/node_modules/bar.js"));
assert!(set.matches("apps/web/node_modules/dep/index.js"));
}
}
mod is_glob {
use super::*;
#[test]
fn returns_true_when_a_glob() {
assert!(is_glob("**"));
assert!(is_glob("**/src/*"));
assert!(is_glob("src/**"));
assert!(is_glob("*.ts"));
assert!(is_glob("file.*"));
assert!(is_glob("file.{js,ts}"));
assert!(is_glob("file.[jstx]"));
assert!(is_glob("file.tsx?"));
}
#[test]
fn returns_false_when_not_glob() {
assert!(!is_glob("dir"));
assert!(!is_glob("file.rs"));
assert!(!is_glob("dir/file.ts"));
assert!(!is_glob("dir/dir/file_test.rs"));
assert!(!is_glob("dir/dirDir/file-ts.js"));
}
#[test]
fn returns_false_when_escaped_glob() {
assert!(!is_glob("\\*.rs"));
assert!(!is_glob("file\\?.js"));
assert!(!is_glob("folder-\\[id\\]"));
}
#[test]
fn returns_true_when_later_glob_is_not_escaped() {
assert!(is_glob("\\*.rs/*.rs"));
assert!(is_glob("folder-\\[id\\]/[name]"));
}
}
mod split_patterns {
use super::*;
#[test]
fn splits_all_patterns() {
assert_eq!(
split_patterns(["*.file", "!neg1.*", "/*.file2", "/!neg2.*", "!/neg3.*"]),
(
vec!["*.file", "*.file2"],
vec!["neg1.*", "neg2.*", "neg3.*"]
)
);
}
}
mod walk {
use super::*;
#[test]
fn fast_and_slow_return_same_list() {
let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let slow = walk(&dir, ["**/*"]).unwrap();
let fast = walk_fast(&dir, ["**/*"]).unwrap();
assert_eq!(slow.len(), fast.len());
let slow = walk(&dir, ["**/*.snap"]).unwrap();
let fast = walk_fast(&dir, ["**/*.snap"]).unwrap();
assert_eq!(slow.len(), fast.len());
}
}
mod walk_files {
use super::*;
#[test]
fn fast_and_slow_return_same_list() {
let dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
let slow = walk_files(&dir, ["**/*"]).unwrap();
let fast = walk_fast_with_options(
&dir,
["**/*"],
GlobWalkOptions {
only_files: true,
..Default::default()
},
)
.unwrap();
assert_eq!(slow.len(), fast.len());
let slow = walk_files(&dir, ["**/*.snap"]).unwrap();
let fast = walk_fast_with_options(
&dir,
["**/*.snap"],
GlobWalkOptions {
only_files: true,
..Default::default()
},
)
.unwrap();
assert_eq!(slow.len(), fast.len());
}
}
mod walk_fast {
use super::*;
use starbase_sandbox::create_empty_sandbox;
#[test]
fn default_options_are_all_disabled() {
let options = GlobWalkOptions::default();
assert!(!options.cache);
assert!(!options.ignore_dot_dirs);
assert!(!options.ignore_dot_files);
assert!(!options.log_results);
assert!(!options.only_dirs);
assert!(!options.only_files);
}
#[test]
fn handles_dot_folders() {
let sandbox = create_empty_sandbox();
sandbox.create_file("1.txt", "");
sandbox.create_file("dir/2.txt", "");
sandbox.create_file(".hidden/3.txt", "");
let mut paths =
walk_fast_with_options(sandbox.path(), ["**/*.txt"], GlobWalkOptions::default())
.unwrap();
paths.sort();
assert_eq!(
paths,
vec![
sandbox.path().join(".hidden/3.txt"),
sandbox.path().join("1.txt"),
sandbox.path().join("dir/2.txt"),
]
);
let mut paths = walk_fast_with_options(
sandbox.path(),
["**/*.txt"],
GlobWalkOptions::default().dot_dirs(true).dot_files(true),
)
.unwrap();
paths.sort();
assert_eq!(
paths,
vec![
sandbox.path().join("1.txt"),
sandbox.path().join("dir/2.txt"),
]
);
}
#[test]
fn walks_into_nested_node_modules() {
let sandbox = create_empty_sandbox();
sandbox.create_file("node_modules/root.js", "");
sandbox.create_file("packages/a/node_modules/dep.js", "");
sandbox.create_file("packages/a/src/index.js", "");
let mut paths =
walk_fast_with_options(sandbox.path(), ["**/*.js"], GlobWalkOptions::default())
.unwrap();
paths.sort();
assert_eq!(
paths,
vec![
sandbox.path().join("packages/a/node_modules/dep.js"),
sandbox.path().join("packages/a/src/index.js"),
]
);
}
#[test]
fn matches_depth_bounded_patterns() {
let sandbox = create_empty_sandbox();
sandbox.create_file("pkg/moon.yml", "");
sandbox.create_file("pkg/nested/moon.yml", "");
sandbox.create_file("apps/api/moon.yml", "");
sandbox.create_file("apps/api/nested/moon.yml", "");
let mut paths = walk_fast(sandbox.path(), ["*/moon.yml", "apps/*/moon.yml"]).unwrap();
paths.sort();
assert_eq!(
paths,
vec![
sandbox.path().join("apps/api/moon.yml"),
sandbox.path().join("pkg/moon.yml"),
]
);
}
#[test]
fn applies_negations_across_buckets() {
let sandbox = create_empty_sandbox();
sandbox.create_file("src/a.js", "");
sandbox.create_file("dist/b.js", "");
let mut paths = walk_fast(sandbox.path(), ["**/*.js", "!dist/**"]).unwrap();
paths.sort();
assert_eq!(paths, vec![sandbox.path().join("src/a.js")]);
}
}
mod partition_patterns {
use super::*;
use std::collections::BTreeMap;
#[test]
fn basic() {
let map = partition_patterns("/root", ["foo/*", "foo/bar/*.txt", "baz/**/*"]);
assert_eq!(
map,
BTreeMap::from_iter([
("/root/foo".into(), vec!["*".into(), "bar/*.txt".into()]),
("/root/baz".into(), vec!["**/*".into()]),
])
);
}
#[test]
fn no_globs() {
let map = partition_patterns("/root", ["foo/file.txt", "foo/bar/file.txt", "file.txt"]);
assert_eq!(
map,
BTreeMap::from_iter([
("/root".into(), vec!["file.txt".into()]),
(
"/root/foo".into(),
vec!["file.txt".into(), "bar/file.txt".into()]
),
])
);
}
#[test]
fn same_root_dir() {
let map = partition_patterns("/root", ["file.txt", "file.*", "*.{md,mdx}"]);
assert_eq!(
map,
BTreeMap::from_iter([(
"/root".into(),
vec!["file.*".into(), "file.txt".into(), "*.{md,mdx}".into()]
),])
);
}
#[test]
fn same_nested_dir() {
let map = partition_patterns(
"/root",
["nes/ted/file.txt", "nes/ted/file.*", "nes/ted/*.{md,mdx}"],
);
assert_eq!(
map,
BTreeMap::from_iter([(
"/root/nes/ted".into(),
vec!["file.*".into(), "file.txt".into(), "*.{md,mdx}".into()]
),])
);
}
#[test]
fn dot_dir() {
let map = partition_patterns("/root", [".dir/**/*.yml"]);
assert_eq!(
map,
BTreeMap::from_iter([("/root/.dir".into(), vec!["**/*.yml".into()]),])
);
}
#[test]
fn with_negations() {
let map = partition_patterns(
"/root",
[
"./packages/*",
"!packages/cli",
"!packages/core-*",
"website",
],
);
assert_eq!(
map,
BTreeMap::from_iter([
(
"/root".into(),
vec![
"website".into(),
"!packages/cli".into(),
"!packages/core-*".into()
]
),
(
"/root/packages".into(),
vec!["*".into(), "!cli".into(), "!core-*".into()]
),
])
);
}
#[test]
fn keeps_negations_in_broad_buckets() {
let map = partition_patterns("/root", ["**/*.js", "!dist/**"]);
assert_eq!(
map,
BTreeMap::from_iter([("/root".into(), vec!["**/*.js".into(), "!dist/**".into()])])
);
}
#[test]
fn global_negations() {
let map = partition_patterns(
"/root",
[
"foo/file.txt",
"foo/bar/file.txt",
"file.txt",
"!**/node_modules/**",
],
);
assert_eq!(
map,
BTreeMap::from_iter([
(
"/root".into(),
vec!["file.txt".into(), "!**/node_modules/**".into(),]
),
(
"/root/foo".into(),
vec![
"file.txt".into(),
"bar/file.txt".into(),
"!**/node_modules/**".into(),
]
),
])
);
}
#[test]
fn glob_stars() {
let map = partition_patterns("/root", ["**/file.txt", "dir/sub/**/*", "other/**/*.txt"]);
assert_eq!(
map,
BTreeMap::from_iter([
("/root".into(), vec!["**/file.txt".into()]),
("/root/dir/sub".into(), vec!["**/*".into()]),
("/root/other".into(), vec!["**/*.txt".into()]),
])
);
}
}