//! Integration coverage for the client paste-request contract. //! //! Scope: validate key loading, encryption metadata, and truncation behavior //! through the public paste helper. //! Targets: `client/src/paste.rs`. //! Why: these checks are pure policy and crypto framing, so they belong in the //! centralized `testing/tests` contract suite. use chacha20poly1305::aead::Aead; use chacha20poly1305::{ChaCha20Poly1305, Key, KeyInit, Nonce}; use lesavka_client::paste::build_paste_request; use serial_test::serial; use temp_env::with_var; const TEST_KEY_HEX: &str = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; #[test] #[serial] fn build_paste_request_requires_a_shared_key() { with_var("LESAVKA_PASTE_KEY", None::<&str>, || { let err = build_paste_request("hello").expect_err("missing key should fail"); assert!(format!("{err:#}").contains("LESAVKA_PASTE_KEY")); }); } #[test] #[serial] fn build_paste_request_sets_encryption_fields() { with_var("LESAVKA_PASTE_KEY", Some(TEST_KEY_HEX), || { let req = build_paste_request("hello world").expect("build request"); assert!(req.encrypted); assert_eq!(req.nonce.len(), 12); assert!(!req.data.is_empty()); }); } #[test] #[serial] fn build_paste_request_truncates_plaintext_before_encryption() { with_var("LESAVKA_PASTE_KEY", Some(TEST_KEY_HEX), || { with_var("LESAVKA_PASTE_MAX", Some("5"), || { let req = build_paste_request("hello-from-lesavka").expect("build truncated request"); let key = lesavka_common::paste::decode_shared_key(TEST_KEY_HEX).expect("decode key"); let cipher = ChaCha20Poly1305::new(Key::from_slice(&key)); let nonce = Nonce::from_slice(&req.nonce); let plaintext = cipher .decrypt(nonce, req.data.as_ref()) .expect("decrypt request data"); assert_eq!(std::str::from_utf8(&plaintext).expect("utf8"), "hello"); }); }); }