webpage_quality_analyzer 1.0.2

High-performance webpage quality analyzer with 115 comprehensive metrics - Rust library with WASM, C++, and Python bindings
Documentation
#[cfg(test)]
mod field_selector_tests {
    use super::super::json_optimizer::{FieldSelector, OptimizedSerializer, SerializationOptions};
    use crate::analyze;
    use crate::models::models::PageQualityReport;
    use crate::test_fixtures::SAMPLE_ARTICLE_HTML;
    use serde_json::Value;

    #[tokio::test]
    async fn test_field_selector_include_only() {
        // Create a test report
        let report = create_test_report().await;

        // Create selector that includes only specific fields
        let selector = FieldSelector::builder()
            .include_fields(["url", "score", "verdict"])
            .build();

        let json = OptimizedSerializer::serialize_with_selector(&report, &selector, None).unwrap();
        let value: Value = serde_json::from_str(&json).unwrap();

        // Should only have the included fields
        let obj = value.as_object().unwrap();
        assert!(obj.contains_key("url"));
        assert!(obj.contains_key("score"));
        assert!(obj.contains_key("verdict"));

        // Should not have excluded fields
        assert!(!obj.contains_key("metrics"));
        assert!(!obj.contains_key("processed_document"));
        assert!(!obj.contains_key("metadata"));
    }

    #[tokio::test]
    async fn test_field_selector_exclude_fields() {
        let report = create_test_report().await;

        // Create selector that excludes specific fields
        let selector = FieldSelector::builder()
            .exclude_fields(["processed_document", "metadata"])
            .build();

        let json = OptimizedSerializer::serialize_with_selector(&report, &selector, None).unwrap();
        let value: Value = serde_json::from_str(&json).unwrap();

        let obj = value.as_object().unwrap();

        // Should have non-excluded fields
        assert!(obj.contains_key("url"));
        assert!(obj.contains_key("score"));
        assert!(obj.contains_key("metrics"));

        // Should not have excluded fields
        assert!(!obj.contains_key("processed_document"));
        assert!(!obj.contains_key("metadata"));
    }

    #[tokio::test]
    async fn test_field_selector_nested_paths() {
        let report = create_test_report().await;

        // Create selector with nested path filtering
        let selector = FieldSelector::builder()
            .include_sections(["metrics"])
            .exclude_fields(["metrics.html_analysis.accessibility"])
            .build();

        let json = OptimizedSerializer::serialize_with_selector(&report, &selector, None).unwrap();
        let value: Value = serde_json::from_str(&json).unwrap();

        let obj = value.as_object().unwrap();

        // Should have metrics section
        assert!(obj.contains_key("metrics"));

        // Should not have other top-level sections
        assert!(!obj.contains_key("processed_document"));
        assert!(!obj.contains_key("metadata"));

        // Check nested exclusion within metrics
        if let Some(Value::Object(metrics)) = obj.get("metrics") {
            if let Some(Value::Object(html_analysis)) = metrics.get("html_analysis") {
                assert!(!html_analysis.contains_key("accessibility"));
            }
        }
    }

    #[tokio::test]
    async fn test_field_selector_section_include_exclude() {
        let report = create_test_report().await;

        // Include sections but exclude specific one
        let selector = FieldSelector::builder()
            .include_sections(["url", "score", "metrics", "processed_document"])
            .exclude_sections(["processed_document"])
            .build();

        let json = OptimizedSerializer::serialize_with_selector(&report, &selector, None).unwrap();
        let value: Value = serde_json::from_str(&json).unwrap();

        let obj = value.as_object().unwrap();

        // Should have included sections
        assert!(obj.contains_key("url"));
        assert!(obj.contains_key("score"));
        assert!(obj.contains_key("metrics"));

        // Should not have excluded section (exclusion takes precedence)
        assert!(!obj.contains_key("processed_document"));
    }

