-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtests.rs
More file actions
153 lines (131 loc) · 4.94 KB
/
Copy pathtests.rs
File metadata and controls
153 lines (131 loc) · 4.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
use quasar_svm::{Account, Instruction, Pubkey, QuasarSvm};
use solana_address::Address;
/// Lever program discriminator for PowerStatus account (must match
/// #[account(discriminator = 1)]).
const POWER_STATUS_DISCRIMINATOR: u8 = 1;
fn setup() -> QuasarSvm {
let elf = include_bytes!("../target/deploy/quasar_lever.so");
QuasarSvm::new().with_program(&Pubkey::from(crate::ID), elf)
}
fn signer(address: Pubkey) -> Account {
quasar_svm::token::create_keyed_system_account(&address, 10_000_000_000)
}
/// Derive the power PDA address.
fn power_pda() -> (Pubkey, u8) {
Pubkey::find_program_address(&[b"power"], &Pubkey::from(crate::ID))
}
fn empty_pda(address: Pubkey) -> Account {
Account {
address,
lamports: 0,
data: vec![],
owner: quasar_svm::system_program::ID,
executable: false,
}
}
fn power_account(address: Pubkey, is_on: bool) -> Account {
// Account data: [discriminator: u8] [is_on: u8]
let data = vec![POWER_STATUS_DISCRIMINATOR, if is_on { 1 } else { 0 }];
Account {
address,
lamports: 1_000_000_000,
data,
owner: Pubkey::from(crate::ID),
executable: false,
}
}
/// Build initialize instruction data (discriminator = 0).
fn build_initialize() -> Vec<u8> {
vec![0u8]
}
/// Build switch_power instruction data (discriminator = 1).
///
/// Wire format: [discriminator = 1] [name: u8 length prefix + bytes].
///
/// The lever's switch_power instruction takes `String<50>`, which Quasar
/// serialises with a single-byte length prefix (matching every other
/// Quasar program: account-data, close-account, rent, realloc,
/// repository-layout). An earlier version of this builder used a u32
/// length prefix, which produced a malformed payload that happened to
/// pass because the handler ignored the deserialised name.
fn build_switch_power(name: &str) -> Vec<u8> {
let mut data = Vec::with_capacity(2 + name.len());
data.push(1u8); // discriminator = 1
data.push(name.len() as u8);
data.extend_from_slice(name.as_bytes());
data
}
#[test]
fn test_initialize_lever() {
let mut svm = setup();
let payer = Pubkey::new_unique();
let (power_addr, _bump) = power_pda();
let system_program = quasar_svm::system_program::ID;
let ix = Instruction {
program_id: Pubkey::from(crate::ID),
accounts: vec![
solana_instruction::AccountMeta::new(Address::from(payer.to_bytes()), true),
solana_instruction::AccountMeta::new(Address::from(power_addr.to_bytes()), false),
solana_instruction::AccountMeta::new_readonly(
Address::from(system_program.to_bytes()),
false,
),
],
data: build_initialize(),
};
let result = svm.process_instruction(&ix, &[signer(payer), empty_pda(power_addr)]);
result.assert_success();
// Power should be off (false) after initialization.
let account = result.account(&power_addr).unwrap();
assert_eq!(account.data.len(), 2, "discriminator + is_on");
assert_eq!(account.data[1], 0, "power should be off initially");
}
#[test]
fn test_switch_power_on() {
let mut svm = setup();
let (power_addr, _bump) = power_pda();
let ix = Instruction {
program_id: Pubkey::from(crate::ID),
accounts: vec![
solana_instruction::AccountMeta::new(Address::from(power_addr.to_bytes()), false),
],
data: build_switch_power("Alice"),
};
// Start with power off.
let result = svm.process_instruction(&ix, &[power_account(power_addr, false)]);
result.assert_success();
let logs = result.logs.join("\n");
assert!(logs.contains("pulling the power switch"), "should log switch");
assert!(logs.contains("now on"), "should say power is on");
// Verifies wire format: a stale u32 length prefix would corrupt the
// deserialised name (e.g. "\0\0\0Al" instead of "Alice").
assert!(
logs.contains("Alice"),
"deserialised name should round-trip exactly; logs: {logs}"
);
let account = result.account(&power_addr).unwrap();
assert_eq!(account.data[1], 1, "power should now be on");
}
#[test]
fn test_switch_power_off() {
let mut svm = setup();
let (power_addr, _bump) = power_pda();
let ix = Instruction {
program_id: Pubkey::from(crate::ID),
accounts: vec![
solana_instruction::AccountMeta::new(Address::from(power_addr.to_bytes()), false),
],
data: build_switch_power("Bob"),
};
// Start with power on.
let result = svm.process_instruction(&ix, &[power_account(power_addr, true)]);
result.assert_success();
let logs = result.logs.join("\n");
assert!(logs.contains("now off"), "should say power is off");
assert!(
logs.contains("Bob"),
"deserialised name should round-trip exactly; logs: {logs}"
);
let account = result.account(&power_addr).unwrap();
assert_eq!(account.data[1], 0, "power should now be off");
}