Coverage Report

Created: 2025-09-08 21:26

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/noah/src/ruchy/src/wasm/portability.rs
Line
Count
Source
1
//! Portability scoring for WebAssembly components (RUCHY-0819)
2
//!
3
//! Analyzes and scores the portability of Ruchy-generated WASM components
4
//! across different platforms and runtimes.
5
6
#[cfg(test)]
7
mod tests {
8
    use super::*;
9
    
10
    use std::collections::{HashMap, HashSet};
11
    
12
    // Helper functions for consistent test setup
13
    fn create_test_config() -> AnalysisConfig {
14
        AnalysisConfig {
15
            target_platforms: vec![
16
                "wasmtime".to_string(),
17
                "wasmer".to_string(),
18
                "browser".to_string(),
19
            ],
20
            check_api_compatibility: true,
21
            check_size_constraints: true,
22
            check_performance: true,
23
            check_security: true,
24
            strict_mode: false,
25
        }
26
    }
27
    
28
    fn create_test_component_info() -> ComponentInfo {
29
        let mut features = HashSet::new();
30
        features.insert("memory".to_string());
31
        features.insert("tables".to_string());
32
        
33
        ComponentInfo {
34
            name: "test_component".to_string(),
35
            version: "1.0.0".to_string(),
36
            size: 1024 * 10, // 10KB
37
            exports_count: 5,
38
            imports_count: 3,
39
            features,
40
        }
41
    }
42
    
43
    fn create_test_portability_score() -> PortabilityScore {
44
        let mut platform_scores = HashMap::new();
45
        platform_scores.insert("wasmtime".to_string(), 0.95);
46
        platform_scores.insert("wasmer".to_string(), 0.92);
47
        platform_scores.insert("browser".to_string(), 0.88);
48
        
49
        let mut feature_scores = HashMap::new();
50
        feature_scores.insert("memory".to_string(), 0.9);
51
        feature_scores.insert("threading".to_string(), 0.7);
52
        feature_scores.insert("simd".to_string(), 0.6);
53
        
54
        PortabilityScore {
55
            overall_score: 0.85,
56
            platform_scores,
57
            feature_scores,
58
            api_compatibility: 0.90,
59
            size_efficiency: 0.88,
60
            performance_portability: 0.82,
61
            security_compliance: 0.95,
62
        }
63
    }
64
    
65
    fn create_test_analyzer() -> PortabilityAnalyzer {
66
        PortabilityAnalyzer::new()
67
    }
68
    
69
    fn create_test_analyzer_with_config() -> PortabilityAnalyzer {
70
        let config = create_test_config();
71
        PortabilityAnalyzer::new_with_config(config)
72
    }
73
    
74
    // ========== AnalysisConfig Tests ==========
75
    
76
    #[test]
77
    fn test_analysis_config_creation() {
78
        let config = create_test_config();
79
        assert_eq!(config.target_platforms.len(), 3);
80
        assert!(config.check_api_compatibility);
81
        assert!(config.check_size_constraints);
82
        assert!(config.check_performance);
83
        assert!(config.check_security);
84
        assert!(!config.strict_mode);
85
    }
86
    
87
    #[test]
88
    fn test_analysis_config_default() {
89
        let config = AnalysisConfig::default();
90
        assert!(!config.target_platforms.is_empty());
91
        assert!(config.check_api_compatibility);
92
        assert!(!config.strict_mode);
93
    }
94
    
95
    #[test]
96
    fn test_analysis_config_clone() {
97
        let config1 = create_test_config();
98
        let config2 = config1.clone();
99
        assert_eq!(config1.target_platforms, config2.target_platforms);
100
        assert_eq!(config1.strict_mode, config2.strict_mode);
101
    }
102
    
103
    #[test]
104
    fn test_analysis_config_serialization() {
105
        let config = create_test_config();
106
        let json = serde_json::to_string(&config).unwrap();
107
        let deserialized: AnalysisConfig = serde_json::from_str(&json).unwrap();
108
        assert_eq!(config.target_platforms, deserialized.target_platforms);
109
    }
110
    
111
    // ========== ComponentInfo Tests ==========
112
    
113
    #[test]
114
    fn test_component_info_creation() {
115
        let info = create_test_component_info();
116
        assert_eq!(info.name, "test_component");
117
        assert_eq!(info.version, "1.0.0");
118
        assert_eq!(info.size, 10240);
119
        assert_eq!(info.exports_count, 5);
120
        assert_eq!(info.imports_count, 3);
121
        assert_eq!(info.features.len(), 2);
122
    }
123
    
124
    #[test]
125
    fn test_component_info_without_features() {
126
        let info = ComponentInfo {
127
            name: "minimal".to_string(),
128
            version: "0.1.0".to_string(),
129
            size: 1024,
130
            exports_count: 0,
131
            imports_count: 0,
132
            features: HashSet::new(),
133
        };
134
        assert_eq!(info.exports_count, 0);
135
        assert_eq!(info.imports_count, 0);
136
        assert!(info.features.is_empty());
137
    }
138
    
139
    #[test]
140
    fn test_component_info_serialization() {
141
        let info = create_test_component_info();
142
        let json = serde_json::to_string(&info).unwrap();
143
        let deserialized: ComponentInfo = serde_json::from_str(&json).unwrap();
144
        assert_eq!(info.name, deserialized.name);
145
        assert_eq!(info.size, deserialized.size);
146
    }
147
    
148
    // ========== PortabilityScore Tests ==========
149
    
150
    #[test]
151
    fn test_portability_score_creation() {
152
        let score = create_test_portability_score();
153
        assert_eq!(score.overall_score, 0.85);
154
        assert_eq!(score.platform_scores.len(), 3);
155
        assert_eq!(score.feature_scores.len(), 3);
156
        assert_eq!(score.api_compatibility, 0.90);
157
        assert_eq!(score.security_compliance, 0.95);
158
    }
159
    
160
    #[test]
161
    fn test_portability_score_platform_lookup() {
162
        let score = create_test_portability_score();
163
        assert_eq!(*score.platform_scores.get("wasmtime").unwrap(), 0.95);
164
        assert_eq!(*score.platform_scores.get("wasmer").unwrap(), 0.92);
165
        assert_eq!(*score.platform_scores.get("browser").unwrap(), 0.88);
166
    }
167
    
168
    #[test]
169
    fn test_portability_score_feature_lookup() {
170
        let score = create_test_portability_score();
171
        assert_eq!(*score.feature_scores.get("memory").unwrap(), 0.9);
172
        assert_eq!(*score.feature_scores.get("threading").unwrap(), 0.7);
173
        assert_eq!(*score.feature_scores.get("simd").unwrap(), 0.6);
174
    }
175
    
176
    #[test]
177
    fn test_portability_score_perfect() {
178
        let mut score = create_test_portability_score();
179
        score.overall_score = 1.0;
180
        score.api_compatibility = 1.0;
181
        score.size_efficiency = 1.0;
182
        score.performance_portability = 1.0;
183
        score.security_compliance = 1.0;
184
        
185
        assert_eq!(score.overall_score, 1.0);
186
        assert_eq!(score.api_compatibility, 1.0);
187
        assert_eq!(score.size_efficiency, 1.0);
188
        assert_eq!(score.performance_portability, 1.0);
189
        assert_eq!(score.security_compliance, 1.0);
190
    }
191
    
192
    #[test]
193
    fn test_portability_score_failing() {
194
        let mut score = create_test_portability_score();
195
        score.overall_score = 0.4;
196
        assert!(score.overall_score < 0.5);
197
    }
198
    
199
    // ========== CompatibilityIssue Tests ==========
200
    
201
    #[test]
202
    fn test_compatibility_issue_creation() {
203
        let issue = CompatibilityIssue {
204
            severity: IssueSeverity::Warning,
205
            category: IssueCategory::ApiIncompatibility,
206
            affected_platforms: vec!["browser".to_string()],
207
            description: "Missing API support".to_string(),
208
            fix_suggestion: Some("Use polyfill or alternative API".to_string()),
209
        };
210
        
211
        assert_eq!(issue.severity, IssueSeverity::Warning);
212
        assert_eq!(issue.category, IssueCategory::ApiIncompatibility);
213
        assert_eq!(issue.affected_platforms.len(), 1);
214
        assert!(issue.fix_suggestion.is_some());
215
    }
216
    
217
    #[test]
218
    fn test_compatibility_issue_severity_levels() {
219
        let severities = [IssueSeverity::Error,
220
            IssueSeverity::Warning,
221
            IssueSeverity::Info];
222
        
223
        assert_eq!(severities.len(), 3);
224
        assert_ne!(severities[0], severities[1]);
225
    }
226
    
227
    #[test]
228
    fn test_compatibility_issue_categories() {
229
        let categories = [IssueCategory::ApiIncompatibility,
230
            IssueCategory::FeatureNotSupported,
231
            IssueCategory::Performance,
232
            IssueCategory::SizeConstraint,
233
            IssueCategory::Security,
234
            IssueCategory::Configuration];
235
        
236
        assert_eq!(categories.len(), 6);
237
    }
238
    
239
    // ========== Recommendation Tests ==========
240
    
241
    #[test]
242
    fn test_recommendation_creation() {
243
        let rec = Recommendation {
244
            priority: RecommendationPriority::High,
245
            title: "Optimize memory usage".to_string(),
246
            description: "Reduce memory allocation".to_string(),
247
            impact: 0.1,
248
            platforms: vec!["wasmtime".to_string(), "wasmer".to_string()],
249
        };
250
        
251
        assert_eq!(rec.priority, RecommendationPriority::High);
252
        assert_eq!(rec.title, "Optimize memory usage");
253
        assert_eq!(rec.impact, 0.1);
254
        assert_eq!(rec.platforms.len(), 2);
255
    }
256
    
257
    #[test]
258
    fn test_recommendation_priorities() {
259
        let priorities = [RecommendationPriority::Low,
260
            RecommendationPriority::Medium,
261
            RecommendationPriority::High];
262
        
263
        assert_eq!(priorities.len(), 3);
264
    }
265
    
266
    #[test]
267
    fn test_recommendation_serialization() {
268
        let rec = Recommendation {
269
            priority: RecommendationPriority::Medium,
270
            title: "Test recommendation".to_string(),
271
            description: "Test description".to_string(),
272
            impact: 0.05,
273
            platforms: vec!["browser".to_string()],
274
        };
275
        
276
        let json = serde_json::to_string(&rec).unwrap();
277
        let deserialized: Recommendation = serde_json::from_str(&json).unwrap();
278
        assert_eq!(rec.title, deserialized.title);
279
        assert_eq!(rec.impact, deserialized.impact);
280
    }
281
    
282
    // ========== PlatformSupport Tests ==========
283
    
284
    #[test]
285
    fn test_platform_support_creation() {
286
        let support = PlatformSupport {
287
            platform: "wasmtime".to_string(),
288
            support_level: SupportLevel::Full,
289
            compatibility_score: 0.9,
290
            required_modifications: vec![],
291
            runtime_requirements: Some("1.0-2.0".to_string()),
292
        };
293
        
294
        assert_eq!(support.platform, "wasmtime");
295
        assert_eq!(support.support_level, SupportLevel::Full);
296
        assert!(support.required_modifications.is_empty());
297
        assert_eq!(support.compatibility_score, 0.9);
298
    }
299
    
300
    #[test]
301
    fn test_platform_support_partial() {
302
        let support = PlatformSupport {
303
            platform: "browser".to_string(),
304
            support_level: SupportLevel::Partial,
305
            compatibility_score: 0.7,
306
            required_modifications: vec!["Remove filesystem access".to_string()],
307
            runtime_requirements: None,
308
        };
309
        
310
        assert_eq!(support.support_level, SupportLevel::Partial);
311
        assert_eq!(support.required_modifications.len(), 1);
312
        assert_eq!(support.compatibility_score, 0.7);
313
        assert!(support.runtime_requirements.is_none());
314
    }
315
    
316
    // ========== FeatureUsage Tests ==========
317
    
318
    #[test]
319
    fn test_feature_usage_creation() {
320
        let mut core = HashSet::new();
321
        core.insert("memory".to_string());
322
        core.insert("tables".to_string());
323
        
324
        let mut proposal = HashSet::new();
325
        proposal.insert("simd".to_string());
326
        
327
        let usage = FeatureUsage {
328
            core_features: core,
329
            proposal_features: proposal,
330
            platform_specific: HashMap::new(),
331
            compatibility: HashMap::new(),
332
        };
333
        
334
        assert_eq!(usage.core_features.len(), 2);
335
        assert_eq!(usage.proposal_features.len(), 1);
336
        assert!(usage.platform_specific.is_empty());
337
    }
338
    
339
    #[test]
340
    fn test_feature_usage_with_proposals() {
341
        let mut proposals = HashSet::new();
342
        proposals.insert("threads".to_string());
343
        proposals.insert("simd".to_string());
344
        
345
        let usage = FeatureUsage {
346
            core_features: HashSet::new(),
347
            proposal_features: proposals,
348
            platform_specific: HashMap::new(),
349
            compatibility: HashMap::new(),
350
        };
351
        
352
        assert_eq!(usage.proposal_features.len(), 2);
353
        assert!(usage.proposal_features.contains(&"threads".to_string()));
354
    }
355
    
356
    // ========== SizeAnalysis Tests ==========
357
    
358
    #[test]
359
    fn test_size_analysis_creation() {
360
        let analysis = SizeAnalysis {
361
            total_size: 10240,
362
            code_size: 6000,
363
            data_size: 2000,
364
            custom_sections_size: 1240,
365
            section_sizes: HashMap::new(),
366
            platform_limits: HashMap::new(),
367
        };
368
        
369
        assert_eq!(analysis.total_size, 10240);
370
        assert_eq!(analysis.code_size, 6000);
371
        assert_eq!(analysis.data_size, 2000);
372
        assert_eq!(analysis.custom_sections_size, 1240);
373
    }
374
    
375
    #[test]
376
    fn test_size_analysis_with_sections() {
377
        let mut sections = HashMap::new();
378
        sections.insert("code".to_string(), 6000);
379
        sections.insert("data".to_string(), 2000);
380
        sections.insert("debug".to_string(), 500);
381
        
382
        let analysis = SizeAnalysis {
383
            total_size: 10240,
384
            code_size: 6000,
385
            data_size: 2000,
386
            custom_sections_size: 1500,
387
            section_sizes: sections,
388
            platform_limits: HashMap::new(),
389
        };
390
        
391
        assert_eq!(analysis.section_sizes.len(), 3);
392
        assert_eq!(*analysis.section_sizes.get("debug").unwrap(), 500);
393
    }
394
    
395
    // ========== PortabilityAnalyzer Tests ==========
396
    
397
    #[test]
398
    fn test_analyzer_creation() {
399
        let analyzer = create_test_analyzer();
400
        // Default config has 6 platforms
401
        assert_eq!(analyzer.config.target_platforms.len(), 6);
402
    }
403
    
404
    #[test]
405
    fn test_analyzer_with_custom_config() {
406
        let mut config = create_test_config();
407
        config.strict_mode = true;
408
        config.check_performance = false;
409
        
410
        let analyzer = PortabilityAnalyzer::new_with_config(config);
411
        assert!(analyzer.config.strict_mode);
412
        assert!(!analyzer.config.check_performance);
413
    }
414
    
415
    #[test]
416
    fn test_analyzer_default_config() {
417
        let analyzer = create_test_analyzer();
418
        // Test that analyzer is created successfully
419
        assert!(analyzer.config.check_api_compatibility);
420
        assert!(analyzer.config.check_size_constraints);
421
        assert!(analyzer.config.check_performance);
422
        assert!(analyzer.config.check_security);
423
    }
424
    
425
    #[test]
426
    fn test_analyzer_custom_config() {
427
        let analyzer = create_test_analyzer_with_config();
428
        // Verify custom config is applied
429
        assert_eq!(analyzer.config.target_platforms.len(), 3);
430
        assert!(analyzer.config.target_platforms.contains(&"wasmtime".to_string()));
431
        assert!(analyzer.config.target_platforms.contains(&"wasmer".to_string()));
432
        assert!(analyzer.config.target_platforms.contains(&"browser".to_string()));
433
    }
434
    
435
    #[test]
436
    fn test_analyzer_strict_mode() {
437
        let mut config = create_test_config();
438
        config.strict_mode = true;
439
        let analyzer = PortabilityAnalyzer::new_with_config(config);
440
        assert!(analyzer.config.strict_mode);
441
        
442
        // Test non-strict mode
443
        let mut config2 = create_test_config();
444
        config2.strict_mode = false;
445
        let analyzer2 = PortabilityAnalyzer::new_with_config(config2);
446
        assert!(!analyzer2.config.strict_mode);
447
    }
448
    
449
    // ========== PortabilityReport Tests ==========
450
    
451
    #[test]
452
    fn test_portability_report_creation() {
453
        let report = PortabilityReport {
454
            component_info: create_test_component_info(),
455
            score: create_test_portability_score(),
456
            issues: vec![],
457
            recommendations: vec![],
458
            platform_support: HashMap::new(),
459
            feature_usage: FeatureUsage {
460
                core_features: HashSet::new(),
461
                proposal_features: HashSet::new(),
462
                platform_specific: HashMap::new(),
463
                compatibility: HashMap::new(),
464
            },
465
            size_analysis: SizeAnalysis {
466
                total_size: 0,
467
                code_size: 0,
468
                data_size: 0,
469
                custom_sections_size: 0,
470
                section_sizes: HashMap::new(),
471
                platform_limits: HashMap::new(),
472
            },
473
        };
474
        
475
        assert_eq!(report.component_info.name, "test_component");
476
        assert_eq!(report.score.overall_score, 0.85);
477
        assert!(report.issues.is_empty());
478
        assert!(report.recommendations.is_empty());
479
    }
480
    
481
    #[test]
482
    fn test_portability_report_with_issues() {
483
        let issue = CompatibilityIssue {
484
            severity: IssueSeverity::Warning,
485
            category: IssueCategory::FeatureNotSupported,
486
            affected_platforms: vec!["browser".to_string()],
487
            description: "Threading not supported".to_string(),
488
            fix_suggestion: Some("Use web workers".to_string()),
489
        };
490
        
491
        let report = PortabilityReport {
492
            component_info: create_test_component_info(),
493
            score: create_test_portability_score(),
494
            issues: vec![issue],
495
            recommendations: vec![],
496
            platform_support: HashMap::new(),
497
            feature_usage: FeatureUsage {
498
                core_features: HashSet::new(),
499
                proposal_features: HashSet::new(),
500
                platform_specific: HashMap::new(),
501
                compatibility: HashMap::new(),
502
            },
503
            size_analysis: SizeAnalysis {
504
                total_size: 0,
505
                code_size: 0,
506
                data_size: 0,
507
                custom_sections_size: 0,
508
                section_sizes: HashMap::new(),
509
                platform_limits: HashMap::new(),
510
            },
511
        };
512
        
513
        assert_eq!(report.issues.len(), 1);
514
        assert_eq!(report.issues[0].severity, IssueSeverity::Warning);
515
    }
516
    
517
    #[test]
518
    fn test_portability_report_serialization() {
519
        let report = PortabilityReport {
520
            component_info: create_test_component_info(),
521
            score: create_test_portability_score(),
522
            issues: vec![],
523
            recommendations: vec![],
524
            platform_support: HashMap::new(),
525
            feature_usage: FeatureUsage {
526
                core_features: HashSet::new(),
527
                proposal_features: HashSet::new(),
528
                platform_specific: HashMap::new(),
529
                compatibility: HashMap::new(),
530
            },
531
            size_analysis: SizeAnalysis {
532
                total_size: 0,
533
                code_size: 0,
534
                data_size: 0,
535
                custom_sections_size: 0,
536
                section_sizes: HashMap::new(),
537
                platform_limits: HashMap::new(),
538
            },
539
        };
540
        
541
        let json = serde_json::to_string(&report).unwrap();
542
        let deserialized: PortabilityReport = serde_json::from_str(&json).unwrap();
543
        
544
        assert_eq!(report.component_info.name, deserialized.component_info.name);
545
        assert_eq!(report.score.overall_score, deserialized.score.overall_score);
546
    }
547
    
548
    // ========== Integration Tests ==========
549
    
550
    #[test]
551
    fn test_full_portability_analysis_workflow() {
552
        // Test creating complete portability report
553
        let report = PortabilityReport {
554
            component_info: create_test_component_info(),
555
            score: create_test_portability_score(),
556
            issues: vec![
557
                CompatibilityIssue {
558
                    severity: IssueSeverity::Info,
559
                    category: IssueCategory::Performance,
560
                    affected_platforms: vec!["browser".to_string()],
561
                    description: "Performance may vary".to_string(),
562
                    fix_suggestion: None,
563
                },
564
            ],
565
            recommendations: vec![
566
                Recommendation {
567
                    priority: RecommendationPriority::Low,
568
                    title: "Consider optimization".to_string(),
569
                    description: "Optimize for browser platform".to_string(),
570
                    impact: 0.05,
571
                    platforms: vec!["browser".to_string()],
572
                },
573
            ],
574
            platform_support: HashMap::new(),
575
            feature_usage: FeatureUsage {
576
                core_features: HashSet::new(),
577
                proposal_features: HashSet::new(),
578
                platform_specific: HashMap::new(),
579
                compatibility: HashMap::new(),
580
            },
581
            size_analysis: SizeAnalysis {
582
                total_size: 10240,
583
                code_size: 6000,
584
                data_size: 2000,
585
                custom_sections_size: 1240,
586
                section_sizes: HashMap::new(),
587
                platform_limits: HashMap::new(),
588
            },
589
        };
590
        
591
        // Check report completeness
592
        assert!(!report.component_info.name.is_empty());
593
        assert!(report.score.overall_score >= 0.0);
594
        assert!(report.score.overall_score <= 1.0);
595
        assert_eq!(report.issues.len(), 1);
596
        assert_eq!(report.recommendations.len(), 1);
597
    }
598
    
599
    #[test]
600
    fn test_enum_variants() {
601
        // Test all IssueSeverity variants
602
        let severities = vec![
603
            IssueSeverity::Error,
604
            IssueSeverity::Warning,
605
            IssueSeverity::Info,
606
        ];
607
        for s in &severities {
608
            assert!(matches!(s, IssueSeverity::Error | IssueSeverity::Warning | IssueSeverity::Info));
609
        }
610
        
611
        // Test all IssueCategory variants
612
        let categories = [IssueCategory::ApiIncompatibility,
613
            IssueCategory::FeatureNotSupported,
614
            IssueCategory::SizeConstraint,
615
            IssueCategory::Performance,
616
            IssueCategory::Security,
617
            IssueCategory::Configuration];
618
        assert_eq!(categories.len(), 6);
619
        
620
        // Test RecommendationPriority variants
621
        let priorities = [RecommendationPriority::Low,
622
            RecommendationPriority::Medium,
623
            RecommendationPriority::High];
624
        assert_eq!(priorities.len(), 3);
625
        
626
        // Test SupportLevel variants
627
        let levels = [SupportLevel::Full,
628
            SupportLevel::Partial,
629
            SupportLevel::None];
630
        assert_eq!(levels.len(), 3);
631
    }
632
    
633
    #[test]
634
    fn test_complex_portability_score() {
635
        let mut platform_scores = HashMap::new();
636
        platform_scores.insert("wasmtime".to_string(), 1.0);
637
        platform_scores.insert("wasmer".to_string(), 0.95);
638
        platform_scores.insert("browser".to_string(), 0.75);
639
        platform_scores.insert("node".to_string(), 0.85);
640
        
641
        let mut feature_scores = HashMap::new();
642
        feature_scores.insert("memory".to_string(), 1.0);
643
        feature_scores.insert("tables".to_string(), 1.0);
644
        feature_scores.insert("threading".to_string(), 0.5);
645
        feature_scores.insert("simd".to_string(), 0.8);
646
        feature_scores.insert("bulk-memory".to_string(), 0.9);
647
        
648
        let score = PortabilityScore {
649
            overall_score: 0.875,
650
            platform_scores,
651
            feature_scores,
652
            api_compatibility: 0.92,
653
            size_efficiency: 0.95,
654
            performance_portability: 0.78,
655
            security_compliance: 1.0,
656
        };
657
        
658
        assert_eq!(score.platform_scores.len(), 4);
659
        assert_eq!(score.feature_scores.len(), 5);
660
        assert_eq!(score.security_compliance, 1.0);
661
    }
662
    
663
    #[test]
664
    fn test_edge_case_scores() {
665
        // Test minimum scores
666
        let min_score = PortabilityScore {
667
            overall_score: 0.0,
668
            platform_scores: HashMap::new(),
669
            feature_scores: HashMap::new(),
670
            api_compatibility: 0.0,
671
            size_efficiency: 0.0,
672
            performance_portability: 0.0,
673
            security_compliance: 0.0,
674
        };
675
        
676
        assert_eq!(min_score.overall_score, 0.0);
677
        assert!(min_score.platform_scores.is_empty());
678
        
679
        // Test maximum scores
680
        let mut perfect_platforms = HashMap::new();
681
        perfect_platforms.insert("all".to_string(), 1.0);
682
        
683
        let max_score = PortabilityScore {
684
            overall_score: 1.0,
685
            platform_scores: perfect_platforms,
686
            feature_scores: HashMap::new(),
687
            api_compatibility: 1.0,
688
            size_efficiency: 1.0,
689
            performance_portability: 1.0,
690
            security_compliance: 1.0,
691
        };
692
        
693
        assert_eq!(max_score.overall_score, 1.0);
694
        assert_eq!(max_score.api_compatibility, 1.0);
695
    }
696
    
697
    #[test]
698
    fn test_component_info_edge_cases() {
699
        // Test component with maximum values
700
        let mut max_features = HashSet::new();
701
        for i in 0..20 {
702
            max_features.insert(format!("feature_{i}"));
703
        }
704
        
705
        let large_component = ComponentInfo {
706
            name: "large_component".to_string(),
707
            version: "99.99.99".to_string(),
708
            size: usize::MAX,
709
            exports_count: 1000,
710
            imports_count: 500,
711
            features: max_features,
712
        };
713
        
714
        assert_eq!(large_component.features.len(), 20);
715
        assert_eq!(large_component.exports_count, 1000);
716
        assert_eq!(large_component.size, usize::MAX);
717
        
718
        // Test component with minimum values
719
        let minimal_component = ComponentInfo {
720
            name: String::new(),
721
            version: String::new(),
722
            size: 0,
723
            exports_count: 0,
724
            imports_count: 0,
725
            features: HashSet::new(),
726
        };
727
        
728
        assert!(minimal_component.name.is_empty());
729
        assert_eq!(minimal_component.size, 0);
730
    }
731
    
732
    #[test]
733
    fn test_platform_support_variations() {
734
        let support_variations = vec![
735
            PlatformSupport {
736
                platform: "wasmtime".to_string(),
737
                support_level: SupportLevel::Full,
738
                compatibility_score: 1.0,
739
                required_modifications: vec![],
740
                runtime_requirements: Some(">=1.0.0".to_string()),
741
            },
742
            PlatformSupport {
743
                platform: "wasmer".to_string(),
744
                support_level: SupportLevel::Partial,
745
                compatibility_score: 0.8,
746
                required_modifications: vec!["Remove SIMD".to_string()],
747
                runtime_requirements: Some(">=2.0.0".to_string()),
748
            },
749
            PlatformSupport {
750
                platform: "browser".to_string(),
751
                support_level: SupportLevel::None,
752
                compatibility_score: 0.0,
753
                required_modifications: vec!["Complete rewrite".to_string()],
754
                runtime_requirements: None,
755
            },
756
        ];
757
        
758
        assert_eq!(support_variations.len(), 3);
759
        assert_eq!(support_variations[0].support_level, SupportLevel::Full);
760
        assert_eq!(support_variations[1].support_level, SupportLevel::Partial);
761
        assert_eq!(support_variations[2].support_level, SupportLevel::None);
762
    }
763
    
764
    #[test]
765
    fn test_feature_usage_complex() {
766
        let mut core_features = HashSet::new();
767
        core_features.insert("memory".to_string());
768
        core_features.insert("tables".to_string());
769
        core_features.insert("globals".to_string());
770
        
771
        let mut proposal_features = HashSet::new();
772
        proposal_features.insert("threads".to_string());
773
        proposal_features.insert("simd".to_string());
774
        proposal_features.insert("reference-types".to_string());
775
        
776
        let mut platform_specific = HashMap::new();
777
        let mut browser_features = HashSet::new();
778
        browser_features.insert("webgl".to_string());
779
        platform_specific.insert("browser".to_string(), browser_features);
780
        
781
        let usage = FeatureUsage {
782
            core_features: core_features.clone(),
783
            proposal_features: proposal_features.clone(),
784
            platform_specific,
785
            compatibility: HashMap::new(),
786
        };
787
        
788
        assert_eq!(usage.core_features.len(), 3);
789
        assert_eq!(usage.proposal_features.len(), 3);
790
        assert_eq!(usage.platform_specific.len(), 1);
791
        assert!(usage.core_features.contains("memory"));
792
        assert!(usage.proposal_features.contains("threads"));
793
    }
794
    
795
    #[test]
796
    fn test_size_analysis_comprehensive() {
797
        let mut section_sizes = HashMap::new();
798
        section_sizes.insert("type".to_string(), 1024);
799
        section_sizes.insert("import".to_string(), 512);
800
        section_sizes.insert("function".to_string(), 256);
801
        section_sizes.insert("table".to_string(), 128);
802
        section_sizes.insert("memory".to_string(), 64);
803
        section_sizes.insert("global".to_string(), 32);
804
        section_sizes.insert("export".to_string(), 256);
805
        section_sizes.insert("start".to_string(), 8);
806
        section_sizes.insert("element".to_string(), 512);
807
        section_sizes.insert("code".to_string(), 8192);
808
        section_sizes.insert("data".to_string(), 4096);
809
        
810
        let mut platform_limits = HashMap::new();
811
        platform_limits.insert("browser".to_string(), 1024 * 1024 * 4); // 4MB
812
        platform_limits.insert("wasmtime".to_string(), 1024 * 1024 * 1024); // 1GB
813
        
814
        let analysis = SizeAnalysis {
815
            total_size: 15080,
816
            code_size: 8192,
817
            data_size: 4096,
818
            custom_sections_size: 0,
819
            section_sizes,
820
            platform_limits,
821
        };
822
        
823
        assert_eq!(analysis.section_sizes.len(), 11);
824
        assert_eq!(analysis.platform_limits.len(), 2);
825
        assert_eq!(*analysis.section_sizes.get("code").unwrap(), 8192);
826
        assert_eq!(*analysis.platform_limits.get("browser").unwrap(), 4_194_304);
827
    }
828
}
829
830
use anyhow::Result;
831
use serde::{Deserialize, Serialize};
832
use std::collections::{HashMap, HashSet};
833
use std::fmt;
834
use super::component::WasmComponent;
835
836
/// Portability analyzer for WASM components
837
pub struct PortabilityAnalyzer {
838
    /// Analysis configuration
839
    config: AnalysisConfig,
840
    
841
    /// Feature compatibility matrix
842
    compatibility_matrix: CompatibilityMatrix,
843
    
844
    /// Platform requirements
845
    platform_requirements: HashMap<String, PlatformRequirements>,
846
}
847
848
/// Portability score for a component
849
#[derive(Debug, Clone, Serialize, Deserialize)]
850
pub struct PortabilityScore {
851
    /// Overall portability score (0.0 - 1.0)
852
    pub overall_score: f64,
853
    
854
    /// Platform-specific scores
855
    pub platform_scores: HashMap<String, f64>,
856
    
857
    /// Feature compatibility scores
858
    pub feature_scores: HashMap<String, f64>,
859
    
860
    /// API compatibility score
861
    pub api_compatibility: f64,
862
    
863
    /// Size efficiency score
864
    pub size_efficiency: f64,
865
    
866
    /// Performance portability score
867
    pub performance_portability: f64,
868
    
869
    /// Safety compliance score
870
    pub security_compliance: f64,
871
}
872
873
/// Detailed portability report
874
#[derive(Debug, Clone, Serialize, Deserialize)]
875
pub struct PortabilityReport {
876
    /// Component information
877
    pub component_info: ComponentInfo,
878
    
879
    /// Portability score
880
    pub score: PortabilityScore,
881
    
882
    /// Compatibility issues
883
    pub issues: Vec<CompatibilityIssue>,
884
    
885
    /// Recommendations
886
    pub recommendations: Vec<Recommendation>,
887
    
888
    /// Platform support matrix
889
    pub platform_support: HashMap<String, PlatformSupport>,
890
    
891
    /// Feature usage analysis
892
    pub feature_usage: FeatureUsage,
893
    
894
    /// Size analysis
895
    pub size_analysis: SizeAnalysis,
896
}
897
898
/// Analysis configuration
899
#[derive(Debug, Clone, Serialize, Deserialize)]
900
pub struct AnalysisConfig {
901
    /// Target platforms to analyze
902
    pub target_platforms: Vec<String>,
903
    
904
    /// Check API compatibility
905
    pub check_api_compatibility: bool,
906
    
907
    /// Check size constraints
908
    pub check_size_constraints: bool,
909
    
910
    /// Check performance characteristics
911
    pub check_performance: bool,
912
    
913
    /// Check safety requirements
914
    pub check_security: bool,
915
    
916
    /// Strict mode (fail on any incompatibility)
917
    pub strict_mode: bool,
918
}
919
920
/// Component information
921
#[derive(Debug, Clone, Serialize, Deserialize)]
922
pub struct ComponentInfo {
923
    /// Component name
924
    pub name: String,
925
    
926
    /// Component version
927
    pub version: String,
928
    
929
    /// Component size in bytes
930
    pub size: usize,
931
    
932
    /// Number of exports
933
    pub exports_count: usize,
934
    
935
    /// Number of imports
936
    pub imports_count: usize,
937
    
938
    /// Used features
939
    pub features: HashSet<String>,
940
}
941
942
/// Compatibility issue
943
#[derive(Debug, Clone, Serialize, Deserialize)]
944
pub struct CompatibilityIssue {
945
    /// Issue severity
946
    pub severity: IssueSeverity,
947
    
948
    /// Issue category
949
    pub category: IssueCategory,
950
    
951
    /// Affected platforms
952
    pub affected_platforms: Vec<String>,
953
    
954
    /// Issue description
955
    pub description: String,
956
    
957
    /// Suggested fix
958
    pub fix_suggestion: Option<String>,
959
}
960
961
/// Issue severity levels
962
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
963
pub enum IssueSeverity {
964
    /// Informational
965
    Info,
966
    /// Warning
967
    Warning,
968
    /// Error (blocks deployment)
969
    Error,
970
    /// Critical (safety or major functionality issue)
971
    Critical,
972
}
973
974
/// Issue categories
975
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
976
pub enum IssueCategory {
977
    /// API incompatibility
978
    ApiIncompatibility,
979
    /// Feature not supported
980
    FeatureNotSupported,
981
    /// Size constraint violation
982
    SizeConstraint,
983
    /// Performance concern
984
    Performance,
985
    /// Safety concern
986
    Security,
987
    /// Configuration issue
988
    Configuration,
989
}
990
991
/// Recommendation for improving portability
992
#[derive(Debug, Clone, Serialize, Deserialize)]
993
pub struct Recommendation {
994
    /// Recommendation priority
995
    pub priority: RecommendationPriority,
996
    
997
    /// Recommendation title
998
    pub title: String,
999
    
1000
    /// Detailed description
1001
    pub description: String,
1002
    
1003
    /// Expected impact on portability score
1004
    pub impact: f64,
1005
    
1006
    /// Affected platforms
1007
    pub platforms: Vec<String>,
1008
}
1009
1010
impl fmt::Display for Recommendation {
1011
0
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1012
0
        write!(f, "{}", self.title)
1013
0
    }
