diff --git a/pallets/reactions/tests/src/lib.rs b/pallets/reactions/tests/src/lib.rs index 71dc1931..503f1e9e 100644 --- a/pallets/reactions/tests/src/lib.rs +++ b/pallets/reactions/tests/src/lib.rs @@ -1,6 +1,4 @@ #[cfg(test)] mod mock; #[cfg(test)] -mod tests; -#[cfg(test)] -mod tests_utils; +mod tests; \ No newline at end of file diff --git a/pallets/reactions/tests/src/mock.rs b/pallets/reactions/tests/src/mock.rs index 5c070cec..93627a98 100644 --- a/pallets/reactions/tests/src/mock.rs +++ b/pallets/reactions/tests/src/mock.rs @@ -1,5 +1,6 @@ use frame_support::{pallet_prelude::ConstU32, parameter_types, traits::Everything}; use sp_core::H256; +use sp_io::TestExternalities; use sp_runtime::{ testing::Header, traits::{BlakeTwo256, IdentityLookup}, @@ -138,3 +139,16 @@ impl pallet_reactions::Config for Test { type Event = Event; type WeightInfo = (); } + +pub struct ExtBuilder; + +impl ExtBuilder { + pub fn build() -> TestExternalities { + let storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); + + let mut ext = TestExternalities::from(storage); + ext.execute_with(|| System::set_block_number(1)); + + ext + } +} diff --git a/pallets/reactions/tests/src/tests.rs b/pallets/reactions/tests/src/tests.rs index cec5ef42..03feb1b3 100644 --- a/pallets/reactions/tests/src/tests.rs +++ b/pallets/reactions/tests/src/tests.rs @@ -1,62 +1,156 @@ use frame_support::{assert_noop, assert_ok}; +use frame_system::pallet_prelude::OriginFor; -use pallet_posts::Error as PostsError; -use pallet_reactions::Error as ReactionsError; +use pallet_posts::{Error as PostsError, Post, PostById, PostExtension, PostUpdate}; +use pallet_reactions::{Error as ReactionsError, ReactionKind}; +use pallet_reactions::Event::{PostReactionCreated, PostReactionDeleted, PostReactionUpdated}; +use pallet_spaces::types::{Space, SpaceUpdate}; +use subsocial_support::{Content, SpaceId}; -use crate::{mock::*, tests_utils::*}; +use crate::mock::*; + +fn create_space(origin: OriginFor) -> Space { + let space_id = pallet_spaces::NextSpaceId::::get(); + + Spaces::create_space(origin.clone(), Content::None, None).expect("Spaces::create_space failed"); + + let space = pallet_spaces::SpaceById::::get(space_id).expect("Space not found"); + + space +} + +fn create_post_in_space(origin: OriginFor, space_id: SpaceId) -> Post { + let post_id = pallet_posts::NextPostId::::get(); + + Posts::create_post( + origin.clone().into(), + Some(space_id), + PostExtension::RegularPost, + Content::None, + ) + .expect("Posts::create_post failed"); + + let post = PostById::::get(post_id).expect("Post not found"); + + post +} + +fn create_post(origin: OriginFor) -> Post { + let space = create_space(origin.clone()); + + create_post_in_space(origin, space.id) +} + +fn create_hidden_post(origin: OriginFor) -> Post { + let post = create_post(origin.clone()); + + Posts::update_post( + origin.clone(), + post.id, + PostUpdate { space_id: None, content: None, hidden: true.into() }, + ) + .expect("Couldn't hide post"); + + post +} + +fn create_post_in_hidden_space(origin: OriginFor) -> Post { + let post = create_post(origin.clone()); + + Spaces::update_space( + origin.clone(), + post.space_id.unwrap(), + SpaceUpdate { content: None, hidden: true.into(), permissions: None }, + ) + .expect("Couldn't hide space"); + + post +} #[test] fn create_post_reaction_should_work_upvote() { - ExtBuilder::build_with_post().execute_with(|| { - assert_ok!(_create_post_reaction(Some(Origin::signed(ACCOUNT2)), None, None)); // ReactionId 1 by ACCOUNT2 which is permitted by default + ExtBuilder::build().execute_with(|| { + let account = 5; + let origin = Origin::signed(account); + let post = create_post(origin.clone()); + + let reaction_id = Reactions::next_reaction_id(); + assert_ok!(Reactions::create_post_reaction(origin, post.id, ReactionKind::Upvote)); + let next_reaction_id = Reactions::next_reaction_id(); // Check storages - assert_eq!(Reactions::reaction_ids_by_post_id(POST1), vec![REACTION1]); - assert_eq!(Reactions::next_reaction_id(), REACTION2); + assert_eq!(Reactions::reaction_ids_by_post_id(post.id), vec![reaction_id]); + assert_eq!(Reactions::next_reaction_id(), next_reaction_id); - // Check post reaction counters - let post = Posts::post_by_id(POST1).unwrap(); + System::assert_last_event(PostReactionCreated { + account, + post_id: post.id, + reaction_id, + reaction_kind: ReactionKind::Upvote, + }.into()); + + // Check post reaction counters again + let post = Posts::post_by_id(post.id).unwrap(); assert_eq!(post.upvotes_count, 1); assert_eq!(post.downvotes_count, 0); // Check whether data stored correctly - let reaction = Reactions::reaction_by_id(REACTION1).unwrap(); - assert_eq!(reaction.created.account, ACCOUNT2); - assert_eq!(reaction.kind, reaction_upvote()); + let reaction = Reactions::reaction_by_id(reaction_id).unwrap(); + assert_eq!(reaction.created.account, account); + assert_eq!(reaction.kind, ReactionKind::Upvote); }); } #[test] fn create_post_reaction_should_work_downvote() { - ExtBuilder::build_with_post().execute_with(|| { - assert_ok!(_create_post_reaction( - Some(Origin::signed(ACCOUNT2)), - None, - Some(reaction_downvote()) - )); // ReactionId 1 by ACCOUNT2 which is permitted by default + ExtBuilder::build().execute_with(|| { + let account = 5; + let origin = Origin::signed(account); + let post = create_post(origin.clone()); + + let reaction_id = Reactions::next_reaction_id(); + assert_ok!(Reactions::create_post_reaction(origin, post.id, ReactionKind::Downvote)); + let next_reaction_id = Reactions::next_reaction_id(); + + System::assert_last_event(PostReactionCreated { + account, + post_id: post.id, + reaction_id, + reaction_kind: ReactionKind::Downvote, + }.into()); // Check storages - assert_eq!(Reactions::reaction_ids_by_post_id(POST1), vec![REACTION1]); - assert_eq!(Reactions::next_reaction_id(), REACTION2); + assert_eq!(Reactions::reaction_ids_by_post_id(post.id), vec![reaction_id]); + assert_eq!(Reactions::next_reaction_id(), next_reaction_id); // Check post reaction counters - let post = Posts::post_by_id(POST1).unwrap(); + let post = Posts::post_by_id(post.id).unwrap(); assert_eq!(post.upvotes_count, 0); assert_eq!(post.downvotes_count, 1); // Check whether data stored correctly - let reaction = Reactions::reaction_by_id(REACTION1).unwrap(); - assert_eq!(reaction.created.account, ACCOUNT2); - assert_eq!(reaction.kind, reaction_downvote()); + let reaction = Reactions::reaction_by_id(reaction_id).unwrap(); + assert_eq!(reaction.created.account, account); + assert_eq!(reaction.kind, ReactionKind::Downvote); }); } #[test] fn create_post_reaction_should_fail_when_account_has_already_reacted() { - ExtBuilder::build_with_reacted_post_and_two_spaces().execute_with(|| { - // Try to catch an error creating reaction by the same account + ExtBuilder::build().execute_with(|| { + let account = 5; + let origin = Origin::signed(account); + let post = create_post(origin.clone()); + + assert_ok!(Reactions::create_post_reaction(origin.clone(), post.id, ReactionKind::Upvote)); + assert_noop!( - _create_default_post_reaction(), + Reactions::create_post_reaction(origin.clone(), post.id, ReactionKind::Downvote), + ReactionsError::::AccountAlreadyReacted + ); + + assert_noop!( + Reactions::create_post_reaction(origin.clone(), post.id, ReactionKind::Upvote), ReactionsError::::AccountAlreadyReacted ); }); @@ -65,19 +159,24 @@ fn create_post_reaction_should_fail_when_account_has_already_reacted() { #[test] fn create_post_reaction_should_fail_when_post_not_found() { ExtBuilder::build().execute_with(|| { - // Try to catch an error creating reaction by the same account - assert_noop!(_create_default_post_reaction(), PostsError::::PostNotFound); + let origin = Origin::signed(34); + let non_existing_post_id = 56; + + assert_noop!( + Reactions::create_post_reaction(origin, non_existing_post_id, ReactionKind::Upvote), + PostsError::::PostNotFound, + ); }); } #[test] fn create_post_reaction_should_fail_when_trying_to_react_in_hidden_space() { - ExtBuilder::build_with_post().execute_with(|| { - // Hide the space - assert_ok!(_update_space(None, None, Some(space_update(None, Some(true))))); + ExtBuilder::build().execute_with(|| { + let origin = Origin::signed(8); + let post = create_post_in_hidden_space(origin.clone()); assert_noop!( - _create_default_post_reaction(), + Reactions::create_post_reaction(origin, post.id, ReactionKind::Downvote), ReactionsError::::CannotReactWhenSpaceHidden ); }); @@ -85,13 +184,170 @@ fn create_post_reaction_should_fail_when_trying_to_react_in_hidden_space() { #[test] fn create_post_reaction_should_fail_when_trying_to_react_on_hidden_post() { - ExtBuilder::build_with_post().execute_with(|| { - // Hide the post - assert_ok!(_update_post(None, None, Some(post_update(None, None, Some(true))))); + ExtBuilder::build().execute_with(|| { + let origin = Origin::signed(2); + let post = create_hidden_post(origin.clone()); assert_noop!( - _create_default_post_reaction(), + Reactions::create_post_reaction(origin, post.id, ReactionKind::Upvote), ReactionsError::::CannotReactWhenPostHidden ); }); } + + +#[test] +fn update_post_reaction_should_fail_when_reaction_not_found() { + ExtBuilder::build().execute_with(|| { + let origin = Origin::signed(13); + let post = create_post(origin.clone()); + let non_existing_reaction_id = 56; + + assert_noop!( + Reactions::update_post_reaction(origin, post.id, non_existing_reaction_id, ReactionKind::Upvote), + ReactionsError::::ReactionByAccountNotFound + ); + }); +} + +#[test] +fn update_post_reaction_should_fail_when_not_reaction_owner() { + ExtBuilder::build().execute_with(|| { + let owner_origin = Origin::signed(13); + let not_owner_origin = Origin::signed(123); + + let post = create_post(owner_origin.clone()); + + let reaction_id = Reactions::next_reaction_id(); + assert_ok!(Reactions::create_post_reaction(owner_origin, post.id, ReactionKind::Upvote)); + + + assert_noop!( + Reactions::update_post_reaction(not_owner_origin, post.id, reaction_id, ReactionKind::Downvote), + ReactionsError::::ReactionByAccountNotFound + ); + }); +} + +#[test] +fn update_post_reaction_should_fail_when_setting_same_reaction() { + ExtBuilder::build().execute_with(|| { + let origin = Origin::signed(432); + + let post = create_post(origin.clone()); + let reaction_id = Reactions::next_reaction_id(); + assert_ok!(Reactions::create_post_reaction(origin.clone(), post.id, ReactionKind::Upvote)); + + + assert_noop!( + Reactions::update_post_reaction(origin, post.id, reaction_id, ReactionKind::Upvote), + ReactionsError::::SameReaction + ); + }); +} + +#[test] +fn update_post_reaction_should_work() { + ExtBuilder::build().execute_with(|| { + let account = 423; + let origin = Origin::signed(account); + + let post = create_post(origin.clone()); + let reaction_id = Reactions::next_reaction_id(); + assert_ok!(Reactions::create_post_reaction(origin.clone(), post.id, ReactionKind::Upvote)); + + let post = Posts::post_by_id(post.id).unwrap(); + assert_eq!(post.upvotes_count, 1); + assert_eq!(post.downvotes_count, 0); + + assert_ok!( + Reactions::update_post_reaction(origin, post.id, reaction_id, ReactionKind::Downvote), + ); + + System::assert_last_event(PostReactionUpdated { + account, + post_id: post.id, + reaction_id, + reaction_kind: ReactionKind::Downvote, + }.into()); + + let post = Posts::post_by_id(post.id).unwrap(); + assert_eq!(post.upvotes_count, 0); + assert_eq!(post.downvotes_count, 1); + + // Check whether data stored correctly + let reaction = Reactions::reaction_by_id(reaction_id).unwrap(); + assert_eq!(reaction.created.account, account); + assert_eq!(reaction.kind, ReactionKind::Downvote); + }); +} + +////// + + +#[test] +fn delete_post_reaction_should_fail_when_reaction_not_found() { + ExtBuilder::build().execute_with(|| { + let origin = Origin::signed(13); + let post = create_post(origin.clone()); + let non_existing_reaction_id = 56; + + assert_noop!( + Reactions::delete_post_reaction(origin, post.id, non_existing_reaction_id), + ReactionsError::::ReactionByAccountNotFound + ); + }); +} + +#[test] +fn delete_post_reaction_should_fail_when_not_reaction_owner() { + ExtBuilder::build().execute_with(|| { + let owner_origin = Origin::signed(13); + let not_owner_origin = Origin::signed(123); + + let post = create_post(owner_origin.clone()); + + let reaction_id = Reactions::next_reaction_id(); + assert_ok!(Reactions::create_post_reaction(owner_origin, post.id, ReactionKind::Upvote)); + + + assert_noop!( + Reactions::delete_post_reaction(not_owner_origin, post.id, reaction_id), + ReactionsError::::ReactionByAccountNotFound + ); + }); +} + +#[test] +fn delete_post_reaction_should_work() { + ExtBuilder::build().execute_with(|| { + let account = 423; + let origin = Origin::signed(account); + + let post = create_post(origin.clone()); + let reaction_id = Reactions::next_reaction_id(); + assert_ok!(Reactions::create_post_reaction(origin.clone(), post.id, ReactionKind::Upvote)); + + let post = Posts::post_by_id(post.id).unwrap(); + assert_eq!(post.upvotes_count, 1); + assert_eq!(post.downvotes_count, 0); + + assert_ok!( + Reactions::delete_post_reaction(origin, post.id, reaction_id), + ); + + System::assert_last_event(PostReactionDeleted { + account, + post_id: post.id, + reaction_id, + reaction_kind: ReactionKind::Upvote, + }.into()); + + let post = Posts::post_by_id(post.id).unwrap(); + assert_eq!(post.upvotes_count, 0); + assert_eq!(post.downvotes_count, 0); + + // Check whether data is deleted + assert!(Reactions::reaction_by_id(reaction_id).is_none()); + }); +} \ No newline at end of file diff --git a/pallets/reactions/tests/src/tests_utils.rs b/pallets/reactions/tests/src/tests_utils.rs deleted file mode 100644 index f294fe0c..00000000 --- a/pallets/reactions/tests/src/tests_utils.rs +++ /dev/null @@ -1,237 +0,0 @@ -use frame_support::{assert_ok, pallet_prelude::*}; -use sp_core::storage::Storage; -use sp_io::TestExternalities; - -use pallet_permissions::SpacePermissions; -use pallet_posts::{PostExtension, PostUpdate}; -use pallet_reactions::{ReactionId, ReactionKind}; -use pallet_spaces::types::SpaceUpdate; -use subsocial_support::{Content, PostId, SpaceId}; - -use crate::mock::*; - -////// Ext Builder - -pub struct ExtBuilder; - -impl ExtBuilder { - fn configure_storages(storage: &mut Storage) { - let mut accounts = Vec::new(); - for account in ACCOUNT1..=ACCOUNT3 { - accounts.push(account); - } - - let _ = pallet_balances::GenesisConfig:: { - balances: accounts.iter().cloned().map(|k| (k, 100)).collect(), - } - .assimilate_storage(storage); - } - - /// Default ext configuration with BlockNumber 1 - pub fn build() -> TestExternalities { - let mut storage = frame_system::GenesisConfig::default().build_storage::().unwrap(); - - Self::configure_storages(&mut storage); - - let mut ext = TestExternalities::from(storage); - ext.execute_with(|| System::set_block_number(1)); - - ext - } - - fn add_default_space() { - assert_ok!(_create_default_space()); - } - - fn add_another_space() { - assert_ok!(_create_space_with_content(another_space_content_ipfs())); - } - - fn add_post() { - Self::add_default_space(); - assert_ok!(_create_default_post()); - } - - /// Custom ext configuration with SpaceId 1, PostId 1 and BlockNumber 1 - pub fn build_with_post() -> TestExternalities { - let mut ext = Self::build(); - ext.execute_with(Self::add_post); - ext - } - - /// Custom ext configuration with SpaceId 1-2, PostId 1 where BlockNumber 1 - pub fn build_with_post_and_two_spaces() -> TestExternalities { - let mut ext = Self::build_with_post(); - ext.execute_with(Self::add_another_space); - ext - } - - /// Custom ext configuration with SpaceId 1, PostId 1 and ReactionId 1 (on post) where - /// BlockNumber is 1 - pub fn build_with_reacted_post_and_two_spaces() -> TestExternalities { - let mut ext = Self::build_with_post_and_two_spaces(); - ext.execute_with(|| { - assert_ok!(_create_default_post_reaction()); - }); - ext - } -} - -////// Consts - -pub(crate) const ACCOUNT1: AccountId = 1; -pub(crate) const ACCOUNT2: AccountId = 2; -pub(crate) const ACCOUNT3: AccountId = 3; - -pub(crate) const SPACE1: SpaceId = 1001; - -pub(crate) const POST1: PostId = 1; - -pub(crate) const REACTION1: ReactionId = 1; -pub(crate) const REACTION2: ReactionId = 2; - -///////////// Space Utils - -pub(crate) fn space_content_ipfs() -> Content { - Content::IPFS(b"bafyreib3mgbou4xln42qqcgj6qlt3cif35x4ribisxgq7unhpun525l54e".to_vec()) -} - -pub(crate) fn another_space_content_ipfs() -> Content { - Content::IPFS(b"bafyrelt3cif35x4ribisxgq7unhpun525l54eib3mgbou4xln42qqcgj6q".to_vec()) -} - -pub(crate) fn space_update(content: Option, hidden: Option) -> SpaceUpdate { - SpaceUpdate { content, hidden, permissions: None } -} - -pub(crate) fn _create_default_space() -> DispatchResult { - _create_space(None, None, None) -} - -pub(crate) fn _create_space( - origin: Option, - content: Option, - permissions: Option>, -) -> DispatchResult { - Spaces::create_space( - origin.unwrap_or_else(|| Origin::signed(ACCOUNT1)), - content.unwrap_or_else(space_content_ipfs), - permissions.unwrap_or_default(), - ) -} - -pub(crate) fn _create_space_with_content(content: Content) -> DispatchResult { - _create_space(None, Some(content), None) -} - -pub(crate) fn _update_space( - origin: Option, - space_id: Option, - update: Option, -) -> DispatchResult { - Spaces::update_space( - origin.unwrap_or_else(|| Origin::signed(ACCOUNT1)), - space_id.unwrap_or(SPACE1), - update.unwrap_or_else(|| space_update(None, None)), - ) -} - -///////////// Post Utils - -pub(crate) fn post_content_ipfs() -> Content { - Content::IPFS(b"bafyreidzue2dtxpj6n4x5mktrt7las5wz5diqma47zr25uau743dhe76we".to_vec()) -} - -pub(crate) fn post_update( - space_id: Option, - content: Option, - hidden: Option, -) -> PostUpdate { - PostUpdate { space_id, content, hidden } -} - -pub(crate) fn extension_regular_post() -> PostExtension { - PostExtension::RegularPost -} - -pub(crate) fn _create_default_post() -> DispatchResult { - _create_post(None, None, None, None) -} - -pub(crate) fn _create_post( - origin: Option, - space_id_opt: Option>, - extension: Option, - content: Option, -) -> DispatchResult { - Posts::create_post( - origin.unwrap_or_else(|| Origin::signed(ACCOUNT1)), - space_id_opt.unwrap_or(Some(SPACE1)), - extension.unwrap_or_else(extension_regular_post), - content.unwrap_or_else(post_content_ipfs), - ) -} - -pub(crate) fn _update_post( - origin: Option, - post_id: Option, - update: Option, -) -> DispatchResult { - Posts::update_post( - origin.unwrap_or_else(|| Origin::signed(ACCOUNT1)), - post_id.unwrap_or(POST1), - update.unwrap_or_else(|| post_update(None, None, None)), - ) -} - -//////// Reaction utils - -pub(crate) fn reaction_upvote() -> ReactionKind { - ReactionKind::Upvote -} - -pub(crate) fn reaction_downvote() -> ReactionKind { - ReactionKind::Downvote -} - -pub(crate) fn _create_default_post_reaction() -> DispatchResult { - _create_post_reaction(None, None, None) -} - -pub(crate) fn _create_post_reaction( - origin: Option, - post_id: Option, - kind: Option, -) -> DispatchResult { - Reactions::create_post_reaction( - origin.unwrap_or_else(|| Origin::signed(ACCOUNT1)), - post_id.unwrap_or(POST1), - kind.unwrap_or_else(reaction_upvote), - ) -} - -pub(crate) fn _update_post_reaction( - origin: Option, - post_id: Option, - reaction_id: ReactionId, - kind: Option, -) -> DispatchResult { - Reactions::update_post_reaction( - origin.unwrap_or_else(|| Origin::signed(ACCOUNT1)), - post_id.unwrap_or(POST1), - reaction_id, - kind.unwrap_or_else(reaction_upvote), - ) -} - -pub(crate) fn _delete_post_reaction( - origin: Option, - post_id: Option, - reaction_id: ReactionId, -) -> DispatchResult { - Reactions::delete_post_reaction( - origin.unwrap_or_else(|| Origin::signed(ACCOUNT1)), - post_id.unwrap_or(POST1), - reaction_id, - ) -}