webpage_quality_analyzer 1.0.2

High-performance webpage quality analyzer with 115 comprehensive metrics - Rust library with WASM, C++, and Python bindings
Documentation
//! End-to-End Verification Test for Phase 1 & 2
//! Tests the complete flow from ProfileModifier through AnalyzerBuilder to actual analysis

use webpage_quality_analyzer::{analyze, Analyzer};

const TEST_HTML: &str = r#"
<!DOCTYPE html>
<html>
<head>
    <title>Test Page</title>
    <meta name="description" content="A test page for verification">
</head>
<body>
    <h1>Main Heading</h1>
    <p>This is a test paragraph with some content.</p>
    <img src="test.jpg" alt="Test image">
</body>
</html>
"#;

const TEST_URL: &str = "http://example.com";

#[tokio::test]
async fn test_phase1_phase2_end_to_end_flow() {
    // Test the complete flow: ProfileModifier → AnalyzerBuilder → Analysis

    // 1. Test with default analyze() function
    let result_basic = analyze(TEST_URL, Some(TEST_HTML)).await;
    assert!(result_basic.is_ok(), "Basic analysis should succeed");

    // 2. Test with metrics disabled (Phase 2 functionality)
    let analyzer_disabled: Analyzer = Analyzer::builder()
        .with_profile_name("content_article")
        .unwrap()
        .disable_metric("word_count")
        .unwrap()
        .disable_metric("readability_fk")
        .unwrap()
        .build()
        .unwrap();

    let result_disabled = analyzer_disabled.run(TEST_URL, Some(TEST_HTML)).await;

    assert!(
        result_disabled.is_ok(),
        "Analysis with disabled metrics should succeed"
    );
    let report_disabled = result_disabled.unwrap();

    // Should still produce valid report with remaining metrics
    assert!(
        report_disabled.score > 0.0,
        "Score should be calculated even with disabled metrics"
    );

    // 3. Test bulk disable (Phase 2 functionality)
    let analyzer_bulk: Analyzer = Analyzer::builder()
        .with_profile_name("news")
        .unwrap()
        .disable_metrics(vec!["title_len".to_string(), "images_count".to_string()])
        .unwrap()
        .build()
        .unwrap();

    let result_bulk = analyzer_bulk.run(TEST_URL, Some(TEST_HTML)).await;
    assert!(result_bulk.is_ok(), "Bulk disable should work");

    // 4. Test enable/disable chaining (Phase 2 functionality)
    let analyzer_chain: Analyzer = Analyzer::builder()
        .with_profile_name("blog")
        .unwrap()
        .disable_metric("title_len")
        .unwrap()
        .enable_metric("word_count")
        .unwrap()
        .disable_metric("readability_fk")
        .unwrap()
        .build()
        .unwrap();

    let result_chain = analyzer_chain.run(TEST_URL, Some(TEST_HTML)).await;
    assert!(result_chain.is_ok(), "Chained operations should work");

    // 5. Verify error handling with invalid metric name
    let result_invalid: Result<Analyzer, _> = Analyzer::builder()
        .with_profile_name("content_article")
        .unwrap()
        .disable_metric("invalid_metric_name_xyz")
        .and_then(|b| b.build());

    assert!(
        result_invalid.is_err(),
        "Invalid metric name should produce error"
    );
    let error_msg = result_invalid.unwrap_err().to_string();
    assert!(
        error_msg.contains("invalid_metric_name_xyz"),
        "Error should mention invalid metric"
    );

    println!("✅ Phase 1 & 2 end-to-end tests PASSED!");
}

#[tokio::test]
async fn test_profile_modifier_integration() {
    // Verify ProfileModifier is properly integrated with ConfigManager

    use webpage_quality_analyzer::config::ConfigManager;

    let mut manager = ConfigManager::new();

    // Load base profile
    let profile = manager
        .get_profile("content_article")
        .expect("content_article profile should exist");
    assert_eq!(profile.metadata.name, "Content Article");

    // This test verifies ProfileModifier can be used independently
    // and that set_runtime_profile works
    let result = manager.set_runtime_profile(profile.clone());
    assert!(result.is_ok(), "set_runtime_profile should succeed");

    // Verify we can still get the profile after setting it
    let retrieved = manager
        .get_profile("content_article")
        .expect("content_article profile should exist");
    assert_eq!(retrieved.metadata.name, "Content Article");

    println!("✅ ProfileModifier integration test PASSED!");
}

#[tokio::test]
async fn test_complete_verification_workflow() {
    // Complete workflow test covering all Phase 1 & 2 features

    // Test 1: Basic profile loading using Level 1 API
    let report1 = analyze(TEST_URL, Some(TEST_HTML)).await.unwrap();
    assert!(report1.score > 0.0);

    // Test 2: Profile with disabled metrics
    let analyzer2: Analyzer = Analyzer::builder()
        .with_profile_name("content_article")
        .unwrap()
        .disable_metrics(vec![
            "title_len".to_string(),
            "images_count".to_string(),
            "readability_fk".to_string(),
        ])
        .unwrap()
        .build()
        .unwrap();

    let report2 = analyzer2.run(TEST_URL, Some(TEST_HTML)).await.unwrap();
    assert!(report2.score > 0.0);

    // Test 3: Complex chaining
    let analyzer3: Analyzer = Analyzer::builder()
        .with_profile_name("blog")
        .unwrap()
        .enable_metric("word_count")
        .unwrap()
        .enable_metric("paragraph_count")
        .unwrap()
        .disable_metric("title_len")
        .unwrap()
        .build()
        .unwrap();

    let report3 = analyzer3.run(TEST_URL, Some(TEST_HTML)).await.unwrap();
    assert!(report3.score > 0.0);

    println!("✅ All end-to-end verification tests passed!");
    println!("   - Default profile analysis: PASS");
    println!("   - Metric toggling: PASS");
    println!("   - Bulk operations: PASS");
    println!("   - Error handling: PASS");
}