From 807e2b18df4d14b9013043b57f1ab15d2267cb79 Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Fri, 13 Sep 2024 12:53:02 -0400 Subject: [PATCH] finish tests, fix transfer to reset price --- steps/30/src/tests.rs | 11 +- steps/31/src/tests.rs | 11 +- steps/32/src/tests.rs | 11 +- steps/33/src/tests.rs | 11 +- steps/34/src/tests.rs | 11 +- steps/35/src/tests.rs | 11 +- steps/36/src/tests.rs | 11 +- steps/37/src/tests.rs | 11 +- steps/38/src/tests.rs | 11 +- steps/39/src/tests.rs | 11 +- steps/40/src/tests.rs | 11 +- steps/41/src/tests.rs | 11 +- steps/42/src/tests.rs | 11 +- steps/43/src/tests.rs | 22 ++-- steps/44/README.md | 11 ++ steps/44/src/impls.rs | 1 + steps/44/src/tests.rs | 192 +++++++++++++++++++++++++++ steps/45/src/impls.rs | 1 + steps/45/src/tests.rs | 200 +++++++++++++++++++++++++++++ steps/46/src/impls.rs | 1 + steps/46/src/tests.rs | 200 +++++++++++++++++++++++++++++ steps/47/src/impls.rs | 1 + steps/47/src/tests.rs | 215 +++++++++++++++++++++++++++++++ steps/48/src/impls.rs | 1 + steps/48/src/tests.rs | 215 +++++++++++++++++++++++++++++++ steps/49/src/impls.rs | 1 + steps/49/src/tests.rs | 228 +++++++++++++++++++++++++++++++++ steps/50/src/impls.rs | 1 + steps/50/src/tests.rs | 228 +++++++++++++++++++++++++++++++++ steps/51/src/impls.rs | 1 + steps/51/src/tests.rs | 245 +++++++++++++++++++++++++++++++++++ steps/52/src/impls.rs | 1 + steps/52/src/tests.rs | 245 +++++++++++++++++++++++++++++++++++ steps/53/src/impls.rs | 1 + steps/53/src/tests.rs | 292 ++++++++++++++++++++++++++++++++++++++++++ 35 files changed, 2320 insertions(+), 126 deletions(-) diff --git a/steps/30/src/tests.rs b/steps/30/src/tests.rs index b8635457..f4166ad2 100644 --- a/steps/30/src/tests.rs +++ b/steps/30/src/tests.rs @@ -29,8 +29,6 @@ construct_runtime! { } } -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -155,18 +153,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/31/src/tests.rs b/steps/31/src/tests.rs index b8635457..f4166ad2 100644 --- a/steps/31/src/tests.rs +++ b/steps/31/src/tests.rs @@ -29,8 +29,6 @@ construct_runtime! { } } -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -155,18 +153,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/32/src/tests.rs b/steps/32/src/tests.rs index 042bfbda..f3681f01 100644 --- a/steps/32/src/tests.rs +++ b/steps/32/src/tests.rs @@ -29,8 +29,6 @@ construct_runtime! { } } -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -155,18 +153,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/33/src/tests.rs b/steps/33/src/tests.rs index 042bfbda..f3681f01 100644 --- a/steps/33/src/tests.rs +++ b/steps/33/src/tests.rs @@ -29,8 +29,6 @@ construct_runtime! { } } -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -155,18 +153,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/34/src/tests.rs b/steps/34/src/tests.rs index 6fa89b88..09d0ac97 100644 --- a/steps/34/src/tests.rs +++ b/steps/34/src/tests.rs @@ -29,8 +29,6 @@ construct_runtime! { } } -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -155,18 +153,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/35/src/tests.rs b/steps/35/src/tests.rs index 6fa89b88..09d0ac97 100644 --- a/steps/35/src/tests.rs +++ b/steps/35/src/tests.rs @@ -29,8 +29,6 @@ construct_runtime! { } } -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -155,18 +153,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/36/src/tests.rs b/steps/36/src/tests.rs index 00fd57f7..61a38e41 100644 --- a/steps/36/src/tests.rs +++ b/steps/36/src/tests.rs @@ -29,8 +29,6 @@ construct_runtime! { } } -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -155,18 +153,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/37/src/tests.rs b/steps/37/src/tests.rs index 00fd57f7..61a38e41 100644 --- a/steps/37/src/tests.rs +++ b/steps/37/src/tests.rs @@ -29,8 +29,6 @@ construct_runtime! { } } -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -155,18 +153,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/38/src/tests.rs b/steps/38/src/tests.rs index 00fd57f7..61a38e41 100644 --- a/steps/38/src/tests.rs +++ b/steps/38/src/tests.rs @@ -29,8 +29,6 @@ construct_runtime! { } } -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; - #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -155,18 +153,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/39/src/tests.rs b/steps/39/src/tests.rs index 50e01347..c1ea5ea6 100644 --- a/steps/39/src/tests.rs +++ b/steps/39/src/tests.rs @@ -28,8 +28,6 @@ construct_runtime! { PalletKitties: pallet_kitties, } } - -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; const ALICE: u64 = 1; const BOB: u64 = 2; @@ -157,18 +155,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/40/src/tests.rs b/steps/40/src/tests.rs index 50e01347..c1ea5ea6 100644 --- a/steps/40/src/tests.rs +++ b/steps/40/src/tests.rs @@ -28,8 +28,6 @@ construct_runtime! { PalletKitties: pallet_kitties, } } - -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; const ALICE: u64 = 1; const BOB: u64 = 2; @@ -157,18 +155,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/41/src/tests.rs b/steps/41/src/tests.rs index 75ca56e4..222a831b 100644 --- a/steps/41/src/tests.rs +++ b/steps/41/src/tests.rs @@ -28,8 +28,6 @@ construct_runtime! { PalletKitties: pallet_kitties, } } - -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; const ALICE: u64 = 1; const BOB: u64 = 2; @@ -157,18 +155,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/42/src/tests.rs b/steps/42/src/tests.rs index 75ca56e4..222a831b 100644 --- a/steps/42/src/tests.rs +++ b/steps/42/src/tests.rs @@ -28,8 +28,6 @@ construct_runtime! { PalletKitties: pallet_kitties, } } - -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; const ALICE: u64 = 1; const BOB: u64 = 2; @@ -157,18 +155,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } diff --git a/steps/43/src/tests.rs b/steps/43/src/tests.rs index 7314e76e..57510b3d 100644 --- a/steps/43/src/tests.rs +++ b/steps/43/src/tests.rs @@ -28,8 +28,6 @@ construct_runtime! { PalletKitties: pallet_kitties, } } - -const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1 }; const ALICE: u64 = 1; const BOB: u64 = 2; @@ -158,18 +156,13 @@ fn cannot_mint_duplicate_kitty() { }) } -#[test] -fn kitty_struct_created_correctly() { - let _kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; -} - #[test] fn kitty_struct_has_expected_traits() { new_test_ext().execute_with(|| { - let kitty = Kitty:: { dna: [0u8; 32], owner: 1 }; + let kitty = DEFAULT_KITTY; let bytes = kitty.encode(); let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); - assert_eq!(Kitty::::max_encoded_len(), 40); + assert!(Kitty::::max_encoded_len() > 0); let _info = Kitty::::type_info(); }) } @@ -273,3 +266,14 @@ fn transfer_logic_works() { assert_eq!(kitty.owner, BOB); }); } + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} diff --git a/steps/44/README.md b/steps/44/README.md index dc9f337d..18385623 100644 --- a/steps/44/README.md +++ b/steps/44/README.md @@ -130,6 +130,17 @@ We are going to use `BalanceOf` in the `Kitty` struct to keep track if it is For this we can use an `Option>`, where `None` denotes that a kitty is not for sale, and `Some(price)` denotes the kitty is for sale at some `price`. +### Resetting the Price Field + +In this step, we are introducing a new `price` field to the `Kitty` struct, and we must consider how that might affect existing logic in our Pallet. + +The price is something that should only be set by the owner of the kitty, and describes what the current owner would want to sell the kitty for. + +However, when a kitty is transferred to a new owner, that new owner may not agree with the existing price or want to sell the kitty at all! + +Thus, whenever we transfer the kitty, we will want to reset the `price` to `None` to make sure it is not immediately for sale. +The new owner will be able to set the new price if they want to sell their new kitty. + ## Your Turn Now that you know how to create and use the `BalanceOf` type, add the type alias to your Pallet as shown in the template. diff --git a/steps/44/src/impls.rs b/steps/44/src/impls.rs index 6ae2e34b..c569f2af 100644 --- a/steps/44/src/impls.rs +++ b/steps/44/src/impls.rs @@ -41,6 +41,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + /* 🚧 TODO 🚧: Set the `kitty.price` to `None` for the new owner. */ let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/44/src/tests.rs b/steps/44/src/tests.rs index 2969c31c..57510b3d 100644 --- a/steps/44/src/tests.rs +++ b/steps/44/src/tests.rs @@ -28,6 +28,8 @@ construct_runtime! { PalletKitties: pallet_kitties, } } +const ALICE: u64 = 1; +const BOB: u64 = 2; #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { @@ -85,3 +87,193 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} diff --git a/steps/45/src/impls.rs b/steps/45/src/impls.rs index 5ec04ae9..bee571d1 100644 --- a/steps/45/src/impls.rs +++ b/steps/45/src/impls.rs @@ -40,6 +40,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + kitty.price = None; let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/45/src/tests.rs b/steps/45/src/tests.rs index 2969c31c..2a02d4e7 100644 --- a/steps/45/src/tests.rs +++ b/steps/45/src/tests.rs @@ -29,6 +29,10 @@ construct_runtime! { } } +const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1, price: None }; +const ALICE: u64 = 1; +const BOB: u64 = 2; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -85,3 +89,199 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} + +#[test] +fn balance_of_type_works() { + // Inside our tests, the `BalanceOf` type has a concrete type of `u64`. + let _example_balance: BalanceOf = 1337u64; +} diff --git a/steps/46/src/impls.rs b/steps/46/src/impls.rs index 686cb0ab..e7fa6b60 100644 --- a/steps/46/src/impls.rs +++ b/steps/46/src/impls.rs @@ -40,6 +40,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + kitty.price = None; let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/46/src/tests.rs b/steps/46/src/tests.rs index 2969c31c..2a02d4e7 100644 --- a/steps/46/src/tests.rs +++ b/steps/46/src/tests.rs @@ -29,6 +29,10 @@ construct_runtime! { } } +const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1, price: None }; +const ALICE: u64 = 1; +const BOB: u64 = 2; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -85,3 +89,199 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} + +#[test] +fn balance_of_type_works() { + // Inside our tests, the `BalanceOf` type has a concrete type of `u64`. + let _example_balance: BalanceOf = 1337u64; +} diff --git a/steps/47/src/impls.rs b/steps/47/src/impls.rs index f1e996c7..53fb204a 100644 --- a/steps/47/src/impls.rs +++ b/steps/47/src/impls.rs @@ -40,6 +40,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + kitty.price = None; let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/47/src/tests.rs b/steps/47/src/tests.rs index 2969c31c..5bb638fa 100644 --- a/steps/47/src/tests.rs +++ b/steps/47/src/tests.rs @@ -29,6 +29,10 @@ construct_runtime! { } } +const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1, price: None }; +const ALICE: u64 = 1; +const BOB: u64 = 2; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -85,3 +89,214 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} + +#[test] +fn balance_of_type_works() { + // Inside our tests, the `BalanceOf` type has a concrete type of `u64`. + let _example_balance: BalanceOf = 1337u64; +} + +#[test] +fn set_price_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::PriceSet { owner: ALICE, kitty_id, new_price: Some(1337) }.into(), + ); + }) +} diff --git a/steps/48/src/impls.rs b/steps/48/src/impls.rs index 4cbc8abc..c486f9ed 100644 --- a/steps/48/src/impls.rs +++ b/steps/48/src/impls.rs @@ -40,6 +40,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + kitty.price = None; let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/48/src/tests.rs b/steps/48/src/tests.rs index 2969c31c..5bb638fa 100644 --- a/steps/48/src/tests.rs +++ b/steps/48/src/tests.rs @@ -29,6 +29,10 @@ construct_runtime! { } } +const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1, price: None }; +const ALICE: u64 = 1; +const BOB: u64 = 2; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -85,3 +89,214 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} + +#[test] +fn balance_of_type_works() { + // Inside our tests, the `BalanceOf` type has a concrete type of `u64`. + let _example_balance: BalanceOf = 1337u64; +} + +#[test] +fn set_price_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::PriceSet { owner: ALICE, kitty_id, new_price: Some(1337) }.into(), + ); + }) +} diff --git a/steps/49/src/impls.rs b/steps/49/src/impls.rs index d6c9f188..79ec6585 100644 --- a/steps/49/src/impls.rs +++ b/steps/49/src/impls.rs @@ -40,6 +40,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + kitty.price = None; let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/49/src/tests.rs b/steps/49/src/tests.rs index 2969c31c..a1e86a46 100644 --- a/steps/49/src/tests.rs +++ b/steps/49/src/tests.rs @@ -29,6 +29,10 @@ construct_runtime! { } } +const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1, price: None }; +const ALICE: u64 = 1; +const BOB: u64 = 2; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -85,3 +89,227 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} + +#[test] +fn balance_of_type_works() { + // Inside our tests, the `BalanceOf` type has a concrete type of `u64`. + let _example_balance: BalanceOf = 1337u64; +} + +#[test] +fn set_price_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::PriceSet { owner: ALICE, kitty_id, new_price: Some(1337) }.into(), + ); + }) +} + +#[test] +fn set_price_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.price, None); + let kitty_id = kitty.dna; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + let kitty = Kitties::::get(kitty_id).unwrap(); + assert_eq!(kitty.price, Some(1337)); + }) +} diff --git a/steps/50/src/impls.rs b/steps/50/src/impls.rs index 9fec611b..953fa5c2 100644 --- a/steps/50/src/impls.rs +++ b/steps/50/src/impls.rs @@ -40,6 +40,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + kitty.price = None; let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/50/src/tests.rs b/steps/50/src/tests.rs index 2969c31c..a1e86a46 100644 --- a/steps/50/src/tests.rs +++ b/steps/50/src/tests.rs @@ -29,6 +29,10 @@ construct_runtime! { } } +const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1, price: None }; +const ALICE: u64 = 1; +const BOB: u64 = 2; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -85,3 +89,227 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} + +#[test] +fn balance_of_type_works() { + // Inside our tests, the `BalanceOf` type has a concrete type of `u64`. + let _example_balance: BalanceOf = 1337u64; +} + +#[test] +fn set_price_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::PriceSet { owner: ALICE, kitty_id, new_price: Some(1337) }.into(), + ); + }) +} + +#[test] +fn set_price_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.price, None); + let kitty_id = kitty.dna; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + let kitty = Kitties::::get(kitty_id).unwrap(); + assert_eq!(kitty.price, Some(1337)); + }) +} diff --git a/steps/51/src/impls.rs b/steps/51/src/impls.rs index 889e7a2e..81f657e7 100644 --- a/steps/51/src/impls.rs +++ b/steps/51/src/impls.rs @@ -40,6 +40,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + kitty.price = None; let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/51/src/tests.rs b/steps/51/src/tests.rs index 2969c31c..03c3f44b 100644 --- a/steps/51/src/tests.rs +++ b/steps/51/src/tests.rs @@ -29,6 +29,10 @@ construct_runtime! { } } +const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1, price: None }; +const ALICE: u64 = 1; +const BOB: u64 = 2; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -85,3 +89,244 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} + +#[test] +fn balance_of_type_works() { + // Inside our tests, the `BalanceOf` type has a concrete type of `u64`. + let _example_balance: BalanceOf = 1337u64; +} + +#[test] +fn set_price_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::PriceSet { owner: ALICE, kitty_id, new_price: Some(1337) }.into(), + ); + }) +} + +#[test] +fn set_price_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.price, None); + let kitty_id = kitty.dna; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + let kitty = Kitties::::get(kitty_id).unwrap(); + assert_eq!(kitty.price, Some(1337)); + }) +} + +#[test] +fn do_buy_kitty_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + assert_ok!(Balances::mint_into(&BOB, 100_000)); + assert_ok!(PalletKitties::buy_kitty(RuntimeOrigin::signed(BOB), kitty_id, 1337)); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::Sold { buyer: BOB, kitty_id, price: 1337 }.into(), + ); + }) +} diff --git a/steps/52/src/impls.rs b/steps/52/src/impls.rs index 2bb33859..e9dca34a 100644 --- a/steps/52/src/impls.rs +++ b/steps/52/src/impls.rs @@ -41,6 +41,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + kitty.price = None; let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/52/src/tests.rs b/steps/52/src/tests.rs index 2969c31c..03c3f44b 100644 --- a/steps/52/src/tests.rs +++ b/steps/52/src/tests.rs @@ -29,6 +29,10 @@ construct_runtime! { } } +const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1, price: None }; +const ALICE: u64 = 1; +const BOB: u64 = 2; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -85,3 +89,244 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} + +#[test] +fn balance_of_type_works() { + // Inside our tests, the `BalanceOf` type has a concrete type of `u64`. + let _example_balance: BalanceOf = 1337u64; +} + +#[test] +fn set_price_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::PriceSet { owner: ALICE, kitty_id, new_price: Some(1337) }.into(), + ); + }) +} + +#[test] +fn set_price_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.price, None); + let kitty_id = kitty.dna; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + let kitty = Kitties::::get(kitty_id).unwrap(); + assert_eq!(kitty.price, Some(1337)); + }) +} + +#[test] +fn do_buy_kitty_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + assert_ok!(Balances::mint_into(&BOB, 100_000)); + assert_ok!(PalletKitties::buy_kitty(RuntimeOrigin::signed(BOB), kitty_id, 1337)); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::Sold { buyer: BOB, kitty_id, price: 1337 }.into(), + ); + }) +} diff --git a/steps/53/src/impls.rs b/steps/53/src/impls.rs index a266e73c..179c26e2 100644 --- a/steps/53/src/impls.rs +++ b/steps/53/src/impls.rs @@ -41,6 +41,7 @@ impl Pallet { let mut kitty = Kitties::::get(kitty_id).ok_or(Error::::NoKitty)?; ensure!(kitty.owner == from, Error::::NotOwner); kitty.owner = to.clone(); + kitty.price = None; let mut to_owned = KittiesOwned::::get(&to); to_owned.try_push(kitty_id).map_err(|_| Error::::TooManyOwned)?; diff --git a/steps/53/src/tests.rs b/steps/53/src/tests.rs index 2969c31c..fab1f489 100644 --- a/steps/53/src/tests.rs +++ b/steps/53/src/tests.rs @@ -29,6 +29,10 @@ construct_runtime! { } } +const DEFAULT_KITTY: Kitty = Kitty { dna: [0u8; 32], owner: 1, price: None }; +const ALICE: u64 = 1; +const BOB: u64 = 2; + #[derive_impl(frame_system::config_preludes::TestDefaultConfig)] impl frame_system::Config for TestRuntime { type Block = Block; @@ -85,3 +89,291 @@ fn create_kitty_emits_event() { System::assert_last_event(Event::::Created { owner: 1 }.into()); }) } + +#[test] +fn count_for_kitties_created_correctly() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // You can `set` the value using an `u32`. + CountForKitties::::set(1337u32); + // You can `put` the value directly with a `u32`. + CountForKitties::::put(1337u32); + }) +} + +#[test] +fn mint_increments_count_for_kitty() { + new_test_ext().execute_with(|| { + // Querying storage before anything is set will return `0`. + assert_eq!(CountForKitties::::get(), 0); + // Call `mint` to create a new kitty. + assert_ok!(PalletKitties::mint(1, [1u8; 32])); + // Now the storage should be `1` + assert_eq!(CountForKitties::::get(), 1); + // Let's call it two more times... + assert_ok!(PalletKitties::mint(2, [2u8; 32])); + assert_ok!(PalletKitties::mint(3, [3u8; 32])); + // Now the storage should be `3` + assert_eq!(CountForKitties::::get(), 3); + }) +} + +#[test] +fn mint_errors_when_overflow() { + new_test_ext().execute_with(|| { + // Set the count to the largest value possible. + CountForKitties::::set(u32::MAX); + // `create_kitty` should not succeed because of safe math. + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyKitties + ); + }) +} + +#[test] +fn kitties_map_created_correctly() { + new_test_ext().execute_with(|| { + let zero_key = [0u8; 32]; + assert_eq!(Kitties::::contains_key(zero_key), false); + Kitties::::insert(zero_key, DEFAULT_KITTY); + assert_eq!(Kitties::::contains_key(zero_key), true); + }) +} + +#[test] +fn create_kitty_adds_to_map() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_eq!(Kitties::::iter().count(), 1); + }) +} + +#[test] +fn cannot_mint_duplicate_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1, [0u8; 32])); + assert_noop!(PalletKitties::mint(2, [0u8; 32]), Error::::DuplicateKitty); + }) +} + +#[test] +fn kitty_struct_has_expected_traits() { + new_test_ext().execute_with(|| { + let kitty = DEFAULT_KITTY; + let bytes = kitty.encode(); + let _new_kitty = Kitty::::decode(&mut &bytes[..]).unwrap(); + assert!(Kitty::::max_encoded_len() > 0); + let _info = Kitty::::type_info(); + }) +} + +#[test] +fn mint_stores_owner_in_kitty() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::mint(1337, [42u8; 32])); + let kitty = Kitties::::get([42u8; 32]).unwrap(); + assert_eq!(kitty.owner, 1337); + assert_eq!(kitty.dna, [42u8; 32]); + }) +} + +#[test] +fn create_kitty_makes_unique_kitties() { + new_test_ext().execute_with(|| { + // Two calls to `create_kitty` should work. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(2))); + // And should result in two kitties in our system. + assert_eq!(CountForKitties::::get(), 2); + assert_eq!(Kitties::::iter().count(), 2); + }) +} + +#[test] +fn kitties_owned_created_correctly() { + new_test_ext().execute_with(|| { + // Initially users have no kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 0); + // Let's create two kitties. + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + // Now they should have two kitties owned. + assert_eq!(KittiesOwned::::get(1).len(), 2); + }); +} + +#[test] +fn cannot_own_too_many_kitties() { + new_test_ext().execute_with(|| { + // If your max owned is different than 100, you will need to update this. + for _ in 0..100 { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(1))); + } + assert_noop!( + PalletKitties::create_kitty(RuntimeOrigin::signed(1)), + Error::::TooManyOwned + ); + }); +} + +#[test] +fn transfer_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + // Create a kitty to transfer + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Get the kitty id. + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + System::assert_last_event( + Event::::Transferred { from: ALICE, to: BOB, kitty_id }.into(), + ); + }); +} + +#[test] +fn transfer_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + // Starting state looks good. + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + assert_eq!(KittiesOwned::::get(BOB), vec![]); + // Cannot transfer to yourself. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), ALICE, kitty_id), + Error::::TransferToSelf + ); + // Cannot transfer a non-existent kitty. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, [0u8; 32]), + Error::::NoKitty + ); + // Cannot transfer kitty you do not own. + assert_noop!( + PalletKitties::transfer(RuntimeOrigin::signed(BOB), ALICE, kitty_id), + Error::::NotOwner + ); + // Transfer should work when parameters are right. + assert_ok!(PalletKitties::transfer(RuntimeOrigin::signed(ALICE), BOB, kitty_id)); + // Storage is updated correctly. + assert_eq!(KittiesOwned::::get(ALICE), vec![]); + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.owner, BOB); + }); +} + +#[test] +fn native_balance_associated_type_works() { + new_test_ext().execute_with(|| { + assert_ok!(<::NativeBalance as Mutate<_>>::mint_into(&ALICE, 1337)); + assert_eq!( + <::NativeBalance as Inspect<_>>::total_balance(&ALICE), + 1337 + ); + }); +} + +#[test] +fn balance_of_type_works() { + // Inside our tests, the `BalanceOf` type has a concrete type of `u64`. + let _example_balance: BalanceOf = 1337u64; +} + +#[test] +fn set_price_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::PriceSet { owner: ALICE, kitty_id, new_price: Some(1337) }.into(), + ); + }) +} + +#[test] +fn set_price_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty = &Kitties::::iter_values().collect::>()[0]; + assert_eq!(kitty.price, None); + let kitty_id = kitty.dna; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + let kitty = Kitties::::get(kitty_id).unwrap(); + assert_eq!(kitty.price, Some(1337)); + }) +} + +#[test] +fn do_buy_kitty_emits_event() { + new_test_ext().execute_with(|| { + // We need to set block number to 1 to view events. + System::set_block_number(1); + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty_id = Kitties::::iter_keys().collect::>()[0]; + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + assert_ok!(Balances::mint_into(&BOB, 100_000)); + assert_ok!(PalletKitties::buy_kitty(RuntimeOrigin::signed(BOB), kitty_id, 1337)); + // Assert the last event by our blockchain is the `Created` event with the correct owner. + System::assert_last_event( + Event::::Sold { buyer: BOB, kitty_id, price: 1337 }.into(), + ); + }) +} + +#[test] +fn do_buy_kitty_logic_works() { + new_test_ext().execute_with(|| { + assert_ok!(PalletKitties::create_kitty(RuntimeOrigin::signed(ALICE))); + let kitty = &Kitties::::iter_values().collect::>()[0]; + let kitty_id = kitty.dna; + assert_eq!(kitty.owner, ALICE); + assert_eq!(KittiesOwned::::get(ALICE), vec![kitty_id]); + // Cannot buy kitty which does not exist. + assert_noop!( + PalletKitties::buy_kitty(RuntimeOrigin::signed(BOB), [0u8; 32], 1337), + Error::::NoKitty + ); + // Cannot buy kitty which is not for sale. + assert_noop!( + PalletKitties::buy_kitty(RuntimeOrigin::signed(BOB), kitty_id, 1337), + Error::::NotForSale + ); + assert_ok!(PalletKitties::set_price(RuntimeOrigin::signed(ALICE), kitty_id, Some(1337))); + // Cannot buy kitty for a lower price. + assert_noop!( + PalletKitties::buy_kitty(RuntimeOrigin::signed(BOB), kitty_id, 1336), + Error::::MaxPriceTooLow + ); + // Cannot buy kitty if you don't have the funds. + assert_noop!( + PalletKitties::buy_kitty(RuntimeOrigin::signed(BOB), kitty_id, 1337), + frame::arithmetic::ArithmeticError::Underflow + ); + // Cannot buy kitty if it would kill your account (i.e. set your balance to 0). + assert_ok!(Balances::mint_into(&BOB, 1337)); + assert!( + PalletKitties::buy_kitty(RuntimeOrigin::signed(BOB), kitty_id, 1337).is_err(), + // TODO: assert_noop on DispatchError::Token(TokenError::NotExpendable) + ); + // When everything is right, it works. + assert_ok!(Balances::mint_into(&BOB, 100_000)); + assert_ok!(PalletKitties::buy_kitty(RuntimeOrigin::signed(BOB), kitty_id, 1337)); + // State is updated correctly. + assert_eq!(KittiesOwned::::get(BOB), vec![kitty_id]); + let kitty = Kitties::::get(kitty_id).unwrap(); + assert_eq!(kitty.owner, BOB); + // Price is reset to `None`. + assert_eq!(kitty.price, None); + }) +}