scirs2_stats/
api_consistency_validation.rs

1//! Comprehensive API consistency validation framework
2//!
3//! This module provides tools and infrastructure for validating API consistency
4//! across the entire scirs2-stats library. It includes:
5//! - Function signature validation
6//! - Parameter naming consistency checks
7//! - Return type standardization validation
8//! - Error handling consistency verification
9//! - Documentation completeness analysis
10//! - Performance characteristics validation
11//! - Cross-module API compatibility checks
12//! - SciPy compatibility verification
13
14use crate::error::StatsResult;
15use serde::{Deserialize, Serialize};
16use serde_json;
17use std::collections::{HashMap, HashSet};
18use std::fmt::Debug;
19
20/// API consistency validation framework
21pub struct APIConsistencyValidator {
22    /// Configuration for validation
23    pub config: ValidationConfig,
24    /// Validation results
25    pub results: ValidationResults,
26    /// Function registry for cross-module validation
27    pub function_registry: FunctionRegistry,
28}
29
30/// Configuration for API validation
31#[derive(Debug, Clone)]
32pub struct ValidationConfig {
33    /// Enable parameter naming validation
34    pub validate_parameter_names: bool,
35    /// Enable return type validation
36    pub validate_return_types: bool,
37    /// Enable error handling validation
38    pub validate_error_handling: bool,
39    /// Enable documentation validation
40    pub validate_documentation: bool,
41    /// Enable performance validation
42    pub validate_performance: bool,
43    /// Enable SciPy compatibility validation
44    pub validate_scipy_compatibility: bool,
45    /// Strict mode (fail on any inconsistency)
46    pub strict_mode: bool,
47    /// Custom naming conventions
48    pub naming_conventions: NamingConventions,
49}
50
51/// Naming conventions for API consistency
52#[derive(Debug, Clone)]
53pub struct NamingConventions {
54    /// Standard parameter names for common concepts
55    pub parameter_names: HashMap<String, Vec<String>>,
56    /// Function name patterns
57    pub function_patterns: Vec<FunctionPattern>,
58    /// Module naming rules
59    pub module_patterns: Vec<String>,
60}
61
62/// Function pattern for naming validation
63#[derive(Debug, Clone)]
64pub struct FunctionPattern {
65    /// Pattern description
66    pub description: String,
67    /// Regular expression pattern
68    pub pattern: String,
69    /// Category of functions this applies to
70    pub category: FunctionCategory,
71}
72
73/// Categories of functions for validation
74#[derive(Debug, Clone, PartialEq, Eq, Hash)]
75pub enum FunctionCategory {
76    /// Descriptive statistics functions
77    DescriptiveStats,
78    /// Statistical tests
79    StatisticalTests,
80    /// Distribution functions
81    Distributions,
82    /// Regression functions
83    Regression,
84    /// Correlation functions
85    Correlation,
86    /// Utility functions
87    Utilities,
88    /// Advanced algorithms
89    Advanced,
90}
91
92/// Results of API validation
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct ValidationResults {
95    /// Overall validation status
96    pub overall_status: ValidationStatus,
97    /// Individual check results
98    pub check_results: Vec<ValidationCheck>,
99    /// Inconsistencies found
100    pub inconsistencies: Vec<APIInconsistency>,
101    /// Warnings (non-critical issues)
102    pub warnings: Vec<ValidationWarning>,
103    /// Summary statistics
104    pub summary: ValidationSummary,
105}
106
107/// Validation status
108#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
109pub enum ValidationStatus {
110    /// All checks passed
111    Passed,
112    /// Some warnings but no critical issues
113    PassedWithWarnings,
114    /// Critical inconsistencies found
115    Failed,
116    /// Validation not yet run
117    NotRun,
118}
119
120/// Individual validation check
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct ValidationCheck {
123    /// Name of the check
124    pub name: String,
125    /// Category of the check
126    pub category: CheckCategory,
127    /// Status of this check
128    pub status: ValidationStatus,
129    /// Description of what was checked
130    pub description: String,
131    /// Details about the check result
132    pub details: String,
133    /// Severity level
134    pub severity: Severity,
135}
136
137/// Categories of validation checks
138#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
139pub enum CheckCategory {
140    /// Parameter naming consistency
141    ParameterNaming,
142    /// Return type consistency
143    ReturnTypes,
144    /// Error handling consistency
145    ErrorHandling,
146    /// Documentation quality
147    Documentation,
148    /// Performance characteristics
149    Performance,
150    /// Cross-module compatibility
151    CrossModule,
152    /// SciPy compatibility
153    ScipyCompatibility,
154}
155
156/// Severity levels for validation issues
157#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
158pub enum Severity {
159    /// Critical issue that breaks consistency
160    Critical,
161    /// Major issue that should be addressed
162    Major,
163    /// Minor issue or suggestion
164    Minor,
165    /// Informational note
166    Info,
167}
168
169/// API inconsistency detected
170#[derive(Debug, Clone, Serialize, Deserialize)]
171pub struct APIInconsistency {
172    /// Type of inconsistency
173    pub inconsistency_type: InconsistencyType,
174    /// Functions/modules involved
175    pub affected_functions: Vec<String>,
176    /// Description of the issue
177    pub description: String,
178    /// Suggested fix
179    pub suggested_fix: String,
180    /// Severity level
181    pub severity: Severity,
182    /// Impact on users
183    pub impact: String,
184}
185
186/// Types of API inconsistencies
187#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
188pub enum InconsistencyType {
189    /// Parameter naming inconsistency
190    ParameterNaming,
191    /// Inconsistent return types
192    ReturnTypeInconsistency,
193    /// Different error handling patterns
194    ErrorHandlingInconsistency,
195    /// Missing or inconsistent documentation
196    DocumentationInconsistency,
197    /// Performance characteristic differences
198    PerformanceInconsistency,
199    /// SciPy compatibility issues
200    ScipyCompatibilityIssue,
201}
202
203/// Validation warning (non-critical issue)
204#[derive(Debug, Clone, Serialize, Deserialize)]
205pub struct ValidationWarning {
206    /// Warning message
207    pub message: String,
208    /// Category of warning
209    pub category: CheckCategory,
210    /// Affected function/module
211    pub location: String,
212    /// Suggestion for improvement
213    pub suggestion: String,
214}
215
216/// Summary of validation results
217#[derive(Debug, Clone, Serialize, Deserialize)]
218pub struct ValidationSummary {
219    /// Total number of checks performed
220    pub total_checks: usize,
221    /// Number of passed checks
222    pub passed_checks: usize,
223    /// Number of failed checks
224    pub failed_checks: usize,
225    /// Number of warnings
226    pub warning_count: usize,
227    /// Number of critical issues
228    pub critical_issues: usize,
229    /// Overall consistency score (0-100)
230    pub consistency_score: f64,
231}
232
233/// Function registry for cross-module validation
234#[derive(Debug, Clone)]
235pub struct FunctionRegistry {
236    /// Registered functions by module
237    pub functions_by_module: HashMap<String, Vec<FunctionSignature>>,
238    /// Functions by category
239    pub functions_by_category: HashMap<FunctionCategory, Vec<FunctionSignature>>,
240    /// Parameter usage statistics
241    pub parameter_usage: HashMap<String, ParameterUsage>,
242}
243
244/// Function signature information
245#[derive(Debug, Clone)]
246pub struct FunctionSignature {
247    /// Function name
248    pub name: String,
249    /// Module containing the function
250    pub module: String,
251    /// Function category
252    pub category: FunctionCategory,
253    /// Parameter information
254    pub parameters: Vec<ParameterInfo>,
255    /// Return type information
256    pub return_type: ReturnTypeInfo,
257    /// Error types that can be returned
258    pub error_types: Vec<String>,
259    /// Documentation status
260    pub documentation_status: DocumentationStatus,
261}
262
263/// Parameter information
264#[derive(Debug, Clone)]
265pub struct ParameterInfo {
266    /// Parameter name
267    pub name: String,
268    /// Parameter type
269    pub param_type: String,
270    /// Whether parameter is optional
271    pub optional: bool,
272    /// Default value if any
273    pub default_value: Option<String>,
274    /// Parameter description
275    pub description: String,
276}
277
278/// Return type information
279#[derive(Debug, Clone)]
280pub struct ReturnTypeInfo {
281    /// Return type name
282    pub type_name: String,
283    /// Whether return is wrapped in Result
284    pub is_result: bool,
285    /// Generic type parameters
286    pub generic_params: Vec<String>,
287    /// Description of return value
288    pub description: String,
289}
290
291/// Documentation status
292#[derive(Debug, Clone, PartialEq)]
293pub enum DocumentationStatus {
294    /// Complete documentation
295    Complete,
296    /// Partial documentation
297    Partial,
298    /// Missing documentation
299    Missing,
300    /// Documentation present but poor quality
301    PoorQuality,
302}
303
304/// Parameter usage statistics
305#[derive(Debug, Clone)]
306pub struct ParameterUsage {
307    /// Parameter name
308    pub name: String,
309    /// Number of functions using this parameter
310    pub usage_count: usize,
311    /// Different type signatures seen
312    pub type_signatures: HashSet<String>,
313    /// Modules where this parameter is used
314    pub modules: HashSet<String>,
315    /// Common alternative names
316    pub alternative_names: Vec<String>,
317}
318
319impl Default for ValidationConfig {
320    fn default() -> Self {
321        Self {
322            validate_parameter_names: true,
323            validate_return_types: true,
324            validate_error_handling: true,
325            validate_documentation: true,
326            validate_performance: false, // Expensive, off by default
327            validate_scipy_compatibility: true,
328            strict_mode: false,
329            naming_conventions: NamingConventions::default(),
330        }
331    }
332}
333
334impl Default for NamingConventions {
335    fn default() -> Self {
336        let mut parameter_names = HashMap::new();
337
338        // Standard parameter names for common statistical concepts
339        parameter_names.insert(
340            "data".to_string(),
341            vec!["data".to_string(), "x".to_string(), "array".to_string()],
342        );
343        parameter_names.insert(
344            "axis".to_string(),
345            vec!["axis".to_string(), "dim".to_string()],
346        );
347        parameter_names.insert(
348            "degrees_of_freedom".to_string(),
349            vec!["ddof".to_string(), "df".to_string()],
350        );
351        parameter_names.insert(
352            "alpha".to_string(),
353            vec!["alpha".to_string(), "significance".to_string()],
354        );
355        parameter_names.insert(
356            "alternative".to_string(),
357            vec!["alternative".to_string(), "alt".to_string()],
358        );
359        parameter_names.insert(
360            "method".to_string(),
361            vec!["method".to_string(), "algorithm".to_string()],
362        );
363
364        let function_patterns = vec![
365            FunctionPattern {
366                description: "Statistical test functions should end with 'test'".to_string(),
367                pattern: r".*test$".to_string(),
368                category: FunctionCategory::StatisticalTests,
369            },
370            FunctionPattern {
371                description: "Correlation functions should contain 'corr'".to_string(),
372                pattern: r".*corr.*".to_string(),
373                category: FunctionCategory::Correlation,
374            },
375            FunctionPattern {
376                description: "Distribution functions should be named after the distribution"
377                    .to_string(),
378                pattern: r"^[a-z_]+$".to_string(),
379                category: FunctionCategory::Distributions,
380            },
381        ];
382
383        Self {
384            parameter_names,
385            function_patterns,
386            module_patterns: vec!["^[a-z_]+$".to_string()],
387        }
388    }
389}
390
391impl APIConsistencyValidator {
392    /// Create new API consistency validator
393    pub fn new(config: ValidationConfig) -> Self {
394        Self {
395            config,
396            results: ValidationResults::new(),
397            function_registry: FunctionRegistry::new(),
398        }
399    }
400
401    /// Run complete API consistency validation
402    pub fn validate_all(&mut self) -> StatsResult<&ValidationResults> {
403        // Reset results
404        self.results = ValidationResults::new();
405
406        // Run individual validation checks
407        if self.config.validate_parameter_names {
408            self.validate_parameter_naming()?;
409        }
410
411        if self.config.validate_return_types {
412            self.validate_return_type_consistency()?;
413        }
414
415        if self.config.validate_error_handling {
416            self.validate_error_handling_consistency()?;
417        }
418
419        if self.config.validate_documentation {
420            self.validate_documentation_quality()?;
421        }
422
423        if self.config.validate_performance {
424            self.validate_performance_characteristics()?;
425        }
426
427        if self.config.validate_scipy_compatibility {
428            self.validate_scipy_compatibility()?;
429        }
430
431        // Compute summary
432        self.compute_validation_summary();
433
434        // Determine overall status
435        self.results.overall_status = self.determine_overall_status();
436
437        Ok(&self.results)
438    }
439
440    /// Validate parameter naming consistency
441    fn validate_parameter_naming(&mut self) -> StatsResult<()> {
442        let mut check = ValidationCheck {
443            name: "Parameter Naming Consistency".to_string(),
444            category: CheckCategory::ParameterNaming,
445            status: ValidationStatus::NotRun,
446            description: "Checking consistency of parameter names across functions".to_string(),
447            details: String::new(),
448            severity: Severity::Major,
449        };
450
451        // Analyze parameter usage patterns
452        let mut parameter_analysis = HashMap::new();
453
454        for (module, functions) in &self.function_registry.functions_by_module {
455            for function in functions {
456                for param in &function.parameters {
457                    let entry = parameter_analysis
458                        .entry(param.name.clone())
459                        .or_insert_with(ParameterUsageAnalysis::new);
460
461                    entry.add_usage(
462                        module.clone(),
463                        function.name.clone(),
464                        param.param_type.clone(),
465                    );
466                }
467            }
468        }
469
470        // Check for inconsistencies
471        let mut inconsistencies_found = 0;
472        let mut details = Vec::new();
473
474        for (param_name, analysis) in &parameter_analysis {
475            if analysis.type_variations.len() > 1 {
476                // Same parameter name used with different types
477                let inconsistency = APIInconsistency {
478                    inconsistency_type: InconsistencyType::ParameterNaming,
479                    affected_functions: analysis.functions.clone(),
480                    description: format!(
481                        "Parameter '{}' used with different types: {:?}",
482                        param_name, analysis.type_variations
483                    ),
484                    suggested_fix: format!(
485                        "Standardize parameter '{}' to use consistent type across all functions",
486                        param_name
487                    ),
488                    severity: Severity::Major,
489                    impact: "May cause confusion for users and complicate generic programming"
490                        .to_string(),
491                };
492
493                self.results.inconsistencies.push(inconsistency);
494                inconsistencies_found += 1;
495            }
496
497            // Check against naming conventions
498            if let Some(standard_names) = self
499                .config
500                .naming_conventions
501                .parameter_names
502                .get(param_name)
503            {
504                if !standard_names.contains(param_name) {
505                    let warning = ValidationWarning {
506                        message: format!(
507                            "Parameter '{}' doesn't follow naming convention. Consider: {:?}",
508                            param_name, standard_names
509                        ),
510                        category: CheckCategory::ParameterNaming,
511                        location: format!("Functions: {:?}", analysis.functions),
512                        suggestion: format!("Use one of the standard names: {:?}", standard_names),
513                    };
514
515                    self.results.warnings.push(warning);
516                }
517            }
518        }
519
520        details.push(format!(
521            "Analyzed {} unique parameter names",
522            parameter_analysis.len()
523        ));
524        details.push(format!(
525            "Found {} type inconsistencies",
526            inconsistencies_found
527        ));
528
529        check.details = details.join("; ");
530        check.status = if inconsistencies_found == 0 {
531            ValidationStatus::Passed
532        } else if self.config.strict_mode {
533            ValidationStatus::Failed
534        } else {
535            ValidationStatus::PassedWithWarnings
536        };
537
538        self.results.check_results.push(check);
539        Ok(())
540    }
541
542    /// Validate return type consistency
543    fn validate_return_type_consistency(&mut self) -> StatsResult<()> {
544        let mut check = ValidationCheck {
545            name: "Return Type Consistency".to_string(),
546            category: CheckCategory::ReturnTypes,
547            status: ValidationStatus::NotRun,
548            description: "Checking consistency of return types across similar functions"
549                .to_string(),
550            details: String::new(),
551            severity: Severity::Major,
552        };
553
554        let mut return_type_patterns = HashMap::new();
555        let mut inconsistencies_found = 0;
556
557        // Group functions by category and analyze return types
558        for (category, functions) in &self.function_registry.functions_by_category {
559            let mut category_return_types = HashSet::new();
560
561            for function in functions {
562                category_return_types.insert(function.return_type.type_name.clone());
563            }
564
565            return_type_patterns.insert(category.clone(), category_return_types);
566
567            // Check for excessive variation in return types within category
568            if functions.len() > 3 && return_type_patterns[category].len() > functions.len() / 2 {
569                let inconsistency = APIInconsistency {
570                    inconsistency_type: InconsistencyType::ReturnTypeInconsistency,
571                    affected_functions: functions.iter().map(|f| f.name.clone()).collect(),
572                    description: format!(
573                        "Functions in {:?} category have inconsistent return types: {:?}",
574                        category, return_type_patterns[category]
575                    ),
576                    suggested_fix: "Standardize return types within functional categories"
577                        .to_string(),
578                    severity: Severity::Major,
579                    impact: "Makes API harder to learn and use consistently".to_string(),
580                };
581
582                self.results.inconsistencies.push(inconsistency);
583                inconsistencies_found += 1;
584            }
585        }
586
587        // Check Result<T> usage consistency
588        let mut result_usage_patterns = HashMap::new();
589        for (module, functions) in &self.function_registry.functions_by_module {
590            let result_count = functions.iter().filter(|f| f.return_type.is_result).count();
591            let total_count = functions.len();
592
593            result_usage_patterns.insert(module.clone(), (result_count, total_count));
594        }
595
596        check.details = format!(
597            "Analyzed return types across {} categories, found {} inconsistencies",
598            return_type_patterns.len(),
599            inconsistencies_found
600        );
601
602        check.status = if inconsistencies_found == 0 {
603            ValidationStatus::Passed
604        } else {
605            ValidationStatus::Failed
606        };
607
608        self.results.check_results.push(check);
609        Ok(())
610    }
611
612    /// Validate error handling consistency
613    fn validate_error_handling_consistency(&mut self) -> StatsResult<()> {
614        let mut check = ValidationCheck {
615            name: "Error Handling Consistency".to_string(),
616            category: CheckCategory::ErrorHandling,
617            status: ValidationStatus::NotRun,
618            description: "Checking consistency of error handling patterns".to_string(),
619            details: String::new(),
620            severity: Severity::Critical,
621        };
622
623        let mut error_patterns = HashMap::new();
624        let mut inconsistencies_found = 0;
625
626        // Analyze error handling patterns
627        for (module, functions) in &self.function_registry.functions_by_module {
628            for function in functions {
629                // Check if function returns Result
630                if !function.return_type.is_result
631                    && function.category != FunctionCategory::Utilities
632                {
633                    let warning = ValidationWarning {
634                        message: format!(
635                            "Function '{}' in module '{}' doesn't return Result<T> but may fail",
636                            function.name, module
637                        ),
638                        category: CheckCategory::ErrorHandling,
639                        location: format!("{}::{}", module, function.name),
640                        suggestion: "Consider returning Result<T> for fallible operations"
641                            .to_string(),
642                    };
643
644                    self.results.warnings.push(warning);
645                }
646
647                // Collect error type patterns
648                for error_type in &function.error_types {
649                    error_patterns
650                        .entry(error_type.clone())
651                        .or_insert_with(Vec::new)
652                        .push(format!("{}::{}", module, function.name));
653                }
654            }
655        }
656
657        // Check for consistent error types
658        let expected_error_types = ["StatsError".to_string()];
659        for (error_type, functions) in &error_patterns {
660            if !expected_error_types.contains(error_type) {
661                let inconsistency = APIInconsistency {
662                    inconsistency_type: InconsistencyType::ErrorHandlingInconsistency,
663                    affected_functions: functions.clone(),
664                    description: format!(
665                        "Non-standard error type '{}' used in functions: {:?}",
666                        error_type, functions
667                    ),
668                    suggested_fix: "Use StatsError for consistent error handling".to_string(),
669                    severity: Severity::Major,
670                    impact: "Inconsistent error handling makes error recovery difficult"
671                        .to_string(),
672                };
673
674                self.results.inconsistencies.push(inconsistency);
675                inconsistencies_found += 1;
676            }
677        }
678
679        check.details = format!(
680            "Analyzed error handling in {} functions, found {} inconsistencies",
681            self.function_registry
682                .functions_by_module
683                .values()
684                .map(|funcs| funcs.len())
685                .sum::<usize>(),
686            inconsistencies_found
687        );
688
689        check.status = if inconsistencies_found == 0 {
690            ValidationStatus::Passed
691        } else {
692            ValidationStatus::Failed
693        };
694
695        self.results.check_results.push(check);
696        Ok(())
697    }
698
699    /// Validate documentation quality
700    fn validate_documentation_quality(&mut self) -> StatsResult<()> {
701        let mut check = ValidationCheck {
702            name: "Documentation Quality".to_string(),
703            category: CheckCategory::Documentation,
704            status: ValidationStatus::NotRun,
705            description: "Checking completeness and quality of documentation".to_string(),
706            details: String::new(),
707            severity: Severity::Minor,
708        };
709
710        let mut doc_stats = DocumentationStats::new();
711        let mut poorly_documented_functions = Vec::new();
712
713        for (module, functions) in &self.function_registry.functions_by_module {
714            for function in functions {
715                doc_stats.total_functions += 1;
716
717                match function.documentation_status {
718                    DocumentationStatus::Complete => doc_stats.complete_docs += 1,
719                    DocumentationStatus::Partial => doc_stats.partial_docs += 1,
720                    DocumentationStatus::Missing => {
721                        doc_stats.missing_docs += 1;
722                        poorly_documented_functions.push(format!("{}::{}", module, function.name));
723                    }
724                    DocumentationStatus::PoorQuality => {
725                        doc_stats.poor_quality_docs += 1;
726                        poorly_documented_functions.push(format!("{}::{}", module, function.name));
727                    }
728                }
729            }
730        }
731
732        // Check documentation completeness
733        let completion_rate = doc_stats.complete_docs as f64 / doc_stats.total_functions as f64;
734
735        if completion_rate < 0.8 {
736            let inconsistency = APIInconsistency {
737                inconsistency_type: InconsistencyType::DocumentationInconsistency,
738                affected_functions: poorly_documented_functions,
739                description: format!(
740                    "Documentation completion rate is {:.1}%, below 80% threshold",
741                    completion_rate * 100.0
742                ),
743                suggested_fix: "Add comprehensive documentation to all public functions"
744                    .to_string(),
745                severity: Severity::Minor,
746                impact: "Poor documentation reduces library usability and adoption".to_string(),
747            };
748
749            self.results.inconsistencies.push(inconsistency);
750        }
751
752        check.details = format!(
753            "Documentation completion: {:.1}% ({}/{} functions documented)",
754            completion_rate * 100.0,
755            doc_stats.complete_docs,
756            doc_stats.total_functions
757        );
758
759        check.status = if completion_rate >= 0.8 {
760            ValidationStatus::Passed
761        } else {
762            ValidationStatus::PassedWithWarnings
763        };
764
765        self.results.check_results.push(check);
766        Ok(())
767    }
768
769    /// Validate performance characteristics
770    fn validate_performance_characteristics(&mut self) -> StatsResult<()> {
771        let mut check = ValidationCheck {
772            name: "Performance Characteristics".to_string(),
773            category: CheckCategory::Performance,
774            status: ValidationStatus::NotRun,
775            description: "Checking consistency of performance characteristics".to_string(),
776            details: String::new(),
777            severity: Severity::Minor,
778        };
779
780        // This would involve benchmarking similar functions and comparing performance
781        // For now, we'll do a basic check of function complexity patterns
782
783        let mut performance_issues = Vec::new();
784
785        // Check for functions that should have SIMD variants
786        for (module, functions) in &self.function_registry.functions_by_module {
787            for function in functions {
788                if function.category == FunctionCategory::DescriptiveStats
789                    && !function.name.contains("simd")
790                    && !function.name.contains("parallel")
791                {
792                    // Check if SIMD variant exists
793                    let simd_variant_name = format!("{}_simd", function.name);
794                    let has_simd_variant = functions.iter().any(|f| f.name == simd_variant_name);
795
796                    if !has_simd_variant {
797                        performance_issues.push(format!("{}::{}", module, function.name));
798                    }
799                }
800            }
801        }
802
803        if !performance_issues.is_empty() {
804            let warning = ValidationWarning {
805                message: format!(
806                    "{} functions might benefit from SIMD optimization",
807                    performance_issues.len()
808                ),
809                category: CheckCategory::Performance,
810                location: "Various modules".to_string(),
811                suggestion:
812                    "Consider implementing SIMD variants for performance-critical functions"
813                        .to_string(),
814            };
815
816            self.results.warnings.push(warning);
817        }
818
819        check.details = format!(
820            "Analyzed performance patterns, identified {} optimization opportunities",
821            performance_issues.len()
822        );
823
824        check.status = ValidationStatus::Passed; // Performance issues are warnings, not failures
825
826        self.results.check_results.push(check);
827        Ok(())
828    }
829
830    /// Validate SciPy compatibility
831    fn validate_scipy_compatibility(&mut self) -> StatsResult<()> {
832        let mut check = ValidationCheck {
833            name: "SciPy Compatibility".to_string(),
834            category: CheckCategory::ScipyCompatibility,
835            status: ValidationStatus::NotRun,
836            description: "Checking compatibility with SciPy API patterns".to_string(),
837            details: String::new(),
838            severity: Severity::Major,
839        };
840
841        // Define expected SciPy-compatible function signatures
842        let scipy_functions = self.get_expected_scipy_functions();
843        let mut compatibility_issues = Vec::new();
844
845        for (scipy_name, expected_sig) in &scipy_functions {
846            // Check if we have this function
847            let mut found = false;
848            for functions in self.function_registry.functions_by_module.values() {
849                for function in functions {
850                    if function.name == *scipy_name {
851                        found = true;
852
853                        // Check parameter compatibility
854                        if !self.check_parameter_compatibility(
855                            &function.parameters,
856                            &expected_sig.parameters,
857                        ) {
858                            compatibility_issues.push(format!(
859                                "Function '{}' has incompatible parameters with SciPy",
860                                scipy_name
861                            ));
862                        }
863                        break;
864                    }
865                }
866                if found {
867                    break;
868                }
869            }
870
871            if !found {
872                compatibility_issues.push(format!(
873                    "Missing SciPy-compatible function: '{}'",
874                    scipy_name
875                ));
876            }
877        }
878
879        if !compatibility_issues.is_empty() {
880            let inconsistency = APIInconsistency {
881                inconsistency_type: InconsistencyType::ScipyCompatibilityIssue,
882                affected_functions: compatibility_issues.clone(),
883                description: format!(
884                    "Found {} SciPy compatibility issues",
885                    compatibility_issues.len()
886                ),
887                suggested_fix:
888                    "Implement missing functions or adjust parameters for SciPy compatibility"
889                        .to_string(),
890                severity: Severity::Major,
891                impact: "Reduces ease of migration from SciPy".to_string(),
892            };
893
894            self.results.inconsistencies.push(inconsistency);
895        }
896
897        check.details = format!(
898            "Checked {} SciPy functions, found {} compatibility issues",
899            scipy_functions.len(),
900            compatibility_issues.len()
901        );
902
903        check.status = if compatibility_issues.is_empty() {
904            ValidationStatus::Passed
905        } else {
906            ValidationStatus::Failed
907        };
908
909        self.results.check_results.push(check);
910        Ok(())
911    }
912
913    /// Get expected SciPy-compatible function signatures
914    fn get_expected_scipy_functions(&self) -> HashMap<String, FunctionSignature> {
915        let mut functions = HashMap::new();
916
917        // Add some key SciPy functions for compatibility checking
918        functions.insert(
919            "mean".to_string(),
920            FunctionSignature {
921                name: "mean".to_string(),
922                module: "stats".to_string(),
923                category: FunctionCategory::DescriptiveStats,
924                parameters: vec![ParameterInfo {
925                    name: "data".to_string(),
926                    param_type: "ArrayView1<F>".to_string(),
927                    optional: false,
928                    default_value: None,
929                    description: "Input data".to_string(),
930                }],
931                return_type: ReturnTypeInfo {
932                    type_name: "StatsResult<F>".to_string(),
933                    is_result: true,
934                    generic_params: vec!["F".to_string()],
935                    description: "Mean value".to_string(),
936                },
937                error_types: vec!["StatsError".to_string()],
938                documentation_status: DocumentationStatus::Complete,
939            },
940        );
941
942        functions.insert(
943            "std".to_string(),
944            FunctionSignature {
945                name: "std".to_string(),
946                module: "stats".to_string(),
947                category: FunctionCategory::DescriptiveStats,
948                parameters: vec![
949                    ParameterInfo {
950                        name: "data".to_string(),
951                        param_type: "ArrayView1<F>".to_string(),
952                        optional: false,
953                        default_value: None,
954                        description: "Input data".to_string(),
955                    },
956                    ParameterInfo {
957                        name: "ddof".to_string(),
958                        param_type: "usize".to_string(),
959                        optional: true,
960                        default_value: Some("0".to_string()),
961                        description: "Delta degrees of freedom".to_string(),
962                    },
963                ],
964                return_type: ReturnTypeInfo {
965                    type_name: "StatsResult<F>".to_string(),
966                    is_result: true,
967                    generic_params: vec!["F".to_string()],
968                    description: "Standard deviation".to_string(),
969                },
970                error_types: vec!["StatsError".to_string()],
971                documentation_status: DocumentationStatus::Complete,
972            },
973        );
974
975        // Add more SciPy functions as needed...
976
977        functions
978    }
979
980    /// Check parameter compatibility between actual and expected signatures
981    fn check_parameter_compatibility(
982        &self,
983        actual: &[ParameterInfo],
984        expected: &[ParameterInfo],
985    ) -> bool {
986        if actual.len() != expected.len() {
987            return false;
988        }
989
990        for (actual_param, expected_param) in actual.iter().zip(expected.iter()) {
991            if actual_param.name != expected_param.name {
992                return false;
993            }
994
995            // Basic type compatibility check (simplified)
996            if actual_param.param_type != expected_param.param_type {
997                return false;
998            }
999        }
1000
1001        true
1002    }
1003
1004    /// Compute validation summary
1005    fn compute_validation_summary(&mut self) {
1006        let total_checks = self.results.check_results.len();
1007        let passed_checks = self
1008            .results
1009            .check_results
1010            .iter()
1011            .filter(|c| c.status == ValidationStatus::Passed)
1012            .count();
1013        let failed_checks = self
1014            .results
1015            .check_results
1016            .iter()
1017            .filter(|c| c.status == ValidationStatus::Failed)
1018            .count();
1019        let warning_count = self.results.warnings.len();
1020        let critical_issues = self
1021            .results
1022            .inconsistencies
1023            .iter()
1024            .filter(|i| i.severity == Severity::Critical)
1025            .count();
1026
1027        // Calculate consistency score
1028        let consistency_score = if total_checks > 0 {
1029            let base_score = (passed_checks as f64 / total_checks as f64) * 100.0;
1030            let warning_penalty = (warning_count as f64 * 2.0).min(20.0);
1031            let critical_penalty = (critical_issues as f64 * 10.0).min(50.0);
1032
1033            (base_score - warning_penalty - critical_penalty).max(0.0)
1034        } else {
1035            0.0
1036        };
1037
1038        self.results.summary = ValidationSummary {
1039            total_checks,
1040            passed_checks,
1041            failed_checks,
1042            warning_count,
1043            critical_issues,
1044            consistency_score,
1045        };
1046    }
1047
1048    /// Determine overall validation status
1049    fn determine_overall_status(&self) -> ValidationStatus {
1050        let critical_issues = self
1051            .results
1052            .inconsistencies
1053            .iter()
1054            .any(|i| i.severity == Severity::Critical);
1055
1056        let failed_checks = self
1057            .results
1058            .check_results
1059            .iter()
1060            .any(|c| c.status == ValidationStatus::Failed);
1061
1062        if critical_issues || (failed_checks && self.config.strict_mode) {
1063            ValidationStatus::Failed
1064        } else if !self.results.warnings.is_empty() || failed_checks {
1065            ValidationStatus::PassedWithWarnings
1066        } else {
1067            ValidationStatus::Passed
1068        }
1069    }
1070
1071    /// Register a function for validation
1072    pub fn register_function(&mut self, functionsig: FunctionSignature) {
1073        // Add to module registry
1074        self.function_registry
1075            .functions_by_module
1076            .entry(functionsig.module.clone())
1077            .or_default()
1078            .push(functionsig.clone());
1079
1080        // Add to category registry
1081        self.function_registry
1082            .functions_by_category
1083            .entry(functionsig.category.clone())
1084            .or_default()
1085            .push(functionsig.clone());
1086
1087        // Update parameter usage statistics
1088        for param in &functionsig.parameters {
1089            let usage = self
1090                .function_registry
1091                .parameter_usage
1092                .entry(param.name.clone())
1093                .or_insert_with(|| ParameterUsage {
1094                    name: param.name.clone(),
1095                    usage_count: 0,
1096                    type_signatures: HashSet::new(),
1097                    modules: HashSet::new(),
1098                    alternative_names: Vec::new(),
1099                });
1100
1101            usage.usage_count += 1;
1102            usage.type_signatures.insert(param.param_type.clone());
1103            usage.modules.insert(functionsig.module.clone());
1104        }
1105    }
1106
1107    /// Generate validation report
1108    pub fn generate_report(&self) -> ValidationReport {
1109        ValidationReport::new(&self.results)
1110    }
1111}
1112
1113impl ValidationResults {
1114    fn new() -> Self {
1115        Self {
1116            overall_status: ValidationStatus::NotRun,
1117            check_results: Vec::new(),
1118            inconsistencies: Vec::new(),
1119            warnings: Vec::new(),
1120            summary: ValidationSummary {
1121                total_checks: 0,
1122                passed_checks: 0,
1123                failed_checks: 0,
1124                warning_count: 0,
1125                critical_issues: 0,
1126                consistency_score: 0.0,
1127            },
1128        }
1129    }
1130}
1131
1132impl FunctionRegistry {
1133    fn new() -> Self {
1134        Self {
1135            functions_by_module: HashMap::new(),
1136            functions_by_category: HashMap::new(),
1137            parameter_usage: HashMap::new(),
1138        }
1139    }
1140}
1141
1142/// Parameter usage analysis helper
1143#[derive(Debug)]
1144struct ParameterUsageAnalysis {
1145    functions: Vec<String>,
1146    modules: HashSet<String>,
1147    type_variations: HashSet<String>,
1148}
1149
1150impl ParameterUsageAnalysis {
1151    fn new() -> Self {
1152        Self {
1153            functions: Vec::new(),
1154            modules: HashSet::new(),
1155            type_variations: HashSet::new(),
1156        }
1157    }
1158
1159    fn add_usage(&mut self, module: String, function: String, paramtype: String) {
1160        self.functions.push(format!("{}::{}", module, function));
1161        self.modules.insert(module);
1162        self.type_variations.insert(paramtype);
1163    }
1164}
1165
1166/// Documentation statistics helper
1167#[derive(Debug)]
1168struct DocumentationStats {
1169    total_functions: usize,
1170    complete_docs: usize,
1171    partial_docs: usize,
1172    missing_docs: usize,
1173    poor_quality_docs: usize,
1174}
1175
1176impl DocumentationStats {
1177    fn new() -> Self {
1178        Self {
1179            total_functions: 0,
1180            complete_docs: 0,
1181            partial_docs: 0,
1182            missing_docs: 0,
1183            poor_quality_docs: 0,
1184        }
1185    }
1186}
1187
1188/// Validation report generator
1189pub struct ValidationReport {
1190    results: ValidationResults,
1191}
1192
1193impl ValidationReport {
1194    pub fn new(results: &ValidationResults) -> Self {
1195        Self {
1196            results: results.clone(),
1197        }
1198    }
1199
1200    /// Generate markdown report
1201    pub fn to_markdown(&self) -> String {
1202        let mut report = String::new();
1203
1204        report.push_str("# API Consistency Validation Report\n\n");
1205
1206        // Overall status
1207        report.push_str(&format!(
1208            "**Overall Status:** {:?}\n",
1209            self.results.overall_status
1210        ));
1211        report.push_str(&format!(
1212            "**Consistency Score:** {:.1}%\n\n",
1213            self.results.summary.consistency_score
1214        ));
1215
1216        // Summary
1217        report.push_str("## Summary\n\n");
1218        report.push_str(&format!(
1219            "- **Total Checks:** {}\n",
1220            self.results.summary.total_checks
1221        ));
1222        report.push_str(&format!(
1223            "- **Passed:** {}\n",
1224            self.results.summary.passed_checks
1225        ));
1226        report.push_str(&format!(
1227            "- **Failed:** {}\n",
1228            self.results.summary.failed_checks
1229        ));
1230        report.push_str(&format!(
1231            "- **Warnings:** {}\n",
1232            self.results.summary.warning_count
1233        ));
1234        report.push_str(&format!(
1235            "- **Critical Issues:** {}\n\n",
1236            self.results.summary.critical_issues
1237        ));
1238
1239        // Individual checks
1240        report.push_str("## Check Results\n\n");
1241        for check in &self.results.check_results {
1242            report.push_str(&format!("### {}\n", check.name));
1243            report.push_str(&format!("**Status:** {:?}\n", check.status));
1244            report.push_str(&format!("**Category:** {:?}\n", check.category));
1245            report.push_str(&format!("**Description:** {}\n", check.description));
1246            report.push_str(&format!("**Details:** {}\n\n", check.details));
1247        }
1248
1249        // Inconsistencies
1250        if !self.results.inconsistencies.is_empty() {
1251            report.push_str("## Inconsistencies Found\n\n");
1252            for (i, inconsistency) in self.results.inconsistencies.iter().enumerate() {
1253                report.push_str(&format!("### Issue {}\n", i + 1));
1254                report.push_str(&format!(
1255                    "**Type:** {:?}\n",
1256                    inconsistency.inconsistency_type
1257                ));
1258                report.push_str(&format!("**Severity:** {:?}\n", inconsistency.severity));
1259                report.push_str(&format!("**Description:** {}\n", inconsistency.description));
1260                report.push_str(&format!(
1261                    "**Suggested Fix:** {}\n",
1262                    inconsistency.suggested_fix
1263                ));
1264                report.push_str(&format!("**Impact:** {}\n\n", inconsistency.impact));
1265            }
1266        }
1267
1268        // Warnings
1269        if !self.results.warnings.is_empty() {
1270            report.push_str("## Warnings\n\n");
1271            for warning in &self.results.warnings {
1272                report.push_str(&format!(
1273                    "- **{}:** {} ({})\n",
1274                    warning.location, warning.message, warning.suggestion
1275                ));
1276            }
1277        }
1278
1279        report
1280    }
1281
1282    /// Generate JSON report
1283    pub fn to_json(&self) -> serde_json::Result<String> {
1284        serde_json::to_string_pretty(&self.results)
1285    }
1286}
1287
1288/// Convenience function to validate API consistency
1289#[allow(dead_code)]
1290pub fn validate_api_consistency(
1291    config: Option<ValidationConfig>,
1292) -> StatsResult<ValidationResults> {
1293    let config = config.unwrap_or_default();
1294    let mut validator = APIConsistencyValidator::new(config);
1295
1296    // In a real implementation, this would automatically discover and register
1297    // all functions in the library. For now, we'll return basic results.
1298
1299    validator.validate_all()?;
1300    Ok(validator.results)
1301}
1302
1303#[cfg(test)]
1304mod tests {
1305    use super::*;
1306
1307    #[test]
1308    fn test_validation_config_default() {
1309        let config = ValidationConfig::default();
1310        assert!(config.validate_parameter_names);
1311        assert!(config.validate_return_types);
1312        assert!(config.validate_error_handling);
1313        assert!(!config.strict_mode);
1314    }
1315
1316    #[test]
1317    fn test_function_registry() {
1318        let registry = FunctionRegistry::new();
1319
1320        let functionsig = FunctionSignature {
1321            name: "mean".to_string(),
1322            module: "descriptive".to_string(),
1323            category: FunctionCategory::DescriptiveStats,
1324            parameters: vec![ParameterInfo {
1325                name: "data".to_string(),
1326                param_type: "ArrayView1<f64>".to_string(),
1327                optional: false,
1328                default_value: None,
1329                description: "Input data".to_string(),
1330            }],
1331            return_type: ReturnTypeInfo {
1332                type_name: "StatsResult<f64>".to_string(),
1333                is_result: true,
1334                generic_params: vec!["f64".to_string()],
1335                description: "Mean value".to_string(),
1336            },
1337            error_types: vec!["StatsError".to_string()],
1338            documentation_status: DocumentationStatus::Complete,
1339        };
1340
1341        let mut validator = APIConsistencyValidator::new(ValidationConfig::default());
1342        validator.register_function(functionsig);
1343
1344        assert_eq!(validator.function_registry.functions_by_module.len(), 1);
1345        assert_eq!(validator.function_registry.functions_by_category.len(), 1);
1346    }
1347
1348    #[test]
1349    fn test_validation_report() {
1350        let results = ValidationResults::new();
1351        let report = ValidationReport::new(&results);
1352        let markdown = report.to_markdown();
1353
1354        assert!(markdown.contains("API Consistency Validation Report"));
1355        assert!(markdown.contains("Overall Status"));
1356    }
1357}