test: address mutants discovered during fuzzing

This commit is contained in:
Roman 2026-06-11 17:37:21 +08:00
parent c063872f1c
commit 759d4a849e
No known key found for this signature in database
GPG Key ID: 583BDF43C238B83E
8 changed files with 220 additions and 0 deletions

View File

@ -210,6 +210,17 @@ mod tests {
kind
}
#[test]
fn proof_inner_roundtrip() {
// `Proof::from_inner(b).into_inner()` must return exactly `b`. Catches
// mutations of `into_inner` returning `vec![]`, `vec![0]`, or `vec![1]`,
// and of `from_inner` discarding its argument.
let bytes = vec![0xDE_u8, 0xAD, 0xBE, 0xEF];
assert_eq!(Proof::from_inner(bytes.clone()).into_inner(), bytes);
assert!(Proof::from_inner(vec![]).into_inner().is_empty());
assert_eq!(Proof::from_inner(vec![0xFF]).into_inner(), vec![0xFF_u8]);
}
#[test]
fn prove_privacy_preserving_execution_circuit_public_and_private_pre_accounts() {
let recipient_keys = test_private_account_keys_1();

View File

@ -498,6 +498,20 @@ mod tests {
}
}
#[test]
fn elf_returns_the_program_bytecode_constant() {
// `Program::elf` must return exactly the compile-time ELF, never an empty
// or placeholder slice. Catches mutations returning `Vec::leak(Vec::new())`,
// `Vec::leak(vec![0])`, or `Vec::leak(vec![1])`.
let at = Program::authenticated_transfer_program();
assert!(!at.elf().is_empty());
assert_eq!(at.elf(), AUTHENTICATED_TRANSFER_ELF);
let token = Program::token();
assert!(!token.elf().is_empty());
assert_eq!(token.elf(), TOKEN_ELF);
}
#[test]
fn program_execution() {
let program = Program::simple_balance_transfer();

View File

@ -16,3 +16,18 @@ impl Message {
self.bytecode
}
}
#[cfg(test)]
mod tests {
use super::Message;
#[test]
fn bytecode_roundtrip() {
// `Message::new(b).into_bytecode()` must return exactly `b`. Catches
// mutations of `into_bytecode` returning `vec![]`, `vec![0]`, or `vec![1]`.
let bytecode = vec![0x7F_u8, 0x45, 0x4C, 0x46]; // ELF magic
assert_eq!(Message::new(bytecode.clone()).into_bytecode(), bytecode);
assert!(Message::new(vec![]).into_bytecode().is_empty());
assert_eq!(Message::new(vec![0xAB]).into_bytecode(), vec![0xAB_u8]);
}
}

View File

