use super::*;
use std::path::PathBuf;
#[test]
fn test_quality_grade_from_rust_project_score_a_plus() {
assert_eq!(QualityGrade::from_rust_project_score(114), QualityGrade::APlus);
assert_eq!(QualityGrade::from_rust_project_score(110), QualityGrade::APlus);
assert_eq!(QualityGrade::from_rust_project_score(105), QualityGrade::APlus);
}
#[test]
fn test_quality_grade_from_rust_project_score_a() {
assert_eq!(QualityGrade::from_rust_project_score(104), QualityGrade::A);
assert_eq!(QualityGrade::from_rust_project_score(100), QualityGrade::A);
assert_eq!(QualityGrade::from_rust_project_score(95), QualityGrade::A);
}
#[test]
fn test_quality_grade_from_rust_project_score_a_minus() {
assert_eq!(QualityGrade::from_rust_project_score(94), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_rust_project_score(90), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_rust_project_score(85), QualityGrade::AMinus);
}
#[test]
fn test_quality_grade_from_rust_project_score_below() {
assert_eq!(QualityGrade::from_rust_project_score(84), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_rust_project_score(75), QualityGrade::B);
assert_eq!(QualityGrade::from_rust_project_score(65), QualityGrade::C);
assert_eq!(QualityGrade::from_rust_project_score(55), QualityGrade::D);
assert_eq!(QualityGrade::from_rust_project_score(40), QualityGrade::F);
}
#[test]
fn test_quality_grade_from_repo_score_a_plus() {
assert_eq!(QualityGrade::from_repo_score(110), QualityGrade::APlus);
assert_eq!(QualityGrade::from_repo_score(100), QualityGrade::APlus);
assert_eq!(QualityGrade::from_repo_score(95), QualityGrade::APlus);
}
#[test]
fn test_quality_grade_from_readme_score() {
assert_eq!(QualityGrade::from_readme_score(20), QualityGrade::APlus);
assert_eq!(QualityGrade::from_readme_score(18), QualityGrade::APlus);
assert_eq!(QualityGrade::from_readme_score(17), QualityGrade::A);
assert_eq!(QualityGrade::from_readme_score(15), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_readme_score(12), QualityGrade::BPlus);
}
#[test]
fn test_quality_grade_from_sqi() {
assert_eq!(QualityGrade::from_sqi(98.5), QualityGrade::APlus);
assert_eq!(QualityGrade::from_sqi(92.0), QualityGrade::A);
assert_eq!(QualityGrade::from_sqi(87.0), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_sqi(75.0), QualityGrade::B);
}
#[test]
fn test_quality_grade_is_release_ready() {
assert!(QualityGrade::APlus.is_release_ready());
assert!(QualityGrade::A.is_release_ready());
assert!(QualityGrade::AMinus.is_release_ready());
assert!(!QualityGrade::BPlus.is_release_ready());
assert!(!QualityGrade::B.is_release_ready());
assert!(!QualityGrade::F.is_release_ready());
}
#[test]
fn test_quality_grade_is_a_plus() {
assert!(QualityGrade::APlus.is_a_plus());
assert!(!QualityGrade::A.is_a_plus());
assert!(!QualityGrade::AMinus.is_a_plus());
}
#[test]
fn test_quality_grade_symbol() {
assert_eq!(QualityGrade::APlus.symbol(), "A+");
assert_eq!(QualityGrade::A.symbol(), "A");
assert_eq!(QualityGrade::AMinus.symbol(), "A-");
assert_eq!(QualityGrade::BPlus.symbol(), "B+");
assert_eq!(QualityGrade::F.symbol(), "F");
}
#[test]
fn test_quality_grade_icon() {
assert_eq!(QualityGrade::APlus.icon(), "✅");
assert_eq!(QualityGrade::A.icon(), "⚠️");
assert_eq!(QualityGrade::AMinus.icon(), "⚠️");
assert_eq!(QualityGrade::BPlus.icon(), "❌");
}
#[test]
fn test_quality_grade_display() {
assert_eq!(format!("{}", QualityGrade::APlus), "A+");
assert_eq!(format!("{}", QualityGrade::AMinus), "A-");
}
#[test]
fn test_score_percentage() {
let score = Score::new(85, 100, QualityGrade::AMinus);
assert!((score.percentage() - 85.0).abs() < f64::EPSILON);
let score_zero_max = Score::new(0, 0, QualityGrade::F);
assert!((score_zero_max.percentage() - 0.0).abs() < f64::EPSILON);
}
#[test]
fn test_score_normalized() {
let score = Score::new(105, 114, QualityGrade::APlus);
let normalized = score.normalized();
assert!(normalized > 90.0 && normalized < 93.0);
}
#[test]
fn test_image_format_from_extension() {
assert_eq!(ImageFormat::from_extension("png"), Some(ImageFormat::Png));
assert_eq!(ImageFormat::from_extension("PNG"), Some(ImageFormat::Png));
assert_eq!(ImageFormat::from_extension("jpg"), Some(ImageFormat::Jpg));
assert_eq!(ImageFormat::from_extension("jpeg"), Some(ImageFormat::Jpg));
assert_eq!(ImageFormat::from_extension("webp"), Some(ImageFormat::WebP));
assert_eq!(ImageFormat::from_extension("svg"), Some(ImageFormat::Svg));
assert_eq!(ImageFormat::from_extension("gif"), None);
}
#[test]
fn test_image_format_extension() {
assert_eq!(ImageFormat::Png.extension(), "png");
assert_eq!(ImageFormat::Jpg.extension(), "jpg");
assert_eq!(ImageFormat::WebP.extension(), "webp");
assert_eq!(ImageFormat::Svg.extension(), "svg");
}
#[test]
fn test_hero_image_missing() {
let result = HeroImageResult::missing();
assert!(!result.present);
assert!(!result.valid);
assert!(result.path.is_none());
assert!(!result.issues.is_empty());
}
#[test]
fn test_hero_image_found() {
let result = HeroImageResult::found(PathBuf::from("docs/hero.png"), ImageFormat::Png);
assert!(result.present);
assert!(result.valid);
assert_eq!(result.path, Some(PathBuf::from("docs/hero.png")));
assert_eq!(result.format, Some(ImageFormat::Png));
}
#[test]
fn test_hero_image_detect_missing() {
let temp_dir = std::env::temp_dir().join("test_hero_missing");
let _ = std::fs::create_dir_all(&temp_dir);
let result = HeroImageResult::detect(&temp_dir);
assert!(!result.present);
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_hero_image_detect_docs_png() {
let temp_dir = std::env::temp_dir().join("test_hero_docs_png");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(temp_dir.join("docs")).unwrap();
let png_data = vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A];
std::fs::write(temp_dir.join("docs/hero.png"), &png_data).unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert_eq!(result.format, Some(ImageFormat::Png));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_hero_image_detect_docs_svg() {
let temp_dir = std::env::temp_dir().join("test_hero_docs_svg");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(temp_dir.join("docs")).unwrap();
std::fs::write(temp_dir.join("docs/hero.svg"), "<svg></svg>").unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert_eq!(result.format, Some(ImageFormat::Svg));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_hero_image_detect_assets() {
let temp_dir = std::env::temp_dir().join("test_hero_assets");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(temp_dir.join("assets")).unwrap();
std::fs::write(temp_dir.join("assets/hero.webp"), [0u8; 100]).unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert_eq!(result.format, Some(ImageFormat::WebP));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_hero_image_detect_from_readme() {
let temp_dir = std::env::temp_dir().join("test_hero_readme");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(&temp_dir).unwrap();
std::fs::write(temp_dir.join("README.md"), "# Test\n\n").unwrap();
std::fs::write(temp_dir.join("hero_img.png"), [0u8; 100]).unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert_eq!(result.format, Some(ImageFormat::Png));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_hero_image_detect_readme_html_img() {
let temp_dir = std::env::temp_dir().join("test_hero_html");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(&temp_dir).unwrap();
std::fs::write(temp_dir.join("README.md"), "# Test\n<img src=\"banner.jpg\" alt=\"banner\">\n")
.unwrap();
std::fs::write(temp_dir.join("banner.jpg"), [0u8; 100]).unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert_eq!(result.format, Some(ImageFormat::Jpg));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_hero_image_detect_readme_external_url_skipped() {
let temp_dir = std::env::temp_dir().join("test_hero_external");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(&temp_dir).unwrap();
std::fs::write(temp_dir.join("README.md"), "# Test\n\n")
.unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(!result.present);
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_hero_image_validate_large_file() {
let temp_dir = std::env::temp_dir().join("test_hero_large");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(temp_dir.join("docs")).unwrap();
let large_data = vec![0u8; 3 * 1024 * 1024];
std::fs::write(temp_dir.join("docs/hero.png"), &large_data).unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert!(!result.valid); assert!(!result.issues.is_empty());
assert!(result.issues[0].contains("too large"));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_hero_image_priority_order() {
let temp_dir = std::env::temp_dir().join("test_hero_priority");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(temp_dir.join("docs")).unwrap();
std::fs::create_dir_all(temp_dir.join("assets")).unwrap();
std::fs::write(temp_dir.join("docs/hero.png"), [0u8; 100]).unwrap();
std::fs::write(temp_dir.join("assets/hero.svg"), "<svg></svg>").unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert_eq!(result.format, Some(ImageFormat::Png));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_hero_image_svg_priority_in_docs() {
let temp_dir = std::env::temp_dir().join("test_hero_svg_priority");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(temp_dir.join("docs")).unwrap();
std::fs::write(temp_dir.join("docs/hero.svg"), "<svg></svg>").unwrap();
std::fs::write(temp_dir.join("docs/hero.png"), [0u8; 100]).unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert_eq!(result.format, Some(ImageFormat::Svg));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_quality_issue_creation() {
let issue = QualityIssue::new("test_issue", "Test message", IssueSeverity::Error);
assert_eq!(issue.issue_type, "test_issue");
assert_eq!(issue.message, "Test message");
assert_eq!(issue.severity, IssueSeverity::Error);
assert!(issue.recommendation.is_none());
}
#[test]
fn test_quality_issue_with_recommendation() {
let issue =
QualityIssue::new("test", "msg", IssueSeverity::Warning).with_recommendation("Fix it");
assert_eq!(issue.recommendation, Some("Fix it".to_string()));
}
#[test]
fn test_quality_issue_score_below_threshold() {
let issue = QualityIssue::score_below_threshold("rust_project", 80, 85);
assert!(issue.message.contains("80"));
assert!(issue.message.contains("85"));
assert_eq!(issue.severity, IssueSeverity::Error);
}
#[test]
fn test_quality_issue_missing_hero() {
let issue = QualityIssue::missing_hero_image();
assert!(issue.message.contains("hero"));
assert!(issue.recommendation.is_some());
}
#[test]
fn test_stack_layer_from_component() {
assert_eq!(StackLayer::from_component("trueno"), StackLayer::Compute);
assert_eq!(StackLayer::from_component("trueno-viz"), StackLayer::Compute);
assert_eq!(StackLayer::from_component("aprender"), StackLayer::Ml);
assert_eq!(StackLayer::from_component("depyler"), StackLayer::Transpilers);
assert_eq!(StackLayer::from_component("batuta"), StackLayer::Orchestration);
assert_eq!(StackLayer::from_component("certeza"), StackLayer::Quality);
assert_eq!(StackLayer::from_component("alimentar"), StackLayer::DataMlops);
assert_eq!(StackLayer::from_component("presentar"), StackLayer::Presentation);
}
#[test]
fn test_stack_layer_display_name() {
assert_eq!(StackLayer::Compute.display_name(), "COMPUTE PRIMITIVES");
assert_eq!(StackLayer::Ml.display_name(), "ML ALGORITHMS");
}
#[test]
fn test_component_quality_sqi_calculation() {
let rust = Score::new(114, 114, QualityGrade::APlus);
let repo = Score::new(110, 110, QualityGrade::APlus);
let readme = Score::new(20, 20, QualityGrade::APlus);
let hero = HeroImageResult::found(PathBuf::from("hero.png"), ImageFormat::Png);
let sqi = ComponentQuality::calculate_sqi(&rust, &repo, &readme, &hero);
assert!((sqi - 100.0).abs() < 0.1);
}
#[test]
fn test_component_quality_sqi_with_missing_hero() {
let rust = Score::new(114, 114, QualityGrade::APlus);
let repo = Score::new(110, 110, QualityGrade::APlus);
let readme = Score::new(20, 20, QualityGrade::APlus);
let hero = HeroImageResult::missing();
let sqi = ComponentQuality::calculate_sqi(&rust, &repo, &readme, &hero);
assert!((sqi - 90.0).abs() < 0.1);
}
#[test]
fn test_component_quality_creation() {
let rust = Score::new(107, 114, QualityGrade::APlus);
let repo = Score::new(98, 110, QualityGrade::APlus);
let readme = Score::new(20, 20, QualityGrade::APlus);
let hero = HeroImageResult::found(PathBuf::from("hero.png"), ImageFormat::Png);
let quality =
ComponentQuality::new("trueno", PathBuf::from("/path/to/trueno"), rust, repo, readme, hero);
assert_eq!(quality.name, "trueno");
assert_eq!(quality.layer, StackLayer::Compute);
assert!(quality.sqi > 90.0);
assert!(quality.grade.is_release_ready());
assert!(quality.release_ready);
}
#[test]
fn test_component_quality_not_release_ready() {
let rust = Score::new(70, 114, QualityGrade::B);
let repo = Score::new(75, 110, QualityGrade::B);
let readme = Score::new(12, 20, QualityGrade::BPlus);
let hero = HeroImageResult::missing();
let quality =
ComponentQuality::new("weak-crate", PathBuf::from("/path"), rust, repo, readme, hero);
assert!(!quality.release_ready);
assert!(!quality.grade.is_release_ready());
assert!(!quality.issues.is_empty());
}
#[test]
fn test_quality_summary_empty() {
let summary = QualitySummary::from_components(&[]);
assert_eq!(summary.total_components, 0);
assert_eq!(summary.a_plus_count, 0);
}
#[test]
fn test_quality_summary_calculation() {
let components = vec![
create_test_component("a", 112, 105, 20, true), create_test_component("b", 100, 92, 17, true), create_test_component("c", 80, 75, 12, false), ];
let summary = QualitySummary::from_components(&components);
assert_eq!(summary.total_components, 3);
assert_eq!(summary.a_plus_count, 1);
assert_eq!(summary.a_minus_count, 1);
assert_eq!(summary.below_threshold_count, 1);
assert_eq!(summary.missing_hero_count, 1);
}
#[test]
fn test_stack_quality_report_creation() {
let components = vec![
create_test_component("trueno", 107, 98, 20, true),
create_test_component("aprender", 105, 95, 18, true),
];
let report = StackQualityReport::from_components(components);
assert_eq!(report.summary.total_components, 2);
assert!(report.release_ready);
assert!(report.blocked_components.is_empty());
assert!(report.stack_quality_index > 90.0);
}
#[test]
fn test_stack_quality_report_with_blocked() {
let components = vec![
create_test_component("trueno", 107, 98, 20, true),
create_test_component("weak", 70, 70, 10, false),
];
let report = StackQualityReport::from_components(components);
assert!(!report.release_ready);
assert_eq!(report.blocked_components, vec!["weak".to_string()]);
assert!(!report.recommendations.is_empty());
}
#[test]
fn test_stack_quality_report_is_all_a_plus() {
let components = vec![
create_test_component("a", 114, 110, 20, true), create_test_component("b", 112, 105, 20, true), ];
let report = StackQualityReport::from_components(components);
assert!(report.is_all_a_plus());
}
#[test]
fn test_stack_quality_report_not_all_a_plus() {
let components = vec![
create_test_component("a", 110, 100, 20, true),
create_test_component("b", 95, 90, 16, true), ];
let report = StackQualityReport::from_components(components);
assert!(!report.is_all_a_plus());
}
#[test]
fn test_quality_grade_ordering() {
assert!(QualityGrade::APlus < QualityGrade::A);
assert!(QualityGrade::A < QualityGrade::AMinus);
assert!(QualityGrade::AMinus < QualityGrade::BPlus);
assert!(QualityGrade::BPlus < QualityGrade::B);
assert!(QualityGrade::B < QualityGrade::C);
assert!(QualityGrade::C < QualityGrade::D);
assert!(QualityGrade::D < QualityGrade::F);
}
#[test]
fn test_quality_grade_all_icons() {
assert_eq!(QualityGrade::B.icon(), "❌");
assert_eq!(QualityGrade::C.icon(), "❌");
assert_eq!(QualityGrade::D.icon(), "❌");
assert_eq!(QualityGrade::F.icon(), "❌");
}
#[test]
fn test_quality_grade_all_symbols() {
assert_eq!(QualityGrade::B.symbol(), "B");
assert_eq!(QualityGrade::C.symbol(), "C");
assert_eq!(QualityGrade::D.symbol(), "D");
}
#[test]
fn test_quality_grade_from_repo_score_all_ranges() {
assert_eq!(QualityGrade::from_repo_score(94), QualityGrade::A);
assert_eq!(QualityGrade::from_repo_score(90), QualityGrade::A);
assert_eq!(QualityGrade::from_repo_score(89), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_repo_score(85), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_repo_score(84), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_repo_score(80), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_repo_score(79), QualityGrade::B);
assert_eq!(QualityGrade::from_repo_score(70), QualityGrade::B);
assert_eq!(QualityGrade::from_repo_score(69), QualityGrade::C);
assert_eq!(QualityGrade::from_repo_score(60), QualityGrade::C);
assert_eq!(QualityGrade::from_repo_score(59), QualityGrade::D);
assert_eq!(QualityGrade::from_repo_score(50), QualityGrade::D);
assert_eq!(QualityGrade::from_repo_score(49), QualityGrade::F);
}
#[test]
fn test_quality_grade_from_readme_score_all_ranges() {
assert_eq!(QualityGrade::from_readme_score(16), QualityGrade::A);
assert_eq!(QualityGrade::from_readme_score(14), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_readme_score(13), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_readme_score(11), QualityGrade::B);
assert_eq!(QualityGrade::from_readme_score(10), QualityGrade::B);
assert_eq!(QualityGrade::from_readme_score(9), QualityGrade::C);
assert_eq!(QualityGrade::from_readme_score(8), QualityGrade::C);
assert_eq!(QualityGrade::from_readme_score(7), QualityGrade::D);
assert_eq!(QualityGrade::from_readme_score(6), QualityGrade::D);
assert_eq!(QualityGrade::from_readme_score(5), QualityGrade::F);
}
#[test]
fn test_stack_layer_all_display_names() {
assert_eq!(StackLayer::Training.display_name(), "TRAINING & INFERENCE");
assert_eq!(StackLayer::DataMlops.display_name(), "DATA & MLOPS");
assert_eq!(StackLayer::Transpilers.display_name(), "TRANSPILERS");
assert_eq!(StackLayer::Orchestration.display_name(), "ORCHESTRATION");
assert_eq!(StackLayer::Quality.display_name(), "QUALITY");
assert_eq!(StackLayer::Presentation.display_name(), "PRESENTATION");
}
#[test]
fn test_stack_layer_from_component_extended() {
assert_eq!(StackLayer::from_component("entrenar"), StackLayer::Training);
assert_eq!(StackLayer::from_component("realizar"), StackLayer::Training);
assert_eq!(StackLayer::from_component("ruchy"), StackLayer::Transpilers);
assert_eq!(StackLayer::from_component("decy"), StackLayer::Transpilers);
assert_eq!(StackLayer::from_component("unknown-crate"), StackLayer::Orchestration);
}
fn create_test_component(
name: &str,
rust: u32,
repo: u32,
readme: u32,
has_hero: bool,
) -> ComponentQuality {
let rust_score = Score::new(rust, 114, QualityGrade::from_rust_project_score(rust));
let repo_score = Score::new(repo, 110, QualityGrade::from_repo_score(repo));
let readme_score = Score::new(readme, 20, QualityGrade::from_readme_score(readme));
let hero = if has_hero {
HeroImageResult::found(PathBuf::from("hero.png"), ImageFormat::Png)
} else {
HeroImageResult::missing()
};
ComponentQuality::new(name, PathBuf::from("/test"), rust_score, repo_score, readme_score, hero)
}
mod proptests {
use super::*;
use proptest::prelude::*;
proptest! {
#![proptest_config(ProptestConfig::with_cases(50))]
#[test]
fn prop_rust_project_score_valid_grade(score in 0u32..200) {
let grade = QualityGrade::from_rust_project_score(score);
prop_assert!(matches!(
grade,
QualityGrade::APlus | QualityGrade::A | QualityGrade::AMinus |
QualityGrade::BPlus | QualityGrade::B | QualityGrade::C |
QualityGrade::D | QualityGrade::F
));
}
#[test]
fn prop_repo_score_valid_grade(score in 0u32..200) {
let grade = QualityGrade::from_repo_score(score);
prop_assert!(matches!(
grade,
QualityGrade::APlus | QualityGrade::A | QualityGrade::AMinus |
QualityGrade::BPlus | QualityGrade::B | QualityGrade::C |
QualityGrade::D | QualityGrade::F
));
}
#[test]
fn prop_sqi_valid_grade(sqi in 0.0f64..150.0) {
let grade = QualityGrade::from_sqi(sqi);
prop_assert!(matches!(
grade,
QualityGrade::APlus | QualityGrade::A | QualityGrade::AMinus |
QualityGrade::BPlus | QualityGrade::B | QualityGrade::C |
QualityGrade::D | QualityGrade::F
));
}
#[test]
fn prop_higher_score_better_grade(low in 0u32..80, high in 80u32..115) {
let low_grade = QualityGrade::from_rust_project_score(low);
let high_grade = QualityGrade::from_rust_project_score(high);
prop_assert!(high_grade <= low_grade);
}
#[test]
fn prop_score_percentage_valid(value in 0u32..200, max in 1u32..200) {
let grade = QualityGrade::from_rust_project_score(value);
let score = Score::new(value.min(max), max, grade);
let pct = score.percentage();
prop_assert!((0.0..=100.0).contains(&pct));
}
#[test]
fn prop_sqi_valid_range(
rust in 0u32..115,
repo in 0u32..111,
readme in 0u32..21
) {
let rust_score = Score::new(rust.min(114), 114, QualityGrade::from_rust_project_score(rust));
let repo_score = Score::new(repo.min(110), 110, QualityGrade::from_repo_score(repo));
let readme_score = Score::new(readme.min(20), 20, QualityGrade::from_readme_score(readme));
let hero = HeroImageResult::missing();
let sqi = ComponentQuality::calculate_sqi(&rust_score, &repo_score, &readme_score, &hero);
prop_assert!((0.0..=100.0).contains(&sqi), "SQI {} not in [0, 100]", sqi);
}
#[test]
fn prop_grade_symbol_nonempty(score in 0u32..120) {
let grade = QualityGrade::from_rust_project_score(score);
prop_assert!(!grade.symbol().is_empty());
}
#[test]
fn prop_release_ready_consistent(score in 0u32..115) {
let grade = QualityGrade::from_rust_project_score(score);
let is_ready = grade.is_release_ready();
if (85..=114).contains(&score) {
prop_assert!(is_ready, "Score {} should be release ready", score);
}
if score < 85 {
prop_assert!(!is_ready, "Score {} should NOT be release ready", score);
}
}
}
}
#[test]
fn test_generate_recommendations_missing_hero() {
let mut comp = create_test_component("no_hero", 105, 95, 18, false);
comp.hero_image.valid = false;
comp.release_ready = false;
let report = StackQualityReport::from_components(vec![comp]);
assert!(report.recommendations.iter().any(|r| r.contains("hero")));
}
#[test]
fn test_generate_recommendations_low_rust_score() {
let mut comp = create_test_component("low_rust", 70, 60, 10, true);
comp.rust_score = Score::new(70, 114, QualityGrade::B);
comp.release_ready = false;
let report = StackQualityReport::from_components(vec![comp]);
assert!(report
.recommendations
.iter()
.any(|r| r.contains("test coverage") || r.contains("documentation")));
}
#[test]
fn test_quality_summary_with_below_threshold() {
let mut comp = create_test_component("low", 70, 60, 10, false);
comp.grade = QualityGrade::B;
comp.release_ready = false;
let summary = QualitySummary::from_components(&[comp]);
assert_eq!(summary.below_threshold_count, 1);
}
#[test]
fn test_quality_issue_all_severity_levels() {
let error = QualityIssue::new("err", "Error message", IssueSeverity::Error);
let warning = QualityIssue::new("warn", "Warning message", IssueSeverity::Warning);
let info = QualityIssue::new("info", "Info message", IssueSeverity::Info);
assert_eq!(error.severity, IssueSeverity::Error);
assert_eq!(warning.severity, IssueSeverity::Warning);
assert_eq!(info.severity, IssueSeverity::Info);
}
#[test]
fn test_component_quality_hero_penalty() {
let rust = Score::new(114, 114, QualityGrade::APlus);
let repo = Score::new(110, 110, QualityGrade::APlus);
let readme = Score::new(20, 20, QualityGrade::APlus);
let hero = HeroImageResult::missing();
let quality =
ComponentQuality::new("test".to_string(), PathBuf::from("/test"), rust, repo, readme, hero);
assert!(quality.sqi < 100.0);
assert!(!quality.hero_image.valid);
}
#[test]
fn test_stack_layer_all_variants() {
let layers = vec![
StackLayer::Compute,
StackLayer::Ml,
StackLayer::Training,
StackLayer::Transpilers,
StackLayer::Orchestration,
StackLayer::DataMlops,
StackLayer::Quality,
StackLayer::Presentation,
];
for layer in layers {
assert!(!layer.display_name().is_empty());
}
}
#[test]
fn test_quality_grade_all_variants_display() {
let grades = vec![
QualityGrade::APlus,
QualityGrade::A,
QualityGrade::AMinus,
QualityGrade::BPlus,
QualityGrade::B,
QualityGrade::C,
QualityGrade::D,
QualityGrade::F,
];
for grade in grades {
assert!(!grade.symbol().is_empty());
assert!(!grade.icon().is_empty());
let _s = format!("{}", grade);
}
}
#[test]
fn test_image_format_all_variants() {
let formats: Vec<ImageFormat> =
vec![ImageFormat::Png, ImageFormat::Jpg, ImageFormat::Svg, ImageFormat::WebP];
for fmt in formats {
assert!(!fmt.extension().is_empty());
}
}
#[test]
fn test_score_zero_max_edge_case() {
let score = Score::new(0, 100, QualityGrade::F);
assert!(score.percentage() >= 0.0);
assert_eq!(score.normalized(), 0.0);
}
#[test]
fn test_qcov_001_grade_from_rust_project_score() {
assert_eq!(QualityGrade::from_rust_project_score(114), QualityGrade::APlus);
assert_eq!(QualityGrade::from_rust_project_score(105), QualityGrade::APlus);
assert_eq!(QualityGrade::from_rust_project_score(104), QualityGrade::A);
assert_eq!(QualityGrade::from_rust_project_score(95), QualityGrade::A);
assert_eq!(QualityGrade::from_rust_project_score(94), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_rust_project_score(85), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_rust_project_score(84), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_rust_project_score(80), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_rust_project_score(79), QualityGrade::B);
assert_eq!(QualityGrade::from_rust_project_score(70), QualityGrade::B);
assert_eq!(QualityGrade::from_rust_project_score(69), QualityGrade::C);
assert_eq!(QualityGrade::from_rust_project_score(60), QualityGrade::C);
assert_eq!(QualityGrade::from_rust_project_score(59), QualityGrade::D);
assert_eq!(QualityGrade::from_rust_project_score(50), QualityGrade::D);
assert_eq!(QualityGrade::from_rust_project_score(49), QualityGrade::F);
assert_eq!(QualityGrade::from_rust_project_score(0), QualityGrade::F);
}
#[test]
fn test_qcov_002_grade_from_repo_score() {
assert_eq!(QualityGrade::from_repo_score(110), QualityGrade::APlus);
assert_eq!(QualityGrade::from_repo_score(95), QualityGrade::APlus);
assert_eq!(QualityGrade::from_repo_score(94), QualityGrade::A);
assert_eq!(QualityGrade::from_repo_score(90), QualityGrade::A);
assert_eq!(QualityGrade::from_repo_score(89), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_repo_score(85), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_repo_score(84), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_repo_score(80), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_repo_score(79), QualityGrade::B);
assert_eq!(QualityGrade::from_repo_score(70), QualityGrade::B);
assert_eq!(QualityGrade::from_repo_score(69), QualityGrade::C);
assert_eq!(QualityGrade::from_repo_score(60), QualityGrade::C);
assert_eq!(QualityGrade::from_repo_score(59), QualityGrade::D);
assert_eq!(QualityGrade::from_repo_score(50), QualityGrade::D);
assert_eq!(QualityGrade::from_repo_score(49), QualityGrade::F);
}
#[test]
fn test_qcov_003_grade_from_readme_score() {
assert_eq!(QualityGrade::from_readme_score(20), QualityGrade::APlus);
assert_eq!(QualityGrade::from_readme_score(18), QualityGrade::APlus);
assert_eq!(QualityGrade::from_readme_score(17), QualityGrade::A);
assert_eq!(QualityGrade::from_readme_score(16), QualityGrade::A);
assert_eq!(QualityGrade::from_readme_score(15), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_readme_score(14), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_readme_score(13), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_readme_score(12), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_readme_score(11), QualityGrade::B);
assert_eq!(QualityGrade::from_readme_score(10), QualityGrade::B);
assert_eq!(QualityGrade::from_readme_score(9), QualityGrade::C);
assert_eq!(QualityGrade::from_readme_score(8), QualityGrade::C);
assert_eq!(QualityGrade::from_readme_score(7), QualityGrade::D);
assert_eq!(QualityGrade::from_readme_score(6), QualityGrade::D);
assert_eq!(QualityGrade::from_readme_score(5), QualityGrade::F);
}
#[test]
fn test_qcov_004_grade_from_sqi() {
assert_eq!(QualityGrade::from_sqi(100.0), QualityGrade::APlus);
assert_eq!(QualityGrade::from_sqi(95.0), QualityGrade::APlus);
assert_eq!(QualityGrade::from_sqi(94.0), QualityGrade::A);
assert_eq!(QualityGrade::from_sqi(90.0), QualityGrade::A);
assert_eq!(QualityGrade::from_sqi(89.0), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_sqi(85.0), QualityGrade::AMinus);
assert_eq!(QualityGrade::from_sqi(84.0), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_sqi(80.0), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_sqi(79.0), QualityGrade::B);
assert_eq!(QualityGrade::from_sqi(70.0), QualityGrade::B);
assert_eq!(QualityGrade::from_sqi(69.0), QualityGrade::C);
assert_eq!(QualityGrade::from_sqi(60.0), QualityGrade::C);
assert_eq!(QualityGrade::from_sqi(59.0), QualityGrade::D);
assert_eq!(QualityGrade::from_sqi(50.0), QualityGrade::D);
assert_eq!(QualityGrade::from_sqi(49.0), QualityGrade::F);
}
#[test]
fn test_qcov_005_grade_release_ready() {
assert!(QualityGrade::APlus.is_release_ready());
assert!(QualityGrade::A.is_release_ready());
assert!(QualityGrade::AMinus.is_release_ready());
assert!(!QualityGrade::BPlus.is_release_ready());
assert!(!QualityGrade::B.is_release_ready());
assert!(!QualityGrade::C.is_release_ready());
assert!(!QualityGrade::D.is_release_ready());
assert!(!QualityGrade::F.is_release_ready());
}
#[test]
fn test_qcov_006_grade_is_a_plus() {
assert!(QualityGrade::APlus.is_a_plus());
assert!(!QualityGrade::A.is_a_plus());
assert!(!QualityGrade::AMinus.is_a_plus());
}
#[test]
fn test_qcov_007_grade_icons() {
assert_eq!(QualityGrade::APlus.icon(), "✅");
assert_eq!(QualityGrade::A.icon(), "⚠️");
assert_eq!(QualityGrade::AMinus.icon(), "⚠️");
assert_eq!(QualityGrade::BPlus.icon(), "❌");
assert_eq!(QualityGrade::B.icon(), "❌");
assert_eq!(QualityGrade::C.icon(), "❌");
assert_eq!(QualityGrade::D.icon(), "❌");
assert_eq!(QualityGrade::F.icon(), "❌");
}
#[test]
fn test_qcov_008_image_format_extensions() {
assert_eq!(ImageFormat::from_extension("png"), Some(ImageFormat::Png));
assert_eq!(ImageFormat::from_extension("PNG"), Some(ImageFormat::Png));
assert_eq!(ImageFormat::from_extension("jpg"), Some(ImageFormat::Jpg));
assert_eq!(ImageFormat::from_extension("jpeg"), Some(ImageFormat::Jpg));
assert_eq!(ImageFormat::from_extension("webp"), Some(ImageFormat::WebP));
assert_eq!(ImageFormat::from_extension("svg"), Some(ImageFormat::Svg));
assert_eq!(ImageFormat::from_extension("bmp"), None);
assert_eq!(ImageFormat::from_extension("gif"), None);
}
#[test]
fn test_qcov_009_image_format_extension_strings() {
assert_eq!(ImageFormat::Png.extension(), "png");
assert_eq!(ImageFormat::Jpg.extension(), "jpg");
assert_eq!(ImageFormat::WebP.extension(), "webp");
assert_eq!(ImageFormat::Svg.extension(), "svg");
}
#[test]
fn test_qcov_010_hero_image_result_missing() {
let hero = HeroImageResult::missing();
assert!(!hero.present);
assert!(hero.path.is_none());
assert!(!hero.valid);
assert!(!hero.issues.is_empty());
}
#[test]
fn test_qcov_011_hero_image_result_found() {
let hero = HeroImageResult::found(PathBuf::from("/test/hero.png"), ImageFormat::Png);
assert!(hero.present);
assert!(hero.path.is_some());
assert_eq!(hero.format, Some(ImageFormat::Png));
assert!(hero.valid);
}
#[test]
fn test_qcov_012_score_percentage_zero_max() {
let score = Score::new(50, 0, QualityGrade::F);
assert_eq!(score.percentage(), 0.0);
}
#[test]
fn test_qcov_013_score_percentage_normal() {
let score = Score::new(50, 100, QualityGrade::D);
assert_eq!(score.percentage(), 50.0);
assert_eq!(score.normalized(), 50.0);
}
#[test]
fn test_qcov_014_quality_issue_new() {
let issue = QualityIssue::new("test_type", "msg", IssueSeverity::Error);
assert_eq!(issue.issue_type, "test_type");
assert_eq!(issue.message, "msg");
assert_eq!(issue.severity, IssueSeverity::Error);
}
#[test]
fn test_qcov_015_quality_issue_with_recommendation() {
let issue =
QualityIssue::new("test", "msg", IssueSeverity::Warning).with_recommendation("fix it");
assert_eq!(issue.recommendation, Some("fix it".to_string()));
}
#[test]
fn test_qcov_016_quality_issue_score_below_threshold() {
let issue = QualityIssue::score_below_threshold("coverage", 70, 80);
assert!(issue.message.contains("70"));
assert!(issue.message.contains("80"));
assert_eq!(issue.severity, IssueSeverity::Error);
}
#[test]
fn test_qcov_017_quality_issue_missing_hero() {
let issue = QualityIssue::missing_hero_image();
assert!(issue.message.contains("hero"));
assert_eq!(issue.severity, IssueSeverity::Error);
}
#[test]
fn test_qcov_018_stack_layer_all_variants() {
let layers = vec![
StackLayer::Compute,
StackLayer::Ml,
StackLayer::Training,
StackLayer::Transpilers,
StackLayer::Orchestration,
StackLayer::Quality,
StackLayer::DataMlops,
StackLayer::Presentation,
];
for layer in layers {
assert!(!layer.display_name().is_empty());
}
}
#[test]
fn test_qcov_019_stack_layer_from_component() {
assert_eq!(StackLayer::from_component("trueno"), StackLayer::Compute);
assert_eq!(StackLayer::from_component("aprender"), StackLayer::Ml);
assert_eq!(StackLayer::from_component("entrenar"), StackLayer::Training);
assert_eq!(StackLayer::from_component("batuta"), StackLayer::Orchestration);
assert_eq!(StackLayer::from_component("depyler"), StackLayer::Transpilers);
}
#[test]
fn test_qcov_020_quality_summary_from_components() {
let comps = vec![
create_test_component("a", 105, 95, 18, true),
create_test_component("b", 70, 60, 10, false),
];
let summary = QualitySummary::from_components(&comps);
assert_eq!(summary.total_components, 2);
assert!(summary.a_plus_count + summary.below_threshold_count <= 2);
}
#[test]
fn test_qcov_024_report_is_all_a_plus() {
let all_aplus = vec![create_test_component("a", 110, 100, 20, true)];
let report = StackQualityReport::from_components(all_aplus);
assert!(report.is_all_a_plus());
let not_all_aplus = vec![create_test_component("b", 70, 60, 10, false)];
let report2 = StackQualityReport::from_components(not_all_aplus);
assert!(!report2.is_all_a_plus());
}
#[test]
fn test_qcov_025_hero_detect_missing() {
let temp_dir = std::env::temp_dir().join("qcov_025_test");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(&temp_dir).unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(!result.present);
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_qcov_026_hero_detect_with_docs_hero() {
let temp_dir = std::env::temp_dir().join("qcov_026_test");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(temp_dir.join("docs")).unwrap();
std::fs::write(temp_dir.join("docs/hero.png"), [0x89, 0x50, 0x4E, 0x47]).unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert_eq!(result.format, Some(ImageFormat::Png));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_qcov_027_hero_detect_with_assets_hero() {
let temp_dir = std::env::temp_dir().join("qcov_027_test");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(temp_dir.join("assets")).unwrap();
std::fs::write(temp_dir.join("assets/hero.svg"), "<svg></svg>").unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
assert_eq!(result.format, Some(ImageFormat::Svg));
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_qcov_028_hero_detect_from_readme() {
let temp_dir = std::env::temp_dir().join("qcov_028_test");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(&temp_dir).unwrap();
std::fs::write(temp_dir.join("README.md"), "# Test\n\n").unwrap();
std::fs::write(temp_dir.join("local-image.png"), [0x89, 0x50, 0x4E, 0x47]).unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(result.present);
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_qcov_029_hero_detect_readme_external_url() {
let temp_dir = std::env::temp_dir().join("qcov_029_test");
let _ = std::fs::remove_dir_all(&temp_dir);
std::fs::create_dir_all(&temp_dir).unwrap();
std::fs::write(temp_dir.join("README.md"), "# Test\n\n")
.unwrap();
let result = HeroImageResult::detect(&temp_dir);
assert!(!result.present);
let _ = std::fs::remove_dir_all(&temp_dir);
}
#[test]
fn test_qcov_030_quality_summary_empty() {
let summary = QualitySummary::from_components(&[]);
assert_eq!(summary.total_components, 0);
assert_eq!(summary.a_plus_count, 0);
}
#[test]
fn test_qcov_031_grade_boundary_values() {
assert_eq!(QualityGrade::from_rust_project_score(104), QualityGrade::A);
assert_eq!(QualityGrade::from_rust_project_score(80), QualityGrade::BPlus);
assert_eq!(QualityGrade::from_rust_project_score(60), QualityGrade::C);
assert_eq!(QualityGrade::from_rust_project_score(50), QualityGrade::D);
}
#[test]
fn test_qcov_032_quality_report_empty() {
let report = StackQualityReport::from_components(vec![]);
assert!(report.is_all_a_plus()); assert_eq!(report.summary.total_components, 0);
}
#[test]
fn test_qcov_033_format_text_empty_report() {
let report = StackQualityReport::from_components(vec![]);
let text = format_report_text(&report);
assert!(text.contains("SUMMARY"));
}
#[test]
fn test_qcov_034_component_quality_default_issues() {
let comp = create_test_component("test", 105, 95, 18, true);
assert!(comp.issues.len() <= 2);
}
#[test]
fn test_qcov_035_stack_layer_display_names() {
assert_eq!(StackLayer::Compute.display_name(), "COMPUTE PRIMITIVES");
assert_eq!(StackLayer::Ml.display_name(), "ML ALGORITHMS");
assert_eq!(StackLayer::Training.display_name(), "TRAINING & INFERENCE");
assert_eq!(StackLayer::Transpilers.display_name(), "TRANSPILERS");
assert_eq!(StackLayer::Orchestration.display_name(), "ORCHESTRATION");
assert_eq!(StackLayer::DataMlops.display_name(), "DATA & MLOPS");
assert_eq!(StackLayer::Quality.display_name(), "QUALITY");
assert_eq!(StackLayer::Presentation.display_name(), "PRESENTATION");
}