use std::path::Path;
pub fn is_test_file(path: &Path) -> bool {
path.file_name()
.and_then(|name| name.to_str())
.is_some_and(|name| name.ends_with(".t.sol") || name.ends_with(".test.sol"))
}
pub fn is_test_contract_name(name: &str) -> bool {
name.ends_with("Test") || name.starts_with("Test") || name.starts_with("test")
}
pub fn is_test_function_name(name: &str) -> bool {
let base = name.rsplit('.').next().unwrap_or(name);
base.starts_with("test") || base.starts_with("Test")
}
pub fn uses_foundry_test_import(source: &str) -> bool {
source.contains("forge-std/Test.sol") || source.contains("forge-std/src/Test.sol")
}
pub fn uses_hardhat_test_import(source: &str) -> bool {
source.contains("hardhat/console.sol")
|| source.contains("@nomicfoundation/hardhat")
|| source.contains("@nomiclabs/hardhat")
}
pub fn is_test_context(path: &Path, source: &str, contract_name: Option<&str>) -> bool {
is_test_file(path)
|| uses_foundry_test_import(source)
|| uses_hardhat_test_import(source)
|| contract_name.is_some_and(is_test_contract_name)
}
pub fn has_floating_pragma(source: &str) -> bool {
source.lines().any(|line| {
let trimmed = line.trim();
trimmed.starts_with("pragma solidity")
&& (trimmed.contains('^') || trimmed.contains(">="))
&& !trimmed.contains('<')
})
}
pub fn function_is_test(
path: &Path,
source: &str,
contract_name: Option<&str>,
function_name: &str,
) -> bool {
is_test_context(path, source, contract_name) || is_test_function_name(function_name)
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn test_foundry_test_file_detection() {
assert!(is_test_file(&PathBuf::from("Token.t.sol")));
assert!(is_test_file(&PathBuf::from("Token.test.sol")));
assert!(!is_test_file(&PathBuf::from("Token.sol")));
}
#[test]
fn test_hardhat_test_context_detection() {
assert!(uses_hardhat_test_import(r#"import "hardhat/console.sol";"#));
assert!(is_test_context(
&PathBuf::from("Token.test.sol"),
"",
Some("Token")
));
}
#[test]
fn test_floating_pragma_detection() {
assert!(has_floating_pragma("pragma solidity ^0.8.0;"));
assert!(!has_floating_pragma("pragma solidity 0.8.20;"));
}
}