//! Integration tests for CSV parsing. //! //! AI AGENT NOTE: These tests verify full CSV parsing with actual files. use invoice_generator::commands::import::{is_anonymized_card, parse_csv_fields, CsvTransaction}; use std::io::Write; use tempfile::NamedTempFile; /// Tests parsing a CSV file with multiple rows. #[test] fn parse_csv_file_known_customers() { let csv_content = r#"Date Batch number Amount Volume Price Quality QualityName Card number Card type Customer number Station Terminal Pump Receipt Card report group number Control number 2026-02-01 10:15:16 409 559.26 35.85 15.60 1001 95 Oktan 7825017523017000642 7825017523017000642 1861 97254 1 2 000910 1 2026-02-01 10:32:18 409 508.40 32.59 15.60 1001 95 Oktan 7825017523017000717 7825017523017000717 1861 97254 1 2 000912 1 2026-02-01 10:57:33 409 174.41 11.18 15.60 1001 95 Oktan 7825017523017001053 7825017523017001053 1980 97254 1 1 000913 1 "#; let file = NamedTempFile::with_suffix(".csv").unwrap(); file.as_file().write_all(csv_content.as_bytes()).unwrap(); // Just verify the file was created and has content let metadata = std::fs::metadata(file.path()).unwrap(); assert!(metadata.len() > 0); } /// Tests that anonymized cards are correctly identified. #[test] fn anonymized_card_detection() { // Known card (full number) assert!(!is_anonymized_card("7825017523017000642")); assert!(!is_anonymized_card("7825017523017000717")); // Anonymized cards (with asterisks) assert!(is_anonymized_card("554477******9952")); assert!(is_anonymized_card("673706*********0155")); assert!(is_anonymized_card("404776******7006")); // Edge cases assert!(!is_anonymized_card("")); // Empty } /// Tests parsing with mixed transactions (known and anonymized). #[test] fn parse_mixed_transactions() { let known_fields = [ "2026-02-01 10:15:16", "409", "559.26", "35.85", "15.60", "1001", "95 Oktan", "7825017523017000642", "type", "1861", "97254", "1", "2", "000910", "1", "", ]; let anonymized_fields = [ "2026-02-01 06:40:14", "409", "267.23", "17.13", "15.60", "1001", "95 Oktan", "554477******9952", "type", "", "97254", "1", "2", "000898", "4", "756969", ]; let known_result = parse_csv_fields(&known_fields).unwrap(); let anonymized_result = parse_csv_fields(&anonymized_fields).unwrap(); assert!(known_result.is_some()); assert!(anonymized_result.is_some()); let known_tx = known_result.unwrap(); let anonymized_tx = anonymized_result.unwrap(); // Known customer has customer_number assert_eq!(known_tx.customer_number, "1861"); assert!(!is_anonymized_card(&known_tx.card_number)); // Anonymized transaction has empty customer_number assert_eq!(anonymized_tx.customer_number, ""); assert!(is_anonymized_card(&anonymized_tx.card_number)); } /// Tests that transactions are counted correctly. #[test] fn transaction_counting() { let fields_1 = [ "2026-02-01 10:15:16", "409", "559.26", "35.85", "15.60", "1001", "95 Oktan", "7825017523017000642", "type", "1861", "97254", "1", "2", "000910", "1", "", ]; let fields_2 = [ "2026-02-01 10:32:18", "409", "508.40", "32.59", "15.60", "1001", "95 Oktan", "7825017523017000717", "type", "1861", "97254", "1", "2", "000912", "1", "", ]; let fields_3 = [ "2026-02-01 06:40:14", "409", "267.23", "17.13", "15.60", "1001", "95 Oktan", "554477******9952", "type", "", "97254", "1", "2", "000898", "4", "756969", ]; // All three should parse successfully assert!(parse_csv_fields(&fields_1).unwrap().is_some()); assert!(parse_csv_fields(&fields_2).unwrap().is_some()); assert!(parse_csv_fields(&fields_3).unwrap().is_some()); } /// Tests that duplicate customers are handled. #[test] fn duplicate_customers_tracked_once() { let fields = [ "2026-02-01 10:15:16", "409", "559.26", "35.85", "15.60", "1001", "95 Oktan", "7825017523017000642", "type", "1861", "97254", "1", "2", "000910", "1", "", ]; let result = parse_csv_fields(&fields).unwrap().unwrap(); // Customer 1861 should be tracked assert_eq!(result.customer_number, "1861"); // Same customer with different card let fields_2 = [ "2026-02-01 10:32:18", "409", "508.40", "32.59", "15.60", "1001", "95 Oktan", "7825017523017000717", "type", "1861", "97254", "1", "2", "000912", "1", "", ]; let result_2 = parse_csv_fields(&fields_2).unwrap().unwrap(); // Same customer, different card assert_eq!(result_2.customer_number, "1861"); assert_ne!(result.card_number, result_2.card_number); } /// Tests diesel product parsing. #[test] fn diesel_product_parsing() { let fields = [ "2026-02-01 10:05:16", "409", "543.22", "31.40", "17.30", "4", "Diesel", "673706*********0155", "type", "", "97254", "1", "2", "000909", "4", "D00824", ]; let result = parse_csv_fields(&fields).unwrap().unwrap(); assert_eq!(result.quality_name, "Diesel"); assert_eq!(result.quality, 4); assert_eq!(result.price, 17.30); assert_eq!(result.control_number, "D00824"); } /// Tests that amount > 0 filter works. #[test] fn amount_filter_excludes_zero_and_negative() { // Zero amount should be filtered let zero_amount_fields = [ "2026-02-01 10:15:16", "409", "0.00", "0.00", "15.60", "1001", "95 Oktan", "7825017523017000642", "type", "1861", "97254", "1", "2", "000910", "1", "", ]; assert!(parse_csv_fields(&zero_amount_fields).unwrap().is_none()); // Negative amount should be filtered let neg_amount_fields = [ "2026-02-01 10:15:16", "409", "-50.00", "-3.00", "15.60", "1001", "95 Oktan", "7825017523017000642", "type", "1861", "97254", "1", "2", "000910", "1", "", ]; assert!(parse_csv_fields(&neg_amount_fields).unwrap().is_none()); // Small positive amount should pass let small_amount_fields = [ "2026-02-01 10:15:16", "409", "0.01", "0.001", "15.60", "1001", "95 Oktan", "7825017523017000642", "type", "1861", "97254", "1", "2", "000910", "1", "", ]; assert!(parse_csv_fields(&small_amount_fields).unwrap().is_some()); }