Skip to content

feat(testing): verify indexed keys in event assertions #1401

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 12 commits 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
12 changes: 12 additions & 0 deletions packages/access/src/accesscontrol/accesscontrol.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@ pub mod AccessControlComponent {
/// or the deployer address if `_grant_role` is called from the constructor.
#[derive(Drop, Debug, PartialEq, starknet::Event)]
pub struct RoleGranted {
#[key]
pub role: felt252,
#[key]
pub account: ContractAddress,
#[key]
pub sender: ContractAddress,
}

Expand All @@ -63,8 +66,11 @@ pub mod AccessControlComponent {
/// or the deployer address if `_grant_role_with_delay` is called from the constructor.
#[derive(Drop, Debug, PartialEq, starknet::Event)]
pub struct RoleGrantedWithDelay {
#[key]
pub role: felt252,
#[key]
pub account: ContractAddress,
#[key]
pub sender: ContractAddress,
pub delay: u64,
}
Expand All @@ -76,8 +82,11 @@ pub mod AccessControlComponent {
/// - If using `renounce_role`, it is the role bearer (i.e. `account`).
#[derive(Drop, Debug, PartialEq, starknet::Event)]
pub struct RoleRevoked {
#[key]
pub role: felt252,
#[key]
pub account: ContractAddress,
#[key]
pub sender: ContractAddress,
}

Expand All @@ -87,8 +96,11 @@ pub mod AccessControlComponent {
/// `RoleAdminChanged` not being emitted signaling this.
#[derive(Drop, Debug, PartialEq, starknet::Event)]
pub struct RoleAdminChanged {
#[key]
pub role: felt252,
#[key]
pub previous_admin_role: felt252,
#[key]
pub new_admin_role: felt252,
}

Expand Down
38 changes: 38 additions & 0 deletions packages/access/src/tests/test_accesscontrol.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use openzeppelin_test_common::mocks::access::DualCaseAccessControlMock;
use openzeppelin_testing::constants::{
ADMIN, AUTHORIZED, OTHER, OTHER_ADMIN, OTHER_ROLE, ROLE, TIMESTAMP, ZERO,
};
use openzeppelin_testing::events::assert_indexed_keys;
use openzeppelin_testing::{EventSpyExt, EventSpyQueue as EventSpy, spy_events};
use snforge_std::{start_cheat_block_timestamp_global, start_cheat_caller_address, test_address};
use starknet::ContractAddress;
Expand Down Expand Up @@ -746,3 +747,40 @@ impl AccessControlSpyHelpersImpl of AccessControlSpyHelpers {
self.assert_only_event(from_address, expected);
}
}

#[test]
fn test_role_granted_event_indexed_keys() {
let role = ROLE;
let account = OTHER;
let sender = ADMIN;

let grant_event = AccessControlComponent::RoleGranted { role, account, sender };
let expected_keys = array![role.into(), account.into(), sender.into()];
assert_indexed_keys(@grant_event, @expected_keys);
}

#[test]
fn test_role_revoked_event_indexed_keys() {
let role = ROLE;
let account = OTHER;
let sender = ADMIN;

let revoke_event = AccessControlComponent::RoleRevoked { role, account, sender };
let expected_keys = array![role.into(), account.into(), sender.into()];
assert_indexed_keys(@revoke_event, @expected_keys);
}

#[test]
fn test_role_admin_changed_event_indexed_keys() {
let role = ROLE;
let previous_admin_role = ZERO;
let new_admin_role = ADMIN;

let admin_event = AccessControlComponent::RoleAdminChanged {
role: role.into(),
previous_admin_role: previous_admin_role.into(),
new_admin_role: new_admin_role.into(),
};
let expected_keys = array![role.into(), previous_admin_role.into(), new_admin_role.into()];
assert_indexed_keys(@admin_event, @expected_keys);
}
12 changes: 11 additions & 1 deletion packages/access/src/tests/test_ownable.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use core::num::traits::Zero;
use openzeppelin_test_common::mocks::access::DualCaseOwnableMock;
use openzeppelin_test_common::ownable::OwnableSpyHelpers;
use openzeppelin_testing::constants::{OTHER, OWNER, RECIPIENT, ZERO};
use openzeppelin_testing::spy_events;
use openzeppelin_testing::events::{assert_indexed_keys, spy_events};
use snforge_std::{start_cheat_caller_address, test_address};
use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess};
use crate::ownable::OwnableComponent;
Expand Down Expand Up @@ -204,3 +204,13 @@ fn test_renounceOwnership_from_nonowner() {
start_cheat_caller_address(test_address(), OTHER);
state.renounceOwnership();
}

#[test]
fn test_ownership_transferred_event_indexed_keys() {
let previous_owner = ZERO;
let new_owner = OWNER;

let transfer_event = OwnableComponent::OwnershipTransferred { previous_owner, new_owner };
let expected_keys = array![previous_owner.into(), new_owner.into()];
assert_indexed_keys(@transfer_event, @expected_keys);
}
22 changes: 21 additions & 1 deletion packages/account/src/tests/test_account.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ use openzeppelin_test_common::mocks::simple::{ISimpleMockDispatcher, ISimpleMock
use openzeppelin_testing as utils;
use openzeppelin_testing::constants::stark::{KEY_PAIR, KEY_PAIR_2};
use openzeppelin_testing::constants::{
CALLER, MIN_TRANSACTION_VERSION, OTHER, QUERY_OFFSET, QUERY_VERSION, SALT, ZERO,
CALLER, MIN_TRANSACTION_VERSION, NEW_PUBKEY, OTHER, PUBKEY, QUERY_OFFSET, QUERY_VERSION, SALT,
ZERO,
};
use openzeppelin_testing::events::assert_indexed_keys;
use openzeppelin_testing::signing::StarkKeyPair;
use openzeppelin_testing::spy_events;
use snforge_std::{
Expand Down Expand Up @@ -497,3 +499,21 @@ fn test__set_public_key() {
spy.assert_only_event_owner_added(account_address, public_key);
assert_eq!(state.get_public_key(), public_key);
}

#[test]
fn test_owner_added_event_indexed_keys() {
let new_owner = NEW_PUBKEY;

let owner_added_event = AccountComponent::OwnerAdded { new_owner_guid: new_owner };
let expected_keys = array![new_owner.into()];
assert_indexed_keys(@owner_added_event, @expected_keys);
}

#[test]
fn test_owner_removed_event_indexed_keys() {
let removed_owner = PUBKEY;

let owner_removed_event = AccountComponent::OwnerRemoved { removed_owner_guid: removed_owner };
let expected_keys = array![removed_owner.into()];
assert_indexed_keys(@owner_removed_event, @expected_keys);
}
23 changes: 22 additions & 1 deletion packages/account/src/tests/test_eth_account.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use openzeppelin_test_common::mocks::simple::{ISimpleMockDispatcher, ISimpleMock
use openzeppelin_testing as utils;
use openzeppelin_testing::constants::secp256k1::{KEY_PAIR, KEY_PAIR_2};
use openzeppelin_testing::constants::{
CALLER, MIN_TRANSACTION_VERSION, OTHER, QUERY_VERSION, SALT, ZERO,
CALLER, ETH_SIGNER, MIN_TRANSACTION_VERSION, NEW_ETH_SIGNER, OTHER, QUERY_VERSION, SALT, ZERO,
};
use openzeppelin_testing::events::assert_indexed_keys;
use openzeppelin_testing::signing::Secp256k1KeyPair;
use openzeppelin_testing::spy_events;
use openzeppelin_utils::serde::SerializedAppend;
Expand Down Expand Up @@ -540,3 +541,23 @@ fn test__set_public_key() {

assert_eq!(state.get_public_key(), key_pair.public_key);
}

#[test]
fn test_eth_owner_added_event_indexed_keys() {
let new_owner = NEW_ETH_SIGNER;

let owner_added_event = EthAccountComponent::OwnerAdded { new_owner_guid: new_owner };
let expected_keys = array![new_owner.into()];
assert_indexed_keys(@owner_added_event, @expected_keys);
}

#[test]
fn test_eth_owner_removed_event_indexed_keys() {
let removed_owner = ETH_SIGNER;

let owner_removed_event = EthAccountComponent::OwnerRemoved {
removed_owner_guid: removed_owner,
};
let expected_keys = array![removed_owner.into()];
assert_indexed_keys(@owner_removed_event, @expected_keys);
}
24 changes: 24 additions & 0 deletions packages/governance/src/tests/test_votes.cairo
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// use core::num::traits::Zero;
use openzeppelin_test_common::mocks::votes::ERC721VotesMock::SNIP12MetadataImpl;
use openzeppelin_test_common::mocks::votes::{ERC20VotesMock, ERC721VotesMock};
use openzeppelin_testing as utils;
use openzeppelin_testing::constants::{DELEGATEE, DELEGATOR, OTHER, RECIPIENT, SUPPLY, ZERO};
use openzeppelin_testing::events::assert_indexed_keys;
use openzeppelin_testing::{AsAddressTrait, EventSpyExt, EventSpyQueue as EventSpy, spy_events};
use openzeppelin_token::erc20::ERC20Component::InternalTrait;
use openzeppelin_token::erc20::interface::IERC20;
Expand Down Expand Up @@ -673,3 +675,25 @@ impl VotesSpyHelpersImpl of VotesSpyHelpers {
self.assert_no_events_left_from(contract);
}
}

#[test]
fn test_delegate_changed_event_indexed_keys() {
let delegator = DELEGATOR;
let from_delegate = ZERO;
let to_delegate = RECIPIENT;

let delegate_event = VotesComponent::DelegateChanged { delegator, from_delegate, to_delegate };
let expected_keys = array![delegator.into(), from_delegate.into(), to_delegate.into()];
assert_indexed_keys(@delegate_event, @expected_keys);
}

#[test]
fn test_delegate_votes_changed_event_indexed_keys() {
let delegate = DELEGATOR;
let previous_votes = 0;
let new_votes = SUPPLY;

let votes_event = VotesComponent::DelegateVotesChanged { delegate, previous_votes, new_votes };
let expected_keys = array![delegate.into()];
assert_indexed_keys(@votes_event, @expected_keys);
}
21 changes: 20 additions & 1 deletion packages/security/src/tests/test_pausable.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use openzeppelin_test_common::mocks::security::PausableMock;
use openzeppelin_testing::constants::CALLER;
use openzeppelin_testing::constants::{CALLER, OWNER};
use openzeppelin_testing::events::assert_indexed_keys;
use openzeppelin_testing::{EventSpyExt, EventSpyQueue as EventSpy, spy_events};
use snforge_std::{start_cheat_caller_address, test_address};
use starknet::ContractAddress;
Expand Down Expand Up @@ -150,3 +151,21 @@ impl PausableSpyHelpersImpl of PausableSpyHelpers {
self.assert_no_events_left_from(contract);
}
}

#[test]
fn test_paused_event_indexed_keys() {
let account = OWNER;

let paused_event = PausableComponent::Paused { account };
let expected_keys = array![account.into()];
assert_indexed_keys(@paused_event, @expected_keys);
}

#[test]
fn test_unpaused_event_indexed_keys() {
let account = OWNER;

let unpaused_event = PausableComponent::Unpaused { account };
let expected_keys = array![account.into()];
assert_indexed_keys(@unpaused_event, @expected_keys);
}
4 changes: 4 additions & 0 deletions packages/testing/src/constants.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,14 @@ pub const OTHER_ROLE: felt252 = 'OTHER_ROLE';
pub const CHAIN_ID: felt252 = 'CHAIN_ID';
pub const TOKEN_ID: u256 = 21;
pub const TOKEN_ID_2: u256 = 121;
pub const TOKEN_ID_3: u256 = 321;
pub const TOKEN_VALUE: u256 = 42;
pub const TOKEN_VALUE_2: u256 = 142;
pub const TOKEN_VALUE_3: u256 = 342;
pub const PUBKEY: felt252 = 'PUBKEY';
pub const NEW_PUBKEY: felt252 = 0x26da8d11938b76025862be14fdb8b28438827f73e75e86f7bfa38b196951fa7;
pub const ETH_SIGNER: felt252 = 'ETH_SIGNER';
pub const NEW_ETH_SIGNER: felt252 = 'NEW_ETH_SIGNER';
pub const DAPP_NAME: felt252 = 'DAPP_NAME';
pub const DAPP_VERSION: felt252 = 'DAPP_VERSION';
pub const SALT: felt252 = 'SALT';
Expand Down
24 changes: 24 additions & 0 deletions packages/testing/src/events.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,27 @@ fn is_emitted<T, impl TEvent: starknet::Event<T>, impl TDrop: Drop<T>>(
}
return is_emitted;
}

/// Asserts that the event's indexed keys match the expected values in order.
/// This checks that specific fields are properly marked as indexed in the event definition.
pub fn assert_indexed_keys<T, impl TEvent: starknet::Event<T>, impl TDrop: Drop<T>>(
event: @T, expected_indexed_values: @Array<felt252>,
) {
let mut actual_keys = array![];
let mut data = array![];
event.append_keys_and_data(ref actual_keys, ref data);

assert!(
actual_keys.len() == expected_indexed_values.len(),
"Number of indexed keys does not match expected",
);

let mut i = 0;
while i != actual_keys.len() {
assert!(
*actual_keys.at(i) == *expected_indexed_values.at(i),
"Indexed key value does not match expected",
);
i += 1;
}
}
2 changes: 1 addition & 1 deletion packages/testing/src/lib.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ pub use deployment::{
declare_and_deploy, declare_and_deploy_at, declare_class, deploy, deploy_another_at, deploy_at,
};

pub use events::{EventSpyExt, EventSpyQueue, spy_events};
pub use events::{EventSpyExt, EventSpyQueue, assert_indexed_keys, spy_events};
38 changes: 38 additions & 0 deletions packages/token/src/tests/erc1155/test_erc1155.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use openzeppelin_testing::constants::{
EMPTY_DATA, OPERATOR, OTHER, OWNER, RECIPIENT, TOKEN_ID, TOKEN_ID_2, TOKEN_VALUE, TOKEN_VALUE_2,
ZERO,
};
use openzeppelin_testing::events::assert_indexed_keys;
use openzeppelin_testing::{EventSpyExt, EventSpyQueue as EventSpy, spy_events};
use snforge_std::{start_cheat_caller_address, test_address};
use starknet::ContractAddress;
Expand Down Expand Up @@ -1412,3 +1413,40 @@ impl ERC1155HooksSpyHelpersImpl of ERC1155HooksSpyHelpers {
self.assert_emitted_single(contract, expected);
}
}

#[test]
fn test_transfer_single_event_indexed_keys() {
let operator = OPERATOR;
let from = OWNER;
let to = RECIPIENT;
let id = TOKEN_ID;
let value = TOKEN_VALUE;

let transfer_event = ERC1155Component::TransferSingle { operator, from, to, id, value };
let expected_keys = array![operator.into(), from.into(), to.into()];
assert_indexed_keys(@transfer_event, @expected_keys);
}

#[test]
fn test_transfer_batch_event_indexed_keys() {
let operator = OPERATOR;
let from = OWNER;
let to = RECIPIENT;
let ids = array![TOKEN_ID, TOKEN_ID_2].span();
let values = array![TOKEN_VALUE, TOKEN_VALUE_2].span();

let transfer_event = ERC1155Component::TransferBatch { operator, from, to, ids, values };
let expected_keys = array![operator.into(), from.into(), to.into()];
assert_indexed_keys(@transfer_event, @expected_keys);
}

#[test]
fn test_approval_for_all_event_indexed_keys() {
let owner = OWNER;
let operator = OPERATOR;
let approved = true;

let approval_event = ERC1155Component::ApprovalForAll { owner, operator, approved };
let expected_keys = array![owner.into(), operator.into()];
assert_indexed_keys(@approval_event, @expected_keys);
}
30 changes: 30 additions & 0 deletions packages/token/src/tests/erc20/test_erc20.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use core::num::traits::Bounded;
use openzeppelin_test_common::erc20::ERC20SpyHelpers;
use openzeppelin_test_common::mocks::erc20::{DualCaseERC20Mock, SnakeERC20MockWithHooks};
use openzeppelin_testing::constants::{NAME, OWNER, RECIPIENT, SPENDER, SUPPLY, SYMBOL, VALUE, ZERO};
use openzeppelin_testing::events::assert_indexed_keys;
use openzeppelin_testing::{EventSpyExt, EventSpyQueue as EventSpy, spy_events};
use snforge_std::{start_cheat_caller_address, test_address};
use starknet::ContractAddress;
Expand Down Expand Up @@ -687,3 +688,32 @@ impl ERC20HooksSpyHelpersImpl of ERC20HooksSpyHelpers {
self.assert_emitted_single(contract, expected);
}
}

#[test]
fn test_transfer_event_indexed_keys() {
let mut state = setup();
let from = OWNER;
let to = RECIPIENT;
let value = VALUE;

let transfer_event = ERC20Component::Transfer { from, to, value };
let expected_keys = array![from.into(), to.into()];
assert_indexed_keys(@transfer_event, @expected_keys);
}

#[test]
fn test_approval_event_indexed_keys() {
let owner = OWNER;
let spender = SPENDER;
let value = VALUE;

let approval_event = ERC20Component::Approval { owner, spender, value };
let expected_keys = array![owner.into(), spender.into()];
assert_indexed_keys(@approval_event, @expected_keys);
}

#[test]
fn test_setup() {
let mut _state = setup();
// ... rest of the test
}
Loading
Loading