@ -613,6 +613,62 @@ pub mod tests {
PublicTransaction::new(message, witness_set)
}
#[test]
fn genesis_system_accounts_have_expected_contents() {
// System-account IDs must be distinct and non-default, and the genesis
// faucet/bridge accounts must carry their expected field values. Catches
// mutations that replace `system_faucet_account`/`system_bridge_account`
// with `Default::default()`, delete their `balance`/`program_owner`
// fields, or replace `system_bridge_account_id` with `Default::default()`.
let faucet_id = system_faucet_account_id();
let bridge_id = system_bridge_account_id();
assert_ne!(bridge_id, AccountId::default());
assert_ne!(faucet_id, bridge_id);
let state = V03State::new_with_genesis_accounts(&[], vec![], 0);
let default_owner = Account::default().program_owner;
let faucet = state.get_account_by_id(faucet_id);
assert_eq!(faucet.balance, u128::MAX, "faucet must hold u128::MAX");
assert_ne!(
faucet.program_owner, default_owner,
"faucet must have a non-default program_owner"
);
let bridge = state.get_account_by_id(bridge_id);
assert_ne!(
bridge.program_owner, default_owner,
"bridge must have a non-default program_owner"
);
}
#[test]
fn genesis_commitment_set_digest_differs_from_empty_state() {
// The genesis state inserts DUMMY_COMMITMENT, so its commitment-set digest
// must differ from a freshly-created empty state's all-zero root. Catches
// the mutation that replaces `commitment_set_digest` with `Default::default()`.
let genesis = V03State::new_with_genesis_accounts(&[], vec![], 0);
let empty = V03State::new();
assert_ne!(
genesis.commitment_set_digest(),
empty.commitment_set_digest()
);
}
#[test]
fn add_pinata_token_program_sets_non_default_owner_and_data() {
// The account created by `add_pinata_token_program` must have a non-default
// `program_owner` and non-default `data`. Catches deletion of either field
// from the struct literal.
let id = AccountId::new([0xAB_u8; 32]);
let mut state = V03State::new_with_genesis_accounts(&[], vec![], 0);
state.add_pinata_token_program(id);
let acc = state.get_account_by_id(id);
let default = Account::default();
assert_ne!(acc.program_owner, default.program_owner);
assert_ne!(acc.data, default.data);
}
#[test]
fn new_with_genesis() {
let key1 = PrivateKey::try_new([1; 32]).unwrap();

View File

@ -526,6 +526,44 @@ mod tests {
validated_state_diff::ValidatedStateDiff,
};
#[test]
fn public_diff_reflects_a_successful_transfer() {
// A successful native transfer must record the debited sender in
// `public_diff()`. Catches the mutation that replaces `public_diff` with
// `HashMap::new()` (which would hide every account change).
use authenticated_transfer_core::Instruction as AtInstruction;
let from_key = PrivateKey::try_new([1_u8; 32]).unwrap();
let from = AccountId::from(&PublicKey::new_from_private_key(&from_key));
let to_key = PrivateKey::try_new([2_u8; 32]).unwrap();
let to = AccountId::from(&PublicKey::new_from_private_key(&to_key));
let state = V03State::new_with_genesis_accounts(&[(from, 100)], vec![], 0);
let program_id = Program::authenticated_transfer_program().id();
let message = Message::try_new(
program_id,
vec![from, to],
vec![Nonce(0), Nonce(0)],
AtInstruction::Transfer { amount: 5 },
)
.unwrap();
let witness_set = WitnessSet::for_message(&message, &[&from_key, &to_key]);
let tx = crate::PublicTransaction::new(message, witness_set);
let diff = ValidatedStateDiff::from_public_transaction(&tx, &state, 1, 0)
.expect("a valid native transfer must validate");
let public_diff = diff.public_diff();
assert!(
public_diff.contains_key(&from),
"public_diff must contain the debited sender",
);
assert_eq!(
public_diff[&from].balance, 95,
"sender balance in the diff must reflect the debit",
);
}
/// Privacy-path version of the authorization-injection attack. The test passes when the
/// attack is rejected and the victim's balance is left untouched.
///

View File

@ -53,3 +53,33 @@ impl From<BasicAuth> for BasicAuthCredentials {
Self::new(value.username, value.password)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use super::BasicAuth;
#[test]
fn parse_preserves_non_empty_password() {
let auth = BasicAuth::from_str("user:secret").expect("must parse");
assert_eq!(auth.username, "user");
assert_eq!(auth.password.as_deref(), Some("secret"));
}
#[test]
fn parse_empty_password_is_none() {
// A trailing colon means an empty password, which must become `None`.
// Catches deletion of `!` in `.filter(|p| !p.is_empty())`, which would
// instead yield `Some("")`.
let auth = BasicAuth::from_str("user:").expect("must parse");
assert_eq!(auth.password, None);
}
#[test]
fn parse_username_only_has_no_password() {
let auth = BasicAuth::from_str("alice").expect("must parse");
assert_eq!(auth.username, "alice");
assert_eq!(auth.password, None);
}
}

View File

@ -93,4 +93,16 @@ mod tests {
let deserialized = HashType::from_str(&serialized).unwrap();
assert_eq!(original, deserialized);
}
#[test]
fn as_ref_returns_exact_inner_bytes() {
// `HashType::as_ref` must return exactly the inner `[u8; 32]` — not an
// empty slice or a placeholder. Catches mutations of `as_ref` that return
// `Vec::leak(Vec::new())`, `vec![0]`, or `vec![1]`.
let known = [0x42_u8; 32];
let hash = HashType(known);
assert_eq!(hash.as_ref(), &known);
assert_eq!(hash.as_ref().len(), 32);
assert_eq!(HashType([0_u8; 32]).as_ref().len(), 32);
}
}

View File

@ -188,3 +188,47 @@ fn validate_doesnt_modify_account(
Ok(())
}
}
#[cfg(test)]
mod tests {
use lee::{
AccountId, CLOCK_01_PROGRAM_ACCOUNT_ID, PrivateKey, PublicKey, V03State,
system_bridge_account_id, system_faucet_account_id,
};
use crate::test_utils::create_transaction_native_token_transfer;
#[test]
fn system_account_ids_are_distinct_and_non_default() {
let faucet = system_faucet_account_id();
let bridge = system_bridge_account_id();
assert_ne!(faucet, AccountId::default());
assert_ne!(bridge, AccountId::default());
assert_ne!(faucet, bridge);
}
#[test]
fn validate_on_state_rejects_modifying_a_system_account() {
// A native transfer that credits a clock system account *changes* that
// account, so `validate_doesnt_modify_account` must reject it. Catches
// the `!=` → `==` inversion at `validate_doesnt_modify_account` (a changed
// account would no longer be flagged) and `public_diff → HashMap::new()`
// (an empty diff hides the modification).
let sender_key = PrivateKey::try_new([5_u8; 32]).expect("valid key");
let sender_id = AccountId::from(&PublicKey::new_from_private_key(&sender_key));
let state = V03State::new_with_genesis_accounts(&[(sender_id, 10_000)], vec![], 0);
let tx = create_transaction_native_token_transfer(
sender_id,
0,
CLOCK_01_PROGRAM_ACCOUNT_ID,
100,
&sender_key,
);
assert!(
tx.validate_on_state(&state, 1, 0).is_err(),
"validate_on_state must reject a transfer that credits a clock system account",
);
}
}