Skip to content

Commit

Permalink
feat: submit_answer
Browse files Browse the repository at this point in the history
  • Loading branch information
armaanansari121 committed Feb 24, 2025
1 parent 57d1c23 commit 35957e9
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 10 deletions.
31 changes: 28 additions & 3 deletions onchain/src/contracts/lyricsflip.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,34 @@ pub mod LyricsFlip {
cards.span()
}

// TODO
fn submit_answer(self: @ContractState, answer: Answer) -> bool {
false
fn submit_answer(ref self: ContractState, round_id: u64, answer: Answer) -> bool {
// Verify round exists
assert(self.rounds.entry(round_id).round_id.read() != 0, Errors::NON_EXISTING_ROUND);

let caller_address = get_caller_address();

// Verify caller is a participant
assert(self._is_round_player(round_id, caller_address), Errors::NOT_A_PARTICIPANT);

let round = self.rounds.entry(round_id).read();

// Verify round has started and not completed
assert(round.is_started, Errors::ROUND_NOT_STARTED);
assert(!round.is_completed, Errors::ROUND_COMPLETED);

// Get current card index and card
let current_index = round.next_card_index;

let round_cards = self.round_cards.entry(round_id);
let current_card_id = round_cards.at((current_index).into()).read();
let current_card = self.cards.entry(current_card_id).read();

// Compare answer with card data
match answer {
Answer::Artist(value) => { value == current_card.artist },
Answer::Year(value) => { value == current_card.year },
Answer::Title(value) => { value == current_card.title }
}
}
}

Expand Down
4 changes: 1 addition & 3 deletions onchain/src/interfaces/lyricsflip.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,5 @@ pub trait ILyricsFlip<TContractState> {
fn set_role(
ref self: TContractState, recipient: ContractAddress, role: felt252, is_enable: bool,
);

//TODO
fn submit_answer(self: @TContractState, answer: Answer) -> bool;
fn submit_answer(ref self: TContractState, round_id: u64, answer: Answer) -> bool;
}
255 changes: 254 additions & 1 deletion onchain/src/tests/test_lyricsflip.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use LyricsFlip::{InternalFunctions, InternalFunctionsTrait};
use lyricsflip::contracts::lyricsflip::LyricsFlip;
use lyricsflip::interfaces::lyricsflip::{ILyricsFlipDispatcher, ILyricsFlipDispatcherTrait};
use lyricsflip::utils::types::{Card, Genre};
use lyricsflip::utils::types::{Card, Genre, Answer};
use snforge_std::{
ContractClassTrait, DeclareResultTrait, EventSpyAssertionsTrait, declare, spy_events,
start_cheat_block_timestamp_global, start_cheat_caller_address,
Expand Down Expand Up @@ -1007,3 +1007,256 @@ fn test_next_card_should_panic_with_completed_round() {
lyricsflip.next_card(round_id);
stop_cheat_caller_address(lyricsflip.contract_address);
}
#[test]
fn test_submit_correct_artist_answer() {
let lyricsflip = deploy();

// Setup admin and initial card
start_cheat_caller_address(lyricsflip.contract_address, OWNER());
lyricsflip.set_role(ADMIN_ADDRESS(), ADMIN_ROLE, true);
stop_cheat_caller_address(lyricsflip.contract_address);

start_cheat_caller_address(lyricsflip.contract_address, ADMIN_ADDRESS());
let test_card = Card {
card_id: 1,
genre: Genre::HipHop,
artist: 'Test Artist',
title: "Test Title",
year: 2000,
lyrics: "Test Lyrics",
};
lyricsflip.add_card(test_card);
lyricsflip.set_cards_per_round(1);
stop_cheat_caller_address(lyricsflip.contract_address);

// Create and start round
start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1());
let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), 1);
lyricsflip.start_round(round_id);

let answer = Answer::Artist('Test Artist');
let result = lyricsflip.submit_answer(round_id, answer);
assert(result == true, 'Should accept correct artist');

