108 lines
4.8 KiB
Rust
108 lines
4.8 KiB
Rust
// file: crates/ksp-interface-lib/unit_tests/program_instruction.rs
|
|
// version: 1
|
|
|
|
fn meta(byte: u8, writable: bool) -> crate::ProgramAccountMeta {
|
|
let pubkey = crate::Pubkey::new_from_array([byte; 32]);
|
|
if writable {
|
|
return crate::ProgramAccountMeta::writable(pubkey, false);
|
|
}
|
|
return crate::ProgramAccountMeta::readonly(pubkey, false);
|
|
}
|
|
|
|
#[test]
|
|
fn instruction_accepts_empty_accounts_and_data_with_opaque_program_id() {
|
|
let program_id = crate::Pubkey::new_from_array([0xD3_u8; 32]);
|
|
let instruction = crate::ProgramInstruction::try_new(program_id, std::vec::Vec::new(), std::vec::Vec::new());
|
|
assert!(instruction.is_ok());
|
|
let instruction = match instruction {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(instruction.program_id(), &program_id);
|
|
assert!(instruction.accounts().is_empty());
|
|
assert!(instruction.data().is_empty());
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn instruction_preserves_account_order_duplicates_and_opaque_data() {
|
|
let program_id = crate::Pubkey::new_from_array([0x41_u8; 32]);
|
|
let first = meta(1, false);
|
|
let duplicate = meta(2, true);
|
|
let accounts = std::vec![first, duplicate, first];
|
|
let data = std::vec![0_u8, 1, 2, 0xFF];
|
|
let instruction = crate::ProgramInstruction::try_new(program_id, accounts, data.clone());
|
|
assert!(instruction.is_ok());
|
|
let instruction = match instruction {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
assert_eq!(instruction.accounts(), &[first, duplicate, first]);
|
|
assert_eq!(instruction.data(), data.as_slice());
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn instruction_accepts_account_limit_and_rejects_one_above_it() {
|
|
let program_id = crate::Pubkey::new_from_array([0x51_u8; 32]);
|
|
let account = meta(7, false);
|
|
let accepted = crate::ProgramInstruction::try_new(program_id, std::vec![account; crate::MAX_PROGRAM_INSTRUCTION_ACCOUNTS], std::vec::Vec::new());
|
|
assert!(accepted.is_ok());
|
|
let rejected = crate::ProgramInstruction::try_new(program_id, std::vec![account; crate::MAX_PROGRAM_INSTRUCTION_ACCOUNTS + 1], std::vec::Vec::new());
|
|
assert!(rejected.is_err());
|
|
let error = match rejected {
|
|
std::result::Result::Err(value) => value,
|
|
std::result::Result::Ok(_) => return,
|
|
};
|
|
assert_eq!(error.code(), crate::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED);
|
|
assert_eq!(error.message(), "Program instruction account count exceeds the Interface admission limit");
|
|
assert_eq!(error.context().len(), 3);
|
|
assert_eq!(error.context()[0].key(), "field");
|
|
assert_eq!(error.context()[0].value(), "accounts");
|
|
assert_eq!(error.context()[1].key(), "actual_len");
|
|
assert_eq!(error.context()[1].value(), "256");
|
|
assert_eq!(error.context()[2].key(), "maximum_len");
|
|
assert_eq!(error.context()[2].value(), "255");
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn instruction_accepts_data_limit_and_rejects_one_byte_above_it() {
|
|
let program_id = crate::Pubkey::new_from_array([0x61_u8; 32]);
|
|
let accepted = crate::ProgramInstruction::try_new(program_id, std::vec::Vec::new(), std::vec![0xA5_u8; crate::MAX_PROGRAM_INSTRUCTION_DATA_LEN]);
|
|
assert!(accepted.is_ok());
|
|
let rejected = crate::ProgramInstruction::try_new(program_id, std::vec::Vec::new(), std::vec![0x5A_u8; crate::MAX_PROGRAM_INSTRUCTION_DATA_LEN + 1]);
|
|
assert!(rejected.is_err());
|
|
let error = match rejected {
|
|
std::result::Result::Err(value) => value,
|
|
std::result::Result::Ok(_) => return,
|
|
};
|
|
assert_eq!(error.code(), crate::ERROR_CODE_PROGRAM_INSTRUCTION_LIMIT_EXCEEDED);
|
|
assert_eq!(error.message(), "Program instruction data length exceeds the Interface admission limit");
|
|
assert_eq!(error.context().len(), 3);
|
|
assert_eq!(error.context()[0].value(), "data");
|
|
assert_eq!(error.context()[1].value(), "10241");
|
|
assert_eq!(error.context()[2].value(), "10240");
|
|
return;
|
|
}
|
|
|
|
#[test]
|
|
fn instruction_debug_is_bounded_and_omits_accounts_and_payload_bytes() {
|
|
let program_id = crate::Pubkey::new_from_array([0x71_u8; 32]);
|
|
let payload = b"PAYLOAD_SENTINEL_NEVER_RENDER".to_vec();
|
|
let instruction = crate::ProgramInstruction::try_new(program_id, std::vec![meta(8, false), meta(9, true)], payload);
|
|
assert!(instruction.is_ok());
|
|
let instruction = match instruction {
|
|
std::result::Result::Ok(value) => value,
|
|
std::result::Result::Err(_) => return,
|
|
};
|
|
let rendered = std::format!("{instruction:?}");
|
|
assert!(rendered.contains("ProgramInstruction"));
|
|
assert!(rendered.contains("account_count: 2"));
|
|
assert!(rendered.contains("data_len: 29"));
|
|
assert!(!rendered.contains("PAYLOAD_SENTINEL_NEVER_RENDER"));
|
|
assert!(!rendered.contains("is_signer"));
|
|
assert!(!rendered.contains("is_writable"));
|
|
return;
|
|
}
|