#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod scorer_tests {
use super::*;
use tree_sitter::Parser;
fn parse_rust(source: &str) -> Tree {
let mut parser = Parser::new();
parser.set_language(&tree_sitter_rust::language()).unwrap();
parser.parse(source, None).unwrap()
}
#[test]
fn test_scorer_category() {
let analyzer = CouplingAnalyzer::new();
assert_eq!(analyzer.category(), MetricCategory::Coupling);
}
#[test]
fn test_scorer_score_simple_code() {
let source = r#"
fn simple_function() {
let x = 1;
println!("{}", x);
}
"#;
let tree = parse_rust(source);
let analyzer = CouplingAnalyzer::new();
let config = TdgConfig::default();
let mut tracker = PenaltyTracker::new();
let score = analyzer.score(&tree, source, Language::Rust, &config, &mut tracker);
assert!(score.is_ok());
assert!(score.unwrap() >= 0.0);
}
#[test]
fn test_scorer_score_high_coupling_code() {
let source = r#"
use std::collections::HashMap;
use std::collections::HashSet;
use std::io::{Read, Write, BufReader, BufWriter};
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
use std::sync::{Arc, Mutex, RwLock};
pub struct HighCouplingStruct {
map: HashMap<String, i32>,
set: HashSet<i32>,
file: Option<File>,
}
pub fn use_many_dependencies() {
let path = PathBuf::from("test");
let file = File::open(&path).unwrap();
let _reader = BufReader::new(file);
}
"#;
let tree = parse_rust(source);
let analyzer = CouplingAnalyzer::new();
let config = TdgConfig::default();
let mut tracker = PenaltyTracker::new();
let score = analyzer.score(&tree, source, Language::Rust, &config, &mut tracker);
assert!(score.is_ok());
let score_value = score.unwrap();
assert!(score_value >= 0.0);
}
#[test]
fn test_instability_calculation() {
let source = r#"
use crate::other::Dependency;
pub fn public_api() {}
"#;
let tree = parse_rust(source);
let analyzer = CouplingAnalyzer::new();
let afferent = analyzer.calculate_afferent_coupling(tree.root_node(), source);
let efferent = analyzer.calculate_efferent_coupling(tree.root_node(), source);
if afferent + efferent > 0 {
let instability = efferent as f32 / (afferent + efferent) as f32;
assert!(instability >= 0.0);
assert!(instability <= 1.0);
}
}
#[test]
fn test_distance_from_main_sequence() {
let source = r#"
trait AbstractTrait {
fn do_something(&self);
}
struct ConcreteImpl;
impl AbstractTrait for ConcreteImpl {
fn do_something(&self) {}
}
"#;
let tree = parse_rust(source);
let analyzer = CouplingAnalyzer::new();
let afferent = analyzer.calculate_afferent_coupling(tree.root_node(), source);
let efferent = analyzer.calculate_efferent_coupling(tree.root_node(), source);
let abstractness = analyzer.calculate_abstractness(tree.root_node(), source);
let instability = if afferent + efferent > 0 {
efferent as f32 / (afferent + efferent) as f32
} else {
0.0
};
let distance = (instability + abstractness - 1.0).abs();
assert!(distance >= 0.0);
assert!(distance <= 2.0); }
#[test]
fn test_empty_source_coupling() {
let source = "";
let tree = parse_rust(source);
let analyzer = CouplingAnalyzer::new();
let afferent = analyzer.calculate_afferent_coupling(tree.root_node(), source);
let efferent = analyzer.calculate_efferent_coupling(tree.root_node(), source);
let abstractness = analyzer.calculate_abstractness(tree.root_node(), source);
assert_eq!(afferent, 0);
assert_eq!(efferent, 0);
assert_eq!(abstractness, 0.0);
}
#[test]
fn test_extract_import_path() {
let source = r#"
use std::collections::HashMap;
"#;
let tree = parse_rust(source);
let analyzer = CouplingAnalyzer::new();
walk_tree(tree.root_node(), |node| {
if node.kind() == "use_declaration" {
let path = analyzer.extract_import_path(node, source);
assert!(path.is_some());
}
});
}
#[test]
fn test_is_public_function() {
let source = r#"
pub fn public_fn() {}
"#;
let tree = parse_rust(source);
let analyzer = CouplingAnalyzer::new();
walk_tree(tree.root_node(), |node| {
if node.kind() == "function_item" {
let is_pub = analyzer.is_public(node, source);
if let Some(name) = node.child_by_field_name("name") {
let name_text = get_node_text(name, source);
if name_text == "public_fn" {
assert!(is_pub);
}
}
}
});
}
#[test]
fn test_is_private_function() {
let source = r#"
fn private_fn() {}
"#;
let tree = parse_rust(source);
let analyzer = CouplingAnalyzer::new();
walk_tree(tree.root_node(), |node| {
if node.kind() == "function_item" {
let is_pub = analyzer.is_public(node, source);
if let Some(name) = node.child_by_field_name("name") {
let name_text = get_node_text(name, source);
if name_text == "private_fn" {
assert!(!is_pub);
}
}
}
});
}
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod property_tests {
use proptest::prelude::*;
proptest! {
#[test]
fn basic_property_stability(_input in ".*") {
prop_assert!(true);
}
#[test]
fn module_consistency_check(_x in 0u32..1000) {
prop_assert!(_x < 1001);
}
}
}