#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use crate::models::complexity_bound::{BigOClass, ComplexityBound};
use crate::services::big_o_analyzer::*;
use proptest::prelude::*;
use std::path::PathBuf;
prop_compose! {
fn arb_big_o_class()
(choice in 0usize..9)
-> BigOClass
{
match choice {
0 => BigOClass::Constant,
1 => BigOClass::Logarithmic,
2 => BigOClass::Linear,
3 => BigOClass::Linearithmic,
4 => BigOClass::Quadratic,
5 => BigOClass::Cubic,
6 => BigOClass::Exponential,
7 => BigOClass::Factorial,
_ => BigOClass::Unknown,
}
}
}
prop_compose! {
fn arb_complexity_bound()
(
class in arb_big_o_class(),
coefficient in 1u16..100,
)
-> ComplexityBound
{
ComplexityBound::new(class, coefficient, crate::models::complexity_bound::InputVariable::N)
}
}
prop_compose! {
fn arb_function_complexity()
(
file_path in "[a-zA-Z0-9_/\\.-]+",
function_name in "[a-zA-Z_][a-zA-Z0-9_]*",
line_number in 1usize..10000,
time_complexity in arb_complexity_bound(),
space_complexity in arb_complexity_bound(),
confidence in 0u8..101,
notes in prop::collection::vec("[a-zA-Z0-9 .,!?-]+", 0..5),
)
-> FunctionComplexity
{
FunctionComplexity {
file_path: PathBuf::from(file_path),
function_name,
line_number,
time_complexity,
space_complexity,
confidence,
notes,
}
}
}
prop_compose! {
fn arb_pattern_match()
(
pattern_name in "[a-zA-Z0-9_-]+",
occurrences in 0usize..100,
typical_complexity in arb_big_o_class(),
)
-> PatternMatch
{
PatternMatch {
pattern_name,
occurrences,
typical_complexity,
}
}
}
prop_compose! {
fn arb_complexity_distribution()
(
constant in 0usize..100,
logarithmic in 0usize..100,
linear in 0usize..100,
linearithmic in 0usize..100,
quadratic in 0usize..100,
cubic in 0usize..100,
exponential in 0usize..100,
unknown in 0usize..100,
)
-> ComplexityDistribution
{
ComplexityDistribution {
constant,
logarithmic,
linear,
linearithmic,
quadratic,
cubic,
exponential,
unknown,
}
}
}
prop_compose! {
fn arb_analysis_config()
(
project_path in "[a-zA-Z0-9_/\\.-]+",
include_patterns in prop::collection::vec("[a-zA-Z0-9*?_/\\.-]+", 0..5),
exclude_patterns in prop::collection::vec("[a-zA-Z0-9*?_/\\.-]+", 0..5),
confidence_threshold in 0u8..101,
analyze_space_complexity in any::<bool>(),
)
-> BigOAnalysisConfig
{
BigOAnalysisConfig {
project_path: PathBuf::from(project_path),
include_patterns,
exclude_patterns,
confidence_threshold,
analyze_space_complexity,
}
}
}
proptest! {
#[test]
fn analyzer_creation_succeeds(_dummy in 0u8..1) {
let _analyzer = BigOAnalyzer::new();
}
#[test]
fn complexity_bound_coefficients_positive(bound in arb_complexity_bound()) {
prop_assert!(bound.coefficient > 0);
prop_assert!(bound.confidence <= 100);
}
#[test]
fn function_complexity_confidence_bounded(func in arb_function_complexity()) {
prop_assert!(func.confidence <= 100);
prop_assert!(func.line_number > 0);
}
#[test]
fn pattern_match_names_non_empty(pattern in arb_pattern_match()) {
prop_assert!(!pattern.pattern_name.is_empty());
}
#[test]
fn complexity_distribution_valid(dist in arb_complexity_distribution()) {
let _total = dist.constant + dist.logarithmic + dist.linear +
dist.linearithmic + dist.quadratic + dist.cubic +
dist.exponential + dist.unknown;
}
#[test]
fn distribution_total_consistency(
dist in arb_complexity_distribution(),
extra_functions in 0usize..50
) {
let total_from_dist = dist.constant + dist.logarithmic + dist.linear +
dist.linearithmic + dist.quadratic + dist.cubic +
dist.exponential + dist.unknown;
let analyzed_functions = total_from_dist + extra_functions;
let report = BigOAnalysisReport {
analyzed_functions,
complexity_distribution: dist,
high_complexity_functions: vec![],
pattern_matches: vec![],
recommendations: vec![],
};
let report_total = report.complexity_distribution.constant +
report.complexity_distribution.logarithmic +
report.complexity_distribution.linear +
report.complexity_distribution.linearithmic +
report.complexity_distribution.quadratic +
report.complexity_distribution.cubic +
report.complexity_distribution.exponential +
report.complexity_distribution.unknown;
prop_assert!(report.analyzed_functions >= report_total);
}
#[test]
fn analysis_config_paths_reasonable(config in arb_analysis_config()) {
prop_assert!(!config.project_path.as_os_str().is_empty());
prop_assert!(config.confidence_threshold <= 100);
}
#[test]
fn loop_keywords_language_specific(
language in prop::sample::select(vec!["rust", "javascript", "typescript", "python", "unknown"])
) {
let analyzer = BigOAnalyzer::new();
let _created = analyzer;
match language {
"rust" | "javascript" | "typescript" | "python" => {
prop_assert!(true);
}
_ => {
prop_assert!(true);
}
}
}
#[test]
fn recursive_call_detection_concept(
function_name in "[a-zA-Z_][a-zA-Z0-9_]*",
prefix in "[a-zA-Z0-9 \\t]*"
) {
let analyzer = BigOAnalyzer::new();
let call_line = format!("{}{}()", prefix, function_name);
let def_line = format!("fn {}() {{", function_name);
prop_assert!(!call_line.is_empty());
prop_assert!(!def_line.is_empty());
prop_assert!(!function_name.is_empty());
let _ = analyzer;
}
#[test]
fn sorting_operation_detection_concept(
prefix in "[a-zA-Z0-9 \\t]*",
suffix in "[a-zA-Z0-9 ();\\t]*"
) {
let analyzer = BigOAnalyzer::new();
let sort_line1 = format!("{}.sort()", prefix);
let sort_line2 = format!("{}sort({})", prefix, suffix);
let no_sort_line = format!("{}println!()", prefix);
prop_assert!(!sort_line1.is_empty());
prop_assert!(!sort_line2.is_empty());
prop_assert!(!no_sort_line.is_empty());
if !prefix.is_empty() {
prop_assert!(sort_line1.contains(".sort()") || sort_line1.trim() == ".sort()");
}
let _ = analyzer;
}
#[test]
fn binary_search_detection_concept(
prefix in "[a-zA-Z0-9 \\t]*",
suffix in "[a-zA-Z0-9 ();\\t]*"
) {
let analyzer = BigOAnalyzer::new();
let binary_line1 = format!("{}binary_search{}", prefix, suffix);
let binary_line2 = format!("{}binarySearch{}", prefix, suffix);
let no_binary_line = format!("{}linear_search{}", prefix, suffix);
prop_assert!(!binary_line1.is_empty());
prop_assert!(!binary_line2.is_empty());
prop_assert!(!no_binary_line.is_empty());
prop_assert!(binary_line1.contains("binary_search"));
prop_assert!(binary_line2.contains("binarySearch"));
prop_assert!(no_binary_line.contains("linear_search"));
let _ = analyzer;
}
#[test]
fn big_o_class_ordering_consistent(class in arb_big_o_class()) {
let _description = match class {
BigOClass::Constant => "O(1)",
BigOClass::Logarithmic => "O(log n)",
BigOClass::Linear => "O(n)",
BigOClass::Linearithmic => "O(n log n)",
BigOClass::Quadratic => "O(n²)",
BigOClass::Cubic => "O(n³)",
BigOClass::Exponential => "O(2^n)",
BigOClass::Factorial => "O(n!)",
BigOClass::Unknown => "O(?)",
};
}
#[test]
fn complexity_bound_mathematically_valid(bound in arb_complexity_bound()) {
prop_assert!(bound.coefficient > 0);
prop_assert!(bound.confidence <= 100);
prop_assert!(matches!(bound.class,
BigOClass::Constant | BigOClass::Logarithmic | BigOClass::Linear |
BigOClass::Linearithmic | BigOClass::Quadratic | BigOClass::Cubic |
BigOClass::Exponential | BigOClass::Factorial | BigOClass::Unknown
));
}
#[test]
fn analysis_report_structure_consistent(
analyzed_functions in 0usize..1000,
dist in arb_complexity_distribution(),
high_complexity_functions in prop::collection::vec(arb_function_complexity(), 0..20),
pattern_matches in prop::collection::vec(arb_pattern_match(), 0..10),
recommendations in prop::collection::vec("[a-zA-Z0-9 .,!?-]+", 0..10),
) {
let expected_high_complexity_count = high_complexity_functions.len();
let expected_pattern_count = pattern_matches.len();
let expected_recommendation_count = recommendations.len();
let report = BigOAnalysisReport {
analyzed_functions,
complexity_distribution: dist,
high_complexity_functions,
pattern_matches,
recommendations,
};
prop_assert!(report.analyzed_functions == analyzed_functions);
prop_assert!(report.high_complexity_functions.len() == expected_high_complexity_count);
prop_assert!(report.pattern_matches.len() == expected_pattern_count);
prop_assert!(report.recommendations.len() == expected_recommendation_count);
for func in &report.high_complexity_functions {
prop_assert!(func.confidence <= 100);
prop_assert!(func.line_number > 0);
}
}
#[test]
fn pattern_matches_reasonable_counts(patterns in prop::collection::vec(arb_pattern_match(), 1..10)) {
for pattern in &patterns {
prop_assert!(!pattern.pattern_name.is_empty());
}
let total_occurrences: usize = patterns.iter().map(|p| p.occurrences).sum();
prop_assert!(total_occurrences <= patterns.len() * 100); }
#[test]
fn function_complexity_file_paths_valid(funcs in prop::collection::vec(arb_function_complexity(), 0..10)) {
for func in &funcs {
prop_assert!(!func.file_path.as_os_str().is_empty());
prop_assert!(!func.function_name.is_empty());
prop_assert!(func.line_number > 0);
prop_assert!(func.confidence <= 100);
}
}
}
#[test]
fn test_basic_big_o_invariants() {
let analyzer = BigOAnalyzer::new();
let config = BigOAnalysisConfig {
project_path: std::path::PathBuf::from("/tmp"),
include_patterns: vec!["*.rs".to_string()],
exclude_patterns: vec!["target".to_string()],
confidence_threshold: 50,
analyze_space_complexity: true,
};
let report = BigOAnalysisReport {
analyzed_functions: 0,
complexity_distribution: ComplexityDistribution {
constant: 0,
logarithmic: 0,
linear: 0,
linearithmic: 0,
quadratic: 0,
cubic: 0,
exponential: 0,
unknown: 0,
},
high_complexity_functions: vec![],
pattern_matches: vec![],
recommendations: vec![],
};
let _json = analyzer.format_as_json(&report).unwrap();
let _markdown = analyzer.format_as_markdown(&report);
assert!(!config.project_path.as_os_str().is_empty());
assert!(config.confidence_threshold <= 100);
}
#[test]
fn test_complexity_distribution_consistency() {
let dist = ComplexityDistribution {
constant: 5,
logarithmic: 3,
linear: 10,
linearithmic: 2,
quadratic: 4,
cubic: 1,
exponential: 0,
unknown: 5,
};
let total = dist.constant
+ dist.logarithmic
+ dist.linear
+ dist.linearithmic
+ dist.quadratic
+ dist.cubic
+ dist.exponential
+ dist.unknown;
assert_eq!(total, 30);
assert!(dist.constant <= total);
assert!(dist.linear <= total);
}
#[test]
fn test_function_complexity_structure() {
let complexity = FunctionComplexity {
file_path: PathBuf::from("src/lib.rs"),
function_name: "fibonacci".to_string(),
line_number: 42,
time_complexity: ComplexityBound::new(
BigOClass::Exponential,
1,
crate::models::complexity_bound::InputVariable::N,
),
space_complexity: ComplexityBound::new(
BigOClass::Linear,
1,
crate::models::complexity_bound::InputVariable::N,
),
confidence: 85,
notes: vec!["Recursive implementation".to_string()],
};
assert_eq!(complexity.function_name, "fibonacci");
assert_eq!(complexity.line_number, 42);
assert_eq!(complexity.confidence, 85);
assert!(matches!(
complexity.time_complexity.class,
BigOClass::Exponential
));
assert!(matches!(
complexity.space_complexity.class,
BigOClass::Linear
));
}
}