Files
khadhroony-solana-project/crates/ksp-wallet-lib/unit_tests/wallet_v2.rs
2026-08-22 08:18:38 +02:00

127 lines
7.9 KiB
Rust

// file: crates/ksp-wallet-lib/unit_tests/wallet_v2.rs
// version: 1
const V1_FULL_VECTOR: &[u8] = include_bytes!("../tests/fixtures/kspwallet_v1_full_vector.json");
fn runtime() -> tokio::runtime::Runtime {
return tokio::runtime::Builder::new_current_thread().build().expect("Wallet V2 test runtime must build");
}
#[test]
fn v2_create_open_and_generic_dispatch_preserve_authorized_identity() {
let runtime = runtime();
let owner_password_text = std::string::String::from("pre016-v2-owner-password");
let view_password_text = std::string::String::from("pre016-v2-view-password");
let owner = runtime
.block_on(crate::create_wallet_v2(
crate::OwnerPassword::new(owner_password_text.clone()),
std::option::Option::Some(crate::ViewPassword::new(view_password_text.clone())),
crate::WalletCreateMetadataV1::new(std::option::Option::Some(std::string::String::from("pre016-v2")), std::vec::Vec::new()),
))
.expect("V2 wallet creation must succeed");
assert_eq!(owner.format_version(), crate::KSPWALLET_FORMAT_VERSION_V2);
let pubkey = *owner.pubkey();
let bytes = owner.to_native_bytes().expect("V2 owner must serialize native bytes");
assert_eq!(crate::detect_wallet_format(bytes.as_slice()).expect("V2 framing must detect"), crate::WalletFormat::V2);
assert!(owner.to_json_bytes().is_err());
let view = runtime
.block_on(crate::open_wallet_view(bytes.as_slice(), crate::ViewPassword::new(view_password_text)))
.expect("generic VIEW open must dispatch V2");
assert_eq!(view.format_version(), crate::KSPWALLET_FORMAT_VERSION_V2);
assert_eq!(*view.pubkey(), pubkey);
assert_eq!(view.alias(), std::option::Option::Some("pre016-v2"));
let reopened = runtime
.block_on(crate::open_wallet_owner(bytes.as_slice(), crate::OwnerPassword::new(owner_password_text)))
.expect("generic OWNER open must dispatch V2");
assert_eq!(reopened.format_version(), crate::KSPWALLET_FORMAT_VERSION_V2);
assert_eq!(*reopened.pubkey(), pubkey);
}
#[test]
fn generic_dispatch_keeps_v1_read_compatibility() {
let runtime = runtime();
assert_eq!(crate::detect_wallet_format(V1_FULL_VECTOR).expect("V1 framing must detect"), crate::WalletFormat::V1);
let locked = crate::inspect_locked_wallet(V1_FULL_VECTOR).expect("generic inspect must keep V1 compatibility");
assert_eq!(locked.format_version(), crate::KSPWALLET_FORMAT_VERSION_V1);
let owner = runtime
.block_on(crate::open_wallet_owner(V1_FULL_VECTOR, crate::OwnerPassword::new(std::string::String::from("pre005-owner-password"))))
.expect("generic OWNER open must dispatch V1");
assert_eq!(owner.format_version(), crate::KSPWALLET_FORMAT_VERSION_V1);
}
#[test]
fn default_file_creation_is_v2_and_v2_administration_stays_v2() {
let directory = tempfile::Builder::new().prefix("ksp-pre016-v2-").tempdir().expect("V2 test directory must be creatable");
let path = directory.path().join("default.kspwallet");
let runtime = runtime();
let mut owner = runtime
.block_on(crate::create_wallet_file(
path.as_path(),
crate::OwnerPassword::new(std::string::String::from("pre016-default-owner")),
std::option::Option::Some(crate::ViewPassword::new(std::string::String::from("pre016-default-view"))),
crate::WalletCreateMetadataV1::default(),
))
.expect("default file creation must succeed");
assert_eq!(owner.format_version(), crate::KSPWALLET_FORMAT_VERSION_V2);
let locked = runtime.block_on(crate::inspect_locked_wallet_file(path.as_path())).expect("generic inspect must read default file");
assert_eq!(locked.format_version(), crate::KSPWALLET_FORMAT_VERSION_V2);
runtime
.block_on(owner.update_alias(path.as_path(), std::option::Option::Some(std::string::String::from("pre016-updated"))))
.expect("V2 metadata update must persist in V2");
runtime
.block_on(owner.rotate_owner_password(path.as_path(), crate::OwnerPassword::new(std::string::String::from("pre016-owner-rotated"))))
.expect("V2 OWNER rotation must persist in V2");
runtime
.block_on(owner.rotate_view_password(path.as_path(), crate::ViewPassword::new(std::string::String::from("pre016-view-rotated"))))
.expect("V2 VIEW rotation by OWNER must persist in V2");
let reopened_owner = runtime
.block_on(crate::open_wallet_owner_file(path.as_path(), crate::OwnerPassword::new(std::string::String::from("pre016-owner-rotated"))))
.expect("rotated V2 OWNER must reopen through generic dispatch");
assert_eq!(reopened_owner.format_version(), crate::KSPWALLET_FORMAT_VERSION_V2);
assert_eq!(reopened_owner.alias(), std::option::Option::Some("pre016-updated"));
let reopened_view = runtime
.block_on(crate::open_wallet_view_file(path.as_path(), crate::ViewPassword::new(std::string::String::from("pre016-view-rotated"))))
.expect("rotated V2 VIEW must reopen through generic dispatch");
assert_eq!(reopened_view.format_version(), crate::KSPWALLET_FORMAT_VERSION_V2);
assert_eq!(reopened_view.alias(), std::option::Option::Some("pre016-updated"));
runtime.block_on(owner.disable_view(path.as_path())).expect("V2 strong VIEW disable must persist");
let disabled = runtime.block_on(crate::inspect_locked_wallet_file(path.as_path())).expect("disabled V2 must remain inspectable");
assert!(!disabled.view_enabled());
let old_view = runtime.block_on(crate::open_wallet_view_file(path.as_path(), crate::ViewPassword::new(std::string::String::from("pre016-view-rotated"))));
assert_eq!(old_view.expect_err("disabled V2 VIEW must not reopen").code(), crate::ERROR_CODE_CAPABILITY_INSUFFICIENT);
runtime
.block_on(owner.recreate_view(path.as_path(), crate::ViewPassword::new(std::string::String::from("pre016-view-recreated"))))
.expect("V2 strong VIEW recreation must persist");
let mut recreated_view = runtime
.block_on(crate::open_wallet_view_file(path.as_path(), crate::ViewPassword::new(std::string::String::from("pre016-view-recreated"))))
.expect("recreated V2 VIEW must open");
runtime
.block_on(recreated_view.rotate_view_password(path.as_path(), crate::ViewPassword::new(std::string::String::from("pre016-view-self-rotated"))))
.expect("V2 VIEW self-rotation must persist");
let final_view = runtime
.block_on(crate::open_wallet_view_file(path.as_path(), crate::ViewPassword::new(std::string::String::from("pre016-view-self-rotated"))))
.expect("self-rotated V2 VIEW must reopen");
assert_eq!(final_view.format_version(), crate::KSPWALLET_FORMAT_VERSION_V2);
let bytes = std::fs::read(path).expect("V2 file must remain readable for framing canary");
assert_eq!(crate::detect_wallet_format(bytes.as_slice()).expect("administered file must still be V2"), crate::WalletFormat::V2);
}
#[test]
fn explicit_versioned_readers_reject_the_other_native_wire_format() {
let runtime = runtime();
let v1_as_v2 =
runtime.block_on(crate::open_wallet_owner_v2(V1_FULL_VECTOR, crate::OwnerPassword::new(std::string::String::from("irrelevant-before-v2-parse"))));
assert_eq!(v1_as_v2.expect_err("explicit V2 reader must reject V1 framing").code(), crate::ERROR_CODE_FORMAT_INVALID);
let owner = runtime
.block_on(crate::create_wallet_v2(
crate::OwnerPassword::new(std::string::String::from("pre016-strict-v2-owner")),
std::option::Option::None,
crate::WalletCreateMetadata::default(),
))
.expect("strict-reader V2 fixture creation must succeed");
let bytes = owner.to_native_bytes().expect("strict-reader V2 fixture must serialize");
let v2_as_v1 =
runtime.block_on(crate::open_wallet_owner_v1(bytes.as_slice(), crate::OwnerPassword::new(std::string::String::from("irrelevant-before-v1-parse"))));
assert_eq!(v2_as_v1.expect_err("explicit V1 reader must reject V2 framing").code(), crate::ERROR_CODE_FORMAT_INVALID);
}