Coverage Report

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