Skip to content

Commit 032f4e6

Browse files
author
Lewis
committed
enhance test code and provide more explanation in project 2(solana-developers#49)
1 parent facefbd commit 032f4e6

File tree

3 files changed

+96
-23
lines changed

3 files changed

+96
-23
lines changed

project-2-voting/anchor/programs/voting/src/lib.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub mod voting {
1616
ctx.accounts.poll_account.poll_description = description;
1717
ctx.accounts.poll_account.poll_voting_start = start_time;
1818
ctx.accounts.poll_account.poll_voting_end = end_time;
19+
msg!("init poll called");
1920
Ok(())
2021
}
2122

@@ -24,10 +25,17 @@ pub mod voting {
2425
candidate: String) -> Result<()> {
2526
ctx.accounts.candidate_account.candidate_name = candidate;
2627
ctx.accounts.poll_account.poll_option_index += 1;
28+
msg!("init candidate called");
2729
Ok(())
2830
}
2931

3032
pub fn vote(ctx: Context<Vote>, _poll_id: u64, _candidate: String) -> Result<()> {
33+
/*
34+
Please note here we can get Candidate mutable reference, it only indicates
35+
that we can modify it in-memory, not indicating the data on solana chain
36+
has been changed. If write permission is not given on `Vote` metadata,
37+
then solana will silently ignore the change without modifying it.
38+
*/
3139
let candidate_account = &mut ctx.accounts.candidate_account;
3240
let current_time = Clock::get()?.unix_timestamp;
3341

@@ -70,6 +78,8 @@ pub struct InitializeCandidate<'info> {
7078
#[account(mut)]
7179
pub signer: Signer<'info>,
7280

81+
// poll_option_index is changed, so need set mutable
82+
#[account(mut)]
7383
pub poll_account: Account<'info, PollAccount>,
7484

7585
#[account(
@@ -98,10 +108,11 @@ pub struct Vote<'info> {
98108
pub poll_account: Account<'info, PollAccount>,
99109

100110
#[account(
101-
mut,
111+
mut, // Vote() will modify a given candidate
102112
seeds = [poll_id.to_le_bytes().as_ref(), candidate.as_ref()],
103113
bump)]
104114
pub candidate_account: Account<'info, CandidateAccount>,
115+
// no system_account because no creating account in Vote()
105116
}
106117

107118
#[account]

project-2-voting/anchor/tests/bankrun.spec.ts

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import { PublicKey } from '@solana/web3.js';
44
import * as anchor from '@coral-xyz/anchor';
55
import { BN, Program } from "@coral-xyz/anchor";
66

7+
// This is a "Bankrun" way of writing cases. Bankrun helps manage all the setup stuff
8+
// needed for case to run successfully. It doesn't depend on solana-test-validator, so
9+
// it's more convenient way to do testing.
710

