pub mod additional_consent;
pub mod atp_list;
pub mod detection;
pub mod mode_v2;
pub mod validation;
pub use mode_v2::{
encode_gcd_parameter, parse_gcd_parameter, parse_gcs_parameter, ConsentModeV2, ConsentState,
GcdError, GcsError,
};
pub use additional_consent::{
encode_ac_string, parse_ac_string, validate_ac_string_atps, ACError, ACString,
};
pub use atp_list::{ATPError, AdTechProvider, GoogleATPList};
pub use detection::{
detect_google_consent_cookies, detect_google_consent_in_url, detect_in_http_request,
extract_ga_ids, extract_gtm_containers, ConsentSource, GoogleConsentAnalysis,
GoogleConsentData,
};
pub use validation::{
generate_compliance_summary, validate_ac_string_with_atp_list, validate_consent_mode_v2,
validate_google_consent, ConsentComplianceReport, ConsentIssue, ConsentWarning, SeverityLevel,
};
pub const VERSION: &str = "1.0.0";
pub const SUPPORTED_CONSENT_MODES: &[&str] = &["v1", "v2"];
pub const SUPPORTED_AC_VERSIONS: &[u8] = &[1, 2];
pub const GOOGLE_ATP_LIST_URL: &str = "https://storage.googleapis.com/gac/google-atp-list.json";
#[cfg(test)]
mod tests {
use super::*;
use crate::types::Cookie;
#[test]
fn test_full_consent_mode_v2_workflow() {
let gcd = "11l1m1n1p5";
let consent = parse_gcd_parameter(gcd).unwrap();
assert_eq!(consent.ad_storage, ConsentState::GrantedDefault);
assert_eq!(consent.analytics_storage, ConsentState::GrantedUpdate);
let encoded = encode_gcd_parameter(&consent);
assert_eq!(encoded, gcd);
let report = validate_consent_mode_v2(&consent);
assert!(report.is_compliant);
}
#[test]
fn test_full_ac_string_workflow() {
let ac_string = "2~1.35.41.101~dv.9.21.81";
let ac = parse_ac_string(ac_string).unwrap();
assert_eq!(ac.version, 2);
assert_eq!(ac.consented_atps, vec![1, 35, 41, 101]);
assert_eq!(ac.disclosed_atps, vec![9, 21, 81]);
assert!(ac.has_consent(35));
assert!(ac.is_disclosed(81));
assert!(!ac.has_consent(999));
let encoded = encode_ac_string(&ac);
assert_eq!(encoded, ac_string);
let atp_list = GoogleATPList::with_providers(vec![
AdTechProvider::new(1, "Test1".to_string(), vec![]),
AdTechProvider::new(35, "Test35".to_string(), vec![]),
AdTechProvider::new(41, "Test41".to_string(), vec![]),
AdTechProvider::new(101, "Test101".to_string(), vec![]),
AdTechProvider::new(9, "Test9".to_string(), vec![]),
AdTechProvider::new(21, "Test21".to_string(), vec![]),
AdTechProvider::new(81, "Test81".to_string(), vec![]),
]);
let report = validate_ac_string_with_atp_list(&ac, &atp_list);
assert!(report.is_compliant);
}
#[test]
fn test_full_detection_workflow() {
let cookies = vec![
Cookie::new("addtl_consent".to_string(), "2~1.35.41~dv.9.21".to_string()),
Cookie::new("CookieConsent".to_string(), "accepted".to_string()), Cookie::new("_ga".to_string(), "GA1.2.123456.789".to_string()),
Cookie::new("_gid".to_string(), "GA1.2.987654.321".to_string()),
Cookie::new("_gcl_au".to_string(), "1.1234567890.1234567890".to_string()),
];
let analysis = detect_google_consent_cookies(&cookies);
assert!(analysis.ac_string.is_some());
assert!(analysis.consent_cookie.is_some());
assert!(analysis.has_analytics_cookies);
assert!(analysis.has_ads_cookies);
assert_eq!(analysis.detected_products().len(), 2);
let report = validate_google_consent(&analysis);
assert!(report.is_compliant);
assert!(report.score > 80.0);
}
#[test]
fn test_full_url_detection_workflow() {
let url = "https://example.com?gcd=11l1m1n1p5&addtl_consent=2~1.35&utm_source=google";
let data = detect_google_consent_in_url(url).unwrap();
assert!(data.consent_mode_v2.is_some());
assert!(data.ac_string.is_some());
let consent = data.consent_mode_v2.unwrap();
assert!(consent.ad_storage.is_granted());
let ac = data.ac_string.unwrap();
assert_eq!(ac.version, 2);
assert!(ac.has_consent(1));
}
#[test]
fn test_full_validation_workflow() {
let mut analysis = GoogleConsentAnalysis::new();
analysis.has_analytics_cookies = true;
analysis.has_ads_cookies = true;
let report = validate_google_consent(&analysis);
assert!(!report.is_compliant);
assert!(!report.issues.is_empty());
assert!(!report.recommendations.is_empty());
assert!(report.score < 100.0);
let summary = generate_compliance_summary(&report);
assert!(summary.contains("NON-COMPLIANT"));
assert!(summary.contains("Critical Issues"));
analysis.consent_mode_v2 = Some(ConsentModeV2::new_granted());
analysis.ac_string = Some(ACString::with_atps(vec![1, 35], vec![]));
let report2 = validate_google_consent(&analysis);
assert!(report2.is_compliant);
assert!(report2.score > 80.0);
}
}