From e3dfc43e2c4dc80b843b4abf7070fe75a2161283 Mon Sep 17 00:00:00 2001 From: Christian Nennemann Date: Wed, 4 Mar 2026 13:31:22 +0100 Subject: [PATCH] test: add unit tests for token cache round-trip and edge cases --- .../src/client/token_cache.rs | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/crates/quicproquo-client/src/client/token_cache.rs b/crates/quicproquo-client/src/client/token_cache.rs index 8672957..ed6303f 100644 --- a/crates/quicproquo-client/src/client/token_cache.rs +++ b/crates/quicproquo-client/src/client/token_cache.rs @@ -91,3 +91,88 @@ pub fn clear_cached_session(state_path: &Path) { let path = session_cache_path(state_path); std::fs::remove_file(&path).ok(); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn plaintext_round_trip() { + let dir = tempfile::tempdir().unwrap(); + let state_path = dir.path().join("state.bin"); + + let token = hex::encode(b"session-token-bytes"); + save_cached_session(&state_path, "alice", &token, None).unwrap(); + let loaded = load_cached_session(&state_path, None).unwrap(); + assert_eq!(loaded.username, "alice"); + assert_eq!(loaded.token_hex, token); + } + + #[test] + fn encrypted_round_trip() { + let dir = tempfile::tempdir().unwrap(); + let state_path = dir.path().join("state.bin"); + let password = "strong-password"; + + let token = hex::encode(b"encrypted-token"); + save_cached_session(&state_path, "bob", &token, Some(password)).unwrap(); + + // Encrypted file should start with QPCE magic + let raw = std::fs::read(session_cache_path(&state_path)).unwrap(); + assert_eq!(&raw[..4], b"QPCE"); + + let loaded = load_cached_session(&state_path, Some(password)).unwrap(); + assert_eq!(loaded.username, "bob"); + assert_eq!(loaded.token_hex, token); + } + + #[test] + fn wrong_password_returns_none() { + let dir = tempfile::tempdir().unwrap(); + let state_path = dir.path().join("state.bin"); + + let token = hex::encode(b"secret-token"); + save_cached_session(&state_path, "carol", &token, Some("correct")).unwrap(); + let result = load_cached_session(&state_path, Some("wrong")); + assert!(result.is_none()); + } + + #[test] + fn missing_file_returns_none() { + let dir = tempfile::tempdir().unwrap(); + let state_path = dir.path().join("nonexistent.bin"); + assert!(load_cached_session(&state_path, None).is_none()); + } + + #[test] + fn clear_removes_file() { + let dir = tempfile::tempdir().unwrap(); + let state_path = dir.path().join("state.bin"); + + let token = hex::encode(b"to-be-deleted"); + save_cached_session(&state_path, "dave", &token, None).unwrap(); + assert!(session_cache_path(&state_path).exists()); + + clear_cached_session(&state_path); + assert!(!session_cache_path(&state_path).exists()); + } + + #[test] + fn malformed_content_returns_none() { + let dir = tempfile::tempdir().unwrap(); + let state_path = dir.path().join("state.bin"); + let cache_path = session_cache_path(&state_path); + + // Not valid hex on second line + std::fs::write(&cache_path, "alice\nnot-hex-data\n").unwrap(); + assert!(load_cached_session(&state_path, None).is_none()); + + // Only one line + std::fs::write(&cache_path, "alice\n").unwrap(); + assert!(load_cached_session(&state_path, None).is_none()); + + // Empty file + std::fs::write(&cache_path, "").unwrap(); + assert!(load_cached_session(&state_path, None).is_none()); + } +}