Skip to content

Commit

Permalink
✅ Create tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bal7hazar committed Apr 19, 2024
1 parent ef07833 commit 4e92356
Show file tree
Hide file tree
Showing 12 changed files with 317 additions and 34 deletions.
6 changes: 6 additions & 0 deletions examples/matchmaker/src/constants.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ const DEFAULT_RATING: u32 = 1000;

const LEAGUE_SIZE: u8 = 20;

// World

fn WORLD() -> starknet::ContractAddress {
starknet::contract_address_const::<'WORLD'>()
}

// Constants

fn ZERO() -> starknet::ContractAddress {
Expand Down
8 changes: 8 additions & 0 deletions examples/matchmaker/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,11 @@ mod helpers {
mod bitmap;
}

#[cfg(test)]
mod tests {
mod setup;
mod test_create;
mod test_subscribe;
mod test_unsubscribe;
mod test_fight;
}
2 changes: 1 addition & 1 deletion examples/matchmaker/src/models/player.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ impl PlayerAssert of AssertTrait {

#[inline(always)]
fn assert_not_exist(player: Player) {
assert(player.is_non_zero(), errors::PLAYER_ALREADY_EXIST);
assert(player.is_zero(), errors::PLAYER_ALREADY_EXIST);
}

#[inline(always)]
Expand Down
2 changes: 0 additions & 2 deletions examples/matchmaker/src/models/registry.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ mod tests {
registry.subscribe(ref foe_league, ref foe);
let league_id = registry.search_league(league, player);
// [Assert] Registry
league_id.print();
assert(league_id == FAREST_LEAGUE_ID, 'Registry: wrong search league');
}

Expand All @@ -212,7 +211,6 @@ mod tests {
registry.subscribe(ref foe_league, ref foe);
let league_id = registry.search_league(league, player);
// [Assert] Registry
league_id.print();
assert(league_id == LEAGUE_ID, 'Registry: wrong search league');
}

Expand Down
18 changes: 1 addition & 17 deletions examples/matchmaker/src/store.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -75,20 +75,7 @@ impl StoreImpl of StoreTrait {
}

#[inline(always)]
fn add_player_to_league(self: Store, player: Player) {
// [Effect] Add the player to the last slot
let mut league = self.league(player.registry_id, player.league_id);
let mut last_slot = self.slot(league.registry_id, player.league_id, league.size);
last_slot.index = player.index;
last_slot.player_id = player.id;
self.set_slot(last_slot);
// [Effect] Update the league size
league.size += 1;
self.set_league(league);
}

#[inline(always)]
fn remove_player_from_league(self: Store, player: Player) {
fn remove_player_slot(self: Store, player: Player) {
// [Effect] Replace the slot with the last slot if needed
let mut league = self.league(player.registry_id, player.league_id);
let mut last_slot = self.slot(league.registry_id, player.league_id, league.size - 1);
Expand All @@ -100,8 +87,5 @@ impl StoreImpl of StoreTrait {
let mut empty_slot = self.slot(league.registry_id, player.league_id, league.size);
empty_slot.index = league.size - 1;
self.set_slot(empty_slot);
// [Effect] Update the league size
league.size -= 1;
self.set_league(league);
}
}
63 changes: 50 additions & 13 deletions examples/matchmaker/src/systems/maker.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,17 @@ use dojo::world::IWorldDispatcher;

// Interface

#[dojo::interface]
trait IMaker {
fn create();
fn subscribe();
fn unsubscribe();
fn fight();
#[starknet::interface]
trait IMaker<TContractState> {
fn create(self: @TContractState, world: IWorldDispatcher);
fn subscribe(self: @TContractState, world: IWorldDispatcher);
fn unsubscribe(self: @TContractState, world: IWorldDispatcher);
fn fight(self: @TContractState, world: IWorldDispatcher);
}

// Contract

#[dojo::contract]
#[starknet::contract]
mod maker {
// Core imports

Expand All @@ -30,8 +30,17 @@ mod maker {
use starknet::ContractAddress;
use starknet::info::{get_caller_address, get_tx_info};

// Dojo imports

use dojo::world;
use dojo::world::IWorldDispatcher;
use dojo::world::IWorldDispatcherTrait;
use dojo::world::IWorldProvider;
use dojo::world::IDojoResourceProvider;

// Internal imports

use matchmaker::constants::WORLD;
use matchmaker::store::{Store, StoreTrait};
use matchmaker::models::player::{Player, PlayerTrait, PlayerAssert};
use matchmaker::models::league::{League, LeagueTrait, LeagueAssert};
Expand All @@ -48,11 +57,30 @@ mod maker {
const CHARACTER_DUPLICATE: felt252 = 'Battle: character duplicate';
}

// Storage

#[storage]
struct Storage {}

// Implementations

#[abi(embed_v0)]
impl DojoResourceProviderImpl of IDojoResourceProvider<ContractState> {
fn dojo_resource(self: @ContractState) -> felt252 {
'account'
}
}

#[abi(embed_v0)]
impl WorldProviderImpl of IWorldProvider<ContractState> {
fn world(self: @ContractState) -> IWorldDispatcher {
IWorldDispatcher { contract_address: WORLD() }
}
}

#[abi(embed_v0)]
impl MakerImpl of IMaker<ContractState> {
fn create(world: IWorldDispatcher) {
fn create(self: @ContractState, world: IWorldDispatcher) {
// [Setup] Datastore
let mut store: Store = StoreTrait::new(world);

Expand All @@ -66,7 +94,7 @@ mod maker {
store.set_player(player);
}

fn subscribe(world: IWorldDispatcher) {
fn subscribe(self: @ContractState, world: IWorldDispatcher) {
// [Setup] Datastore
let mut store: Store = StoreTrait::new(world);

Expand Down Expand Up @@ -94,7 +122,7 @@ mod maker {
store.set_registry(registry);
}

fn unsubscribe(world: IWorldDispatcher) {
fn unsubscribe(self: @ContractState, world: IWorldDispatcher) {
// [Setup] Datastore
let mut store: Store = StoreTrait::new(world);

Expand All @@ -103,9 +131,12 @@ mod maker {
let mut player = store.player(0, caller);
PlayerAssert::assert_does_exist(player);

// [Effect] Remove slot
store.remove_player_slot(player);

// [Effect] Unsubscribe to Registry
let mut league = store.league(0, player.league_id);
let mut registry = store.registry(0);
let mut league = store.league(player.registry_id, player.league_id);
let mut registry = store.registry(player.registry_id);
registry.unsubscribe(ref league, ref player);

// [Effect] Update Player
Expand All @@ -118,7 +149,7 @@ mod maker {
store.set_registry(registry);
}

fn fight(world: IWorldDispatcher) {
fn fight(self: @ContractState, world: IWorldDispatcher) {
// [Setup] Datastore
let mut store: Store = StoreTrait::new(world);

Expand All @@ -140,12 +171,18 @@ mod maker {
// [Effect] Fight
player.fight(ref foe, seed);

// [Effect] Remove player slot
store.remove_player_slot(player);

// [Effect] Update Player league and slot
registry.unsubscribe(ref player_league, ref player);
let league_id = LeagueTrait::compute_id(player.rating);
let mut player_league = store.league(0, league_id);
let player_slot = registry.subscribe(ref player_league, ref player);

// [Effect] Remove foe slot
store.remove_player_slot(foe);

// [Effect] Update Foe league and slot
registry.unsubscribe(ref foe_league, ref foe);
let foe_league_id = LeagueTrait::compute_id(foe.rating);
Expand Down
93 changes: 93 additions & 0 deletions examples/matchmaker/src/tests/setup.cairo
Original file line number Diff line number Diff line change
@@ -1 +1,94 @@
mod setup {
// Core imports

use core::debug::PrintTrait;

// Starknet imports

use starknet::ContractAddress;
use starknet::testing::{set_contract_address};

// Dojo imports

use dojo::world::{IWorldDispatcherTrait, IWorldDispatcher};
use dojo::test_utils::{spawn_test_world, deploy_contract};

// Internal imports

use matchmaker::models::player::Player;
use matchmaker::models::league::League;
use matchmaker::models::registry::Registry;
use matchmaker::models::slot::Slot;
use matchmaker::systems::maker::{maker, IMakerDispatcher, IMakerDispatcherTrait};

// Constants

fn PLAYER() -> ContractAddress {
starknet::contract_address_const::<'PLAYER'>()
}

fn ANYONE() -> ContractAddress {
starknet::contract_address_const::<'ANYONE'>()
}

fn SOMEONE() -> ContractAddress {
starknet::contract_address_const::<'SOMEONE'>()
}

fn NOONE() -> ContractAddress {
starknet::contract_address_const::<'NOONE'>()
}

const REGISTRY_ID: u32 = 0;

#[derive(Drop)]
struct Systems {
maker: IMakerDispatcher,
}

#[derive(Drop)]
struct Context {
registry_id: u32,
player_id: ContractAddress,
someone_id: ContractAddress,
anyone_id: ContractAddress,
noone_id: ContractAddress,
}

#[inline(always)]
fn spawn() -> (IWorldDispatcher, Systems, Context) {
// [Setup] World
let mut models = core::array::ArrayTrait::new();
models.append(matchmaker::models::player::player::TEST_CLASS_HASH);
models.append(matchmaker::models::league::league::TEST_CLASS_HASH);
models.append(matchmaker::models::registry::registry::TEST_CLASS_HASH);
models.append(matchmaker::models::slot::slot::TEST_CLASS_HASH);
let world = spawn_test_world(models);

// [Setup] Systems
let maker_address = deploy_contract(maker::TEST_CLASS_HASH, array![].span());
let systems = Systems { maker: IMakerDispatcher { contract_address: maker_address }, };

// [Setup] Context
set_contract_address(SOMEONE());
systems.maker.create(world);
systems.maker.subscribe(world);
set_contract_address(ANYONE());
systems.maker.create(world);
systems.maker.subscribe(world);
set_contract_address(NOONE());
systems.maker.create(world);
systems.maker.subscribe(world);
set_contract_address(PLAYER());
let context = Context {
registry_id: REGISTRY_ID,
player_id: PLAYER(),
someone_id: SOMEONE(),
anyone_id: ANYONE(),
noone_id: NOONE()
};

// [Return]
(world, systems, context)
}
}
36 changes: 36 additions & 0 deletions examples/matchmaker/src/tests/test_create.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Core imports

use core::debug::PrintTrait;

// Starknet imports

use starknet::testing::set_contract_address;

// Dojo imports

use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};

// Internal imports

use matchmaker::store::{Store, StoreTrait};
use matchmaker::models::player::{Player, PlayerTrait, PlayerAssert};
use matchmaker::models::registry::{Registry, RegistryTrait, RegistryAssert};
use matchmaker::models::league::{League, LeagueTrait, LeagueAssert};
use matchmaker::models::slot::{Slot, SlotTrait};
use matchmaker::systems::maker::IMakerDispatcherTrait;
use matchmaker::tests::setup::{setup, setup::Systems};

#[test]
fn test_maker_create() {
// [Setup]
let (world, systems, context) = setup::spawn();
let store = StoreTrait::new(world);

// [Create]
systems.maker.create(world);

// [Assert] Player
let player = store.player(context.registry_id, context.player_id);
assert(player.id == context.player_id, 'Create: wrong player id');
assert(player.league_id == 0, 'Create: wrong league id');
}
43 changes: 43 additions & 0 deletions examples/matchmaker/src/tests/test_fight.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Core imports

use core::debug::PrintTrait;

// Starknet imports

use starknet::testing::set_contract_address;

// Dojo imports

use dojo::world::{IWorldDispatcher, IWorldDispatcherTrait};

// Internal imports

use matchmaker::store::{Store, StoreTrait};
use matchmaker::models::player::{Player, PlayerTrait, PlayerAssert};
use matchmaker::models::registry::{Registry, RegistryTrait, RegistryAssert};
use matchmaker::models::league::{League, LeagueTrait, LeagueAssert};
use matchmaker::models::slot::{Slot, SlotTrait};
use matchmaker::systems::maker::IMakerDispatcherTrait;
use matchmaker::tests::setup::{setup, setup::Systems};

#[test]
fn test_maker_fight() {
// [Setup]
let (world, systems, context) = setup::spawn();
let store = StoreTrait::new(world);

// [Create]
systems.maker.create(world);

// [Subscribe]
systems.maker.subscribe(world);

// [Fight]
let player = store.player(context.registry_id, context.player_id);
let rating = player.rating;
systems.maker.fight(world);

// [Assert] Player
let player = store.player(context.registry_id, context.player_id);
assert(player.rating != rating, 'Fight: wrong player rating');
}
Loading

0 comments on commit 4e92356

Please sign in to comment.