Skip to content

enhance test code and provide more explanation in project 2 #50

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion project-2-voting/anchor/programs/voting/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod voting {
ctx.accounts.poll_account.poll_description = description;
ctx.accounts.poll_account.poll_voting_start = start_time;
ctx.accounts.poll_account.poll_voting_end = end_time;
msg!("init poll called");
Ok(())
}

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

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

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

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

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

#[account(
mut,
mut, // Vote() will modify a given candidate
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be emphasized. The original code in video also made such a mistake.

seeds = [poll_id.to_le_bytes().as_ref(), candidate.as_ref()],
bump)]
pub candidate_account: Account<'info, CandidateAccount>,
// no system_account because no creating account in Vote()
}

#[account]
Expand Down
77 changes: 65 additions & 12 deletions project-2-voting/anchor/tests/bankrun.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { PublicKey } from '@solana/web3.js';
import * as anchor from '@coral-xyz/anchor';
import { BN, Program } from "@coral-xyz/anchor";

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

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

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

test("bankrun", async () => {
const context = await startAnchor("", [{name: "voting", programId: PUPPET_PROGRAM_ID}], []);
const provider = new BankrunProvider(context);
let context;
let provider;
let votingProg;
let pollAddress;

const puppetProgram = new Program<Voting>(
IDL,
provider,
);

const [pollAddress] = PublicKey.findProgramAddressSync(
beforeAll(async () => {
console.log("init context,provider,voting program instance ...");
context = await startAnchor("", [{name: "voting", programId: PUPPET_PROGRAM_ID}], []);
provider = new BankrunProvider(context);
votingProg = new Program<Voting>(IDL, provider);
[pollAddress] = PublicKey.findProgramAddressSync(
[Buffer.from("poll"), new anchor.BN(1).toArrayLike(Buffer, "le", 8)],
puppetProgram.programId
votingProg.programId
);
console.log("program id: ", votingProg.programId);
})

await puppetProgram.methods.initializePoll(
test("initialize poll", async () => {
await votingProg.methods.initializePoll(
new anchor.BN(1),
new anchor.BN(0),
new anchor.BN(1759508293),
"test-poll",
"description",
).rpc();

const pollAccount = await puppetProgram.account.pollAccount.fetch(pollAddress);
const pollAccount = await votingProg.account.pollAccount.fetch(pollAddress);
console.log(pollAccount);
expect(pollAccount.pollOptionIndex.toNumber()).toEqual(0);
expect(pollAccount.pollDescription).toEqual("description");
expect(pollAccount.pollVotingStart.toNumber())
.toBeLessThan(pollAccount.pollVotingEnd.toNumber());
});

it("initialize candidate", async() => {
await votingProg.methods.initializeCandidate(
new anchor.BN(1),
"Smooth"
).accounts({pollAccount: pollAddress})
.rpc();

await votingProg.methods.initializeCandidate(
new anchor.BN(1),
"Crunchy"
).accounts({pollAccount: pollAddress})
.rpc();

const [crunchyAddr] = PublicKey.findProgramAddressSync(
[new anchor.BN(1).toArrayLike(Buffer, 'le', 8), Buffer.from("Crunchy")],
votingProg.programId,
);
const crunchyData = await votingProg.account.candidateAccount.fetch(crunchyAddr);
console.log(crunchyData);
expect(crunchyData.candidateVotes.toNumber()).toEqual(0);

const pollData = await votingProg.account.pollAccount.fetch(pollAddress);
expect(pollData.pollOptionIndex.toNumber()).toEqual(2);
});

it("vote", async() => {
await votingProg.methods.vote(
new anchor.BN(1),
"Crunchy"
).rpc();

await votingProg.methods.vote(
new anchor.BN(1),
"Crunchy"
).rpc();
const [crunchyAddr] = PublicKey.findProgramAddressSync(
[new anchor.BN(1).toArrayLike(Buffer, 'le', 8), Buffer.from("Crunchy")],
votingProg.programId,
);
const crunchyData = await votingProg.account.candidateAccount.fetch(crunchyAddr);
expect(crunchyData.candidateVotes.toNumber()).toEqual(2);
});

});
29 changes: 19 additions & 10 deletions project-2-voting/anchor/tests/basic.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,38 @@ import { Program } from '@coral-xyz/anchor';
import { Voting } from '../target/types/voting';
import { PublicKey } from '@solana/web3.js';

// This is "non-Bankrun" way of writing cases.In this case you must use `solana-test-validator`
// automatically(`anchor test` would do that) or
// manually(run `solana-test-validator` in separate terminal)

describe('Voting', () => {
// Configure the client to use the local cluster.
anchor.setProvider(anchor.AnchorProvider.env());

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

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

const [pollAddress] = PublicKey.findProgramAddressSync(
[Buffer.from("poll"), new anchor.BN(1).toArrayLike(Buffer, "le", 8)],
program.programId
);
// better to wrap program's instruction calling in case that program doesn't
// exists in chain and the call just abandons the error
try {
const tx = await program.methods.initializePoll(
new anchor.BN(1),
new anchor.BN(0),
new anchor.BN(1759508293),
"test-poll",
"description",
).rpc();

const tx = await program.methods.initializePoll(
new anchor.BN(1),
new anchor.BN(0),
new anchor.BN(1759508293),
"test-poll",
"description",
)
.rpc();

console.log('Your transaction signature', tx);
console.log('Your transaction signature', tx);
} catch (e) {
console.error('initializePoll failed:', e);
}
});

it('initialize candidates', async () => {
Expand Down