use webpage_quality_analyzer::config::enhanced_models::QualityBandConfig;
use webpage_quality_analyzer::config::profile_builder::ContentType;
use webpage_quality_analyzer::config::{ProfileBuilder, ProfileTemplates};
use webpage_quality_analyzer::metrics::ThresholdSet;
#[tokio::test]
async fn test_profile_builder_basic_usage() {
let profile = ProfileBuilder::new("basic_test")
.with_description("A basic test profile")
.build();
assert!(profile.is_ok(), "Profile building should succeed");
let profile = profile.unwrap();
assert_eq!(profile.metadata.name, "basic_test");
assert_eq!(profile.metadata.description, "A basic test profile");
assert!(
!profile.category_weights.is_empty(),
"Should have default category weights"
);
let total: f32 = profile.category_weights.values().sum();
assert!(
(total - 1.0).abs() < 0.01,
"Weights should sum to 1.0, got {}",
total
);
}
#[tokio::test]
async fn test_profile_builder_with_long_form_article() {
let profile = ProfileBuilder::new("long_article")
.for_content_type(ContentType::LongFormArticle)
.build()
.expect("Failed to build long-form article profile");
assert!(
profile.category_weights.get("content").unwrap() >= &0.70,
"Long-form articles should have high content weight"
);
assert!(
profile.content_expectations.word_count.is_some(),
"Long-form articles should have word count expectations"
);
let word_count = profile.content_expectations.word_count.as_ref().unwrap();
assert!(
word_count.optimal_range.0 >= 500,
"Long-form articles should expect substantial word count"
);
}
#[tokio::test]
async fn test_profile_builder_with_news_article() {
let profile = ProfileBuilder::new("news")
.for_content_type(ContentType::NewsArticle)
.build()
.expect("Failed to build news article profile");
let content_weight = profile.category_weights.get("content").unwrap();
let seo_weight = profile.category_weights.get("seo").unwrap();
assert!(
content_weight > &0.30,
"News should have decent content weight"
);
assert!(
seo_weight > &0.20,
"News should have significant SEO weight"
);
let word_count = profile.content_expectations.word_count.as_ref().unwrap();
assert!(
word_count.optimal_range.1 < 1500,
"News articles should be relatively concise"
);
}
#[tokio::test]
async fn test_profile_builder_with_product_page() {
let profile = ProfileBuilder::new("product")
.for_content_type(ContentType::ProductPage)
.build()
.expect("Failed to build product page profile");
let seo_weight = profile.category_weights.get("seo").unwrap();
let technical_weight = profile.category_weights.get("technical").unwrap();
assert!(seo_weight > &0.25, "Products need strong SEO");
assert!(
technical_weight > &0.10,
"Products need good technical performance"
);
let word_count = profile.content_expectations.word_count.as_ref().unwrap();
assert!(
word_count.minimum < 200,
"Product pages can have minimal text"
);
}
#[tokio::test]
async fn test_profile_builder_custom_weights() {
let profile = ProfileBuilder::new("custom_weights")
.with_metric_weight("word_count", 0.50)
.expect("Failed to set word_count weight")
.with_metric_weight("title_len", 0.30)
.expect("Failed to set title_len weight")
.build()
.expect("Failed to build profile with custom weights");
assert!(
profile.metric_overrides.contains_key("word_count"),
"word_count override should be present"
);
assert!(
profile.metric_overrides.contains_key("title_len"),
"title_len override should be present"
);
assert_eq!(
profile.metric_overrides.get("word_count").unwrap().weight,
0.50
);
assert_eq!(
profile.metric_overrides.get("title_len").unwrap().weight,
0.30
);
}
#[tokio::test]
async fn test_profile_builder_custom_thresholds() {
let thresholds = ThresholdSet {
excellent: 2000.0,
good: 1000.0,
fair: 500.0,
poor: 200.0,
};
let profile = ProfileBuilder::new("custom_thresholds")
.with_custom_threshold("word_count", thresholds.clone())
.expect("Failed to set custom thresholds")
.build()
.expect("Failed to build profile with custom thresholds");
let word_count_override = profile.metric_overrides.get("word_count").unwrap();
assert!(
word_count_override.thresholds.is_some(),
"Custom thresholds should be set"
);
let set_thresholds = word_count_override.thresholds.as_ref().unwrap();
assert_eq!(set_thresholds.excellent, 2000.0);
assert_eq!(set_thresholds.good, 1000.0);
}
#[tokio::test]
async fn test_profile_builder_invalid_weight() {
let result = ProfileBuilder::new("invalid").with_metric_weight("word_count", 1.5);
assert!(result.is_err(), "Invalid weight should be rejected");
}
#[tokio::test]
async fn test_profile_builder_all_content_types() {
let content_types = vec![
ContentType::LongFormArticle,
ContentType::NewsArticle,
ContentType::ProductPage,
ContentType::LandingPage,
ContentType::Portfolio,
ContentType::Documentation,
ContentType::AboutPage,
];
for content_type in content_types {
let profile = ProfileBuilder::new("test")
.for_content_type(content_type)
.build();
assert!(
profile.is_ok(),
"Content type {:?} should build successfully",
content_type
);
}
}
#[tokio::test]
async fn test_profile_builder_method_chaining() {
let profile = ProfileBuilder::new("chained")
.for_content_type(ContentType::LongFormArticle)
.with_description("A heavily customized profile")
.with_tags(vec![
"test".to_string(),
"custom".to_string(),
"chained".to_string(),
])
.with_metric_weight("word_count", 0.40)
.expect("Failed to set word_count weight")
.with_metric_weight("title_len", 0.20)
.expect("Failed to set title_len weight")
.build()
.expect("Failed to build chained profile");
assert_eq!(profile.metadata.name, "chained");
assert_eq!(profile.metadata.description, "A heavily customized profile");
assert_eq!(profile.metadata.tags.len(), 3);
assert!(profile.metric_overrides.contains_key("word_count"));
assert!(profile.metric_overrides.contains_key("title_len"));
}
#[tokio::test]
async fn test_profile_templates_get_template() {
let templates = vec![
"content_article",
"news",
"product",
"landing_page",
"portfolio",
];
for template_name in templates {
let profile = ProfileTemplates::get_template(template_name);
assert!(
profile.is_ok(),
"Template '{}' should be available",
template_name
);
let profile = profile.unwrap();
assert!(
!profile.metadata.name.is_empty(),
"Template should have a name"
);
assert!(
!profile.category_weights.is_empty(),
"Template should have category weights"
);
}
}
#[tokio::test]
async fn test_profile_templates_unknown_template() {
let result = ProfileTemplates::get_template("non_existent_template");
assert!(result.is_err(), "Unknown template should return error");
}
#[tokio::test]
async fn test_profile_templates_list() {
let templates = ProfileTemplates::list_templates();
assert!(!templates.is_empty(), "Should have at least one template");
assert!(
templates.contains(&"content_article"),
"Should include content_article template"
);
assert!(templates.contains(&"news"), "Should include news template");
assert!(
templates.contains(&"product"),
"Should include product template"
);
}
#[tokio::test]
async fn test_end_to_end_custom_profile() {
let profile = ProfileBuilder::new("e2e_test")
.for_content_type(ContentType::LongFormArticle)
.with_description("End-to-end test profile")
.with_metric_weight("word_count", 0.60)
.expect("Failed to set word_count weight")
.build()
.expect("Failed to build e2e profile");
assert_eq!(profile.metadata.name, "e2e_test");
assert_eq!(
profile.metric_overrides.get("word_count").unwrap().weight,
0.60
);
}
#[tokio::test]
async fn test_profile_builder_category_weights() {
let mut weights = std::collections::HashMap::new();
weights.insert("content".to_string(), 0.50);
weights.insert("seo".to_string(), 0.30);
weights.insert("technical".to_string(), 0.10);
weights.insert("structure".to_string(), 0.05);
weights.insert("accessibility".to_string(), 0.05);
let profile = ProfileBuilder::new("custom_categories")
.with_category_weights(weights.clone())
.build()
.expect("Failed to build profile with custom category weights");
assert!(profile.category_weights.contains_key("content"));
assert!(profile.category_weights.contains_key("seo"));
}
#[tokio::test]
async fn test_profile_builder_metric_enable_disable() {
let profile = ProfileBuilder::new("metric_toggle")
.with_metric_enabled("word_count", true)
.with_metric_enabled("title_len", false)
.build()
.expect("Failed to build profile with toggled metrics");
let word_count_override = profile.metric_overrides.get("word_count").unwrap();
let title_override = profile.metric_overrides.get("title_len").unwrap();
assert!(word_count_override.enabled, "word_count should be enabled");
assert!(!title_override.enabled, "title_len should be disabled");
}
#[tokio::test]
async fn test_profile_builder_quality_bands() {
let bands = QualityBandConfig {
excellent: 95.0,
good: 80.0,
fair: 60.0,
poor: 40.0,
};
let profile = ProfileBuilder::new("custom_bands")
.with_quality_bands(bands.clone())
.build()
.expect("Failed to build profile with custom quality bands");
assert_eq!(profile.quality_bands.excellent, 95.0);
assert_eq!(profile.quality_bands.good, 80.0);
assert_eq!(profile.quality_bands.fair, 60.0);
assert_eq!(profile.quality_bands.poor, 40.0);
}
#[tokio::test]
async fn test_profile_templates_content_article_characteristics() {
let profile = ProfileTemplates::get_template("content_article")
.expect("content_article template should exist");
let content_weight = profile
.category_weights
.get("content")
.expect("content category should exist");
assert!(
content_weight >= &0.70,
"Content articles should heavily weight content, got {}",
content_weight
);
let word_count_exp = profile
.content_expectations
.word_count
.expect("Should have word count expectations");
assert!(
word_count_exp.optimal_range.0 >= 500,
"Content articles should expect substantial text"
);
assert!(
word_count_exp.optimal_range.1 >= 1500,
"Content articles should support long-form content"
);
}
#[tokio::test]
async fn test_profile_templates_news_characteristics() {
let profile = ProfileTemplates::get_template("news").expect("news template should exist");
let content_weight = profile
.category_weights
.get("content")
.expect("content category should exist");
let seo_weight = profile
.category_weights
.get("seo")
.expect("seo category should exist");
assert!(
content_weight > &0.30,
"News should have reasonable content weight"
);
assert!(seo_weight > &0.20, "News should have strong SEO weight");
let word_count_exp = profile
.content_expectations
.word_count
.expect("Should have word count expectations");
assert!(
word_count_exp.optimal_range.0 >= 200,
"News articles should have minimum text"
);
assert!(
word_count_exp.optimal_range.1 <= 1000,
"News articles should be relatively concise"
);
}
#[tokio::test]
async fn test_profile_templates_product_characteristics() {
let profile = ProfileTemplates::get_template("product").expect("product template should exist");
let seo_weight = profile
.category_weights
.get("seo")
.expect("seo category should exist");
assert!(
seo_weight > &0.25,
"Product pages need strong SEO, got {}",
seo_weight
);
let word_count_exp = profile
.content_expectations
.word_count
.expect("Should have word count expectations");
assert!(
word_count_exp.minimum < 200,
"Product pages can have minimal text"
);
}