scirs2_core/
apiversioning.rs

1//! API versioning system for backward compatibility
2//!
3//! This module provides version management for scirs2-core APIs,
4//! ensuring smooth transitions between versions and maintaining
5//! backward compatibility.
6
7use std::fmt;
8use std::sync::{Mutex, OnceLock};
9
10/// Represents a semantic version number
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct Version {
13    /// Major version (breaking changes)
14    pub major: u32,
15    /// Minor version (new features, backward compatible)
16    pub minor: u32,
17    /// Patch version (bug fixes)
18    pub patch: u32,
19}
20
21impl Version {
22    /// Create a new version
23    pub const fn new(major: u32, minor: u32, patch: u32) -> Self {
24        Self {
25            major,
26            minor,
27            patch,
28        }
29    }
30
31    /// Parse a version string like "1.2.3" or "1.2.3-beta.1"
32    pub fn parse(versionstr: &str) -> Result<Self, String> {
33        // Split on '-' to handle version suffixes like "-beta.1"
34        let base_version = versionstr.split('-').next().unwrap_or(versionstr);
35
36        // Split the base version on '.'
37        let parts: Vec<&str> = base_version.split('.').collect();
38
39        if parts.len() < 3 {
40            return Err(format!("Invalid version format: {versionstr}"));
41        }
42
43        let major = parts[0].parse::<u32>().map_err(|_| parts[0].to_string())?;
44        let minor = parts[1].parse::<u32>().map_err(|_| parts[1].to_string())?;
45        let patch = parts[2].parse::<u32>().map_err(|_| parts[2].to_string())?;
46
47        Ok(Self::new(major, minor, patch))
48    }
49
50    /// Current version of scirs2-core (Beta 1)
51    pub const CURRENT: Self = Self::new(0, 1, 0);
52
53    /// Current beta release identifier
54    pub const CURRENT_BETA: &'static str = "0.1.0-beta.4";
55
56    /// Check if this version is compatible with another
57    pub fn is_compatible_with(&self, other: &Version) -> bool {
58        // Same major version and greater or equal minor/patch
59        self.major == other.major
60            && (self.minor > other.minor
61                || (self.minor == other.minor && self.patch >= other.patch))
62    }
63}
64
65impl fmt::Display for Version {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        write!(f, "{}.{}.{}", self.major, self.minor, self.patch)
68    }
69}
70
71/// Trait for versioned APIs
72pub trait Versioned {
73    /// Get the version this API was introduced in
74    fn since_version() -> Version;
75
76    /// Get the version this API was deprecated in (if any)
77    fn deprecated_version() -> Option<Version> {
78        None
79    }
80
81    /// Check if this API is available in a given version
82    fn is_available_in(version: &Version) -> bool {
83        version.is_compatible_with(&Self::since_version())
84            && Self::deprecated_version()
85                .map(|dep| version < &dep)
86                .unwrap_or(true)
87    }
88}
89
90/// Macro to mark APIs with version information
91#[macro_export]
92macro_rules! since_version {
93    ($major:expr, $minor:expr, $patch:expr) => {
94        fn since_version() -> $crate::apiversioning::Version {
95            $crate::apiversioning::Version::new($major, $minor, $patch)
96        }
97    };
98}
99
100/// Macro to mark deprecated APIs
101#[macro_export]
102macro_rules! deprecated_in {
103    ($major:expr, $minor:expr, $patch:expr) => {
104        fn deprecated_version() -> Option<$crate::apiversioning::Version> {
105            Some($crate::apiversioning::Version::new($major, $minor, $patch))
106        }
107    };
108}
109
110/// Version registry for tracking API changes
111pub struct VersionRegistry {
112    entries: Vec<ApiEntry>,
113}
114
115#[derive(Debug, Clone)]
116pub struct ApiEntry {
117    pub name: String,
118    pub module: String,
119    pub since: Version,
120    pub deprecated: Option<Version>,
121    pub replacement: Option<String>,
122    pub breakingchanges: Vec<BreakingChange>,
123    pub example_usage: Option<String>,
124    pub migration_example: Option<String>,
125}
126
127#[derive(Debug, Clone)]
128pub struct BreakingChange {
129    pub version: Version,
130    pub description: String,
131    pub impact: BreakingChangeImpact,
132    pub mitigation: String,
133}
134
135#[derive(Debug, Clone, PartialEq, Eq)]
136pub enum BreakingChangeImpact {
137    Low,      // Minor API signature changes
138    Medium,   // Functionality changes
139    High,     // Major restructuring
140    Critical, // Complete removal
141}
142
143impl VersionRegistry {
144    /// Create a new version registry
145    pub fn new() -> Self {
146        Self {
147            entries: Vec::new(),
148        }
149    }
150
151    /// Register a new API
152    pub fn register_api(
153        &mut self,
154        name: impl Into<String>,
155        module: impl Into<String>,
156        since: Version,
157    ) -> &mut Self {
158        let name_str = name.into();
159        let module_str = module.into();
160
161        // Check if the API is already registered
162        if !self
163            .entries
164            .iter()
165            .any(|e| e.name == name_str && e.module == module_str)
166        {
167            self.entries.push(ApiEntry {
168                name: name_str,
169                module: module_str,
170                since,
171                deprecated: None,
172                replacement: None,
173                breakingchanges: Vec::new(),
174                example_usage: None,
175                migration_example: None,
176            });
177        }
178        self
179    }
180
181    /// Register an API with usage example
182    pub fn register_api_with_example(
183        &mut self,
184        name: impl Into<String>,
185        module: impl Into<String>,
186        since: Version,
187        example: impl Into<String>,
188    ) -> &mut Self {
189        let name_str = name.into();
190        let module_str = module.into();
191
192        if !self
193            .entries
194            .iter()
195            .any(|e| e.name == name_str && e.module == module_str)
196        {
197            self.entries.push(ApiEntry {
198                name: name_str,
199                module: module_str,
200                since,
201                deprecated: None,
202                replacement: None,
203                breakingchanges: Vec::new(),
204                example_usage: Some(example.into()),
205                migration_example: None,
206            });
207        }
208        self
209    }
210
211    /// Mark an API as deprecated
212    pub fn deprecate_api(
213        &mut self,
214        name: &str,
215        version: Version,
216        replacement: Option<String>,
217    ) -> Result<(), String> {
218        if let Some(entry) = self.entries.iter_mut().find(|e| e.name == name) {
219            entry.deprecated = Some(version);
220            entry.replacement = replacement;
221            Ok(())
222        } else {
223            Err(format!("API '{name}' not found in registry"))
224        }
225    }
226
227    /// Mark an API as deprecated with migration example
228    pub fn deprecate_api_with_example(
229        &mut self,
230        name: &str,
231        version: Version,
232        replacement: Option<String>,
233        migration_example: impl Into<String>,
234    ) -> Result<(), String> {
235        if let Some(entry) = self.entries.iter_mut().find(|e| e.name == name) {
236            entry.deprecated = Some(version);
237            entry.replacement = replacement;
238            entry.migration_example = Some(migration_example.into());
239            Ok(())
240        } else {
241            Err(format!("API '{name}' not found in registry"))
242        }
243    }
244
245    /// Add a breaking change to an API
246    pub fn add_breaking_change(
247        &mut self,
248        apiname: &str,
249        change: BreakingChange,
250    ) -> Result<(), String> {
251        if let Some(entry) = self.entries.iter_mut().find(|e| e.name == apiname) {
252            entry.breakingchanges.push(change);
253            Ok(())
254        } else {
255            Err(format!("API '{apiname}' not found in registry"))
256        }
257    }
258
259    /// Get all APIs available in a specific version
260    pub fn apis_in_version(&self, version: &Version) -> Vec<&ApiEntry> {
261        self.entries
262            .iter()
263            .filter(|entry| {
264                version.is_compatible_with(&entry.since)
265                    && entry.deprecated.map(|dep| version < &dep).unwrap_or(true)
266            })
267            .collect()
268    }
269
270    /// Get all deprecated APIs in a version
271    pub fn deprecated_apis_in_version(&self, version: &Version) -> Vec<&ApiEntry> {
272        self.entries
273            .iter()
274            .filter(|entry| entry.deprecated.map(|dep| version >= &dep).unwrap_or(false))
275            .collect()
276    }
277
278    /// Generate migration guide between versions
279    pub fn migration_guide(&self, from: &Version, to: &Version) -> String {
280        let mut guide = format!("# Migration Guide: {from} → {to}\n\n");
281
282        guide.push_str(&format!(
283            "This guide helps you upgrade from scirs2-core {from} to {to}.\n\n"
284        ));
285
286        // Breaking changes analysis
287        let breakingchanges: Vec<_> = self
288            .entries
289            .iter()
290            .filter_map(|e| {
291                if !e.breakingchanges.is_empty() {
292                    let relevant_changes: Vec<_> = e
293                        .breakingchanges
294                        .iter()
295                        .filter(|bc| bc.version > *from && bc.version <= *to)
296                        .collect();
297                    if !relevant_changes.is_empty() {
298                        Some((e, relevant_changes))
299                    } else {
300                        None
301                    }
302                } else {
303                    None
304                }
305            })
306            .collect();
307
308        if !breakingchanges.is_empty() {
309            guide.push_str("## âš ī¸ Breaking Changes\n\n");
310
311            for (api, changes) in breakingchanges {
312                guide.push_str(&format!(
313                    "### {name} ({module})\n\n",
314                    name = api.name,
315                    module = api.module
316                ));
317
318                for change in changes {
319                    let impact_icon = match change.impact {
320                        BreakingChangeImpact::Low => "🟡",
321                        BreakingChangeImpact::Medium => "🟠",
322                        BreakingChangeImpact::High => "🔴",
323                        BreakingChangeImpact::Critical => "đŸ’Ĩ",
324                    };
325
326                    guide.push_str(&format!(
327                        "{} **{}**: {}\n\n**Mitigation**: {}\n\n",
328                        impact_icon, change.version, change.description, change.mitigation
329                    ));
330                }
331            }
332        }
333
334        // Find removed APIs
335        let removed: Vec<_> = self
336            .entries
337            .iter()
338            .filter(|e| {
339                from.is_compatible_with(&e.since)
340                    && e.deprecated.map(|d| to >= &d && from < &d).unwrap_or(false)
341            })
342            .collect();
343
344        if !removed.is_empty() {
345            guide.push_str("## đŸ—‘ī¸ Removed APIs\n\n");
346
347            for api in removed {
348                guide.push_str(&format!(
349                    "### {name} ({module})\n\n",
350                    name = api.name,
351                    module = api.module
352                ));
353
354                if let Some(ref replacement) = api.replacement {
355                    guide.push_str(&format!("**Replacement**: {replacement}\n\n"));
356                }
357
358                if let Some(ref migration_example) = api.migration_example {
359                    guide.push_str("**Migration Example**:\n\n");
360                    guide.push_str("```rust\n");
361                    guide.push_str(migration_example);
362                    guide.push_str("\n```\n\n");
363                }
364            }
365        }
366
367        // Find new APIs
368        let new_apis: Vec<_> = self
369            .entries
370            .iter()
371            .filter(|e| to.is_compatible_with(&e.since) && !from.is_compatible_with(&e.since))
372            .collect();
373
374        if !new_apis.is_empty() {
375            guide.push_str("## ✨ New APIs\n\n");
376
377            for api in new_apis {
378                guide.push_str(&format!(
379                    "### {} ({}) - Since {}\n\n",
380                    api.name, api.module, api.since
381                ));
382
383                if let Some(ref example) = api.example_usage {
384                    guide.push_str("**Usage Example**:\n\n");
385                    guide.push_str("```rust\n");
386                    guide.push_str(example);
387                    guide.push_str("\n```\n\n");
388                }
389            }
390        }
391
392        // Migration checklist
393        guide.push_str("## 📋 Migration Checklist\n\n");
394        guide.push_str("- [ ] Update Cargo.toml dependencies\n");
395        guide.push_str("- [ ] Fix compilation errors\n");
396        guide.push_str("- [ ] Update deprecated API usage\n");
397        guide.push_str("- [ ] Run test suite\n");
398        guide.push_str("- [ ] Update documentation\n");
399        guide.push_str("- [ ] Performance testing\n\n");
400
401        guide.push_str("## 📚 Additional Resources\n\n");
402        guide.push_str(&format!(
403            "- [API Documentation](https://docs.rs/scirs2-core/{to})\n"
404        ));
405        guide.push_str(
406            "- [Changelog](https://github.com/cool-japan/scirs/blob/main/CHANGELOG.md)\n",
407        );
408        guide.push_str("- [Examples](https://github.com/cool-japan/scirs/tree/main/examples)\n");
409
410        guide
411    }
412
413    /// Generate a deprecation timeline
414    pub fn deprecation_timeline(&self) -> String {
415        let mut timeline = String::from("# API Deprecation Timeline\n\n");
416
417        let mut deprecated_apis: Vec<_> = self
418            .entries
419            .iter()
420            .filter(|e| e.deprecated.is_some())
421            .collect();
422
423        deprecated_apis.sort_by_key(|e| e.deprecated.unwrap());
424
425        let mut current_version: Option<Version> = None;
426
427        for api in deprecated_apis {
428            let dep_version = api.deprecated.unwrap();
429
430            if current_version != Some(dep_version) {
431                timeline.push_str(&format!("\n## Version {dep_version}\n\n"));
432                current_version = Some(dep_version);
433            }
434
435            timeline.push_str(&format!(
436                "- **{name}** ({module})",
437                name = api.name,
438                module = api.module
439            ));
440
441            if let Some(ref replacement) = api.replacement {
442                timeline.push_str(&format!(" → {replacement}"));
443            }
444
445            timeline.push('\n');
446        }
447
448        timeline
449    }
450}
451
452impl Default for VersionRegistry {
453    fn default() -> Self {
454        Self::new()
455    }
456}
457
458/// API Freeze status for Beta 1 release
459#[derive(Debug, Clone, PartialEq, Eq)]
460pub enum ApiFreezeStatus {
461    /// APIs are still changing (Alpha phase)
462    Unfrozen,
463    /// APIs are frozen for this version (Beta phase)
464    Frozen,
465    /// APIs are stable (Release phase)
466    Stable,
467}
468
469/// Comprehensive API compatibility checker
470#[derive(Debug, Clone)]
471pub struct ApiCompatibilityChecker {
472    /// Current freeze status
473    freeze_status: ApiFreezeStatus,
474    /// Frozen API surface for comparison
475    frozen_apis: Vec<ApiSignature>,
476    /// Compatibility rules
477    #[allow(dead_code)]
478    compatibility_rules: Vec<CompatibilityRule>,
479}
480
481/// API signature for detailed compatibility checking
482#[derive(Debug, Clone, PartialEq, Eq, Hash)]
483pub struct ApiSignature {
484    pub name: String,
485    pub module: String,
486    pub signature_hash: u64,
487    pub parameters: Vec<Parameter>,
488    pub return_type: Option<String>,
489    pub visibility: Visibility,
490    pub stability: StabilityLevel,
491}
492
493/// Parameter definition for API signatures
494#[derive(Debug, Clone, PartialEq, Eq, Hash)]
495pub struct Parameter {
496    pub name: String,
497    pub type_name: String,
498    pub is_optional: bool,
499    pub defaultvalue: Option<String>,
500}
501
502/// API visibility levels
503#[derive(Debug, Clone, PartialEq, Eq, Hash)]
504pub enum Visibility {
505    Public,
506    PublicCrate,
507    Private,
508}
509
510/// API stability levels
511#[derive(Debug, Clone, PartialEq, Eq, Hash)]
512pub enum StabilityLevel {
513    Stable,
514    Unstable,
515    Deprecated,
516    Experimental,
517}
518
519/// Compatibility rules for API changes
520#[derive(Debug, Clone)]
521pub struct CompatibilityRule {
522    pub rule_type: CompatibilityRuleType,
523    pub description: String,
524    pub severity: CompatibilitySeverity,
525    pub auto_fix: Option<String>,
526}
527
528/// Types of compatibility rules
529#[derive(Debug, Clone, PartialEq, Eq)]
530pub enum CompatibilityRuleType {
531    /// Function signature cannot change
532    SignatureChange,
533    /// Public APIs cannot be removed
534    PublicApiRemoval,
535    /// Parameter types cannot change
536    ParameterTypeChange,
537    /// Return types cannot change
538    ReturnTypeChange,
539    /// New required parameters cannot be added
540    NewRequiredParameter,
541    /// Visibility cannot be reduced
542    VisibilityReduction,
543}
544
545/// Severity of compatibility violations
546#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
547pub enum CompatibilitySeverity {
548    /// Will cause compilation failure
549    Breaking,
550    /// May cause runtime issues
551    Warning,
552    /// Informational only
553    Info,
554}
555
556/// Compatibility check result
557#[derive(Debug, Clone)]
558pub struct CompatibilityCheckResult {
559    pub is_compatible: bool,
560    pub violations: Vec<CompatibilityViolation>,
561    pub warnings: Vec<CompatibilityWarning>,
562    pub suggestions: Vec<CompatibilitySuggestion>,
563}
564
565/// Compatibility violation details
566#[derive(Debug, Clone)]
567pub struct CompatibilityViolation {
568    pub apiname: String,
569    pub violation_type: CompatibilityRuleType,
570    pub severity: CompatibilitySeverity,
571    pub description: String,
572    pub old_signature: Option<ApiSignature>,
573    pub new_signature: Option<ApiSignature>,
574    pub fix_suggestion: Option<String>,
575}
576
577/// Compatibility warning
578#[derive(Debug, Clone)]
579pub struct CompatibilityWarning {
580    pub apiname: String,
581    pub message: String,
582    pub impact: String,
583}
584
585/// Compatibility suggestion
586#[derive(Debug, Clone)]
587pub struct CompatibilitySuggestion {
588    pub apiname: String,
589    pub suggestion: String,
590    pub rationale: String,
591}
592
593impl ApiCompatibilityChecker {
594    /// Create a new compatibility checker
595    pub fn new() -> Self {
596        Self {
597            freeze_status: ApiFreezeStatus::Unfrozen,
598            frozen_apis: Vec::new(),
599            compatibility_rules: Self::default_compatibility_rules(),
600        }
601    }
602
603    /// Create checker for Beta 1 (frozen APIs)
604    pub fn for_beta1() -> Self {
605        Self {
606            freeze_status: ApiFreezeStatus::Frozen,
607            frozen_apis: Vec::new(),
608            compatibility_rules: Self::beta1_compatibility_rules(),
609        }
610    }
611
612    /// Default compatibility rules for general API evolution
613    fn default_compatibility_rules() -> Vec<CompatibilityRule> {
614        vec![
615            CompatibilityRule {
616                rule_type: CompatibilityRuleType::PublicApiRemoval,
617                description: "Public APIs cannot be removed without deprecation".to_string(),
618                severity: CompatibilitySeverity::Breaking,
619                auto_fix: Some("Add deprecation annotation".to_string()),
620            },
621            CompatibilityRule {
622                rule_type: CompatibilityRuleType::SignatureChange,
623                description: "Function signatures cannot change in breaking ways".to_string(),
624                severity: CompatibilitySeverity::Breaking,
625                auto_fix: None,
626            },
627            CompatibilityRule {
628                rule_type: CompatibilityRuleType::ParameterTypeChange,
629                description: "Parameter types cannot change".to_string(),
630                severity: CompatibilitySeverity::Breaking,
631                auto_fix: Some("Create new function with different name".to_string()),
632            },
633        ]
634    }
635
636    /// Stricter compatibility rules for Beta 1 API freeze
637    fn beta1_compatibility_rules() -> Vec<CompatibilityRule> {
638        vec![
639            CompatibilityRule {
640                rule_type: CompatibilityRuleType::PublicApiRemoval,
641                description: "No public APIs can be removed during Beta 1 freeze".to_string(),
642                severity: CompatibilitySeverity::Breaking,
643                auto_fix: None,
644            },
645            CompatibilityRule {
646                rule_type: CompatibilityRuleType::SignatureChange,
647                description: "No function signatures can change during API freeze".to_string(),
648                severity: CompatibilitySeverity::Breaking,
649                auto_fix: None,
650            },
651            CompatibilityRule {
652                rule_type: CompatibilityRuleType::NewRequiredParameter,
653                description: "No new required parameters can be added during freeze".to_string(),
654                severity: CompatibilitySeverity::Breaking,
655                auto_fix: Some("Make parameter optional with default value".to_string()),
656            },
657            CompatibilityRule {
658                rule_type: CompatibilityRuleType::VisibilityReduction,
659                description: "API visibility cannot be reduced during freeze".to_string(),
660                severity: CompatibilitySeverity::Breaking,
661                auto_fix: None,
662            },
663        ]
664    }
665
666    /// Freeze the current API surface
667    pub fn freeze_apis(&mut self, apis: Vec<ApiSignature>) -> Result<(), String> {
668        if self.freeze_status == ApiFreezeStatus::Stable {
669            return Err("Cannot freeze APIs that are already stable".to_string());
670        }
671
672        self.frozen_apis = apis;
673        self.freeze_status = ApiFreezeStatus::Frozen;
674        Ok(())
675    }
676
677    /// Check compatibility between current and frozen APIs
678    pub fn check_compatibility(&self, currentapis: &[ApiSignature]) -> CompatibilityCheckResult {
679        let mut violations = Vec::new();
680        let mut warnings = Vec::new();
681        let mut suggestions = Vec::new();
682
683        if self.freeze_status == ApiFreezeStatus::Unfrozen {
684            warnings.push(CompatibilityWarning {
685                apiname: "*".to_string(),
686                message: "APIs are not frozen - no compatibility checking performed".to_string(),
687                impact: "API changes may break compatibility".to_string(),
688            });
689
690            return CompatibilityCheckResult {
691                is_compatible: true,
692                violations,
693                warnings,
694                suggestions,
695            };
696        }
697
698        // Check for removed APIs
699        for frozen_api in &self.frozen_apis {
700            if frozen_api.visibility == Visibility::Public
701                && frozen_api.stability == StabilityLevel::Stable
702                && !currentapis
703                    .iter()
704                    .any(|api| api.name == frozen_api.name && api.module == frozen_api.module)
705            {
706                violations.push(CompatibilityViolation {
707                    apiname: format!(
708                        "{module}::{name}",
709                        module = frozen_api.module,
710                        name = frozen_api.name
711                    ),
712                    violation_type: CompatibilityRuleType::PublicApiRemoval,
713                    severity: CompatibilitySeverity::Breaking,
714                    description: "Public stable API was removed".to_string(),
715                    old_signature: Some(frozen_api.clone()),
716                    new_signature: None,
717                    fix_suggestion: Some("Restore the API or mark as deprecated".to_string()),
718                });
719            }
720        }
721
722        // Check for signature changes
723        for current_api in currentapis {
724            if let Some(frozen_api) = self
725                .frozen_apis
726                .iter()
727                .find(|api| api.name == current_api.name && api.module == current_api.module)
728            {
729                // Check parameter changes first (more specific)
730                if frozen_api.parameters != current_api.parameters {
731                    let has_new_required = current_api.parameters.iter().any(|p| {
732                        !p.is_optional && !frozen_api.parameters.iter().any(|fp| fp.name == p.name)
733                    });
734
735                    if has_new_required {
736                        violations.push(CompatibilityViolation {
737                            apiname: format!(
738                                "{module}::{name}",
739                                module = current_api.module,
740                                name = current_api.name
741                            ),
742                            violation_type: CompatibilityRuleType::NewRequiredParameter,
743                            severity: CompatibilitySeverity::Breaking,
744                            description: "New required parameter added".to_string(),
745                            old_signature: Some(frozen_api.clone()),
746                            new_signature: Some(current_api.clone()),
747                            fix_suggestion: Some("Make new parameters optional".to_string()),
748                        });
749                        continue; // Skip signature hash check for this API
750                    }
751                }
752
753                // Check visibility reduction
754                if Self::is_visibility_reduced(&frozen_api.visibility, &current_api.visibility) {
755                    violations.push(CompatibilityViolation {
756                        apiname: format!(
757                            "{module}::{name}",
758                            module = current_api.module,
759                            name = current_api.name
760                        ),
761                        violation_type: CompatibilityRuleType::VisibilityReduction,
762                        severity: CompatibilitySeverity::Breaking,
763                        description: "API visibility was reduced".to_string(),
764                        old_signature: Some(frozen_api.clone()),
765                        new_signature: Some(current_api.clone()),
766                        fix_suggestion: Some("Restore original visibility".to_string()),
767                    });
768                }
769
770                // Check return type changes
771                if frozen_api.return_type != current_api.return_type {
772                    violations.push(CompatibilityViolation {
773                        apiname: format!(
774                            "{module}::{name}",
775                            module = current_api.module,
776                            name = current_api.name
777                        ),
778                        violation_type: CompatibilityRuleType::ReturnTypeChange,
779                        severity: CompatibilitySeverity::Breaking,
780                        description: "Return type changed".to_string(),
781                        old_signature: Some(frozen_api.clone()),
782                        new_signature: Some(current_api.clone()),
783                        fix_suggestion: Some(
784                            "Restore original return type or create new API".to_string(),
785                        ),
786                    });
787                }
788
789                // Check for other parameter type changes
790                if frozen_api.parameters.len() == current_api.parameters.len() {
791                    for (old_param, new_param) in frozen_api
792                        .parameters
793                        .iter()
794                        .zip(current_api.parameters.iter())
795                    {
796                        if old_param.name == new_param.name
797                            && old_param.type_name != new_param.type_name
798                        {
799                            violations.push(CompatibilityViolation {
800                                apiname: {
801                                    let module = &current_api.module;
802                                    let name = &current_api.name;
803                                    format!("{module}::{name}")
804                                },
805                                violation_type: CompatibilityRuleType::ParameterTypeChange,
806                                severity: CompatibilitySeverity::Breaking,
807                                description: format!(
808                                    "Parameter '{param_name}' type changed from '{old_type}' to '{new_type}'",
809                                    param_name = old_param.name, old_type = old_param.type_name, new_type = new_param.type_name
810                                ),
811                                old_signature: Some(frozen_api.clone()),
812                                new_signature: Some(current_api.clone()),
813                                fix_suggestion: Some(
814                                    "Restore original parameter type or create new API".to_string(),
815                                ),
816                            });
817                        }
818                    }
819                }
820
821                // Check signature hash changes (catch-all for other changes)
822                if frozen_api.signature_hash != current_api.signature_hash
823                    && !violations.iter().any(|v| {
824                        v.apiname
825                            == format!(
826                                "{module}::{name}",
827                                module = current_api.module,
828                                name = current_api.name
829                            )
830                    })
831                {
832                    violations.push(CompatibilityViolation {
833                        apiname: format!(
834                            "{module}::{name}",
835                            module = current_api.module,
836                            name = current_api.name
837                        ),
838                        violation_type: CompatibilityRuleType::SignatureChange,
839                        severity: CompatibilitySeverity::Breaking,
840                        description: "API signature changed in an unspecified way".to_string(),
841                        old_signature: Some(frozen_api.clone()),
842                        new_signature: Some(current_api.clone()),
843                        fix_suggestion: Some(
844                            "Revert signature change or create new API".to_string(),
845                        ),
846                    });
847                }
848            }
849        }
850
851        // Generate suggestions for new APIs
852        for current_api in currentapis {
853            if !self
854                .frozen_apis
855                .iter()
856                .any(|api| api.name == current_api.name && api.module == current_api.module)
857            {
858                suggestions.push(CompatibilitySuggestion {
859                    apiname: format!(
860                        "{module}::{name}",
861                        module = current_api.module,
862                        name = current_api.name
863                    ),
864                    suggestion: "New API detected - ensure proper documentation".to_string(),
865                    rationale: "New APIs should be well-documented and tested".to_string(),
866                });
867            }
868        }
869
870        let is_compatible = violations
871            .iter()
872            .all(|v| v.severity != CompatibilitySeverity::Breaking);
873
874        CompatibilityCheckResult {
875            is_compatible,
876            violations,
877            warnings,
878            suggestions,
879        }
880    }
881
882    /// Check if visibility was reduced
883    fn is_visibility_reduced(old: &Visibility, new: &Visibility) -> bool {
884        use Visibility::*;
885        matches!(
886            (old, new),
887            (Public, PublicCrate) | (Public, Private) | (PublicCrate, Private)
888        )
889    }
890
891    /// Generate detailed compatibility report
892    pub fn generate_compatibility_report(&self, result: &CompatibilityCheckResult) -> String {
893        let mut report = String::from("# API Compatibility Report\n\n");
894
895        report.push_str(&format!("**Freeze Status**: {:?}\n", self.freeze_status));
896        report.push_str(&format!(
897            "**Overall Compatible**: {}\n\n",
898            result.is_compatible
899        ));
900
901        if !result.violations.is_empty() {
902            report.push_str("## ❌ Compatibility Violations\n\n");
903            for violation in &result.violations {
904                let severity_icon = match violation.severity {
905                    CompatibilitySeverity::Breaking => "đŸ’Ĩ",
906                    CompatibilitySeverity::Warning => "âš ī¸",
907                    CompatibilitySeverity::Info => "â„šī¸",
908                };
909
910                report.push_str(&format!(
911                    "{} **{}** ({:?}): {}\n",
912                    severity_icon,
913                    violation.apiname,
914                    violation.violation_type,
915                    violation.description
916                ));
917
918                if let Some(ref fix) = violation.fix_suggestion {
919                    report.push_str(&format!("   - **Fix**: {fix}\n"));
920                }
921                report.push('\n');
922            }
923        }
924
925        if !result.warnings.is_empty() {
926            report.push_str("## âš ī¸ Warnings\n\n");
927            for warning in &result.warnings {
928                report.push_str(&format!(
929                    "- **{}**: {} (Impact: {})\n",
930                    warning.apiname, warning.message, warning.impact
931                ));
932            }
933            report.push('\n');
934        }
935
936        if !result.suggestions.is_empty() {
937            report.push_str("## 💡 Suggestions\n\n");
938            for suggestion in &result.suggestions {
939                report.push_str(&format!(
940                    "- **{}**: {} ({})\n",
941                    suggestion.apiname, suggestion.suggestion, suggestion.rationale
942                ));
943            }
944            report.push('\n');
945        }
946
947        report.push_str("## 📋 Next Steps\n\n");
948        if result.is_compatible {
949            report.push_str("✅ All compatibility checks passed. Safe to proceed.\n");
950        } else {
951            report
952                .push_str("❌ Compatibility violations detected. Address issues before release:\n");
953            report.push_str("1. Review breaking changes listed above\n");
954            report.push_str("2. Apply suggested fixes or revert changes\n");
955            report.push_str("3. Re-run compatibility check\n");
956            report.push_str("4. Update documentation if needed\n");
957        }
958
959        report
960    }
961}
962
963impl Default for ApiCompatibilityChecker {
964    fn default() -> Self {
965        Self::new()
966    }
967}
968
969/// Global version registry
970static REGISTRY: OnceLock<Mutex<VersionRegistry>> = OnceLock::new();
971
972/// Global API compatibility checker
973static API_CHECKER: OnceLock<Mutex<ApiCompatibilityChecker>> = OnceLock::new();
974
975/// Get the global registry for modification
976#[allow(dead_code)]
977pub fn global_registry_mut() -> std::sync::MutexGuard<'static, VersionRegistry> {
978    REGISTRY
979        .get_or_init(|| Mutex::new(VersionRegistry::new()))
980        .lock()
981        .unwrap()
982}
983
984/// Get the global registry for reading
985#[allow(dead_code)]
986pub fn global_registry() -> &'static Mutex<VersionRegistry> {
987    REGISTRY.get_or_init(|| Mutex::new(VersionRegistry::new()))
988}
989
990/// Get the global API checker for modification
991#[allow(dead_code)]
992pub fn global_api_checker_mut() -> std::sync::MutexGuard<'static, ApiCompatibilityChecker> {
993    API_CHECKER
994        .get_or_init(|| Mutex::new(ApiCompatibilityChecker::for_beta1()))
995        .lock()
996        .unwrap()
997}
998
999/// Get the global API checker for reading
1000#[allow(dead_code)]
1001pub fn global_api_checker() -> &'static Mutex<ApiCompatibilityChecker> {
1002    API_CHECKER.get_or_init(|| Mutex::new(ApiCompatibilityChecker::for_beta1()))
1003}
1004
1005/// Helper function to create API signature from function metadata
1006#[allow(dead_code)]
1007pub fn create_api_signature(
1008    name: &str,
1009    module: &str,
1010    parameters: Vec<Parameter>,
1011    return_type: Option<String>,
1012    visibility: Visibility,
1013    stability: StabilityLevel,
1014) -> ApiSignature {
1015    let name_str = name.to_string();
1016    let module_str = module.to_string();
1017
1018    // Create a simple hash based on function signature components
1019    let mut hasher = std::collections::hash_map::DefaultHasher::new();
1020    use std::hash::{Hash, Hasher};
1021
1022    name_str.hash(&mut hasher);
1023    module_str.hash(&mut hasher);
1024    // Hash each parameter
1025    for param in &parameters {
1026        param.name.hash(&mut hasher);
1027        param.type_name.hash(&mut hasher);
1028        param.is_optional.hash(&mut hasher);
1029        if let Some(ref default) = param.defaultvalue {
1030            default.hash(&mut hasher);
1031        }
1032    }
1033    return_type.hash(&mut hasher);
1034    visibility.hash(&mut hasher);
1035
1036    ApiSignature {
1037        name: name_str,
1038        module: module_str,
1039        signature_hash: hasher.finish(),
1040        parameters,
1041        return_type,
1042        visibility,
1043        stability,
1044    }
1045}
1046
1047/// Initialize Beta 1 API freeze with core scirs2 APIs
1048#[allow(dead_code)]
1049pub fn initialize_beta1_freeze() -> Result<(), String> {
1050    let mut checker = global_api_checker_mut();
1051
1052    // Use the same API definitions for consistency
1053    let core_apis = get_test_frozen_apis();
1054
1055    checker.freeze_apis(core_apis)
1056}
1057
1058/// Get the frozen API signatures for testing
1059#[allow(dead_code)]
1060fn get_test_frozen_apis() -> Vec<ApiSignature> {
1061    vec![
1062        create_api_signature(
1063            "simd_add",
1064            "simd_ops",
1065            vec![
1066                Parameter {
1067                    name: "a".to_string(),
1068                    type_name: "&ArrayView1<Self>".to_string(),
1069                    is_optional: false,
1070                    defaultvalue: None,
1071                },
1072                Parameter {
1073                    name: "b".to_string(),
1074                    type_name: "&ArrayView1<Self>".to_string(),
1075                    is_optional: false,
1076                    defaultvalue: None,
1077                },
1078            ],
1079            Some("Array1<Self>".to_string()),
1080            Visibility::Public,
1081            StabilityLevel::Stable,
1082        ),
1083        create_api_signature(
1084            "simd_mul",
1085            "simd_ops",
1086            vec![
1087                Parameter {
1088                    name: "a".to_string(),
1089                    type_name: "&ArrayView1<Self>".to_string(),
1090                    is_optional: false,
1091                    defaultvalue: None,
1092                },
1093                Parameter {
1094                    name: "b".to_string(),
1095                    type_name: "&ArrayView1<Self>".to_string(),
1096                    is_optional: false,
1097                    defaultvalue: None,
1098                },
1099            ],
1100            Some("Array1<Self>".to_string()),
1101            Visibility::Public,
1102            StabilityLevel::Stable,
1103        ),
1104        create_api_signature(
1105            "simd_dot",
1106            "simd_ops",
1107            vec![
1108                Parameter {
1109                    name: "a".to_string(),
1110                    type_name: "&ArrayView1<Self>".to_string(),
1111                    is_optional: false,
1112                    defaultvalue: None,
1113                },
1114                Parameter {
1115                    name: "b".to_string(),
1116                    type_name: "&ArrayView1<Self>".to_string(),
1117                    is_optional: false,
1118                    defaultvalue: None,
1119                },
1120            ],
1121            Some("Self".to_string()),
1122            Visibility::Public,
1123            StabilityLevel::Stable,
1124        ),
1125        // Add new enhanced SIMD operations as experimental
1126        create_api_signature(
1127            "simd_add_cache_optimized",
1128            "simd_ops",
1129            vec![
1130                Parameter {
1131                    name: "a".to_string(),
1132                    type_name: "&ArrayView1<Self>".to_string(),
1133                    is_optional: false,
1134                    defaultvalue: None,
1135                },
1136                Parameter {
1137                    name: "b".to_string(),
1138                    type_name: "&ArrayView1<Self>".to_string(),
1139                    is_optional: false,
1140                    defaultvalue: None,
1141                },
1142            ],
1143            Some("Array1<Self>".to_string()),
1144            Visibility::Public,
1145            StabilityLevel::Experimental,
1146        ),
1147        create_api_signature(
1148            "simd_fma_advanced_optimized",
1149            "simd_ops",
1150            vec![
1151                Parameter {
1152                    name: "a".to_string(),
1153                    type_name: "&ArrayView1<Self>".to_string(),
1154                    is_optional: false,
1155                    defaultvalue: None,
1156                },
1157                Parameter {
1158                    name: "b".to_string(),
1159                    type_name: "&ArrayView1<Self>".to_string(),
1160                    is_optional: false,
1161                    defaultvalue: None,
1162                },
1163                Parameter {
1164                    name: "c".to_string(),
1165                    type_name: "&ArrayView1<Self>".to_string(),
1166                    is_optional: false,
1167                    defaultvalue: None,
1168                },
1169            ],
1170            Some("Array1<Self>".to_string()),
1171            Visibility::Public,
1172            StabilityLevel::Experimental,
1173        ),
1174        create_api_signature(
1175            "Version",
1176            "apiversioning",
1177            vec![],
1178            None,
1179            Visibility::Public,
1180            StabilityLevel::Stable,
1181        ),
1182        create_api_signature(
1183            "ApiCompatibilityChecker",
1184            "apiversioning",
1185            vec![],
1186            None,
1187            Visibility::Public,
1188            StabilityLevel::Stable,
1189        ),
1190    ]
1191}
1192
1193/// Convenience function to check current API compatibility
1194#[allow(dead_code)]
1195pub fn check_current_compatibility() -> Result<CompatibilityCheckResult, String> {
1196    let checker = global_api_checker();
1197    let checker_guard = checker.lock().map_err(|e| e.to_string())?;
1198
1199    // For testing, we'll use the same APIs that were frozen
1200    // In a real implementation, this would be generated from actual code analysis
1201    let current_apis = get_test_frozen_apis();
1202
1203    Ok((*checker_guard).check_compatibility(&current_apis))
1204}
1205
1206#[cfg(test)]
1207mod tests {
1208    use super::*;
1209
1210    #[test]
1211    fn test_version_parse() {
1212        assert_eq!(Version::parse("1.2.3").unwrap(), Version::new(1, 2, 3));
1213        assert_eq!(
1214            Version::parse("0.1.0-beta.4").unwrap(),
1215            Version::new(0, 1, 0)
1216        );
1217        assert_eq!(
1218            Version::parse("10.20.30").unwrap(),
1219            Version::new(10, 20, 30)
1220        );
1221
1222        assert!(Version::parse("1.2").is_err());
1223        assert!(Version::parse("a.b.c").is_err());
1224        assert!(Version::parse("").is_err());
1225    }
1226
1227    #[test]
1228    fn test_version_compatibility() {
1229        let v1_0_0 = Version::new(1, 0, 0);
1230        let v1_1_0 = Version::new(1, 1, 0);
1231        let v1_0_1 = Version::new(1, 0, 1);
1232        let v2_0_0 = Version::new(2, 0, 0);
1233
1234        assert!(v1_1_0.is_compatible_with(&v1_0_0));
1235        assert!(v1_0_1.is_compatible_with(&v1_0_0));
1236        assert!(!v2_0_0.is_compatible_with(&v1_0_0));
1237        assert!(!v1_0_0.is_compatible_with(&v1_1_0));
1238    }
1239
1240    #[test]
1241    fn test_version_registry() {
1242        let mut registry = VersionRegistry::new();
1243
1244        registry
1245            .register_api("Array", "core", Version::new(0, 1, 0))
1246            .register_api("Matrix", "linalg", Version::new(0, 1, 0))
1247            .register_api("OldArray", "core", Version::new(0, 1, 0));
1248
1249        registry
1250            .deprecate_api("OldArray", Version::new(0, 2, 0), Some("Array".to_string()))
1251            .unwrap();
1252
1253        let v0_1_0 = Version::new(0, 1, 0);
1254        let v0_2_0 = Version::new(0, 2, 0);
1255
1256        // Check APIs in v0.1.0
1257        let apis_v1 = registry.apis_in_version(&v0_1_0);
1258        assert_eq!(apis_v1.len(), 3);
1259
1260        // Check APIs in v0.2.0
1261        let apis_v2 = registry.apis_in_version(&v0_2_0);
1262        assert_eq!(apis_v2.len(), 2); // OldArray is deprecated
1263
1264        // Check deprecated APIs
1265        let deprecated = registry.deprecated_apis_in_version(&v0_2_0);
1266        assert_eq!(deprecated.len(), 1);
1267        assert_eq!(deprecated[0].name, "OldArray");
1268    }
1269
1270    #[test]
1271    fn test_migration_guide() {
1272        let mut registry = VersionRegistry::new();
1273
1274        registry
1275            .register_api("Feature1", "module1", Version::new(0, 1, 0))
1276            .register_api("Feature2", "module2", Version::new(0, 2, 0))
1277            .register_api("OldFeature", "module1", Version::new(0, 1, 0));
1278
1279        registry
1280            .deprecate_api(
1281                "OldFeature",
1282                Version::new(0, 2, 0),
1283                Some("Feature2".to_string()),
1284            )
1285            .unwrap();
1286
1287        let guide = registry.migration_guide(&Version::new(0, 1, 0), &Version::new(0, 2, 0));
1288
1289        assert!(guide.contains("Removed APIs"));
1290        assert!(guide.contains("OldFeature"));
1291        assert!(guide.contains("Replacement"));
1292        assert!(guide.contains("Feature2"));
1293        assert!(guide.contains("New APIs"));
1294        assert!(guide.contains("Migration Checklist"));
1295    }
1296
1297    #[test]
1298    fn test_api_compatibility_checker() {
1299        let mut checker = ApiCompatibilityChecker::new();
1300
1301        // Create initial API set
1302        let initial_apis = vec![create_api_signature(
1303            "test_func",
1304            "test_module",
1305            vec![Parameter {
1306                name: "param1".to_string(),
1307                type_name: "i32".to_string(),
1308                is_optional: false,
1309                defaultvalue: None,
1310            }],
1311            Some("String".to_string()),
1312            Visibility::Public,
1313            StabilityLevel::Stable,
1314        )];
1315
1316        // Freeze the APIs
1317        checker.freeze_apis(initial_apis.clone()).unwrap();
1318        assert_eq!(checker.freeze_status, ApiFreezeStatus::Frozen);
1319
1320        // Test compatibility with same APIs
1321        let result = checker.check_compatibility(&initial_apis);
1322        assert!(result.is_compatible);
1323        assert!(result.violations.is_empty());
1324    }
1325
1326    #[test]
1327    fn test_api_signature_changes() {
1328        let mut checker = ApiCompatibilityChecker::for_beta1();
1329
1330        let original_api = create_api_signature(
1331            "test_func",
1332            "test_module",
1333            vec![Parameter {
1334                name: "param1".to_string(),
1335                type_name: "i32".to_string(),
1336                is_optional: false,
1337                defaultvalue: None,
1338            }],
1339            Some("String".to_string()),
1340            Visibility::Public,
1341            StabilityLevel::Stable,
1342        );
1343
1344        checker.freeze_apis(vec![original_api.clone()]).unwrap();
1345
1346        // Test with modified signature (different parameter type)
1347        let modified_api = create_api_signature(
1348            "test_func",
1349            "test_module",
1350            vec![Parameter {
1351                name: "param1".to_string(),
1352                type_name: "f64".to_string(), // Changed type
1353                is_optional: false,
1354                defaultvalue: None,
1355            }],
1356            Some("String".to_string()),
1357            Visibility::Public,
1358            StabilityLevel::Stable,
1359        );
1360
1361        let result = checker.check_compatibility(&[modified_api]);
1362        assert!(!result.is_compatible);
1363        assert!(!result.violations.is_empty());
1364        assert_eq!(
1365            result.violations[0].violation_type,
1366            CompatibilityRuleType::ParameterTypeChange
1367        );
1368    }
1369
1370    #[test]
1371    fn test_api_removal_detection() {
1372        let mut checker = ApiCompatibilityChecker::for_beta1();
1373
1374        let api1 = create_api_signature(
1375            "func1",
1376            "module",
1377            vec![],
1378            None,
1379            Visibility::Public,
1380            StabilityLevel::Stable,
1381        );
1382
1383        let api2 = create_api_signature(
1384            "func2",
1385            "module",
1386            vec![],
1387            None,
1388            Visibility::Public,
1389            StabilityLevel::Stable,
1390        );
1391
1392        checker
1393            .freeze_apis(vec![api1.clone(), api2.clone()])
1394            .unwrap();
1395
1396        // Test with one API removed
1397        let result = checker.check_compatibility(&[api1]); // api2 is missing
1398        assert!(!result.is_compatible);
1399        assert_eq!(result.violations.len(), 1);
1400        assert_eq!(
1401            result.violations[0].violation_type,
1402            CompatibilityRuleType::PublicApiRemoval
1403        );
1404    }
1405
1406    #[test]
1407    fn test_visibility_reduction() {
1408        let mut checker = ApiCompatibilityChecker::for_beta1();
1409
1410        let public_api = create_api_signature(
1411            "func",
1412            "module",
1413            vec![],
1414            None,
1415            Visibility::Public,
1416            StabilityLevel::Stable,
1417        );
1418
1419        checker.freeze_apis(vec![public_api]).unwrap();
1420
1421        // Test with reduced visibility
1422        let private_api = create_api_signature(
1423            "func",
1424            "module",
1425            vec![],
1426            None,
1427            Visibility::Private, // Reduced from Public
1428            StabilityLevel::Stable,
1429        );
1430
1431        let result = checker.check_compatibility(&[private_api]);
1432        assert!(!result.is_compatible);
1433        assert_eq!(
1434            result.violations[0].violation_type,
1435            CompatibilityRuleType::VisibilityReduction
1436        );
1437    }
1438
1439    #[test]
1440    fn test_new_required_parameter() {
1441        let mut checker = ApiCompatibilityChecker::for_beta1();
1442
1443        let original_api = create_api_signature(
1444            "func",
1445            "module",
1446            vec![Parameter {
1447                name: "param1".to_string(),
1448                type_name: "i32".to_string(),
1449                is_optional: false,
1450                defaultvalue: None,
1451            }],
1452            None,
1453            Visibility::Public,
1454            StabilityLevel::Stable,
1455        );
1456
1457        checker.freeze_apis(vec![original_api]).unwrap();
1458
1459        // Test with new required parameter
1460        let modified_api = create_api_signature(
1461            "func",
1462            "module",
1463            vec![
1464                Parameter {
1465                    name: "param1".to_string(),
1466                    type_name: "i32".to_string(),
1467                    is_optional: false,
1468                    defaultvalue: None,
1469                },
1470                Parameter {
1471                    name: "param2".to_string(),
1472                    type_name: "String".to_string(),
1473                    is_optional: false, // New required parameter
1474                    defaultvalue: None,
1475                },
1476            ],
1477            None,
1478            Visibility::Public,
1479            StabilityLevel::Stable,
1480        );
1481
1482        let result = checker.check_compatibility(&[modified_api]);
1483        assert!(!result.is_compatible);
1484        assert_eq!(
1485            result.violations[0].violation_type,
1486            CompatibilityRuleType::NewRequiredParameter
1487        );
1488    }
1489
1490    #[test]
1491    fn test_compatibility_report_generation() {
1492        let mut checker = ApiCompatibilityChecker::for_beta1();
1493
1494        let original_api = create_api_signature(
1495            "test_func",
1496            "test_module",
1497            vec![],
1498            None,
1499            Visibility::Public,
1500            StabilityLevel::Stable,
1501        );
1502
1503        checker.freeze_apis(vec![original_api]).unwrap();
1504
1505        // Test with removed API
1506        let result = checker.check_compatibility(&[]); // All APIs removed
1507        let report = checker.generate_compatibility_report(&result);
1508
1509        assert!(report.contains("API Compatibility Report"));
1510        assert!(report.contains("Freeze Status"));
1511        assert!(report.contains("Compatibility Violations"));
1512        assert!(report.contains("Next Steps"));
1513        assert!(report.contains("đŸ’Ĩ")); // Breaking change icon
1514    }
1515
1516    #[test]
1517    fn test_beta1_initialization() {
1518        // Test that we can initialize the Beta 1 freeze
1519        let result = initialize_beta1_freeze();
1520        assert!(result.is_ok());
1521
1522        // Test compatibility check
1523        let compat_result = check_current_compatibility();
1524        assert!(compat_result.is_ok());
1525
1526        let result = compat_result.unwrap();
1527        // Should be compatible since we're checking against the same APIs
1528        assert!(result.is_compatible);
1529    }
1530
1531    #[test]
1532    fn test_api_signature_creation() {
1533        let signature = create_api_signature(
1534            "test_func",
1535            "test_module",
1536            vec![Parameter {
1537                name: "param".to_string(),
1538                type_name: "i32".to_string(),
1539                is_optional: false,
1540                defaultvalue: None,
1541            }],
1542            Some("String".to_string()),
1543            Visibility::Public,
1544            StabilityLevel::Stable,
1545        );
1546
1547        assert_eq!(signature.name, "test_func");
1548        assert_eq!(signature.module, "test_module");
1549        assert_eq!(signature.parameters.len(), 1);
1550        assert_eq!(signature.return_type, Some("String".to_string()));
1551        assert_eq!(signature.visibility, Visibility::Public);
1552        assert_eq!(signature.stability, StabilityLevel::Stable);
1553        assert!(signature.signature_hash != 0); // Should have a hash
1554    }
1555}