use crate::languages::{detect, group_by_language};
use std::path::Path;
#[test]
fn detect_python() {
assert_eq!(detect(Path::new("foo.py")).map(|l| l.name), Some("python"));
}
#[test]
fn detect_javascript() {
assert_eq!(
detect(Path::new("foo.js")).map(|l| l.name),
Some("javascript")
);
}
#[test]
fn detect_typescript() {
assert_eq!(
detect(Path::new("foo.ts")).map(|l| l.name),
Some("typescript")
);
}
#[test]
fn detect_go() {
assert_eq!(detect(Path::new("foo.go")).map(|l| l.name), Some("go"));
}
#[test]
fn detect_rust() {
assert_eq!(detect(Path::new("foo.rs")).map(|l| l.name), Some("rust"));
}
#[test]
fn unknown_extension_returns_none() {
assert!(detect(Path::new("foo.xyz")).is_none());
}
#[test]
fn extension_match_is_case_insensitive() {
assert_eq!(detect(Path::new("FOO.PY")).map(|l| l.name), Some("python"));
assert_eq!(detect(Path::new("Mixed.Go")).map(|l| l.name), Some("go"));
}
#[test]
fn group_by_language_buckets_in_registration_order() {
let paths = [
Path::new("main.go"),
Path::new("a.py"),
Path::new("lib.rs"),
Path::new("b.py"),
];
let grouped = group_by_language(&paths);
let names: Vec<&str> = grouped.iter().map(|(lang, _)| lang.name).collect();
assert_eq!(
names,
vec!["python", "go", "rust"],
"registration order (python, javascript, typescript, go, rust), \
not alphabetical and not first-seen"
);
assert_eq!(
grouped[0].1,
vec![Path::new("a.py"), Path::new("b.py")],
"files land in their own bucket, in the order given"
);
}
#[test]
fn group_by_language_omits_empty_buckets_and_unknown_extensions() {
let grouped = group_by_language(&[Path::new("notes.md"), Path::new("data.xyz")]);
assert!(
grouped.is_empty(),
"no registered language claims these, so there is nothing to report: {:?}",
grouped.iter().map(|(l, _)| l.name).collect::<Vec<_>>()
);
let grouped = group_by_language(&[Path::new("a.py"), Path::new("notes.md")]);
assert_eq!(grouped.len(), 1, "only python is present");
assert_eq!(grouped[0].0.name, "python");
assert_eq!(
grouped[0].1,
vec![Path::new("a.py")],
"the markdown file is dropped, not attached to python"
);
}
#[test]
fn jvm_extensions_resolve_to_their_languages() {
for (path, expected) in [
("Main.java", "java"),
("Main.kt", "kotlin"),
("Main.kts", "kotlin"),
("Main.scala", "scala"),
("Main.sc", "scala"),
("Main.groovy", "groovy"),
("build.gradle", "groovy"),
] {
let detected = detect(Path::new(path));
assert_eq!(
detected.map(|lang| lang.name),
Some(expected),
"{path} should resolve to {expected}"
);
}
}
#[test]
fn gradle_kts_is_kotlin_not_groovy() {
assert_eq!(
detect(Path::new("build.gradle.kts")).map(|lang| lang.name),
Some("kotlin")
);
}
#[test]
fn newly_registered_extensions_and_filenames_resolve_to_their_languages() {
for (path, expected) in [
("deploy.sh", "shell"),
("build.bash", "shell"),
("App.swift", "swift"),
("main.c", "c"),
("header.h", "c"),
("impl.cpp", "cpp"),
("widget.hpp", "cpp"),
("Program.cs", "csharp"),
("app.rb", "ruby"),
("task.rake", "ruby"),
("app.gemspec", "ruby"),
("lib.php", "php"),
("Widget.vue", "vue"),
("Page.svelte", "svelte"),
("main.tf", "terraform"),
("vars.tfvars", "terraform"),
("application.ex", "elixir"),
("test.exs", "elixir"),
("query.sql", "sql"),
("Dockerfile", "docker"),
("Containerfile", "docker"),
("CI.dockerfile", "docker"),
("Gemfile", "ruby"),
("Rakefile", "ruby"),
] {
let detected = detect(Path::new(path));
assert_eq!(
detected.map(|lang| lang.name),
Some(expected),
"{path} should resolve to {expected}"
);
}
}
#[test]
fn extension_wins_over_both_name_rules() {
assert_eq!(
detect(Path::new("Dockerfile.ts")).map(|lang| lang.name),
Some("typescript")
);
}
#[test]
fn dockerfile_variants_resolve_to_docker() {
for (path, expected) in [
("Dockerfile.dev", "docker"),
("Dockerfile.prod", "docker"),
("Dockerfile.web", "docker"),
("Containerfile.tests", "docker"),
("dockerfile.DEV", "docker"),
] {
assert_eq!(
detect(Path::new(path)).map(|lang| lang.name),
Some(expected),
"{path} should resolve to {expected}"
);
}
}
#[test]
fn stem_variants_respect_the_boundaries() {
for path in [
"Dockerfile.", "myDockerfile.dev", "Dockerfiledev", "Gemfile.lock", "Rakefile.backup", ] {
assert!(
detect(Path::new(path)).is_none(),
"{path} should not resolve to a language"
);
}
}
#[test]
fn whole_name_match_is_case_insensitive() {
for (path, expected) in [
("DOCKERFILE", "docker"),
("dockerfile", "docker"),
("gemfile", "ruby"),
("RAKEFILE", "ruby"),
] {
assert_eq!(
detect(Path::new(path)).map(|lang| lang.name),
Some(expected),
"{path} should resolve to {expected}"
);
}
}