123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- mod mock;
- use frame_support::dispatch::{DispatchError, DispatchResult};
- use frame_system::RawOrigin;
- use frame_system::{EventRecord, Phase};
- use crate::*;
- use mock::*;
- struct EventFixture;
- impl EventFixture {
- fn assert_events(expected_raw_events: Vec<RawEvent<u64, u64, u64>>) {
- let expected_events = expected_raw_events
- .iter()
- .map(|ev| EventRecord {
- phase: Phase::Initialization,
- event: TestEvent::discussion(ev.clone()),
- topics: vec![],
- })
- .collect::<Vec<EventRecord<_, _>>>();
- assert_eq!(System::events(), expected_events);
- }
- }
- struct TestPostEntry {
- pub post_id: u64,
- pub text: Vec<u8>,
- pub edition_number: u32,
- }
- struct TestThreadEntry {
- pub thread_id: u64,
- pub title: Vec<u8>,
- }
- fn assert_thread_content(thread_entry: TestThreadEntry, post_entries: Vec<TestPostEntry>) {
- assert!(<ThreadById<Test>>::contains_key(thread_entry.thread_id));
- let actual_thread = <ThreadById<Test>>::get(thread_entry.thread_id);
- let expected_thread = DiscussionThread {
- title: thread_entry.title,
- created_at: 0,
- author_id: 1,
- };
- assert_eq!(actual_thread, expected_thread);
- for post_entry in post_entries {
- let actual_post =
- <PostThreadIdByPostId<Test>>::get(thread_entry.thread_id, post_entry.post_id);
- let expected_post = DiscussionPost {
- text: post_entry.text,
- created_at: 0,
- updated_at: 0,
- author_id: 1,
- thread_id: thread_entry.thread_id,
- edition_number: post_entry.edition_number,
- };
- assert_eq!(actual_post, expected_post);
- }
- }
- struct DiscussionFixture {
- pub title: Vec<u8>,
- pub origin: RawOrigin<u64>,
- pub author_id: u64,
- }
- impl Default for DiscussionFixture {
- fn default() -> Self {
- DiscussionFixture {
- title: b"title".to_vec(),
- origin: RawOrigin::Signed(1),
- author_id: 1,
- }
- }
- }
- impl DiscussionFixture {
- fn with_title(self, title: Vec<u8>) -> Self {
- DiscussionFixture { title, ..self }
- }
- fn create_discussion_and_assert(&self, result: Result<u64, DispatchError>) -> Option<u64> {
- let create_discussion_result =
- Discussions::create_thread(self.author_id, self.title.clone());
- assert_eq!(create_discussion_result, result);
- create_discussion_result.ok()
- }
- }
- struct PostFixture {
- pub text: Vec<u8>,
- pub origin: RawOrigin<u64>,
- pub thread_id: u64,
- pub post_id: Option<u64>,
- pub author_id: u64,
- }
- impl PostFixture {
- fn default_for_thread(thread_id: u64) -> Self {
- PostFixture {
- text: b"text".to_vec(),
- author_id: 1,
- thread_id,
- origin: RawOrigin::Signed(1),
- post_id: None,
- }
- }
- fn with_text(self, text: Vec<u8>) -> Self {
- PostFixture { text, ..self }
- }
- fn with_origin(self, origin: RawOrigin<u64>) -> Self {
- PostFixture { origin, ..self }
- }
- fn with_author(self, author_id: u64) -> Self {
- PostFixture { author_id, ..self }
- }
- fn change_thread_id(self, thread_id: u64) -> Self {
- PostFixture { thread_id, ..self }
- }
- fn change_post_id(self, post_id: u64) -> Self {
- PostFixture {
- post_id: Some(post_id),
- ..self
- }
- }
- fn add_post_and_assert(&mut self, result: DispatchResult) -> Option<u64> {
- let add_post_result = Discussions::add_post(
- self.origin.clone().into(),
- self.author_id,
- self.thread_id,
- self.text.clone(),
- );
- assert_eq!(add_post_result, result);
- if result.is_ok() {
- self.post_id = Some(<PostCount>::get());
- }
- self.post_id
- }
- fn update_post_with_text_and_assert(&mut self, new_text: Vec<u8>, result: DispatchResult) {
- let add_post_result = Discussions::update_post(
- self.origin.clone().into(),
- self.author_id,
- self.thread_id,
- self.post_id.unwrap(),
- new_text,
- );
- assert_eq!(add_post_result, result);
- }
- fn update_post_and_assert(&mut self, result: DispatchResult) {
- self.update_post_with_text_and_assert(self.text.clone(), result);
- }
- }
- #[test]
- fn create_discussion_call_succeeds() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- discussion_fixture.create_discussion_and_assert(Ok(1));
- });
- }
- #[test]
- fn create_post_call_succeeds() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture = PostFixture::default_for_thread(thread_id);
- post_fixture.add_post_and_assert(Ok(()));
- });
- }
- #[test]
- fn update_post_call_succeeds() {
- initial_test_ext().execute_with(|| {
- /*
- Events are not emitted on block 0.
- So any dispatchable calls made during genesis block formation will have no events emitted.
- https://substrate.dev/recipes/2-appetizers/4-events.html
- */
- run_to_block(1);
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture = PostFixture::default_for_thread(thread_id);
- post_fixture.add_post_and_assert(Ok(()));
- post_fixture.update_post_and_assert(Ok(()));
- EventFixture::assert_events(vec![
- RawEvent::ThreadCreated(1, 1),
- RawEvent::PostCreated(1, 1),
- RawEvent::PostUpdated(1, 1),
- ]);
- });
- }
- #[test]
- fn update_post_call_fails_because_of_post_edition_limit() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture = PostFixture::default_for_thread(thread_id);
- post_fixture.add_post_and_assert(Ok(()));
- for _ in 1..6 {
- post_fixture.update_post_and_assert(Ok(()));
- }
- post_fixture.update_post_and_assert(Err(Error::<Test>::PostEditionNumberExceeded.into()));
- });
- }
- #[test]
- fn update_post_call_fails_because_of_the_wrong_author() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture = PostFixture::default_for_thread(thread_id);
- post_fixture.add_post_and_assert(Ok(()));
- post_fixture = post_fixture.with_author(2);
- post_fixture.update_post_and_assert(Err(DispatchError::Other("Invalid author")));
- post_fixture = post_fixture.with_origin(RawOrigin::None).with_author(2);
- post_fixture.update_post_and_assert(Err(Error::<Test>::NotAuthor.into()));
- });
- }
- #[test]
- fn thread_content_check_succeeded() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture1 = PostFixture::default_for_thread(thread_id);
- let post_id1 = post_fixture1.add_post_and_assert(Ok(())).unwrap();
- let mut post_fixture2 = PostFixture::default_for_thread(thread_id);
- let post_id2 = post_fixture2.add_post_and_assert(Ok(())).unwrap();
- post_fixture1.update_post_with_text_and_assert(b"new_text".to_vec(), Ok(()));
- assert_thread_content(
- TestThreadEntry {
- thread_id,
- title: b"title".to_vec(),
- },
- vec![
- TestPostEntry {
- post_id: post_id1,
- text: b"new_text".to_vec(),
- edition_number: 1,
- },
- TestPostEntry {
- post_id: post_id2,
- text: b"text".to_vec(),
- edition_number: 0,
- },
- ],
- );
- });
- }
- #[test]
- fn create_discussion_call_with_bad_title_failed() {
- initial_test_ext().execute_with(|| {
- let mut discussion_fixture = DiscussionFixture::default().with_title(Vec::new());
- discussion_fixture
- .create_discussion_and_assert(Err(Error::<Test>::EmptyTitleProvided.into()));
- discussion_fixture = DiscussionFixture::default().with_title([0; 201].to_vec());
- discussion_fixture.create_discussion_and_assert(Err(Error::<Test>::TitleIsTooLong.into()));
- });
- }
- #[test]
- fn add_post_call_with_invalid_thread_failed() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture = PostFixture::default_for_thread(2);
- post_fixture.add_post_and_assert(Err(Error::<Test>::ThreadDoesntExist.into()));
- });
- }
- #[test]
- fn update_post_call_with_invalid_post_failed() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture1 = PostFixture::default_for_thread(thread_id);
- post_fixture1.add_post_and_assert(Ok(())).unwrap();
- let mut post_fixture2 = post_fixture1.change_post_id(2);
- post_fixture2.update_post_and_assert(Err(Error::<Test>::PostDoesntExist.into()));
- });
- }
- #[test]
- fn update_post_call_with_invalid_thread_failed() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture1 = PostFixture::default_for_thread(thread_id);
- post_fixture1.add_post_and_assert(Ok(())).unwrap();
- let mut post_fixture2 = post_fixture1.change_thread_id(2);
- post_fixture2.update_post_and_assert(Err(Error::<Test>::ThreadDoesntExist.into()));
- });
- }
- #[test]
- fn add_post_call_with_invalid_text_failed() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture1 = PostFixture::default_for_thread(thread_id).with_text(Vec::new());
- post_fixture1.add_post_and_assert(Err(Error::<Test>::EmptyPostProvided.into()));
- let mut post_fixture2 =
- PostFixture::default_for_thread(thread_id).with_text([0; 2001].to_vec());
- post_fixture2.add_post_and_assert(Err(Error::<Test>::PostIsTooLong.into()));
- });
- }
- #[test]
- fn update_post_call_with_invalid_text_failed() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture1 = PostFixture::default_for_thread(thread_id);
- post_fixture1.add_post_and_assert(Ok(()));
- let mut post_fixture2 = post_fixture1.with_text(Vec::new());
- post_fixture2.update_post_and_assert(Err(Error::<Test>::EmptyPostProvided.into()));
- let mut post_fixture3 = post_fixture2.with_text([0; 2001].to_vec());
- post_fixture3.update_post_and_assert(Err(Error::<Test>::PostIsTooLong.into()));
- });
- }
- #[test]
- fn add_discussion_thread_fails_because_of_max_thread_by_same_author_in_a_row_limit_exceeded() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- for idx in 1..=3 {
- discussion_fixture
- .create_discussion_and_assert(Ok(idx))
- .unwrap();
- }
- discussion_fixture
- .create_discussion_and_assert(Err(Error::<Test>::MaxThreadInARowLimitExceeded.into()));
- });
- }
- #[test]
- fn discussion_thread_and_post_counters_are_valid() {
- initial_test_ext().execute_with(|| {
- let discussion_fixture = DiscussionFixture::default();
- let thread_id = discussion_fixture
- .create_discussion_and_assert(Ok(1))
- .unwrap();
- let mut post_fixture1 = PostFixture::default_for_thread(thread_id);
- let _ = post_fixture1.add_post_and_assert(Ok(())).unwrap();
- assert_eq!(Discussions::thread_count(), 1);
- assert_eq!(Discussions::post_count(), 1);
- });
- }
|