#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use std::io::Write;
use tempfile::NamedTempFile;
#[test]
fn test_analyze_simple_rust_code() -> Result<()> {
let mut temp_file = NamedTempFile::with_suffix(".rs")?;
writeln!(
temp_file,
r#"
/// A simple function
pub fn simple_function() -> i32 {{
42
}}
"#
)?;
let analyzer = TdgAnalyzer::new()?;
let score = analyzer.analyze_file(temp_file.path())?;
assert_eq!(score.language, Language::Rust);
assert!(score.total > 0.0);
assert!(score.total <= 100.0);
assert!(score.confidence > 0.0);
Ok(())
}
#[test]
#[ignore = "requires TDG analyzer setup"]
fn test_analyze_complex_code() -> Result<()> {
let source = r#"
fn complex_function(x: i32) -> i32 {
if x > 0 {
if x > 10 {
if x > 20 {
if x > 30 {
return x * 2;
}
}
}
}
x
}
"#;
let analyzer = TdgAnalyzer::new()?;
let score = analyzer.analyze_source(source, Language::Rust, None)?;
assert!(score.structural_complexity < 25.0);
assert!(!score.penalties_applied.is_empty());
Ok(())
}
#[test]
fn test_analyzer_new() {
let analyzer = TdgAnalyzer::new();
assert!(analyzer.is_ok());
}
#[test]
fn test_analyzer_with_config() {
let config = TdgConfig::default();
let analyzer = TdgAnalyzer::with_config(config);
assert!(analyzer.is_ok());
}
#[test]
fn test_analyze_empty_source() {
let analyzer = TdgAnalyzer::new().unwrap();
let result = analyzer.analyze_source("", Language::Rust, None);
assert!(result.is_ok());
let score = result.unwrap();
assert!(score.total >= 0.0);
}
#[test]
fn test_analyze_source_python() {
let source = r#"
def hello():
\"\"\"A simple function.\"\"\"
print("Hello, World!")
import os
from pathlib import Path
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let result = analyzer.analyze_source(source, Language::Python, None);
assert!(result.is_ok());
let score = result.unwrap();
assert_eq!(score.language, Language::Python);
}
#[test]
fn test_analyze_source_javascript() {
let source = r#"
/**
* A documented function
*/
function hello() {
console.log("Hello");
}
import { foo } from './bar';
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let result = analyzer.analyze_source(source, Language::JavaScript, None);
assert!(result.is_ok());
}
#[test]
fn test_analyze_source_typescript() {
let source = r#"
/**
* TypeScript function
*/
function greet(name: string): string {
return `Hello, ${name}`;
}
import { Component } from '@angular/core';
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let result = analyzer.analyze_source(source, Language::TypeScript, None);
assert!(result.is_ok());
}
#[test]
fn test_analyze_source_go() {
let source = r#"
package main
// Hello prints a greeting
func Hello() {
fmt.Println("Hello")
}
import "fmt"
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let result = analyzer.analyze_source(source, Language::Go, None);
assert!(result.is_ok());
}
#[test]
fn test_cyclomatic_complexity_estimation() {
let analyzer = TdgAnalyzer::new().unwrap();
let lines: Vec<&str> = vec![
"if x > 0 {",
" for i in 0..10 {",
" while true {",
" match x {",
" 1 => {},",
" }",
" }",
" }",
"}",
];
let complexity = analyzer.estimate_cyclomatic_complexity(&lines);
assert!(complexity >= 4); }
#[test]
fn test_cyclomatic_complexity_with_logical_operators() {
let analyzer = TdgAnalyzer::new().unwrap();
let lines: Vec<&str> = vec!["if x > 0 && y < 10 {", " if a || b || c {", " }", "}"];
let complexity = analyzer.estimate_cyclomatic_complexity(&lines);
assert!(complexity > 1);
}
#[test]
fn test_nesting_depth_estimation() {
let analyzer = TdgAnalyzer::new().unwrap();
let source = r#"
fn main() {
if true {
if false {
{
// nested
}
}
}
}
"#;
let depth = analyzer.estimate_nesting_depth(source);
assert!(depth >= 3);
}
#[test]
#[ignore] fn test_duplication_ratio_estimation() {
let analyzer = TdgAnalyzer::new().unwrap();
let source = r#"
let x = some_long_function_call(arg1, arg2);
let y = some_long_function_call(arg1, arg2);
let z = some_long_function_call(arg1, arg2);
let a = different_call();
let b = another_call();
"#;
let ratio = analyzer.estimate_duplication_ratio(source);
assert!(ratio > 0.0);
}
#[test]
fn test_duplication_ratio_no_duplicates() {
let analyzer = TdgAnalyzer::new().unwrap();
let source = "let a = 1;\nlet b = 2;\nlet c = 3;";
let ratio = analyzer.estimate_duplication_ratio(source);
assert_eq!(ratio, 0.0);
}
#[test]
fn test_duplication_ratio_short_source() {
let analyzer = TdgAnalyzer::new().unwrap();
let source = "ab";
let ratio = analyzer.estimate_duplication_ratio(source);
assert_eq!(ratio, 0.0);
}
#[test]
fn test_should_skip_directory() {
let analyzer = TdgAnalyzer::new().unwrap();
assert!(analyzer.should_skip_directory(Path::new("node_modules")));
assert!(analyzer.should_skip_directory(Path::new("target")));
assert!(analyzer.should_skip_directory(Path::new(".git")));
assert!(analyzer.should_skip_directory(Path::new("__pycache__")));
assert!(analyzer.should_skip_directory(Path::new("venv")));
assert!(analyzer.should_skip_directory(Path::new(".venv")));
assert!(analyzer.should_skip_directory(Path::new("vendor")));
assert!(!analyzer.should_skip_directory(Path::new("src")));
assert!(!analyzer.should_skip_directory(Path::new("lib")));
}
#[test]
fn test_should_analyze_file() {
let analyzer = TdgAnalyzer::new().unwrap();
assert!(analyzer.should_analyze_file(Path::new("main.rs")));
assert!(analyzer.should_analyze_file(Path::new("app.py")));
assert!(analyzer.should_analyze_file(Path::new("index.js")));
assert!(analyzer.should_analyze_file(Path::new("app.ts")));
assert!(analyzer.should_analyze_file(Path::new("component.jsx")));
assert!(analyzer.should_analyze_file(Path::new("component.tsx")));
assert!(analyzer.should_analyze_file(Path::new("main.go")));
assert!(analyzer.should_analyze_file(Path::new("Main.java")));
assert!(analyzer.should_analyze_file(Path::new("main.c")));
assert!(analyzer.should_analyze_file(Path::new("main.cpp")));
assert!(analyzer.should_analyze_file(Path::new("main.swift")));
assert!(analyzer.should_analyze_file(Path::new("main.kt")));
assert!(!analyzer.should_analyze_file(Path::new("README.md")));
assert!(!analyzer.should_analyze_file(Path::new("config.yaml")));
}
#[test]
fn test_should_analyze_file_no_extension() {
let analyzer = TdgAnalyzer::new().unwrap();
assert!(!analyzer.should_analyze_file(Path::new("Makefile")));
}
#[test]
fn test_analyze_coupling_high_imports() {
let source = (0..30)
.map(|i| format!("use module_{i};\n"))
.collect::<String>();
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_coupling(&source, &mut tracker);
assert!(score < analyzer.config.weights.coupling);
}
#[test]
fn test_analyze_coupling_python_imports() {
let source = r#"
import os
import sys
from pathlib import Path
import json
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_coupling(source, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_analyze_coupling_c_includes() {
let source = r#"
#include <stdio.h>
#include <stdlib.h>
#include "myheader.h"
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_coupling(source, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_analyze_documentation_rust() {
let source = r#"
/// Documentation line 1
/// Documentation line 2
//! Module documentation
fn undocumented() {}
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_documentation(source, Language::Rust, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_analyze_documentation_python() {
let source = r#"
"""
Module docstring
"""
def func():
'''Function docstring'''
pass
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_documentation(source, Language::Python, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_analyze_documentation_empty_source() {
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_documentation("", Language::Rust, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_analyze_consistency_tabs() {
let source = "\tfn foo() {\n\t\treturn 1;\n\t}";
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_consistency(source, Language::Rust, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_analyze_consistency_spaces() {
let source = " fn foo() {\n return 1;\n }";
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_consistency(source, Language::Rust, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_analyze_consistency_mixed() {
let source = "\tfn foo() {\n return 1;\n\t}";
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_consistency(source, Language::Rust, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_analyze_consistency_empty() {
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_consistency("", Language::Rust, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_analyze_consistency_no_indentation() {
let source = "fn foo() {}\nfn bar() {}";
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_consistency(source, Language::Rust, &mut tracker);
assert!(score > 0.0);
}
#[test]
fn test_structural_complexity_high() {
let source = (0..50)
.map(|i| format!("if x > {} {{\n}}\n", i))
.collect::<String>();
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_structural_complexity(&source, &mut tracker);
assert!(score >= 0.0);
}
#[test]
fn test_semantic_complexity_deep_nesting() {
let source = r#"
fn foo() {
{
{
{
{
{
{
// very deep
}
}
}
}
}
}
}
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_semantic_complexity(source, &mut tracker);
assert!(score >= 0.0);
}
#[test]
fn test_analyze_duplication_high() {
let repeated_line = "let result = some_very_long_function_name_here(arg1, arg2, arg3);\n";
let source: String = repeated_line.repeat(20);
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_duplication(&source, &mut tracker);
assert!(score >= 0.0);
}
#[test]
fn test_discover_files_nonexistent() {
let analyzer = TdgAnalyzer::new().unwrap();
let result = analyzer.discover_files(Path::new("/nonexistent/path"));
assert!(result.is_ok());
assert!(result.unwrap().is_empty());
}
#[test]
fn test_analyze_source_with_file_path() {
let analyzer = TdgAnalyzer::new().unwrap();
let result = analyzer.analyze_source(
"fn main() {}",
Language::Rust,
Some(PathBuf::from("/test/file.rs")),
);
assert!(result.is_ok());
let score = result.unwrap();
assert_eq!(score.file_path, Some(PathBuf::from("/test/file.rs")));
}
#[test]
fn test_analyze_file_python() -> Result<()> {
let mut temp_file = NamedTempFile::with_suffix(".py")?;
writeln!(temp_file, "def hello():\n print('hello')")?;
let analyzer = TdgAnalyzer::new()?;
let score = analyzer.analyze_file(temp_file.path())?;
assert_eq!(score.language, Language::Python);
Ok(())
}
#[test]
fn test_analyze_file_javascript() -> Result<()> {
let mut temp_file = NamedTempFile::with_suffix(".js")?;
writeln!(temp_file, "function hello() {{ console.log('hello'); }}")?;
let analyzer = TdgAnalyzer::new()?;
let score = analyzer.analyze_file(temp_file.path())?;
assert_eq!(score.language, Language::JavaScript);
Ok(())
}
#[test]
fn test_analyze_file_lean() -> Result<()> {
let mut temp_file = NamedTempFile::with_suffix(".lean")?;
writeln!(
temp_file,
r#"
-- A simple Lean 4 module
import Mathlib.Data.Nat.Basic
def add (x y : Nat) : Nat := x + y
theorem add_comm (a b : Nat) : a + b = b + a := by
omega
"#
)?;
let analyzer = TdgAnalyzer::new()?;
let score = analyzer.analyze_file(temp_file.path())?;
assert_eq!(score.language, Language::Lean);
assert!(score.total > 0.0);
assert!(!score.has_critical_defects, "Clean Lean file should not have critical defects");
Ok(())
}
#[test]
fn test_analyze_lean_with_sorry_gets_grade_f() -> Result<()> {
let mut temp_file = NamedTempFile::with_suffix(".lean")?;
writeln!(
temp_file,
r#"
import Mathlib.Data.Nat.Basic
theorem hard_theorem : 1 + 1 = 2 := by
sorry
def unfinished : Nat := sorry
"#
)?;
let analyzer = TdgAnalyzer::new()?;
let score = analyzer.analyze_file(temp_file.path())?;
assert_eq!(score.language, Language::Lean);
assert!(score.has_critical_defects, "Lean file with sorry should have critical defects");
assert_eq!(score.critical_defects_count, 2, "Should detect 2 sorry occurrences");
assert_eq!(score.total, 0.0, "Files with sorry should score 0");
assert_eq!(score.grade, crate::tdg::grade::Grade::F, "Files with sorry should get grade F");
Ok(())
}
#[test]
fn test_analyze_lean_sorry_in_comment_not_counted() {
let source = "-- sorry this is a comment\ntheorem real : True := by trivial";
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer.analyze_source(source, Language::Lean, None).unwrap();
assert!(!score.has_critical_defects, "sorry in comments should not trigger critical defects");
}
#[test]
fn test_analyze_lean_sorry_in_block_comment_not_counted() {
let source = "/- sorry in block comment -/\ntheorem real : True := by trivial";
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer.analyze_source(source, Language::Lean, None).unwrap();
assert!(!score.has_critical_defects, "sorry in block comments should not trigger critical defects");
}
#[test]
fn test_analyze_lean_sorry_in_identifier_not_counted() {
let source = "def sorry_helper := 42";
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer.analyze_source(source, Language::Lean, None).unwrap();
assert!(!score.has_critical_defects, "sorry as part of identifier should not trigger critical defects");
}
#[test]
fn test_should_analyze_lean_file() {
let analyzer = TdgAnalyzer::new().unwrap();
assert!(analyzer.should_analyze_file(Path::new("Basic.lean")));
}
#[test]
fn test_should_skip_lake_directory() {
let analyzer = TdgAnalyzer::new().unwrap();
assert!(analyzer.should_skip_directory(Path::new(".lake")));
}
#[test]
fn test_lean_coupling_detects_imports() {
let source = r#"
import Mathlib.Data.Nat.Basic
import Mathlib.Tactic
open Nat
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_coupling(source, &mut tracker);
assert!(score > 0.0, "Lean coupling analysis should detect imports");
}
#[test]
fn test_lean_documentation_detection() {
let source = r#"
-- | A documented function
/-- Documentation comment -/
/-! Module documentation -/
def foo : Nat := 42
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let mut tracker = PenaltyTracker::new();
let score = analyzer.analyze_documentation(source, Language::Lean, &mut tracker);
assert!(score > 0.0, "Lean documentation analysis should detect doc comments");
}
#[test]
fn test_analyze_source_java() {
let source = r#"
/** Javadoc block */
public class Greeter {
public void greet(String name) {
System.out.println("Hello, " + name);
}
}
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer
.analyze_source(source, Language::Java, None)
.expect("Java dispatch must succeed");
assert_eq!(score.language, Language::Java);
}
#[test]
fn test_analyze_source_c() {
let source = r#"
/* A C function */
#include <stdio.h>
int main(void) {
printf("hello\n");
return 0;
}
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer
.analyze_source(source, Language::C, None)
.expect("C dispatch must succeed");
assert_eq!(score.language, Language::C);
}
#[test]
fn test_analyze_source_cpp() {
let source = r#"
/// C++ class
class Foo {
public:
Foo() = default;
void bar() const {}
};
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer
.analyze_source(source, Language::Cpp, None)
.expect("C++ dispatch must succeed");
assert_eq!(score.language, Language::Cpp);
}
#[test]
fn test_analyze_source_lua() {
let source = r#"
-- Module docstring
local M = {}
function M.greet(name)
print("Hello, " .. name)
end
return M
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer
.analyze_source(source, Language::Lua, None)
.expect("Lua dispatch must succeed");
assert_eq!(score.language, Language::Lua);
}
#[test]
fn test_analyze_source_sql() {
let source = r#"
-- Select all users
SELECT id, name
FROM users
WHERE active = TRUE
ORDER BY id ASC;
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer
.analyze_source(source, Language::Sql, None)
.expect("SQL dispatch must succeed");
assert_eq!(score.language, Language::Sql);
}
#[test]
fn test_analyze_source_scala() {
let source = r#"
/** Scala greeter */
object Greeter {
def greet(name: String): String = s"Hello, $name"
}
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer
.analyze_source(source, Language::Scala, None)
.expect("Scala dispatch must succeed");
assert_eq!(score.language, Language::Scala);
}
#[test]
fn test_analyze_source_yaml() {
let source = r#"
# YAML config
name: pmat
version: "3.15.0"
deps:
- serde
- tokio
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer
.analyze_source(source, Language::Yaml, None)
.expect("YAML dispatch must succeed");
assert_eq!(score.language, Language::Yaml);
}
#[test]
fn test_analyze_source_lean() {
let source = r#"
-- | A documented definition
def answer : Nat := 42
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer
.analyze_source(source, Language::Lean, None)
.expect("Lean dispatch must succeed");
assert_eq!(score.language, Language::Lean);
}
#[test]
fn test_analyze_source_markdown() {
let source = r#"# Heading
Some prose.
```rust
fn main() {}
```
"#;
let analyzer = TdgAnalyzer::new().unwrap();
let score = analyzer
.analyze_source(source, Language::Markdown, None)
.expect("Markdown dispatch must succeed");
assert_eq!(score.language, Language::Markdown);
}
}
#[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);
}
}
}