proofmode 0.9.0

Capture, share, and preserve verifiable photos and videos
Documentation
use proofmode::{check_files, generate_proof_from_data, generate_proof_from_file};
use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;

#[cfg(test)]
mod integration_tests {
    use super::*;

    fn create_test_file(content: &[u8]) -> (TempDir, PathBuf) {
        let temp_dir = TempDir::new().expect("Failed to create temp dir");
        let file_path = temp_dir.path().join("test_file.txt");
        fs::write(&file_path, content).expect("Failed to write test file");
        (temp_dir, file_path)
    }

    #[test]
    fn test_generate_proof_from_file_integration() {
        let (_temp_dir, file_path) = create_test_file(b"Integration test content");
        let storage_dir = TempDir::new().expect("Failed to create storage dir");

        let result = generate_proof_from_file(
            &file_path,
            storage_dir.path(),
            "test@example.com",
            "testpassword",
            None,
        );

        assert!(result.is_ok());
        let hash = result.unwrap();
        assert!(!hash.is_empty());
        assert_eq!(hash.len(), 64); // SHA256 hash length

        // Check that proof files were created
        let proof_dir = storage_dir.path().join("proofmode").join(&hash);
        assert!(proof_dir.exists());

        let json_file = proof_dir.join(format!("{}.proof.json", hash));
        let csv_file = proof_dir.join(format!("{}.proof.csv", hash));
        let asc_file = proof_dir.join(format!("{}.asc", hash));

        assert!(json_file.exists());
        assert!(csv_file.exists());
        assert!(asc_file.exists());

        // Verify JSON content
        let json_content = fs::read_to_string(&json_file).unwrap();
        assert!(json_content.contains(&hash));
        assert!(json_content.contains("file_hash_sha256"));
        assert!(json_content.contains("timestamps"));

        // Verify CSV content
        let csv_content = fs::read_to_string(&csv_file).unwrap();
        assert!(csv_content.contains("key,value"));
        assert!(csv_content.contains(&format!("file_hash_sha256,{}", hash)));
    }

    #[test]
    fn test_generate_proof_from_data_integration() {
        let test_data = b"Direct data integration test";
        let storage_dir = TempDir::new().expect("Failed to create storage dir");

        let result = generate_proof_from_data(
            test_data,
            storage_dir.path(),
            "test@example.com",
            "testpassword",
            None,
        );

        assert!(result.is_ok());
        let hash = result.unwrap();
        assert!(!hash.is_empty());

        // Verify the hash matches expected
        let expected_hash = proofmode::crypto::hash::calculate_hash(test_data);
        assert_eq!(hash, expected_hash);
    }

    #[test]
    fn test_multiple_file_generation() {
        let storage_dir = TempDir::new().expect("Failed to create storage dir");

        // Generate proofs for multiple files
        let files_and_hashes = vec![
            ("First file content".as_bytes(), "file1"),
            ("Second file content".as_bytes(), "file2"),
            ("Third file content".as_bytes(), "file3"),
        ];

        let mut generated_hashes = Vec::new();

        for (content, _name) in &files_and_hashes {
            let (_temp_dir, file_path) = create_test_file(content);

            let result = generate_proof_from_file(
                &file_path,
                storage_dir.path(),
                "test@example.com",
                "testpassword",
                None,
            );

            assert!(result.is_ok());
            let hash = result.unwrap();
            generated_hashes.push(hash);
        }

        // Verify all hashes are unique
        assert_eq!(generated_hashes.len(), 3);
        for i in 0..generated_hashes.len() {
            for j in (i + 1)..generated_hashes.len() {
                assert_ne!(generated_hashes[i], generated_hashes[j]);
            }
        }

        // Verify all proof directories exist
        for hash in &generated_hashes {
            let proof_dir = storage_dir.path().join("proofmode").join(hash);
            assert!(proof_dir.exists());
        }
    }

    #[test]
    fn test_check_files_integration() {
        // Create a test file
        let (_temp_dir, file_path) = create_test_file(b"Check integration test");

        let files = vec![file_path.to_string_lossy().to_string()];

        let callback: std::sync::Arc<
            dyn Fn(proofmode::check::utils::MessageType, String) + Send + Sync,
        > = std::sync::Arc::new(|_message_type, _message: String| {});

        let result = check_files(&files, callback);
        assert!(result.is_ok());

        let proof_check = result.unwrap();
        // The check should complete without errors
        assert!(true); // Basic completion test
    }