    #[tokio::test]
    async fn test_field_selector_priority_rules() {
        let report = create_test_report().await;

        // Test that field-level exclusion takes precedence over section inclusion
        let selector = FieldSelector::builder()
            .include_sections(["metrics"])
            .exclude_fields(["metrics"]) // This should take precedence
            .build();

        let json = OptimizedSerializer::serialize_with_selector(&report, &selector, None).unwrap();
        let value: Value = serde_json::from_str(&json).unwrap();

        let obj = value.as_object().unwrap();

        // Should not have metrics due to field-level exclusion
        assert!(!obj.contains_key("metrics"));
    }

    #[tokio::test]
    async fn test_field_selector_batch_processing() {
        let reports = vec![create_test_report().await, create_test_report().await];

        let selector = FieldSelector::builder()
            .include_fields(["url", "score"])
            .build();

        let options = SerializationOptions::batch_processing();
        let json =
            OptimizedSerializer::serialize_batch_with_selector(&reports, &selector, Some(&options))
                .unwrap();

        let value: Value = serde_json::from_str(&json).unwrap();
        let array = value.as_array().unwrap();

        assert_eq!(array.len(), 2);

        for report_value in array {
            let obj = report_value.as_object().unwrap();
            assert!(obj.contains_key("url"));
            assert!(obj.contains_key("score"));
            assert!(!obj.contains_key("metrics"));
            assert!(!obj.contains_key("processed_document"));
        }
    }

    #[tokio::test]
    async fn test_field_selector_builder_fluent_api() {
        // Test the fluent builder API
        let selector = FieldSelector::builder()
            .include_field("url")
            .include_field("score")
            .include_fields(["verdict", "fetched_at"])
            .exclude_field("notes")
            .exclude_fields(["version", "metadata"])
            .include_section("metrics")
            .exclude_section("processed_document")
            .build();

        // Test the should_include_field method
        assert!(selector.should_include_field("url"));
        assert!(selector.should_include_field("score"));
        assert!(selector.should_include_field("verdict"));
        assert!(selector.should_include_field("metrics"));
        assert!(selector.should_include_field("metrics.content.word_count"));

        assert!(!selector.should_include_field("notes"));
        assert!(!selector.should_include_field("version"));
        assert!(!selector.should_include_field("metadata"));
        assert!(!selector.should_include_field("processed_document"));
        assert!(!selector.should_include_field("processed_document.headings"));
    }

    #[test]
    fn test_field_selector_summary() {
        let selector = FieldSelector::builder()
            .include_fields(["url", "score"])
            .exclude_fields(["metadata"])
            .include_sections(["metrics"])
            .build();

        let summary = selector.summary();
        assert!(summary.contains("Include fields: 2"));
        assert!(summary.contains("Exclude fields: 1"));
        assert!(summary.contains("Include sections: 1"));
    }

    #[test]
    fn test_field_selector_default_behavior() {
        let selector = FieldSelector::new();

        // With no rules, should include everything
        assert!(selector.should_include_field("url"));
        assert!(selector.should_include_field("metrics"));
        assert!(selector.should_include_field("processed_document"));
        assert!(selector.should_include_field("any.nested.path"));

        assert_eq!(selector.summary(), "No filtering rules (include all)");
    }

    #[test]
    fn test_field_selector_include_rules_default_exclude() {
        let selector = FieldSelector::builder()
            .include_fields(["url", "score"])
            .build();

        // With include rules, should exclude by default unless explicitly included
        assert!(selector.should_include_field("url"));
        assert!(selector.should_include_field("score"));
        assert!(!selector.should_include_field("metrics"));
        assert!(!selector.should_include_field("processed_document"));
    }

    // Helper function to create a test report
    async fn create_test_report() -> PageQualityReport {
        // Use a simple test case
        analyze("https://example.com", Some(SAMPLE_ARTICLE_HTML))
            .await
            .unwrap()
    }
}