Skip to content

Commit

Permalink
✅ Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bal7hazar committed Sep 18, 2023
1 parent 0d81f11 commit 86562a1
Show file tree
Hide file tree
Showing 12 changed files with 975 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/module.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ mod ERC3525 {

// [Check] Disambiguate function call: only one of `to_token_id` and `to` must be set
assert(to_token_id == 0.into() || to.is_zero(), Errors::INVALID_EXCLUSIVE_ARGS);
assert(to_token_id != 0.into() || !to.is_zero(), Errors::INVALID_EXCLUSIVE_ARGS);

// [Effect] Spend allowance if possible
self._spend_allowance(caller, from_token_id, value);
Expand Down
6 changes: 6 additions & 0 deletions src/tests.cairo
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@ mod unit {
mod constants;
mod test_initialization;
mod test_approvals;
mod test_metadata;
mod test_mint_burn;
mod test_slot_approvable;
mod test_slot_enumerable;
mod test_transfer_to_address;
mod test_transfer_to_token;
mod test_views;
}

mod mocks {
Expand Down
25 changes: 24 additions & 1 deletion src/tests/unit/constants.cairo
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
// Core imports

use zeroable::Zeroable;

// Starknet imports

use starknet::ContractAddress;
use starknet::contract_address_const;
use zeroable::Zeroable;

// Local imports

use cairo_erc_3525::module::ERC3525;
use cairo_erc_3525::extensions::metadata::module::ERC3525Metadata;
use cairo_erc_3525::extensions::slotapprovable::module::ERC3525SlotApprovable;
use cairo_erc_3525::extensions::slotenumerable::module::ERC3525SlotEnumerable;

// State

fn STATE() -> ERC3525::ContractState {
ERC3525::unsafe_new_contract_state()
}

fn STATE_METADATA() -> ERC3525Metadata::ContractState {
ERC3525Metadata::unsafe_new_contract_state()
}

fn STATE_SLOT_APPROVABLE() -> ERC3525SlotApprovable::ContractState {
ERC3525SlotApprovable::unsafe_new_contract_state()
}

fn STATE_SLOT_ENUMERABLE() -> ERC3525SlotEnumerable::ContractState {
ERC3525SlotEnumerable::unsafe_new_contract_state()
}

// Constants

const NAME: felt252 = 'NAME';
Expand Down
8 changes: 8 additions & 0 deletions src/tests/unit/test_approvals.cairo
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
// Starknet imports

use starknet::testing::set_caller_address;

// External imports

use openzeppelin::token::erc721::erc721::ERC721;

// Local imports

use cairo_erc_3525::module::ERC3525;
use cairo_erc_3525::tests::unit::constants::{
STATE, VALUE_DECIMALS, TOKEN_ID_1, INVALID_TOKEN, SLOT_1, VALUE, ZERO, OWNER, OPERATOR, SOMEONE,
Expand Down
2 changes: 2 additions & 0 deletions src/tests/unit/test_initialization.cairo
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Local imports

use cairo_erc_3525::module::ERC3525;
use cairo_erc_3525::tests::unit::constants::{STATE, VALUE_DECIMALS};

Expand Down
54 changes: 54 additions & 0 deletions src/tests/unit/test_metadata.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Core imports

use integer::BoundedInt;
use debug::PrintTrait;

// Starknet imports

use starknet::ContractAddress;
use starknet::testing::set_caller_address;

// External imports

use openzeppelin::token::erc721::erc721::ERC721;

// Local imports

use cairo_erc_3525::tests::mocks::account::Account;
use cairo_erc_3525::module::ERC3525;
use cairo_erc_3525::extensions::metadata::module::ERC3525Metadata;
use cairo_erc_3525::tests::unit::constants::{STATE, STATE_METADATA, VALUE_DECIMALS, SLOT_1, SLOT_2};

// Settings

fn setup() -> ERC3525Metadata::ContractState {
let mut state_metadata = STATE_METADATA();
ERC3525Metadata::InternalImpl::initializer(ref state_metadata);
state_metadata
}

#[test]
#[available_gas(20000000)]
fn test_metadata_contract_uri() {
let mut state_metadata = setup();
let uri = ERC3525Metadata::ERC3525MetadataImpl::contract_uri(@state_metadata);
assert(uri == 0, 'Wrong contract URI');
let new_uri = 'https://example.com';
ERC3525Metadata::InternalImpl::_set_contract_uri(ref state_metadata, new_uri);
let uri = ERC3525Metadata::ERC3525MetadataImpl::contract_uri(@state_metadata);
assert(uri == new_uri, 'Wrong contract URI');
}

#[test]
#[available_gas(20000000)]
fn test_metadata_slot_uri() {
let mut state_metadata = setup();
let uri = ERC3525Metadata::ERC3525MetadataImpl::slot_uri(@state_metadata, SLOT_1);
assert(uri == 0, 'Wrong contract URI');
let new_uri = 'https://example.com';
ERC3525Metadata::InternalImpl::_set_slot_uri(ref state_metadata, SLOT_1, new_uri);
let uri = ERC3525Metadata::ERC3525MetadataImpl::slot_uri(@state_metadata, SLOT_1);
assert(uri == new_uri, 'Wrong contract URI');
let uri = ERC3525Metadata::ERC3525MetadataImpl::slot_uri(@state_metadata, SLOT_2);
assert(uri == 0, 'Wrong contract URI');
}
16 changes: 13 additions & 3 deletions src/tests/unit/test_mint_burn.cairo
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
// Core imports

use debug::PrintTrait;

// Starknet imports

use starknet::get_contract_address;
use starknet::testing::set_caller_address;

// External imports

use openzeppelin::token::erc721::erc721::ERC721;

// Local imports

use cairo_erc_3525::module::ERC3525;
use cairo_erc_3525::tests::unit::constants::{
STATE, VALUE_DECIMALS, TOKEN_ID_1, INVALID_TOKEN, SLOT_1, VALUE, ZERO, OWNER, OPERATOR, SOMEONE,
ANYONE
STATE, VALUE_DECIMALS, TOKEN_ID_1, SLOT_1, VALUE, ZERO, OWNER
};
use debug::PrintTrait;

// Settings

Expand Down
126 changes: 126 additions & 0 deletions src/tests/unit/test_slot_approvable.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Core imports

use debug::PrintTrait;

// Starknet imports

use starknet::testing::set_caller_address;

// External imports

use openzeppelin::token::erc721::erc721::ERC721;

// Local imports

use cairo_erc_3525::module::ERC3525;
use cairo_erc_3525::extensions::slotapprovable::module::ERC3525SlotApprovable;
use cairo_erc_3525::tests::unit::constants::{
STATE, STATE_SLOT_APPROVABLE, VALUE_DECIMALS, TOKEN_ID_1, TOKEN_ID_2, SLOT_1, SLOT_2, VALUE,
ZERO, OWNER, OPERATOR, SOMEONE
};

// Settings

fn setup() -> (ERC3525::ContractState, ERC3525SlotApprovable::ContractState) {
let mut state = STATE();
ERC3525::InternalImpl::initializer(ref state, VALUE_DECIMALS);
let mut state_slot_approvable = STATE_SLOT_APPROVABLE();
ERC3525SlotApprovable::InternalImpl::initializer(ref state_slot_approvable);
(state, state_slot_approvable)
}

// Tests approvals

#[test]
#[available_gas(20000000)]
fn test_slot_approvable_owner_can_approve_slot() {
let (mut state, mut state_slot_approvable) = setup();
set_caller_address(OWNER());
ERC3525SlotApprovable::ERC3525SlotApprovableImpl::set_approval_for_slot(
ref state_slot_approvable, OWNER(), SLOT_1, OPERATOR(), true
);
}

#[test]
#[available_gas(20000000)]
fn test_slot_approvable_operator_can_approve_value() {
let (mut state, mut state_slot_approvable) = setup();
set_caller_address(OWNER());
ERC3525::InternalImpl::_mint(ref state, OWNER(), TOKEN_ID_1, SLOT_1, VALUE);
ERC3525SlotApprovable::ERC3525SlotApprovableImpl::set_approval_for_slot(
ref state_slot_approvable, OWNER(), SLOT_1, OPERATOR(), true
);
set_caller_address(OPERATOR());
ERC3525SlotApprovable::ExternalImpl::approve_value(
ref state_slot_approvable, TOKEN_ID_1, OPERATOR(), VALUE
);
}

#[test]
#[available_gas(20000000)]
#[should_panic(expected: ('ERC3525: caller not allowed',))]
fn test_slot_approvable_operator_cannot_approve_any_token() {
let (mut state, mut state_slot_approvable) = setup();
set_caller_address(OWNER());
ERC3525::InternalImpl::_mint(ref state, OWNER(), TOKEN_ID_1, SLOT_1, VALUE);
ERC3525SlotApprovable::ERC3525SlotApprovableImpl::set_approval_for_slot(
ref state_slot_approvable, OWNER(), SLOT_2, OPERATOR(), true
);
set_caller_address(OPERATOR());
ERC3525SlotApprovable::ExternalImpl::approve_value(
ref state_slot_approvable, TOKEN_ID_1, OPERATOR(), VALUE
);
}

#[test]
#[available_gas(20000000)]
#[should_panic(expected: ('ERC3525: insufficient allowance',))]
fn test_slot_approvable_operator_cannot_transfer_anyones_value() {
let (mut state, mut state_slot_approvable) = setup();
set_caller_address(OWNER());
ERC3525::InternalImpl::_mint(ref state, OWNER(), TOKEN_ID_1, SLOT_1, VALUE);
ERC3525::InternalImpl::_mint(ref state, SOMEONE(), TOKEN_ID_2, SLOT_1, VALUE);
ERC3525SlotApprovable::ERC3525SlotApprovableImpl::set_approval_for_slot(
ref state_slot_approvable, OWNER(), SLOT_1, OPERATOR(), true
);
set_caller_address(OPERATOR());
ERC3525SlotApprovable::ExternalImpl::transfer_value_from(
ref state_slot_approvable, TOKEN_ID_2, 0, OPERATOR(), VALUE
);
}

#[test]
#[available_gas(20000000)]
#[should_panic(expected: ('ERC3525: slot mismatch',))]
fn test_slot_approvable_operator_transfer_value_revert_slot_mismatch() {
let (mut state, mut state_slot_approvable) = setup();
set_caller_address(OWNER());
ERC3525::InternalImpl::_mint(ref state, OWNER(), TOKEN_ID_1, SLOT_1, VALUE);
ERC3525::InternalImpl::_mint(ref state, SOMEONE(), TOKEN_ID_2, SLOT_2, VALUE);
ERC3525SlotApprovable::ERC3525SlotApprovableImpl::set_approval_for_slot(
ref state_slot_approvable, OWNER(), SLOT_1, OPERATOR(), true
);
set_caller_address(OPERATOR());
ERC3525SlotApprovable::ExternalImpl::transfer_value_from(
ref state_slot_approvable, TOKEN_ID_1, TOKEN_ID_2, ZERO(), VALUE
);
}

#[test]
#[available_gas(20000000)]
#[should_panic(expected: ('ERC3525: caller not allowed',))]
fn test_slot_approvable_revoked_slot_operator_cannot_approve() {
let (mut state, mut state_slot_approvable) = setup();
set_caller_address(OWNER());
ERC3525::InternalImpl::_mint(ref state, OWNER(), TOKEN_ID_1, SLOT_1, VALUE);
ERC3525SlotApprovable::ERC3525SlotApprovableImpl::set_approval_for_slot(
ref state_slot_approvable, OWNER(), SLOT_1, OPERATOR(), true
);
ERC3525SlotApprovable::ERC3525SlotApprovableImpl::set_approval_for_slot(
ref state_slot_approvable, OWNER(), SLOT_1, OPERATOR(), false
);
set_caller_address(OPERATOR());
ERC3525SlotApprovable::ExternalImpl::approve_value(
ref state_slot_approvable, TOKEN_ID_1, OPERATOR(), VALUE
);
}
Loading

0 comments on commit 86562a1

Please sign in to comment.