    #[test]
    fn test_hash_consistency() {
        let test_data = b"Consistency test data";

        // Generate hash multiple times
        let hash1 = proofmode::crypto::hash::calculate_hash(test_data);
        let hash2 = proofmode::crypto::hash::calculate_hash(test_data);
        let hash3 = proofmode::crypto::hash::calculate_hash(test_data);

        assert_eq!(hash1, hash2);
        assert_eq!(hash2, hash3);
        assert_eq!(hash1.len(), 64); // SHA256 length
    }

    #[test]
    fn test_different_data_different_hashes() {
        let data1 = b"First piece of data";
        let data2 = b"Second piece of data";
        let data3 = b""; // Empty data

        let hash1 = proofmode::crypto::hash::calculate_hash(data1);
        let hash2 = proofmode::crypto::hash::calculate_hash(data2);
        let hash3 = proofmode::crypto::hash::calculate_hash(data3);

        assert_ne!(hash1, hash2);
        assert_ne!(hash2, hash3);
        assert_ne!(hash1, hash3);
    }

    #[test]
    #[cfg(feature = "sequoia-openpgp")]
    fn test_pgp_integration() {
        use proofmode::crypto::pgp::PgpUtils;

        let mut pgp = PgpUtils::new();

        // Generate keys
        let result = pgp.generate_keys("integration@test.com", "integrationpass");
        assert!(result.is_ok());

        // Get public key
        let public_key = pgp.get_public_key_string();
        assert!(public_key.is_ok());
        let key_string = public_key.unwrap();
        assert!(key_string.contains("-----BEGIN PGP"));
        assert!(key_string.contains("-----END PGP"));

        // Sign some data
        let test_data = b"Integration test signing data";
        let signature = pgp.sign_data(test_data, "integrationpass");
        assert!(signature.is_ok());
        let sig_bytes = signature.unwrap();
        assert!(!sig_bytes.is_empty());

        // Verify signature
        let verification = pgp.verify_signature(test_data, &sig_bytes);
        assert!(verification.is_ok());
        assert!(verification.unwrap());
    }

    #[test]
    fn test_error_handling() {
        // Test with non-existent file
        let non_existent = PathBuf::from("/non/existent/file.txt");
        let storage_dir = TempDir::new().expect("Failed to create storage dir");

        let result = generate_proof_from_file(
            &non_existent,
            storage_dir.path(),
            "test@example.com",
            "testpassword",
            None,
        );

        assert!(result.is_err());
    }

    #[test]
    fn test_storage_path_creation() {
        let storage_dir = TempDir::new().expect("Failed to create storage dir");
        let nested_storage = storage_dir
            .path()
            .join("nested")
            .join("storage")
            .join("path");

        let (_temp_dir, file_path) = create_test_file(b"Storage path test");

        let result = generate_proof_from_file(
            &file_path,
            &nested_storage,
            "test@example.com",
            "testpassword",
            None,
        );

        assert!(result.is_ok());

        // Verify nested directories were created
        assert!(nested_storage.exists());
        let hash = result.unwrap();
        let proof_dir = nested_storage.join("proofmode").join(&hash);
        assert!(proof_dir.exists());
    }

    #[test]
    fn test_metadata_integration() {
        use proofmode::generate_types::Metadata;

        let (_temp_dir, file_path) = create_test_file(b"Metadata integration test");
        let storage_dir = TempDir::new().expect("Failed to create storage dir");

        let metadata = Some(Metadata {
            description: Some("Integration test description".to_string()),
            location: Some("Test Location".to_string()),
            event_type: Some("Test Event".to_string()),
            tags: Some("integration,test,metadata".to_string()),
        });

        let result = generate_proof_from_file(
            &file_path,
            storage_dir.path(),
            "test@example.com",
            "testpassword",
            metadata,
        );

        assert!(result.is_ok());
        let hash = result.unwrap();

        // Verify metadata in proof files
        let proof_dir = storage_dir.path().join("proofmode").join(&hash);
        let json_file = proof_dir.join(format!("{}.proof.json", hash));
        let json_content = fs::read_to_string(&json_file).unwrap();

        assert!(json_content.contains("Integration test description"));
        assert!(json_content.contains("Test Location"));
        assert!(json_content.contains("Test Event"));
        assert!(json_content.contains("integration,test,metadata"));
    }
}