#![cfg_attr(coverage_nightly, coverage(off))]
use anyhow::Result;
use std::path::Path;
use crate::services::enhanced_language_detection::{
detect_project_language_enhanced, LanguageDetection,
};
#[derive(Debug, Clone, Default)]
pub struct LanguageOverride {
pub language: Option<String>,
pub languages: Option<Vec<String>>,
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn get_effective_languages(
override_opts: &LanguageOverride,
path: &Path,
) -> Result<Vec<String>> {
if let Some(lang) = &override_opts.language {
let normalized = normalize_language_name(lang)?;
validate_language_support(&normalized)?;
return Ok(vec![normalized]);
}
if let Some(langs) = &override_opts.languages {
let mut normalized_langs = Vec::new();
for lang in langs {
let normalized = normalize_language_name(lang)?;
validate_language_support(&normalized)?;
normalized_langs.push(normalized);
}
return Ok(normalized_langs);
}
let detection = detect_project_language_enhanced(path);
Ok(vec![detection.language])
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn normalize_language_name(name: &str) -> Result<String> {
let normalized = name.to_lowercase().trim().to_string();
if normalized.is_empty() {
anyhow::bail!("Language name cannot be empty");
}
Ok(normalized)
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn validate_language_support(language: &str) -> Result<()> {
let supported = [
"rust",
"python",
"javascript",
"typescript",
"go",
"cpp",
"c",
"java",
"kotlin",
"swift",
"ruby",
"php",
"bash",
"sh",
"shell",
"wasm",
"wat",
"lean",
];
if supported.contains(&language) {
Ok(())
} else {
anyhow::bail!(
"Language '{}' is not supported. Supported languages: {}",
language,
supported.join(", ")
)
}
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
pub fn has_override(override_opts: &LanguageOverride) -> bool {
override_opts.language.is_some() || override_opts.languages.is_some()
}
#[provable_contracts_macros::contract("pmat-core.yaml", equation = "path_exists")]
pub fn get_language_detection_with_override(
override_opts: &LanguageOverride,
path: &Path,
) -> Result<LanguageDetection> {
if let Some(lang) = &override_opts.language {
let normalized = normalize_language_name(lang)?;
validate_language_support(&normalized)?;
return Ok(LanguageDetection {
language: normalized.clone(),
confidence: 100.0, });
}
Ok(detect_project_language_enhanced(path))
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use tempfile::TempDir;
#[test]
fn test_normalize_language_name() {
assert_eq!(normalize_language_name("Python").unwrap(), "python");
assert_eq!(normalize_language_name("PYTHON").unwrap(), "python");
assert_eq!(normalize_language_name("python").unwrap(), "python");
assert_eq!(normalize_language_name(" Rust ").unwrap(), "rust");
}
#[test]
fn test_normalize_empty_name() {
assert!(normalize_language_name("").is_err());
assert!(normalize_language_name(" ").is_err());
}
#[test]
fn test_validate_supported_languages() {
assert!(validate_language_support("rust").is_ok());
assert!(validate_language_support("python").is_ok());
assert!(validate_language_support("cpp").is_ok());
assert!(validate_language_support("c").is_ok());
}
#[test]
fn test_validate_unsupported_language() {
let result = validate_language_support("fortran");
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("not supported"));
}
#[test]
fn test_single_language_override() {
let temp = create_test_project();
let override_opts = LanguageOverride {
language: Some("python".to_string()),
languages: None,
};
let langs = get_effective_languages(&override_opts, temp.path()).unwrap();
assert_eq!(langs, vec!["python"]);
}
#[test]
fn test_multiple_languages_override() {
let temp = create_test_project();
let override_opts = LanguageOverride {
language: None,
languages: Some(vec!["rust".to_string(), "python".to_string()]),
};
let langs = get_effective_languages(&override_opts, temp.path()).unwrap();
assert_eq!(langs, vec!["rust", "python"]);
}
#[test]
fn test_auto_detection_fallback() {
let temp = create_rust_project();
let override_opts = LanguageOverride::default();
let langs = get_effective_languages(&override_opts, temp.path()).unwrap();
assert_eq!(langs.len(), 1);
assert_eq!(langs[0], "rust");
}
#[test]
fn test_single_override_takes_precedence() {
let temp = create_test_project();
let override_opts = LanguageOverride {
language: Some("python".to_string()),
languages: Some(vec!["rust".to_string()]), };
let langs = get_effective_languages(&override_opts, temp.path()).unwrap();
assert_eq!(langs, vec!["python"]); }
#[test]
fn test_case_insensitive_override() {
let temp = create_test_project();
let override_opts = LanguageOverride {
language: Some("PYTHON".to_string()),
languages: None,
};
let langs = get_effective_languages(&override_opts, temp.path()).unwrap();
assert_eq!(langs, vec!["python"]); }
fn create_test_project() -> TempDir {
let temp = TempDir::new().unwrap();
std::fs::write(temp.path().join("test.txt"), "test").unwrap();
temp
}
fn create_rust_project() -> TempDir {
use std::fs;
let temp = TempDir::new().unwrap();
fs::create_dir_all(temp.path().join("src")).unwrap();
fs::write(temp.path().join("src/main.rs"), "fn main() {}").unwrap();
fs::write(
temp.path().join("Cargo.toml"),
"[package]\nname = \"test\"\n",
)
.unwrap();
temp
}
}