811
const IDL = require("../target/idl/voting.json");
912
import { Voting } from '../target/types/voting';
@@ -12,31 +15,81 @@ const PUPPET_PROGRAM_ID = new PublicKey("5s3PtT8kLYCv1WEp6dSh3T7EuF35Z6jSu5Cvx4h
1215

1316
describe('Create a system account', () => {
1417

15-
test("bankrun", async () => {
16-
const context = await startAnchor("", [{name: "voting", programId: PUPPET_PROGRAM_ID}], []);
17-
const provider = new BankrunProvider(context);
18+
let context;
19+
let provider;
20+
let votingProg;
21+
let pollAddress;
1822

19-
const puppetProgram = new Program<Voting>(
20-
IDL,
21-
provider,
22-
);
23-
24-
const [pollAddress] = PublicKey.findProgramAddressSync(
23+
beforeAll(async () => {
24+
console.log("init context,provider,voting program instance ...");
25+
context = await startAnchor("", [{name: "voting", programId: PUPPET_PROGRAM_ID}], []);
26+
provider = new BankrunProvider(context);
27+
votingProg = new Program<Voting>(IDL, provider);
28+
[pollAddress] = PublicKey.findProgramAddressSync(
2529
[Buffer.from("poll"), new anchor.BN(1).toArrayLike(Buffer, "le", 8)],
26-
puppetProgram.programId
30+
votingProg.programId
2731
);
32+
console.log("program id: ", votingProg.programId);
33+
})
2834

29-
await puppetProgram.methods.initializePoll(
35+
test("initialize poll", async () => {
36+
await votingProg.methods.initializePoll(
3037
new anchor.BN(1),
3138
new anchor.BN(0),
3239
new anchor.BN(1759508293),
3340
"test-poll",
3441
"description",
3542
).rpc();
3643

37-
const pollAccount = await puppetProgram.account.pollAccount.fetch(pollAddress);
44+
const pollAccount = await votingProg.account.pollAccount.fetch(pollAddress);
3845
console.log(pollAccount);
46+
expect(pollAccount.pollOptionIndex.toNumber()).toEqual(0);
47+
expect(pollAccount.pollDescription).toEqual("description");
48+
expect(pollAccount.pollVotingStart.toNumber())
49+
.toBeLessThan(pollAccount.pollVotingEnd.toNumber());
50+
});
51+
52+
it("initialize candidate", async() => {
53+
await votingProg.methods.initializeCandidate(
54+
new anchor.BN(1),
55+
"Smooth"
56+
).accounts({pollAccount: pollAddress})
57+
.rpc();
58+
59+
await votingProg.methods.initializeCandidate(
60+
new anchor.BN(1),
61+
"Crunchy"
62+
).accounts({pollAccount: pollAddress})
63+
.rpc();
64+
65+
const [crunchyAddr] = PublicKey.findProgramAddressSync(
66+
[new anchor.BN(1).toArrayLike(Buffer, 'le', 8), Buffer.from("Crunchy")],
67+
votingProg.programId,
68+
);
69+
const crunchyData = await votingProg.account.candidateAccount.fetch(crunchyAddr);
70+
console.log(crunchyData);
71+
expect(crunchyData.candidateVotes.toNumber()).toEqual(0);
3972

73+
const pollData = await votingProg.account.pollAccount.fetch(pollAddress);
74+
expect(pollData.pollOptionIndex.toNumber()).toEqual(2);
75+
});
76+
77+
it("vote", async() => {
78+
await votingProg.methods.vote(
79+
new anchor.BN(1),
80+
"Crunchy"
81+
).rpc();
82+
83+
await votingProg.methods.vote(
84+
new anchor.BN(1),
85+
"Crunchy"
86+
).rpc();
87+
const [crunchyAddr] = PublicKey.findProgramAddressSync(
88+
[new anchor.BN(1).toArrayLike(Buffer, 'le', 8), Buffer.from("Crunchy")],
89+
votingProg.programId,
90+
);
91+
const crunchyData = await votingProg.account.candidateAccount.fetch(crunchyAddr);
92+
expect(crunchyData.candidateVotes.toNumber()).toEqual(2);
4093
});
4194

4295
});

project-2-voting/anchor/tests/basic.spec.ts

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,38 @@ import { Program } from '@coral-xyz/anchor';
33
import { Voting } from '../target/types/voting';
44
import { PublicKey } from '@solana/web3.js';
55

6+
// This is "non-Bankrun" way of writing cases.In this case you must use `solana-test-validator`
7+
// automatically(`anchor test` would do that) or
8+
// manually(run `solana-test-validator` in separate terminal)
9+
610
describe('Voting', () => {
711
// Configure the client to use the local cluster.
812
anchor.setProvider(anchor.AnchorProvider.env());
913

1014
const program = anchor.workspace.Voting as Program<Voting>;
15+
console.log("program id: ", program.programId);
1116

1217
it('initializePoll', async () => {
1318

1419
const [pollAddress] = PublicKey.findProgramAddressSync(
1520
[Buffer.from("poll"), new anchor.BN(1).toArrayLike(Buffer, "le", 8)],
1621
program.programId
1722
);
23+
// better to wrap program's instruction calling in case that program doesn't
24+
// exists in chain and the call just abandons the error
25+
try {
26+
const tx = await program.methods.initializePoll(
27+
new anchor.BN(1),
28+
new anchor.BN(0),
29+
new anchor.BN(1759508293),
30+
"test-poll",
31+
"description",
32+
).rpc();
1833

19-
const tx = await program.methods.initializePoll(
20-
new anchor.BN(1),
21-
new anchor.BN(0),
22-
new anchor.BN(1759508293),
23-
"test-poll",
24-
"description",
25-
)
26-
.rpc();
27-
28-
console.log('Your transaction signature', tx);
34+
console.log('Your transaction signature', tx);
35+
} catch (e) {
36+
console.error('initializePoll failed:', e);
37+
}
2938
});
3039

3140
it('initialize candidates', async () => {

0 commit comments

Comments
 (0)