jsdet-chrome-ext 0.1.0

Chrome Extension API bridges for jsdet — chrome.tabs, chrome.cookies, chrome.webRequest, etc.
Documentation
//! Parser robustness tests — adversarial inputs that try to crash parsers.
//! Each test feeds malformed data to a parser and verifies it returns
//! an error instead of panicking.

use jsdet_chrome_ext::Manifest;

#[test]
fn manifest_empty_string() {
    assert!(Manifest::parse("").is_err());
}

#[test]
fn manifest_null() {
    assert!(Manifest::parse("null").is_err());
}

#[test]
fn manifest_number() {
    assert!(Manifest::parse("42").is_err());
}

#[test]
fn manifest_array_does_not_panic() {
    // Array is not a valid manifest — should either error or produce default
    let _ = Manifest::parse("[]");
}

#[test]
fn manifest_string() {
    assert!(Manifest::parse("\"hello\"").is_err());
}

#[test]
fn manifest_missing_name() {
    // name is required
    let result = Manifest::parse(r#"{"manifest_version":3,"version":"1.0"}"#);
    // Should either error or use default name
    let _ = result; // Just don't panic
}

#[test]
fn manifest_missing_version() {
    let result = Manifest::parse(r#"{"name":"T","manifest_version":3}"#);
    let _ = result;
}

#[test]
fn manifest_missing_manifest_version() {
    let result = Manifest::parse(r#"{"name":"T","version":"1.0"}"#);
    let _ = result;
}

#[test]
fn manifest_very_long_name() {
    let name = "A".repeat(100_000);
    let json = format!(
        r#"{{"name":"{}","manifest_version":3,"version":"1.0"}}"#,
        name
    );
    let _ = Manifest::parse(&json);
}

#[test]
fn manifest_unicode_name() {
    let _ = Manifest::parse(r#"{"name":"日本語テスト🔥","manifest_version":3,"version":"1.0"}"#);
}

#[test]
fn manifest_null_fields() {
    let _ = Manifest::parse(r#"{"name":null,"manifest_version":null,"version":null}"#);
}

#[test]
fn manifest_wrong_types() {
    let _ = Manifest::parse(r#"{"name":42,"manifest_version":"three","version":true}"#);
}

#[test]
fn manifest_nested_deeply() {
    let deep = "{".repeat(100) + "}".repeat(100).as_str();
    let _ = Manifest::parse(&deep);
}

#[test]
fn manifest_huge_permissions() {
    let perms: Vec<String> = (0..10000).map(|i| format!("\"perm_{i}\"")).collect();
    let json = format!(
        r#"{{"name":"T","manifest_version":3,"version":"1.0","permissions":[{}]}}"#,
        perms.join(",")
    );
    let _ = Manifest::parse(&json);
}

#[test]
fn manifest_special_characters_in_fields() {
    let _ = Manifest::parse(
        r#"{"name":"<script>alert(1)</script>","manifest_version":3,"version":"1.0"}"#,
    );
}

#[test]
fn manifest_backslash_in_name() {
    let _ = Manifest::parse(r#"{"name":"test\\path","manifest_version":3,"version":"1.0"}"#);
}

#[test]
fn manifest_empty_background() {
    let m = Manifest::parse(r#"{"name":"T","manifest_version":3,"version":"1.0","background":{}}"#);
    let _ = m;
}

#[test]
fn manifest_background_with_empty_sw() {
    let m = Manifest::parse(
        r#"{"name":"T","manifest_version":3,"version":"1.0","background":{"service_worker":""}}"#,
    );
    let _ = m;
}

#[test]
fn manifest_content_scripts_empty_matches() {
    let m = Manifest::parse(
        r#"{"name":"T","manifest_version":3,"version":"1.0","content_scripts":[{"matches":[],"js":[]}]}"#,
    );
    let _ = m;
}

#[test]
fn manifest_content_scripts_no_js() {
    let m = Manifest::parse(
        r#"{"name":"T","manifest_version":3,"version":"1.0","content_scripts":[{"matches":["*://*/*"]}]}"#,
    );
    let _ = m;
}

#[test]
fn manifest_mv2_with_background_page() {
    let m = Manifest::parse(
        r#"{"name":"T","manifest_version":2,"version":"1.0","background":{"page":"bg.html"}}"#,
    );
    let _ = m;
}

#[test]
fn manifest_mv2_with_background_scripts() {
    let m = Manifest::parse(
        r#"{"name":"T","manifest_version":2,"version":"1.0","background":{"scripts":["bg1.js","bg2.js"]}}"#,
    );
    if let Ok(m) = m {
        assert_eq!(m.background.as_ref().map(|b| b.scripts.len()), Some(2));
    }
}

#[test]
fn manifest_extra_unknown_fields_ignored() {
    let m = Manifest::parse(
        r#"{"name":"T","manifest_version":3,"version":"1.0","unknown_field":"value","another":42}"#,
    );
    assert!(m.is_ok(), "unknown fields should be ignored");
}

#[test]
fn manifest_duplicate_keys() {
    // JSON spec says last value wins for duplicate keys
    let _ =
        Manifest::parse(r#"{"name":"First","name":"Second","manifest_version":3,"version":"1.0"}"#);
}

#[test]
fn manifest_truncated_json() {
    assert!(Manifest::parse(r#"{"name":"T","manifest_version":3"#).is_err());
}

#[test]
fn manifest_trailing_comma() {
    // Trailing commas are not valid JSON
    assert!(Manifest::parse(r#"{"name":"T","manifest_version":3,"version":"1.0",}"#).is_err());
}