stop_cheat_caller_address(lyricsflip.contract_address);
}

#[test]
fn test_submit_correct_year_answer() {
let lyricsflip = deploy();

// Setup admin and initial card
start_cheat_caller_address(lyricsflip.contract_address, OWNER());
lyricsflip.set_role(ADMIN_ADDRESS(), ADMIN_ROLE, true);
stop_cheat_caller_address(lyricsflip.contract_address);

start_cheat_caller_address(lyricsflip.contract_address, ADMIN_ADDRESS());
let test_card = Card {
card_id: 1,
genre: Genre::HipHop,
artist: 'Test Artist',
title: "Test Title",
year: 2000,
lyrics: "Test Lyrics",
};
lyricsflip.add_card(test_card);
lyricsflip.set_cards_per_round(1);
stop_cheat_caller_address(lyricsflip.contract_address);

// Create and start round
start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1());
let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), 1);
lyricsflip.start_round(round_id);

let answer = Answer::Year(2000);
let result = lyricsflip.submit_answer(round_id, answer);
assert(result == true, 'Should accept correct year');

stop_cheat_caller_address(lyricsflip.contract_address);
}

#[test]
fn test_submit_correct_title_answer() {
let lyricsflip = deploy();

// Setup admin and initial card
start_cheat_caller_address(lyricsflip.contract_address, OWNER());
lyricsflip.set_role(ADMIN_ADDRESS(), ADMIN_ROLE, true);
stop_cheat_caller_address(lyricsflip.contract_address);

start_cheat_caller_address(lyricsflip.contract_address, ADMIN_ADDRESS());
let test_card = Card {
card_id: 1,
genre: Genre::HipHop,
artist: 'Test Artist',
title: "Test Title",
year: 2000,
lyrics: "Test Lyrics",
};
lyricsflip.add_card(test_card);
lyricsflip.set_cards_per_round(1);
stop_cheat_caller_address(lyricsflip.contract_address);

// Create and start round
start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1());
let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), 1);
lyricsflip.start_round(round_id);

let answer = Answer::Title("Test Title");
let result = lyricsflip.submit_answer(round_id, answer);
assert(result == true, 'Should accept correct title');

stop_cheat_caller_address(lyricsflip.contract_address);
}

#[test]
fn test_submit_incorrect_answer() {
let lyricsflip = deploy();

// Setup admin and initial card
start_cheat_caller_address(lyricsflip.contract_address, OWNER());
lyricsflip.set_role(ADMIN_ADDRESS(), ADMIN_ROLE, true);
stop_cheat_caller_address(lyricsflip.contract_address);

start_cheat_caller_address(lyricsflip.contract_address, ADMIN_ADDRESS());
let test_card = Card {
card_id: 1,
genre: Genre::HipHop,
artist: 'Test Artist',
title: "Test Title",
year: 2000,
lyrics: "Test Lyrics",
};
lyricsflip.add_card(test_card);
lyricsflip.set_cards_per_round(1);
stop_cheat_caller_address(lyricsflip.contract_address);

// Create and start round
start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1());
let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), 1);
lyricsflip.start_round(round_id);

// Test incorrect answers for each type
let wrong_artist = Answer::Artist('WrongArtist');
let result = lyricsflip.submit_answer(round_id, wrong_artist);
assert(result == false, 'Should reject wrong artist');

stop_cheat_caller_address(lyricsflip.contract_address);
}

#[test]
#[should_panic(expected: ('Round does not exists',))]
fn test_submit_answer_should_panic_with_non_existing_round() {
let lyricsflip = deploy();

start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1());
let answer = Answer::Year(2000);
lyricsflip.submit_answer(999, answer);
stop_cheat_caller_address(lyricsflip.contract_address);
}

