diff --git a/Scarb.toml b/Scarb.toml index dda5551..105632e 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -6,14 +6,14 @@ edition = "2023_11" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html [dependencies] -starknet = "^2.8.4" +starknet = "^2.8.0" [dev-dependencies] snforge_std = { git = "https://github.com/foundry-rs/starknet-foundry", tag = "v0.31.0" } -assert_macros = "2.8.4" +assert_macros = "2.8.0" [[target.starknet-contract]] sierra = true [scripts] -test = "snforge test" +test = "snforge test" \ No newline at end of file diff --git a/src/division.cairo b/src/division.cairo new file mode 100644 index 0000000..f293d58 --- /dev/null +++ b/src/division.cairo @@ -0,0 +1,3 @@ +pub fn div(x: i8, y: i8) -> i8 { + x / y +} \ No newline at end of file diff --git a/src/errors.cairo b/src/errors.cairo index 94f2680..0eda72a 100644 --- a/src/errors.cairo +++ b/src/errors.cairo @@ -5,4 +5,8 @@ pub mod Errors { pub const SAME_ADDRESS: felt252 = 'CANNOT BE SAME ADDRESS!'; pub const ZERO_VALUE: felt252 = 'CANNOT BE ZERO_VALUE!'; pub const STUDENT_NOT_REGISTERED: felt252 = 'STUDENT NOT REGISTERED!'; + pub const AGE_ZERO: felt252 = 'AGE CANNOT BE ZERO!'; + pub const ADMIN_CANNOT_BE_STUDENT: felt252 = 'ADMIN CANNOT BE STUDENT'; + pub const STUDENT_ALREADY_REGISTERED: felt252 = 'STUDENT ALREADY REGISTERED'; + } diff --git a/src/lib.cairo b/src/lib.cairo index 8ae7bd1..8140130 100644 --- a/src/lib.cairo +++ b/src/lib.cairo @@ -6,4 +6,4 @@ pub mod errors; pub mod accounts; pub mod ownable_counter; -pub mod addition; \ No newline at end of file +pub mod addition; diff --git a/src/multiplication.cairo b/src/multiplication.cairo new file mode 100644 index 0000000..3477169 --- /dev/null +++ b/src/multiplication.cairo @@ -0,0 +1,3 @@ +pub fn mult(x: u8, y: u8) -> u8 { + x * y +} \ No newline at end of file diff --git a/src/student_registry.cairo b/src/student_registry.cairo index 10b0422..fb5e829 100644 --- a/src/student_registry.cairo +++ b/src/student_registry.cairo @@ -60,7 +60,14 @@ pub mod StudentRegistry { ) -> bool { // validation to check if student account is valid address and not a 0 address assert(!self.is_zero_address(_account), Errors::ZERO_ADDRESS); - assert(_age > 0, 'age cannot be 0'); + assert(_age > 0, Errors::AGE_ZERO); + // validation to check that the admin is not registering as a student + let current_admin = self.admin.read(); + assert(_account != current_admin, Errors::ADMIN_CANNOT_BE_STUDENT); + + // check if the student is already registered + let existing_student: Student = self.students_map.entry(_account).read(); + assert(existing_student.age == 0, Errors::STUDENT_ALREADY_REGISTERED); let student = Student { name: _name, account: _account, age: _age, xp: _xp, is_active: _is_active }; diff --git a/src/subtraction.cairo b/src/subtraction.cairo new file mode 100644 index 0000000..31a1f42 --- /dev/null +++ b/src/subtraction.cairo @@ -0,0 +1,5 @@ + +// / * - +pub fn sub(x: u8, y: u8) -> u8 { + x - y +} \ No newline at end of file diff --git a/src/sum.cairo b/src/sum.cairo new file mode 100644 index 0000000..d01947e --- /dev/null +++ b/src/sum.cairo @@ -0,0 +1,3 @@ +pub fn sum_u8(x: u8, y: u8) -> u8 { + x + y +} \ No newline at end of file diff --git a/tests/test_ownable.cairo b/tests/test_ownable.cairo new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_student_registry.cairo b/tests/test_student_registry.cairo index 6bbd26c..c83ad85 100644 --- a/tests/test_student_registry.cairo +++ b/tests/test_student_registry.cairo @@ -1 +1,263 @@ -// Write test for the StudentRegistry contract here +// // Write test for the StudentRegistry contract here +use snforge_std::{declare, ContractClassTrait, DeclareResultTrait}; +use starknet::{ContractAddress}; +use cairo_bootcamp_3::student_registry::{IStudentRegistryDispatcher, IStudentRegistryDispatcherTrait}; + +pub mod Accounts { + use starknet::ContractAddress; + use core::traits::TryInto; + + pub fn zero() -> ContractAddress { + 0x0000000000000000000000000000000000000000.try_into().unwrap() + } + + pub fn admin() -> ContractAddress { + 'admin'.try_into().unwrap() + } + + pub fn student1() -> ContractAddress { + 'student1'.try_into().unwrap() + } + + pub fn student2() -> ContractAddress { + 'student2'.try_into().unwrap() + } + +} + +fn deploy(name: ByteArray) -> ContractAddress { + let contract = declare(name).unwrap().contract_class(); + let constructor_args = array![Accounts::admin().into()]; + let (contract_address, _) = contract.deploy(@constructor_args).unwrap(); + contract_address +} + +#[test] +fn test_can_add_student_correctly() { + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let result0 = contract_dispatcher.add_student( + 'Alice', + Accounts::student1(), + 12, + 30, + true, + ); + assert(result0 == true, 'Student added successfully'); +} + +#[test] +#[should_panic(expected: ('ZERO ADDRESS!',))] +fn test_address_can_not_be_zerro() { + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let result0 = contract_dispatcher.add_student( + 'Alice', + Accounts::zero(), + 12, + 30, + true, + ); + assert(result0 == false, 'Student address is zero'); +} + +#[test] +#[should_panic(expected: ('ADMIN CANNOT BE STUDENT',))] +fn test_cannot_add_admin() { + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let result0 = contract_dispatcher.add_student( + 'Alice', + Accounts::admin(), + 12, + 30, + true, + ); + assert(result0 == false, 'Admin cannot be student'); +} + +#[test] +#[should_panic(expected: ('STUDENT ALREADY REGISTERED',))] +fn test_cannot_add_registered_student() { + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let result0 = contract_dispatcher.add_student( + 'Alice', + Accounts::student1(), + 12, + 30, + true, + ); + assert(result0 == true, 'Student added successfully'); + + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let result0 = contract_dispatcher.add_student( + 'Alice', + Accounts::student1(), + 12, + 30, + true, + ); + assert(result0 == false, 'STUDENT ALREADY REGISTERED'); +} + +#[test] +#[should_panic(expected: ('AGE CANNOT BE ZERO!',))] +fn test_age_can_not_be_zero() { + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let result0 = contract_dispatcher.add_student( + 'Alice', + Accounts::student1(), + 0, + 30, + true, + ); + assert(result0 == false, 'Student added unsuccessfully'); +} + +#[test] +fn test_can_get_student() { + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let result0 = contract_dispatcher.add_student( + 'Alice', + Accounts::student1(), + 12, + 30, + true, + ); + + assert(result0 == true, 'Student added successfully'); + + let (name, account, age, xp, is_active) = contract_dispatcher.get_student(Accounts::student1()); + + assert(name == 'Alice', 'Name should match'); + assert(account == Accounts::student1(), 'Account should match'); + assert(age == 12, 'Age should match'); + assert(xp == 30, 'XP should match'); + assert(is_active == true, 'Is active should match'); +} + +#[test] +#[should_panic(expected: ('ZERO ADDRESS!',))] +fn test_can_not_get_address_zerro() { + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + contract_dispatcher.get_student(Accounts::zero()); +} + +#[test] +fn test_can_delete_student() { + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let result0 = contract_dispatcher.add_student( + 'Alice', + Accounts::student1(), + 12, + 30, + true, + ); + assert(result0 == true, 'Student added successfully'); + + let res = contract_dispatcher.delete_student(Accounts::student1()); + assert(res == true, 'Student deleted successfully'); + + let (name, account, age, xp, is_active) = contract_dispatcher.get_student(Accounts::student1()); + + // Check if the student is effectively deleted + assert(name == '', 'Name should be empty'); + assert(account == Accounts::zero(), 'Account should be zero address'); + assert(age == 0, 'Age should be 0'); + assert(xp == 0, 'XP should be 0'); + assert(!is_active, 'Is active should be false'); +} + +#[test] +fn test_update_student() { + + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let account1 = Accounts::student1(); + + let result0 = contract_dispatcher.add_student( + 'Alice', + account1, + 12, + 30, + true, + ); + assert(result0 == true, 'Student added successfully'); + + let result1 = contract_dispatcher.update_student( + 'Bob', + Accounts::student1(), + 14, + 25, + false, + ); + + assert(result1 == true, 'Student updated successfully'); + + let (name, account, age, xp, is_active) = contract_dispatcher.get_student(Accounts::student1()); + + // Check if the student is effectively deleted + assert(name == 'Bob', 'Name should be empty'); + assert(account == Accounts::student1(), 'Account should be zero address'); + assert(age == 14, 'Age should be 0'); + assert(xp == 25, 'XP should be 0'); + assert(is_active == false, 'Is active should be false'); +} + +#[test] +#[should_panic(expected: ('ZERO ADDRESS!',))] +fn test_can_not_update_address_zero() { + let contract_address = deploy("StudentRegistry"); + + let contract_dispatcher = IStudentRegistryDispatcher { contract_address }; + + let account1 = Accounts::student1(); + + let result0 = contract_dispatcher.add_student( + 'Alice', + account1, + 12, + 30, + true, + ); + assert(result0 == true, 'Student added successfully'); + + let result1 = contract_dispatcher.update_student( + 'Bob', + Accounts::zero(), + 14, + 25, + true, + ); + + assert(result1 == false, 'Student updated unsuccessfully'); +} + + +