Skip to content

Commit

Permalink
Merge branch 'dev' into refactor-move-function
Browse files Browse the repository at this point in the history
  • Loading branch information
Jagadeeshftw authored Feb 9, 2025
2 parents c224fcb + 5ab6f80 commit d833308
Show file tree
Hide file tree
Showing 5 changed files with 247 additions and 8 deletions.
18 changes: 15 additions & 3 deletions .github/workflows/test_contracts.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
name: Test Dojo contracts
name: Build and test Dojo contracts

on: [push, pull_request]

jobs:
sozo-test:
runs-on: ubuntu-latest
env:
DOJO_VERSION: v1.1.2
steps:
- uses: actions/checkout@v3
- run: curl -L https://install.dojoengine.org | bash
- run: /home/runner/.config/.dojo/bin/dojoup -v v1.1.2
- uses: software-mansion/setup-scarb@v1
with:
scarb-version: "2.9.2"
- run: |
curl -L https://install.dojoengine.org | bash
/home/runner/.config/.dojo/bin/dojoup -v ${{ env.DOJO_VERSION }}
- run: |
cd onchain
/home/runner/.config/.dojo/bin/sozo build
/home/runner/.config/.dojo/bin/sozo test
if [[ `git status --porcelain` ]]; then
echo The git repo is dirty
echo "Make sure to run \"sozo build\" after changing Scarb.toml"
exit 1
fi
3 changes: 1 addition & 2 deletions onchain/src/models/game.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use starkludo::models::player::{Player};
// Can either be Ongoing or Ended
#[derive(Serde, Copy, Drop, Introspect, PartialEq, Debug)]
pub enum GameStatus {
Initialised, // Game has been created
Pending, // Waiting for players to join (in multiplayer mode)
Ongoing, // Game is ongoing
Ended // Game has ended
Expand Down Expand Up @@ -104,7 +103,7 @@ impl GameImpl of GameTrait {
id,
created_by,
is_initialised: true,
status: GameStatus::Initialised,
status: GameStatus::Pending,
mode: game_mode,
ready_to_start: false,
player_green,
Expand Down
14 changes: 11 additions & 3 deletions onchain/src/models/player.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ pub struct Player {
pub owner: ContractAddress, // Account owner of player. An account can own multiple players
pub is_bot: bool,
pub total_games_played: u256, // Count of total games played by this player
pub total_games_won: u256, // Count of total games won by this player
pub total_games_completed: u256, // Count of total games completed by this player
pub total_games_won: u256,
}


Expand All @@ -18,7 +19,7 @@ pub struct Player {
pub struct UsernameToAddress {
#[key]
pub username: felt252,
pub address: ContractAddress
pub address: ContractAddress,
}

#[derive(Drop, Copy, Serde)]
Expand All @@ -39,6 +40,13 @@ pub trait PlayerTrait {

impl PlayerImpl of PlayerTrait {
fn new(username: felt252, owner: ContractAddress, is_bot: bool) -> Player {
Player { username, owner, is_bot, total_games_played: 0, total_games_won: 0 }
Player {
username,
owner,
is_bot,
total_games_played: 0,
total_games_completed: 0,
total_games_won: 0,
}
}
}
6 changes: 6 additions & 0 deletions onchain/src/systems/game_actions.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ pub mod GameActions {

assert(caller_username != 0, 'PLAYER NOT REGISTERED');

// Verify that player has not already joined the game
assert(game.player_red != caller_username, 'ALREADY SELECTED RED');
assert(game.player_blue != caller_username, 'ALREADY SELECTED BLUE');
assert(game.player_green != caller_username, 'ALREADY SELECTED GREEN');
assert(game.player_yellow != caller_username, 'ALREADY SELECTED YELLOW');

/// Game starts automatically once the last player joins

// Verify that color is available
Expand Down
214 changes: 214 additions & 0 deletions onchain/src/tests/test_game.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -868,4 +868,218 @@ mod tests {
game = world.read_model(game_id);
assert(game.next_player == game.player_red, 'Red should get an extra turn');
}

#[test]
#[should_panic(expected: ('GAME NOT INITIALISED', 'ENTRYPOINT_FAILED'))]
fn test_join_game_not_initialized() {
let (mut world, game_action_system) = setup_world();
let caller = contract_address_const::<'test_gamer'>();
let username = 'gamer';
let no_of_players: u8 = 3;

testing::set_contract_address(caller);
game_action_system.create_new_player(username, false);

let game_id = game_action_system
.create_new_game(GameMode::MultiPlayer, PlayerColor::Red, no_of_players);

testing::set_contract_address(game_action_system.contract_address);
let mut game: Game = world.read_model(game_id);
game.is_initialised = false;
world.write_model(@game);

testing::set_contract_address(caller);
game_action_system.join(PlayerColor::Red, game_id);
}

#[test]
#[should_panic(expected: ('GAME NOT MULTIPLAYER', 'ENTRYPOINT_FAILED'))]
fn test_join_game_not_multiplayer() {
let (_, game_action_system) = setup_world();
let caller = contract_address_const::<'test_player'>();
let username = 'player';
let no_of_players: u8 = 2;

testing::set_contract_address(caller);
game_action_system.create_new_player(username, false);

let game_id = game_action_system
.create_new_game(GameMode::SinglePlayer, PlayerColor::Red, no_of_players);

game_action_system.join(PlayerColor::Red, game_id);
}

#[test]
#[should_panic(expected: ('PLAYER NOT REGISTERED', 'ENTRYPOINT_FAILED'))]
fn test_join_game_unregistered_player() {
let (_, game_action_system) = setup_world();
let caller = contract_address_const::<'unregistered_player'>();

testing::set_contract_address(caller);

let game_id = game_action_system
.create_new_game(GameMode::MultiPlayer, PlayerColor::Red, 2);

game_action_system.join(PlayerColor::Red, game_id);
}

#[test]
fn test_join_game_successful() {
let (mut world, game_action_system) = setup_world();
let caller = contract_address_const::<'first_gamer'>();
let username = 'gamer';
let second_player_address = contract_address_const::<'second_player'>();
let second_player_username = 'second_player';
let no_of_players: u8 = 3;

testing::set_contract_address(second_player_address);
game_action_system.create_new_player(second_player_username, false);

testing::set_contract_address(caller);
game_action_system.create_new_player(username, false);

let game_id = game_action_system
.create_new_game(GameMode::MultiPlayer, PlayerColor::Red, no_of_players);

// Set game status to pending
testing::set_contract_address(game_action_system.contract_address);
let mut game: Game = world.read_model(game_id);
game.status = GameStatus::Pending;
world.write_model(@game);

// Join game with a different color than used in creating game
testing::set_contract_address(second_player_address);
game_action_system.join(PlayerColor::Blue, game_id);

// Verify join was successful
let joined_game: Game = world.read_model(game_id);
assert(joined_game.player_blue == second_player_username, 'Player should be blue');
}

#[test]
#[should_panic(expected: ("RED already selected", 'ENTRYPOINT_FAILED'))]
fn test_join_game_color_taken() {
let (mut world, game_action_system) = setup_world();
let caller1 = contract_address_const::<'test_gamer1'>();
let username1 = 'gamer1';
let caller2 = contract_address_const::<'test_gamer2'>();
let username2 = 'gamer2';

testing::set_contract_address(caller1);
game_action_system.create_new_player(username1, false);

let game_id = game_action_system
.create_new_game(GameMode::MultiPlayer, PlayerColor::Red, 2);

testing::set_contract_address(game_action_system.contract_address);
let mut game: Game = world.read_model(game_id);
game.status = GameStatus::Pending;
world.write_model(@game);

testing::set_contract_address(caller2);
game_action_system.create_new_player(username2, false);

game_action_system.join(PlayerColor::Red, game_id);
}

#[test]
fn test_join_game_auto_start_when_complete() {
let (mut world, game_action_system) = setup_world();
let caller1 = contract_address_const::<'test_gamer1'>();
let username1 = 'gamer1';
let caller2 = contract_address_const::<'test_gamer2'>();
let username2 = 'gamer2';
let no_of_players: u8 = 2;

testing::set_contract_address(caller1);
game_action_system.create_new_player(username1, false);

let game_id = game_action_system
.create_new_game(GameMode::MultiPlayer, PlayerColor::Green, no_of_players);

// Set game to pending state
testing::set_contract_address(game_action_system.contract_address);
let mut game: Game = world.read_model(game_id);
game.status = GameStatus::Pending;
world.write_model(@game);

testing::set_contract_address(caller2);
game_action_system.create_new_player(username2, false);

game_action_system.join(PlayerColor::Blue, game_id);

let joined_game: Game = world.read_model(game_id);

assert(joined_game.status == GameStatus::Ongoing, 'Game should be ongoing');
assert(joined_game.player_green == username1, 'First player should be green');
assert(joined_game.player_blue == username2, 'Second player should be blue');
}

#[should_panic(expected: ("Number of players cannot be 1", 'ENTRYPOINT_FAILED'))]
#[test]
fn test_join_game_invalid_number_of_players_one() {
let (mut world, game_action_system) = setup_world();
let caller = contract_address_const::<'test_gamer'>();
let username = 'gamer';
let second_player_address = contract_address_const::<'second_player'>();
let second_player_username = 'second_player';
let given_players: u8 = 3;

testing::set_contract_address(second_player_address);
game_action_system.create_new_player(second_player_username, false);

testing::set_contract_address(caller);
game_action_system.create_new_player(username, false);

let game_id = game_action_system
.create_new_game(GameMode::MultiPlayer, PlayerColor::Red, given_players);

// Set number of players to unaccepted value
testing::set_contract_address(game_action_system.contract_address);
let mut game: Game = world.read_model(game_id);
game.status = GameStatus::Pending;
game.number_of_players = 1;
world.write_model(@game);

testing::set_contract_address(second_player_address);
game_action_system.join(PlayerColor::Yellow, game_id);
}

#[test]
fn test_three_player_game_incomplete() {
let (mut world, game_action_system) = setup_world();

let caller1 = contract_address_const::<'test_gamer1'>();
let username1 = 'gamer1';
let caller2 = contract_address_const::<'test_gamer2'>();
let username2 = 'gamer2';

testing::set_contract_address(caller1);
game_action_system.create_new_player(username1, false);
testing::set_contract_address(caller2);
game_action_system.create_new_player(username2, false);

// Create 3-player game
testing::set_contract_address(caller1);
let game_id = game_action_system
.create_new_game(GameMode::MultiPlayer, PlayerColor::Red, 3);

// Set game to pending state
testing::set_contract_address(game_action_system.contract_address);
let mut game: Game = world.read_model(game_id);
game.status = GameStatus::Pending;
world.write_model(@game);

testing::set_contract_address(caller2);
game_action_system.join(PlayerColor::Blue, game_id);

let game: Game = world.read_model(game_id);

// Assert game is still pending with only two players
assert(game.status == GameStatus::Pending, 'Game should be pending');
assert(game.player_red == username1, 'Red player should be set');
assert(game.player_blue == username2, 'Blue player should be set');
assert(game.player_green == 0, 'Green player should be empty');
assert(game.player_yellow == 0, 'Yellow player should be empty');
}
}

0 comments on commit d833308

Please sign in to comment.