#[test]
#[should_panic(expected: ('Not a participant',))]
fn test_submit_answer_should_panic_with_non_participant() {
let lyricsflip = deploy();

// Setup admin and initial card
start_cheat_caller_address(lyricsflip.contract_address, OWNER());
lyricsflip.set_role(ADMIN_ADDRESS(), ADMIN_ROLE, true);
stop_cheat_caller_address(lyricsflip.contract_address);

start_cheat_caller_address(lyricsflip.contract_address, ADMIN_ADDRESS());
let test_card = Card {
card_id: 1,
genre: Genre::HipHop,
artist: 'Test Artist',
title: "Test Title",
year: 2000,
lyrics: "Test Lyrics",
};
lyricsflip.add_card(test_card);
lyricsflip.set_cards_per_round(1);
stop_cheat_caller_address(lyricsflip.contract_address);

// PLAYER_1 creates round
start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1());
let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), 1);
lyricsflip.start_round(round_id);
stop_cheat_caller_address(lyricsflip.contract_address);

// PLAYER_2 tries to submit answer without joining
start_cheat_caller_address(lyricsflip.contract_address, PLAYER_2());
let answer = Answer::Year(2000);
lyricsflip.submit_answer(round_id, answer);
stop_cheat_caller_address(lyricsflip.contract_address);
}

#[test]
#[should_panic(expected: ('Round not started',))]
fn test_submit_answer_should_panic_with_non_started_round() {
let lyricsflip = deploy();

// Setup admin and initial card
start_cheat_caller_address(lyricsflip.contract_address, OWNER());
lyricsflip.set_role(ADMIN_ADDRESS(), ADMIN_ROLE, true);
stop_cheat_caller_address(lyricsflip.contract_address);

start_cheat_caller_address(lyricsflip.contract_address, ADMIN_ADDRESS());
let test_card = Card {
card_id: 1,
genre: Genre::HipHop,
artist: 'Test Artist',
title: "Test Title",
year: 2000,
lyrics: "Test Lyrics",
};
lyricsflip.add_card(test_card);
lyricsflip.set_cards_per_round(1);
stop_cheat_caller_address(lyricsflip.contract_address);

// Create round but don't start it
start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1());
let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), 1);

// Try to submit answer
let answer = Answer::Year(2000);
lyricsflip.submit_answer(round_id, answer);
stop_cheat_caller_address(lyricsflip.contract_address);
}

#[test]
#[should_panic(expected: ('Round already completed',))]
fn test_submit_answer_should_panic_with_completed_round() {
let lyricsflip = deploy();

// Setup admin and initial card
start_cheat_caller_address(lyricsflip.contract_address, OWNER());
lyricsflip.set_role(ADMIN_ADDRESS(), ADMIN_ROLE, true);
stop_cheat_caller_address(lyricsflip.contract_address);

start_cheat_caller_address(lyricsflip.contract_address, ADMIN_ADDRESS());
let test_card = Card {
card_id: 1,
genre: Genre::HipHop,
artist: 'Test Artist',
title: "Test Title",
year: 2000,
lyrics: "Test Lyrics",
};
lyricsflip.add_card(test_card);
lyricsflip.set_cards_per_round(1);
stop_cheat_caller_address(lyricsflip.contract_address);

// Create and start round
start_cheat_caller_address(lyricsflip.contract_address, PLAYER_1());
let round_id = lyricsflip.create_round(Option::Some(Genre::HipHop), 1);
lyricsflip.start_round(round_id);

// Complete the round by calling next card
lyricsflip.next_card(round_id);

// Try to submit another answer after round completion
let another_answer = Answer::Title("Test Title");
lyricsflip.submit_answer(round_id, another_answer);
stop_cheat_caller_address(lyricsflip.contract_address);
}
6 changes: 3 additions & 3 deletions onchain/src/utils/types.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ pub struct QuestionCard<T> {

#[derive(Drop, Serde, starknet::Store)]
pub enum Answer {
Felt252: felt252,
U64: u64,
Bytes: ByteArray,
Artist: felt252,
Year: u64,
Title: ByteArray,
}

0 comments on commit 35957e9

Please sign in to comment.