1014
}
1015
1016
/// Recommendation priority levels
1017
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
1018
pub enum RecommendationPriority {
1019
    /// Low priority
1020
    Low,
1021
    /// Medium priority
1022
    Medium,
1023
    /// High priority
1024
    High,
1025
    /// Critical (must fix)
1026
    Critical,
1027
}
1028
1029
/// Platform support information
1030
#[derive(Debug, Clone, Serialize, Deserialize)]
1031
pub struct PlatformSupport {
1032
    /// Platform name
1033
    pub platform: String,
1034
    
1035
    /// Support level
1036
    pub support_level: SupportLevel,
1037
    
1038
    /// Compatibility score (0.0 - 1.0)
1039
    pub compatibility_score: f64,
1040
    
1041
    /// Required modifications
1042
    pub required_modifications: Vec<String>,
1043
    
1044
    /// Runtime version requirements
1045
    pub runtime_requirements: Option<String>,
1046
}
1047
1048
/// Support levels for platforms
1049
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1050
pub enum SupportLevel {
1051
    /// Full support
1052
    Full,
1053
    /// Partial support (some features missing)
1054
    Partial,
1055
    /// Limited support (major limitations)
1056
    Limited,
1057
    /// No support
1058
    None,
1059
}
1060
1061
/// Feature usage analysis
1062
#[derive(Debug, Clone, Serialize, Deserialize)]
1063
pub struct FeatureUsage {
1064
    /// Core WASM features used
1065
    pub core_features: HashSet<String>,
1066
    
1067
    /// Proposal features used
1068
    pub proposal_features: HashSet<String>,
1069
    
1070
    /// Platform-specific features
1071
    pub platform_specific: HashMap<String, HashSet<String>>,
1072
    
1073
    /// Feature compatibility matrix
1074
    pub compatibility: HashMap<String, Vec<String>>,
1075
}
1076
1077
/// Size analysis for portability
1078
#[derive(Debug, Clone, Serialize, Deserialize)]
1079
pub struct SizeAnalysis {
1080
    /// Total component size
1081
    pub total_size: usize,
1082
    
1083
    /// Code size
1084
    pub code_size: usize,
1085
    
1086
    /// Data size
1087
    pub data_size: usize,
1088
    
1089
    /// Custom sections size
1090
    pub custom_sections_size: usize,
1091
    
1092
    /// Size by section
1093
    pub section_sizes: HashMap<String, usize>,
1094
    
1095
    /// Platform size limits
1096
    pub platform_limits: HashMap<String, usize>,
1097
}
1098
1099
/// Platform requirements
1100
#[derive(Debug, Clone)]
1101
struct PlatformRequirements {
1102
    /// Required features
1103
    required_features: HashSet<String>,
1104
    
1105
    /// Optional features
1106
    optional_features: HashSet<String>,
1107
    
1108
    /// Incompatible features
1109
    incompatible_features: HashSet<String>,
1110
    
1111
    /// Size limit in bytes
1112
    size_limit: Option<usize>,
1113
    
1114
    /// API requirements
1115
    _api_requirements: HashSet<String>,
1116
}
1117
1118
/// Feature compatibility matrix
1119
struct CompatibilityMatrix {
1120
    /// Feature support by platform
1121
    support: HashMap<String, HashMap<String, bool>>,
1122
}
1123
1124
impl Default for AnalysisConfig {
1125
0
    fn default() -> Self {
1126
0
        Self {
1127
0
            target_platforms: vec![
1128
0
                "cloudflare-workers".to_string(),
1129
0
                "fastly-compute".to_string(),
1130
0
                "aws-lambda".to_string(),
1131
0
                "browser".to_string(),
1132
0
                "nodejs".to_string(),
1133
0
                "wasmtime".to_string(),
1134
0
            ],
1135
0
            check_api_compatibility: true,
1136
0
            check_size_constraints: true,
1137
0
            check_performance: true,
1138
0
            check_security: true,
1139
0
            strict_mode: false,
1140
0
        }
1141
0
    }
1142
}
1143
1144
impl Default for PortabilityAnalyzer {
1145
0
    fn default() -> Self {
1146
0
        Self::new()
1147
0
    }
1148
}
1149
1150
impl PortabilityAnalyzer {
1151
    /// Create a new portability analyzer with default config
1152
0
    pub fn new() -> Self {
1153
0
        Self {
1154
0
            config: AnalysisConfig::default(),
1155
0
            compatibility_matrix: Self::build_compatibility_matrix(),
1156
0
            platform_requirements: Self::build_platform_requirements(),
1157
0
        }
1158
0
    }
1159
    
1160
    /// Create a new portability analyzer with specific config
1161
0
    pub fn new_with_config(config: AnalysisConfig) -> Self {
1162
0
        Self {
1163
0
            config,
1164
0
            compatibility_matrix: Self::build_compatibility_matrix(),
1165
0
            platform_requirements: Self::build_platform_requirements(),
1166
0
        }
1167
0
    }
1168
    
1169
    /// Analyze a WASM component's portability
1170
0
    pub fn analyze(&self, component: &WasmComponent) -> Result<PortabilityReport> {
1171
        // Extract component information
1172
0
        let component_info = self.extract_component_info(component)?;
1173
        
1174
        // Calculate portability scores
1175
0
        let score = self.calculate_scores(&component_info)?;
1176
        
1177
        // Find compatibility issues
1178
0
        let issues = self.find_issues(&component_info)?;
1179
        
1180
        // Generate recommendations
1181
0
        let recommendations = self.generate_recommendations(&component_info, &issues)?;
1182
        
1183
        // Analyze platform support
1184
0
        let platform_support = self.analyze_platform_support(&component_info)?;
1185
        
1186
        // Analyze feature usage
1187
0
        let feature_usage = self.analyze_feature_usage(&component_info)?;
1188
        
1189
        // Analyze size
1190
0
        let size_analysis = self.analyze_size(component)?;
1191
        
1192
0
        Ok(PortabilityReport {
1193
0
            component_info,
1194
0
            score,
1195
0
            issues,
1196
0
            recommendations,
1197
0
            platform_support,
1198
0
            feature_usage,
1199
0
            size_analysis,
1200
0
        })
1201
0
    }
1202
    
1203
0
    fn extract_component_info(&self, component: &WasmComponent) -> Result<ComponentInfo> {
1204
0
        let mut features = HashSet::new();
1205
        
1206
        // Analyze bytecode to detect used features
1207
        // In a real implementation, this would parse the WASM module
1208
0
        if component.bytecode.len() > 1024 * 100 {
1209
0
            features.insert("large-module".to_string());
1210
0
        }
1211
        
1212
0
        Ok(ComponentInfo {
1213
0
            name: component.name.clone(),
1214
0
            version: component.version.clone(),
1215
0
            size: component.bytecode.len(),
1216
0
            exports_count: component.exports.len(),
1217
0
            imports_count: component.imports.len(),
1218
0
            features,
1219
0
        })
1220
0
    }
1221
    
1222
0
    fn calculate_scores(&self, info: &ComponentInfo) -> Result<PortabilityScore> {
1223
0
        let mut platform_scores = HashMap::new();
1224
        
1225
        // Calculate scores for each platform
1226
0
        for platform in &self.config.target_platforms {
1227
0
            let score = self.calculate_platform_score(info, platform)?;
1228
0
            platform_scores.insert(platform.clone(), score);
1229
        }
1230
        
1231
        // Calculate feature scores
1232
0
        let feature_scores = self.calculate_feature_scores(info)?;
1233
        
1234
        // Calculate other scores
1235
0
        let api_compatibility = self.calculate_api_compatibility(info)?;
1236
0
        let size_efficiency = self.calculate_size_efficiency(info)?;
1237
0
        let performance_portability = self.calculate_performance_portability(info)?;
1238
0
        let security_compliance = self.calculate_security_compliance(info)?;
1239
        
1240
        // Calculate overall score
1241
0
        let overall_score = Self::calculate_overall_score(
1242
0
            &platform_scores,
1243
0
            &feature_scores,
1244
0
            api_compatibility,
1245
0
            size_efficiency,
1246
0
            performance_portability,
1247
0
            security_compliance,
1248
        );
1249
        
1250
0
        Ok(PortabilityScore {
1251
0
            overall_score,
1252
0
            platform_scores,
1253
0
            feature_scores,
1254
0
            api_compatibility,
1255
0
            size_efficiency,
1256
0
            performance_portability,
1257
0
            security_compliance,
1258
0
        })
1259
0
    }
1260
    
1261
0
    fn calculate_platform_score(&self, info: &ComponentInfo, platform: &str) -> Result<f64> {
1262
0
        let requirements = self.platform_requirements.get(platform);
1263
        
1264
0
        if let Some(reqs) = requirements {
1265
0
            let mut score = 1.0;
1266
            
1267
            // Check size constraints
1268
0
            if let Some(limit) = reqs.size_limit {
1269
0
                if info.size > limit {
1270
0
                    score *= 0.5; // Penalty for exceeding size limit
1271
0
                }
1272
0
            }
1273
            
1274
            // Check feature compatibility
1275
0
            for feature in &info.features {
1276
0
                if reqs.incompatible_features.contains(feature) {
1277
0
                    score *= 0.0; // Incompatible feature
1278
0
                } else if !reqs.required_features.contains(feature) && !reqs.optional_features.contains(feature) {
1279
0
                    score *= 0.8; // Unknown feature
1280
0
                }
1281
            }
1282
            
1283
0
            Ok(score)
1284
        } else {
1285
0
            Ok(0.5) // Unknown platform
1286
        }
1287
0
    }
1288
    
1289
0
    fn calculate_feature_scores(&self, info: &ComponentInfo) -> Result<HashMap<String, f64>> {
1290
0
        let mut scores = HashMap::new();
1291
        
1292
        // Score each feature based on platform support
1293
0
        for feature in &info.features {
1294
0
            let mut support_count = 0;
1295
0
            let total_platforms = self.config.target_platforms.len();
1296
            
1297
0
            for platform in &self.config.target_platforms {
1298
0
                if let Some(platform_features) = self.compatibility_matrix.support.get(platform) {
1299
0
                    if platform_features.get(feature).copied().unwrap_or(false) {
1300
0
                        support_count += 1;
1301
0
                    }
1302
0
                }
1303
            }
1304
            
1305
0
            let score = f64::from(support_count) / total_platforms as f64;
1306
0
            scores.insert(feature.clone(), score);
1307
        }
1308
        
1309
0
        Ok(scores)
1310
0
    }
1311
    
1312
0
    fn calculate_api_compatibility(&self, _info: &ComponentInfo) -> Result<f64> {
1313
        // Check if APIs used are compatible across platforms
1314
        // Simplified implementation
1315
0
        Ok(0.9)
1316
0
    }
1317
    
1318
0
    fn calculate_size_efficiency(&self, info: &ComponentInfo) -> Result<f64> {
1319
        // Score based on component size
1320
0
        let size_kb = info.size as f64 / 1024.0;
1321
        
1322
0
        if size_kb < 50.0 {
1323
0
            Ok(1.0)
1324
0
        } else if size_kb < 100.0 {
1325
0
            Ok(0.9)
1326
0
        } else if size_kb < 500.0 {
1327
0
            Ok(0.7)
1328
0
        } else if size_kb < 1000.0 {
1329
0
            Ok(0.5)
1330
        } else {
1331
0
            Ok(0.3)
1332
        }
1333
0
    }
1334
    
1335
0
    fn calculate_performance_portability(&self, _info: &ComponentInfo) -> Result<f64> {
1336
        // Analyze performance characteristics
1337
        // Simplified implementation
1338
0
        Ok(0.85)
1339
0
    }
1340
    
1341
0
    fn calculate_security_compliance(&self, _info: &ComponentInfo) -> Result<f64> {
1342
        // Check safety requirements
1343
        // Simplified implementation
1344
0
        Ok(0.95)
1345
0
    }
1346
    
1347
0
    fn calculate_overall_score(
1348
0
        platform_scores: &HashMap<String, f64>,
1349
0
        feature_scores: &HashMap<String, f64>,
1350
0
        api_compatibility: f64,
1351
0
        size_efficiency: f64,
1352
0
        performance_portability: f64,
1353
0
        security_compliance: f64,
1354
0
    ) -> f64 {
1355
0
        let platform_avg = if platform_scores.is_empty() {
1356
0
            0.0
1357
        } else {
1358
0
            platform_scores.values().sum::<f64>() / platform_scores.len() as f64
1359
        };
1360
        
1361
0
        let feature_avg = if feature_scores.is_empty() {
1362
0
            1.0
1363
        } else {
1364
0
            feature_scores.values().sum::<f64>() / feature_scores.len() as f64
1365
        };
1366
        
1367
        // Weighted average
1368
0
        platform_avg * 0.3 +
1369
0
         feature_avg * 0.2 +
1370
0
         api_compatibility * 0.2 +
1371
0
         size_efficiency * 0.1 +
1372
0
         performance_portability * 0.1 +
1373
0
         security_compliance * 0.1
1374
0
    }
1375
    
1376
0
    fn find_issues(&self, info: &ComponentInfo) -> Result<Vec<CompatibilityIssue>> {
1377
0
        let mut issues = Vec::new();
1378
        
1379
        // Check size constraints
1380
0
        for platform in &self.config.target_platforms {
1381
0
            if let Some(reqs) = self.platform_requirements.get(platform) {
1382
0
                if let Some(limit) = reqs.size_limit {
1383
0
                    if info.size > limit {
1384
0
                        issues.push(CompatibilityIssue {
1385
0
                            severity: IssueSeverity::Warning,
1386
0
                            category: IssueCategory::SizeConstraint,
1387
0
                            affected_platforms: vec![platform.clone()],
1388
0
                            description: format!(
1389
0
                                "Component size ({} KB) exceeds {} platform limit ({} KB)",
1390
0
                                info.size / 1024,
1391
0
                                platform,
1392
0
                                limit / 1024
1393
0
                            ),
1394
0
                            fix_suggestion: Some("Consider optimizing component size or splitting functionality".to_string()),
1395
0
                        });
1396
0
                    }
1397
0
                }
1398
0
            }
1399
        }
1400
        
1401
0
        Ok(issues)
1402
0
    }
1403
    
1404
0
    fn generate_recommendations(&self, info: &ComponentInfo, issues: &[CompatibilityIssue]) -> Result<Vec<Recommendation>> {
1405
0
        let mut recommendations = Vec::new();
1406
        
1407
        // Size optimization recommendation
1408
0
        if info.size > 100 * 1024 {
1409
0
            recommendations.push(Recommendation {
1410
0
                priority: RecommendationPriority::High,
1411
0
                title: "Optimize component size".to_string(),
1412
0
                description: "Component size can be reduced through optimization techniques".to_string(),
1413
0
                impact: 0.2,
1414
0
                platforms: self.config.target_platforms.clone(),
1415
0
            });
1416
0
        }
1417
        
1418
        // Feature compatibility recommendations
1419
0
        for issue in issues {
1420
0
            if issue.category == IssueCategory::FeatureNotSupported {
1421
0
                recommendations.push(Recommendation {
1422
0
                    priority: RecommendationPriority::Critical,
1423
0
                    title: "Remove incompatible features".to_string(),
1424
0
                    description: issue.description.clone(),
1425
0
                    impact: 0.3,
1426
0
                    platforms: issue.affected_platforms.clone(),
1427
0
                });
1428
0
            }
1429
        }
1430
        
1431
0
        Ok(recommendations)
1432
0
    }
1433
    
1434
0
    fn analyze_platform_support(&self, info: &ComponentInfo) -> Result<HashMap<String, PlatformSupport>> {
1435
0
        let mut support = HashMap::new();
1436
        
1437
0
        for platform in &self.config.target_platforms {
1438
0
            let score = self.calculate_platform_score(info, platform)?;
1439
            
1440
0
            let support_level = if score >= 0.9 {
1441
0
                SupportLevel::Full
1442
0
            } else if score >= 0.7 {
1443
0
                SupportLevel::Partial
1444
0
            } else if score >= 0.3 {
1445
0
                SupportLevel::Limited
1446
            } else {
1447
0
                SupportLevel::None
1448
            };
1449
            
1450
0
            support.insert(platform.clone(), PlatformSupport {
1451
0
                platform: platform.clone(),
1452
0
                support_level,
1453
0
                compatibility_score: score,
1454
0
                required_modifications: Vec::new(),
1455
0
                runtime_requirements: None,
1456
0
            });
1457
        }
1458
        
1459
0
        Ok(support)
1460
0
    }
1461
    
1462
0
    fn analyze_feature_usage(&self, info: &ComponentInfo) -> Result<FeatureUsage> {
1463
0
        Ok(FeatureUsage {
1464
0
            core_features: info.features.clone(),
1465
0
            proposal_features: HashSet::new(),
1466
0
            platform_specific: HashMap::new(),
1467
0
            compatibility: HashMap::new(),
1468
0
        })
1469
0
    }
1470
    
1471
0
    fn analyze_size(&self, component: &WasmComponent) -> Result<SizeAnalysis> {
1472
0
        let mut section_sizes = HashMap::new();
1473
        
1474
        // Add custom sections
1475
0
        for (name, data) in &component.custom_sections {
1476
0
            section_sizes.insert(name.clone(), data.len());
1477
0
        }
1478
        
1479
0
        let custom_sections_size: usize = component.custom_sections.values().map(std::vec::Vec::len).sum();
1480
        
1481
0
        Ok(SizeAnalysis {
1482
0
            total_size: component.bytecode.len(),
1483
0
            code_size: component.bytecode.len() - custom_sections_size,
1484
0
            data_size: 0,
1485
0
            custom_sections_size,
1486
0
            section_sizes,
1487
0
            platform_limits: self.get_platform_limits(),
1488
0
        })
1489
0
    }
1490
    
1491
0
    fn get_platform_limits(&self) -> HashMap<String, usize> {
1492
0
        let mut limits = HashMap::new();
1493
0
        limits.insert("cloudflare-workers".to_string(), 10 * 1024 * 1024); // 10MB
1494
0
        limits.insert("fastly-compute".to_string(), 50 * 1024 * 1024);    // 50MB
1495
0
        limits.insert("aws-lambda".to_string(), 250 * 1024 * 1024);       // 250MB
1496
0
        limits.insert("browser".to_string(), 100 * 1024 * 1024);          // 100MB
1497
0
        limits
1498
0
    }
1499
    
1500
0
    fn build_compatibility_matrix() -> CompatibilityMatrix {
1501
0
        let mut support = HashMap::new();
1502
        
1503
        // Cloudflare Workers feature support
1504
0
        let mut cloudflare = HashMap::new();
1505
0
        cloudflare.insert("simd".to_string(), false);
1506
0
        cloudflare.insert("threads".to_string(), false);
1507
0
        cloudflare.insert("bulk-memory".to_string(), true);
1508
0
        cloudflare.insert("reference-types".to_string(), true);
1509
0
        support.insert("cloudflare-workers".to_string(), cloudflare);
1510
        
1511
        // Browser feature support
1512
0
        let mut browser = HashMap::new();
1513
0
        browser.insert("simd".to_string(), true);
1514
0
        browser.insert("threads".to_string(), true);
1515
0
        browser.insert("bulk-memory".to_string(), true);
1516
0
        browser.insert("reference-types".to_string(), true);
1517
0
        support.insert("browser".to_string(), browser);
1518
        
1519
0
        CompatibilityMatrix { support }
1520
0
    }
1521
    
1522
0
    fn build_platform_requirements() -> HashMap<String, PlatformRequirements> {
1523
0
        let mut requirements = HashMap::new();
1524
        
1525
        // Cloudflare Workers requirements
1526
0
        requirements.insert("cloudflare-workers".to_string(), PlatformRequirements {
1527
0
            required_features: HashSet::new(),
1528
0
            optional_features: HashSet::from(["bulk-memory".to_string(), "reference-types".to_string()]),
1529
0
            incompatible_features: HashSet::from(["threads".to_string()]),
1530
0
            size_limit: Some(10 * 1024 * 1024),
1531
0
            _api_requirements: HashSet::new(),
1532
0
        });
1533
        
1534
        // Browser requirements
1535
0
        requirements.insert("browser".to_string(), PlatformRequirements {
1536
0
            required_features: HashSet::new(),
1537
0
            optional_features: HashSet::from(["simd".to_string(), "threads".to_string()]),
1538
0
            incompatible_features: HashSet::new(),
1539
0
            size_limit: Some(100 * 1024 * 1024),
1540
0
            _api_requirements: HashSet::new(),
1541
0
        });
1542
        
1543
0
        requirements
1544
0
    }
1545
}