benchmarking.rs 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047
  1. #![cfg(feature = "runtime-benchmarks")]
  2. use super::*;
  3. use balances::Module as Balances;
  4. use core::convert::TryInto;
  5. use frame_benchmarking::{account, benchmarks};
  6. use frame_support::storage::StorageMap;
  7. use frame_support::traits::Currency;
  8. use frame_system::Module as System;
  9. use frame_system::{EventRecord, RawOrigin};
  10. use membership::Module as Membership;
  11. use sp_runtime::traits::Bounded;
  12. use sp_std::collections::btree_set::BTreeSet;
  13. use working_group::{
  14. ApplicationById, ApplicationId, ApplyOnOpeningParameters, OpeningById, OpeningId, OpeningType,
  15. StakeParameters, StakePolicy, WorkerById,
  16. };
  17. // We create this trait because we need to be compatible with the runtime
  18. // in the mock for tests. In that case we need to be able to have `membership_id == account_id`
  19. // We can't create an account from an `u32` or from a memberhsip_dd,
  20. // so this trait allows us to get an account id from an u32, in the case of `64` which is what
  21. // the mock use we get the parameter as a return.
  22. // In the case of `AccountId32` we use the method provided by `frame_benchmarking` to get an
  23. // AccountId.
  24. pub trait CreateAccountId {
  25. fn create_account_id(id: u32) -> Self;
  26. }
  27. impl CreateAccountId for u128 {
  28. fn create_account_id(id: u32) -> Self {
  29. id.into()
  30. }
  31. }
  32. impl CreateAccountId for sp_core::crypto::AccountId32 {
  33. fn create_account_id(id: u32) -> Self {
  34. account::<Self>("default", id, SEED)
  35. }
  36. }
  37. // The forum working group instance alias.
  38. pub type ForumWorkingGroupInstance = working_group::Instance1;
  39. // Alias for forum working group
  40. type ForumGroup<T> = working_group::Module<T, ForumWorkingGroupInstance>;
  41. /// Balance alias for `balances` module.
  42. pub type BalanceOf<T> = <T as balances::Trait>::Balance;
  43. const SEED: u32 = 0;
  44. const MAX_BYTES: u32 = 16384;
  45. const MAX_POSTS: u32 = 500;
  46. const MAX_THREADS: u32 = 500;
  47. fn get_byte(num: u32, byte_number: u8) -> u8 {
  48. ((num & (0xff << (8 * byte_number))) >> (8 * byte_number)) as u8
  49. }
  50. fn assert_last_event<T: Trait>(generic_event: <T as Trait>::Event) {
  51. let events = System::<T>::events();
  52. let system_event: <T as frame_system::Trait>::Event = generic_event.into();
  53. // compare to the last event record
  54. let EventRecord { event, .. } = &events[events.len() - 1];
  55. assert_eq!(event, &system_event);
  56. }
  57. fn member_funded_account<T: Trait + membership::Trait + balances::Trait>(
  58. id: u32,
  59. ) -> (T::AccountId, T::MemberId)
  60. where
  61. T::AccountId: CreateAccountId,
  62. {
  63. let account_id = T::AccountId::create_account_id(id);
  64. let handle = handle_from_id::<T>(id);
  65. let _ = Balances::<T>::make_free_balance_be(&account_id, BalanceOf::<T>::max_value());
  66. let params = membership::BuyMembershipParameters {
  67. root_account: account_id.clone(),
  68. controller_account: account_id.clone(),
  69. handle: Some(handle),
  70. metadata: Vec::new(),
  71. referrer_id: None,
  72. };
  73. Membership::<T>::buy_membership(RawOrigin::Signed(account_id.clone()).into(), params).unwrap();
  74. let _ = Balances::<T>::make_free_balance_be(&account_id, BalanceOf::<T>::max_value());
  75. let member_id = T::MemberId::from(id.try_into().unwrap());
  76. Membership::<T>::add_staking_account_candidate(
  77. RawOrigin::Signed(account_id.clone()).into(),
  78. member_id,
  79. )
  80. .unwrap();
  81. Membership::<T>::confirm_staking_account(
  82. RawOrigin::Signed(account_id.clone()).into(),
  83. member_id,
  84. account_id.clone(),
  85. )
  86. .unwrap();
  87. (account_id, member_id)
  88. }
  89. // Method to generate a distintic valid handle
  90. // for a membership. For each index.
  91. fn handle_from_id<T: membership::Trait>(id: u32) -> Vec<u8> {
  92. let min_handle_length = 1;
  93. let mut handle = vec![];
  94. for i in 0..4 {
  95. handle.push(get_byte(id, i));
  96. }
  97. while handle.len() < (min_handle_length as usize) {
  98. handle.push(0u8);
  99. }
  100. handle
  101. }
  102. fn insert_a_leader<
  103. T: Trait + membership::Trait + working_group::Trait<ForumWorkingGroupInstance> + balances::Trait,
  104. >(
  105. id: u64,
  106. ) -> T::AccountId
  107. where
  108. T::AccountId: CreateAccountId,
  109. {
  110. let (caller_id, member_id) = member_funded_account::<T>(id as u32);
  111. let (opening_id, application_id) = add_and_apply_opening::<T>(
  112. &T::Origin::from(RawOrigin::Root),
  113. &caller_id,
  114. &member_id,
  115. &OpeningType::Leader,
  116. );
  117. let mut successful_application_ids = BTreeSet::<ApplicationId>::new();
  118. successful_application_ids.insert(application_id);
  119. ForumGroup::<T>::fill_opening(
  120. RawOrigin::Root.into(),
  121. opening_id,
  122. successful_application_ids,
  123. )
  124. .unwrap();
  125. let actor_id =
  126. <T as common::membership::MembershipTypes>::ActorId::from(id.try_into().unwrap());
  127. assert!(WorkerById::<T, ForumWorkingGroupInstance>::contains_key(
  128. actor_id
  129. ));
  130. caller_id
  131. }
  132. fn insert_a_worker<
  133. T: Trait + membership::Trait + working_group::Trait<ForumWorkingGroupInstance> + balances::Trait,
  134. >(
  135. leader_account_id: T::AccountId,
  136. id: u64,
  137. ) -> T::AccountId
  138. where
  139. T::AccountId: CreateAccountId,
  140. {
  141. let (caller_id, member_id) = member_funded_account::<T>(id as u32);
  142. let leader_origin = RawOrigin::Signed(leader_account_id);
  143. let (opening_id, application_id) = add_and_apply_opening::<T>(
  144. &T::Origin::from(leader_origin.clone()),
  145. &caller_id,
  146. &member_id,
  147. &OpeningType::Regular,
  148. );
  149. let mut successful_application_ids = BTreeSet::<ApplicationId>::new();
  150. successful_application_ids.insert(application_id);
  151. ForumGroup::<T>::fill_opening(leader_origin.into(), opening_id, successful_application_ids)
  152. .unwrap();
  153. let actor_id =
  154. <T as common::membership::MembershipTypes>::ActorId::from(id.try_into().unwrap());
  155. assert!(WorkerById::<T, ForumWorkingGroupInstance>::contains_key(
  156. actor_id
  157. ));
  158. caller_id
  159. }
  160. fn add_and_apply_opening<T: Trait + working_group::Trait<ForumWorkingGroupInstance>>(
  161. add_opening_origin: &T::Origin,
  162. applicant_account_id: &T::AccountId,
  163. applicant_member_id: &T::MemberId,
  164. job_opening_type: &OpeningType,
  165. ) -> (OpeningId, ApplicationId) {
  166. let opening_id = add_opening_helper::<T>(add_opening_origin, job_opening_type);
  167. let application_id =
  168. apply_on_opening_helper::<T>(applicant_account_id, applicant_member_id, &opening_id);
  169. (opening_id, application_id)
  170. }
  171. fn add_opening_helper<T: Trait + working_group::Trait<ForumWorkingGroupInstance>>(
  172. add_opening_origin: &T::Origin,
  173. job_opening_type: &OpeningType,
  174. ) -> OpeningId {
  175. ForumGroup::<T>::add_opening(
  176. add_opening_origin.clone(),
  177. vec![],
  178. *job_opening_type,
  179. StakePolicy {
  180. stake_amount:
  181. <T as working_group::Trait<ForumWorkingGroupInstance>>::MinimumApplicationStake::get(
  182. ),
  183. leaving_unstaking_period: <T as
  184. working_group::Trait<ForumWorkingGroupInstance>>::MinUnstakingPeriodLimit::get() + One::one(),
  185. },
  186. Some(One::one()),
  187. )
  188. .unwrap();
  189. let opening_id = ForumGroup::<T>::next_opening_id() - 1;
  190. assert!(
  191. OpeningById::<T, ForumWorkingGroupInstance>::contains_key(opening_id),
  192. "Opening not added"
  193. );
  194. opening_id
  195. }
  196. fn apply_on_opening_helper<T: Trait + working_group::Trait<ForumWorkingGroupInstance>>(
  197. applicant_account_id: &T::AccountId,
  198. applicant_member_id: &T::MemberId,
  199. opening_id: &OpeningId,
  200. ) -> ApplicationId {
  201. ForumGroup::<T>::apply_on_opening(
  202. RawOrigin::Signed((*applicant_account_id).clone()).into(),
  203. ApplyOnOpeningParameters::<T> {
  204. member_id: *applicant_member_id,
  205. opening_id: *opening_id,
  206. role_account_id: applicant_account_id.clone(),
  207. reward_account_id: applicant_account_id.clone(),
  208. description: vec![],
  209. stake_parameters: StakeParameters {
  210. stake: <T as working_group::Trait<ForumWorkingGroupInstance>>::MinimumApplicationStake::get(),
  211. staking_account_id: applicant_account_id.clone()
  212. },
  213. },
  214. )
  215. .unwrap();
  216. let application_id = ForumGroup::<T>::next_application_id() - 1;
  217. assert!(
  218. ApplicationById::<T, ForumWorkingGroupInstance>::contains_key(application_id),
  219. "Application not added"
  220. );
  221. application_id
  222. }
  223. fn create_new_category<T: Trait>(
  224. account_id: T::AccountId,
  225. parent_category_id: Option<T::CategoryId>,
  226. title: Vec<u8>,
  227. description: Vec<u8>,
  228. ) -> T::CategoryId {
  229. let category_id = Module::<T>::next_category_id();
  230. Module::<T>::create_category(
  231. RawOrigin::Signed(account_id).into(),
  232. parent_category_id,
  233. title,
  234. description,
  235. )
  236. .unwrap();
  237. assert!(<CategoryById<T>>::contains_key(category_id));
  238. category_id
  239. }
  240. fn create_new_thread<T: Trait>(
  241. account_id: T::AccountId,
  242. forum_user_id: crate::ForumUserId<T>,
  243. category_id: T::CategoryId,
  244. title: Vec<u8>,
  245. text: Vec<u8>,
  246. poll: Option<PollInput<T::Moment>>,
  247. ) -> T::ThreadId {
  248. Module::<T>::create_thread(
  249. RawOrigin::Signed(account_id).into(),
  250. forum_user_id,
  251. category_id,
  252. title,
  253. text,
  254. poll,
  255. )
  256. .unwrap();
  257. Module::<T>::next_thread_id() - T::ThreadId::one()
  258. }
  259. fn add_thread_post<T: Trait>(
  260. account_id: T::AccountId,
  261. forum_user_id: crate::ForumUserId<T>,
  262. category_id: T::CategoryId,
  263. thread_id: T::ThreadId,
  264. text: Vec<u8>,
  265. ) -> T::PostId {
  266. Module::<T>::add_post(
  267. RawOrigin::Signed(account_id).into(),
  268. forum_user_id,
  269. category_id,
  270. thread_id,
  271. text,
  272. true,
  273. )
  274. .unwrap();
  275. Module::<T>::next_post_id() - T::PostId::one()
  276. }
  277. fn good_poll_alternative_text() -> Vec<u8> {
  278. b"poll alternative".to_vec()
  279. }
  280. fn good_poll_description() -> Vec<u8> {
  281. b"poll description".to_vec()
  282. }
  283. /// Generates poll input
  284. pub fn generate_poll_input<T: Trait>(
  285. expiration_diff: T::Moment,
  286. alternatives_number: u32,
  287. ) -> PollInput<T::Moment> {
  288. PollInput {
  289. description: good_poll_description(),
  290. end_time: pallet_timestamp::Module::<T>::now() + expiration_diff,
  291. poll_alternatives: {
  292. let mut alternatives = vec![];
  293. for _ in 0..alternatives_number {
  294. alternatives.push(good_poll_alternative_text());
  295. }
  296. alternatives
  297. },
  298. }
  299. }
  300. /// Generates categories tree
  301. pub fn generate_categories_tree<T: Trait>(
  302. caller_id: T::AccountId,
  303. category_depth: u32,
  304. moderator_id: Option<ModeratorId<T>>,
  305. ) -> (T::CategoryId, Option<T::CategoryId>) {
  306. let mut parent_category_id = None;
  307. let mut category_id = T::CategoryId::default();
  308. let categories_counter_before_tree_construction = <Module<T>>::category_counter();
  309. let text = vec![0u8].repeat(MAX_BYTES as usize);
  310. for n in 0..category_depth {
  311. if n > 1 {
  312. parent_category_id = Some((n as u64).into());
  313. }
  314. category_id = create_new_category::<T>(
  315. caller_id.clone(),
  316. parent_category_id,
  317. text.clone(),
  318. text.clone(),
  319. );
  320. if let Some(moderator_id) = moderator_id {
  321. // Set up category membership of moderator.
  322. Module::<T>::update_category_membership_of_moderator(
  323. RawOrigin::Signed(caller_id.clone()).into(),
  324. moderator_id,
  325. category_id,
  326. true,
  327. )
  328. .unwrap();
  329. }
  330. }
  331. assert_eq!(
  332. categories_counter_before_tree_construction + (category_depth as u64).into(),
  333. <Module<T>>::category_counter()
  334. );
  335. (category_id, parent_category_id)
  336. }
  337. benchmarks! {
  338. where_clause { where
  339. T: balances::Trait,
  340. T: membership::Trait,
  341. T: working_group::Trait<ForumWorkingGroupInstance> ,
  342. T::AccountId: CreateAccountId
  343. }
  344. _{ }
  345. create_category{
  346. let lead_id = 0;
  347. let caller_id =
  348. insert_a_leader::<T>(lead_id);
  349. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  350. let j in 0 .. MAX_BYTES;
  351. let k in 0 .. MAX_BYTES;
  352. let title = vec![0u8].repeat(j as usize);
  353. let description = vec![0u8].repeat(k as usize);
  354. // Generate categories tree
  355. let (_, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  356. let parent_category = parent_category_id.map(Module::<T>::category_by_id);
  357. let category_counter = <Module<T>>::category_counter();
  358. }: _ (RawOrigin::Signed(caller_id), parent_category_id, title.clone(), description.clone())
  359. verify {
  360. let new_category = Category {
  361. title_hash: T::calculate_hash(title.as_slice()),
  362. description_hash: T::calculate_hash(description.as_slice()),
  363. archived: false,
  364. num_direct_subcategories: 0,
  365. num_direct_threads: 0,
  366. num_direct_moderators: 0,
  367. parent_category_id,
  368. sticky_thread_ids: vec![],
  369. };
  370. let category_id = Module::<T>::next_category_id() - T::CategoryId::one();
  371. assert_eq!(Module::<T>::category_by_id(category_id), new_category);
  372. assert_eq!(<Module<T>>::category_counter(), category_counter + T::CategoryId::one());
  373. if let (Some(parent_category), Some(parent_category_id)) = (parent_category, parent_category_id) {
  374. assert_eq!(
  375. Module::<T>::category_by_id(parent_category_id).num_direct_subcategories,
  376. parent_category.num_direct_subcategories + 1
  377. );
  378. }
  379. assert_last_event::<T>(
  380. RawEvent::CategoryCreated(
  381. category_id,
  382. parent_category_id,
  383. title,
  384. description
  385. ).into()
  386. );
  387. }
  388. update_category_membership_of_moderator_new{
  389. let moderator_id = 0;
  390. let caller_id =
  391. insert_a_leader::<T>(moderator_id);
  392. let text = vec![0u8].repeat(MAX_BYTES as usize);
  393. // Create category
  394. let category_id = create_new_category::<T>(caller_id.clone(), None, text.clone(), text.clone());
  395. let new_value_flag = true;
  396. }: update_category_membership_of_moderator(
  397. RawOrigin::Signed(caller_id), ModeratorId::<T>::from((moderator_id).try_into().unwrap()), category_id, new_value_flag
  398. )
  399. verify {
  400. let num_direct_moderators = 1;
  401. let new_category = Category {
  402. title_hash: T::calculate_hash(text.as_slice()),
  403. description_hash: T::calculate_hash(text.as_slice()),
  404. archived: false,
  405. num_direct_subcategories: 0,
  406. num_direct_threads: 0,
  407. num_direct_moderators,
  408. parent_category_id: None,
  409. sticky_thread_ids: vec![],
  410. };
  411. assert_eq!(Module::<T>::category_by_id(category_id), new_category);
  412. assert!(<CategoryByModerator<T>>::contains_key(category_id, ModeratorId::<T>::from((moderator_id).try_into().unwrap())));
  413. assert_last_event::<T>(
  414. RawEvent::CategoryMembershipOfModeratorUpdated(
  415. ModeratorId::<T>::from((moderator_id).try_into().unwrap()), category_id, new_value_flag
  416. ).into()
  417. );
  418. }
  419. update_category_membership_of_moderator_old{
  420. let moderator_id = 0;
  421. let caller_id =
  422. insert_a_leader::<T>(moderator_id);
  423. let text = vec![0u8].repeat(MAX_BYTES as usize);
  424. // Create category
  425. let category_id = create_new_category::<T>(caller_id.clone(), None, text.clone(), text.clone());
  426. // Set up category membership of moderator.
  427. Module::<T>::update_category_membership_of_moderator(
  428. RawOrigin::Signed(caller_id.clone()).into(), ModeratorId::<T>::from((moderator_id).try_into().unwrap()), category_id, true
  429. ).unwrap();
  430. let new_value_flag = false;
  431. }: update_category_membership_of_moderator(
  432. RawOrigin::Signed(caller_id), ModeratorId::<T>::from((moderator_id).try_into().unwrap()), category_id, new_value_flag
  433. )
  434. verify {
  435. let num_direct_moderators = 0;
  436. let new_category = Category {
  437. title_hash: T::calculate_hash(text.as_slice()),
  438. description_hash: T::calculate_hash(text.as_slice()),
  439. archived: false,
  440. num_direct_subcategories: 0,
  441. num_direct_threads: 0,
  442. num_direct_moderators,
  443. parent_category_id: None,
  444. sticky_thread_ids: vec![],
  445. };
  446. assert_eq!(Module::<T>::category_by_id(category_id), new_category);
  447. assert!(!<CategoryByModerator<T>>::contains_key(category_id, ModeratorId::<T>::from((moderator_id).try_into().unwrap())));
  448. assert_last_event::<T>(
  449. RawEvent::CategoryMembershipOfModeratorUpdated(
  450. ModeratorId::<T>::from((moderator_id).try_into().unwrap()), category_id, new_value_flag
  451. ).into()
  452. );
  453. }
  454. update_category_archival_status_lead{
  455. let lead_id = 0;
  456. let caller_id =
  457. insert_a_leader::<T>(lead_id);
  458. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  459. let new_archival_status = true;
  460. // Generate categories tree
  461. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  462. }: update_category_archival_status(RawOrigin::Signed(caller_id), PrivilegedActor::Lead, category_id, new_archival_status)
  463. verify {
  464. let text = vec![0u8].repeat(MAX_BYTES as usize);
  465. let new_category = Category {
  466. title_hash: T::calculate_hash(text.as_slice()),
  467. description_hash: T::calculate_hash(text.as_slice()),
  468. archived: new_archival_status,
  469. num_direct_subcategories: 0,
  470. num_direct_threads: 0,
  471. num_direct_moderators: 0,
  472. parent_category_id,
  473. sticky_thread_ids: vec![],
  474. };
  475. assert_eq!(Module::<T>::category_by_id(category_id), new_category);
  476. assert_last_event::<T>(
  477. RawEvent::CategoryArchivalStatusUpdated(
  478. category_id,
  479. new_archival_status,
  480. PrivilegedActor::Lead
  481. ).into()
  482. );
  483. }
  484. update_category_archival_status_moderator{
  485. let moderator_id = 0;
  486. let caller_id =
  487. insert_a_leader::<T>(moderator_id);
  488. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  489. let new_archival_status = true;
  490. // Generate categories tree
  491. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  492. let moderator_id = ModeratorId::<T>::from(moderator_id.try_into().unwrap());
  493. // Set up category membership of moderator.
  494. Module::<T>::update_category_membership_of_moderator(
  495. RawOrigin::Signed(caller_id.clone()).into(), moderator_id, category_id, true
  496. ).unwrap();
  497. }: update_category_archival_status(RawOrigin::Signed(caller_id), PrivilegedActor::Moderator(moderator_id), category_id, new_archival_status)
  498. verify {
  499. let text = vec![0u8].repeat(MAX_BYTES as usize);
  500. let new_category = Category {
  501. title_hash: T::calculate_hash(text.as_slice()),
  502. description_hash: T::calculate_hash(text.as_slice()),
  503. archived: new_archival_status,
  504. num_direct_subcategories: 0,
  505. num_direct_threads: 0,
  506. num_direct_moderators: 1,
  507. parent_category_id,
  508. sticky_thread_ids: vec![],
  509. };
  510. assert_eq!(Module::<T>::category_by_id(category_id), new_category);
  511. assert_last_event::<T>(
  512. RawEvent::CategoryArchivalStatusUpdated(
  513. category_id,
  514. new_archival_status,
  515. PrivilegedActor::Moderator(moderator_id)
  516. ).into()
  517. );
  518. }
  519. update_category_title_lead{
  520. let lead_id = 0;
  521. let caller_id =
  522. insert_a_leader::<T>(lead_id);
  523. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  524. let j in 0 .. MAX_BYTES - 1;
  525. let new_title = vec![0u8].repeat(j as usize);
  526. // Generate categories tree
  527. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  528. }: update_category_title(RawOrigin::Signed(caller_id), PrivilegedActor::Lead, category_id, new_title.clone())
  529. verify {
  530. let text = vec![0u8].repeat(MAX_BYTES as usize);
  531. let new_title_hash = T::calculate_hash(new_title.as_slice());
  532. let new_category = Category {
  533. title_hash: new_title_hash,
  534. description_hash: T::calculate_hash(text.as_slice()),
  535. archived: false,
  536. num_direct_subcategories: 0,
  537. num_direct_threads: 0,
  538. num_direct_moderators: 0,
  539. parent_category_id,
  540. sticky_thread_ids: vec![],
  541. };
  542. assert_eq!(Module::<T>::category_by_id(category_id), new_category);
  543. assert_last_event::<T>(
  544. RawEvent::CategoryTitleUpdated(
  545. category_id,
  546. new_title_hash,
  547. PrivilegedActor::Lead
  548. ).into()
  549. );
  550. }
  551. update_category_title_moderator{
  552. let moderator_id = 0;
  553. let caller_id =
  554. insert_a_leader::<T>(moderator_id);
  555. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  556. let j in 0 .. MAX_BYTES - 1;
  557. let new_title = vec![0u8].repeat(j as usize);
  558. // Generate categories tree
  559. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  560. let moderator_id = ModeratorId::<T>::from(moderator_id.try_into().unwrap());
  561. // Set up category membership of moderator.
  562. Module::<T>::update_category_membership_of_moderator(
  563. RawOrigin::Signed(caller_id.clone()).into(), moderator_id, category_id, true
  564. ).unwrap();
  565. }: update_category_title(RawOrigin::Signed(caller_id), PrivilegedActor::Moderator(moderator_id), category_id, new_title.clone())
  566. verify {
  567. let text = vec![0u8].repeat(MAX_BYTES as usize);
  568. let new_title_hash = T::calculate_hash(new_title.as_slice());
  569. let new_category = Category {
  570. title_hash: new_title_hash,
  571. description_hash: T::calculate_hash(text.as_slice()),
  572. archived: false,
  573. num_direct_subcategories: 0,
  574. num_direct_threads: 0,
  575. num_direct_moderators: 1,
  576. parent_category_id,
  577. sticky_thread_ids: vec![],
  578. };
  579. assert_eq!(Module::<T>::category_by_id(category_id), new_category);
  580. assert_last_event::<T>(
  581. RawEvent::CategoryTitleUpdated(
  582. category_id,
  583. new_title_hash,
  584. PrivilegedActor::Moderator(moderator_id)
  585. ).into()
  586. );
  587. }
  588. update_category_description_lead{
  589. let lead_id = 0;
  590. let caller_id =
  591. insert_a_leader::<T>(lead_id);
  592. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  593. let j in 0 .. MAX_BYTES - 1;
  594. let new_description = vec![0u8].repeat(j as usize);
  595. // Generate categories tree
  596. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  597. }: update_category_description(RawOrigin::Signed(caller_id), PrivilegedActor::Lead, category_id, new_description.clone())
  598. verify {
  599. let text = vec![0u8].repeat(MAX_BYTES as usize);
  600. let new_description_hash = T::calculate_hash(new_description.as_slice());
  601. let new_category = Category {
  602. title_hash: T::calculate_hash(text.as_slice()),
  603. description_hash: new_description_hash,
  604. archived: false,
  605. num_direct_subcategories: 0,
  606. num_direct_threads: 0,
  607. num_direct_moderators: 0,
  608. parent_category_id,
  609. sticky_thread_ids: vec![],
  610. };
  611. assert_eq!(Module::<T>::category_by_id(category_id), new_category);
  612. assert_last_event::<T>(
  613. RawEvent::CategoryDescriptionUpdated(
  614. category_id,
  615. new_description_hash,
  616. PrivilegedActor::Lead
  617. ).into()
  618. );
  619. }
  620. update_category_description_moderator{
  621. let moderator_id = 0;
  622. let caller_id =
  623. insert_a_leader::<T>(moderator_id);
  624. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  625. let j in 0 .. MAX_BYTES - 1;
  626. let new_description = vec![0u8].repeat(j as usize);
  627. // Generate categories tree
  628. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  629. let moderator_id = ModeratorId::<T>::from(moderator_id.try_into().unwrap());
  630. // Set up category membership of moderator.
  631. Module::<T>::update_category_membership_of_moderator(
  632. RawOrigin::Signed(caller_id.clone()).into(), moderator_id, category_id, true
  633. ).unwrap();
  634. }: update_category_description(RawOrigin::Signed(caller_id), PrivilegedActor::Moderator(moderator_id), category_id, new_description.clone())
  635. verify {
  636. let text = vec![0u8].repeat(MAX_BYTES as usize);
  637. let new_description_hash = T::calculate_hash(new_description.as_slice());
  638. let new_category = Category {
  639. title_hash: T::calculate_hash(text.as_slice()),
  640. description_hash: new_description_hash,
  641. archived: false,
  642. num_direct_subcategories: 0,
  643. num_direct_threads: 0,
  644. num_direct_moderators: 1,
  645. parent_category_id,
  646. sticky_thread_ids: vec![],
  647. };
  648. assert_eq!(Module::<T>::category_by_id(category_id), new_category);
  649. assert_last_event::<T>(
  650. RawEvent::CategoryDescriptionUpdated(
  651. category_id,
  652. new_description_hash,
  653. PrivilegedActor::Moderator(moderator_id)
  654. ).into()
  655. );
  656. }
  657. delete_category_lead {
  658. let lead_id = 0;
  659. let caller_id =
  660. insert_a_leader::<T>(lead_id);
  661. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  662. // Generate categories tree
  663. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  664. let category_counter = <Module<T>>::category_counter();
  665. }: delete_category(RawOrigin::Signed(caller_id), PrivilegedActor::Lead, category_id)
  666. verify {
  667. let text = vec![0u8].repeat(MAX_BYTES as usize);
  668. let new_category: Category<T::CategoryId, T::ThreadId, <T as frame_system::Trait>::Hash> = Category {
  669. title_hash: T::calculate_hash(text.as_slice()),
  670. description_hash: T::calculate_hash(text.as_slice()),
  671. archived: false,
  672. num_direct_subcategories: 0,
  673. num_direct_threads: 0,
  674. num_direct_moderators: 0,
  675. parent_category_id: None,
  676. sticky_thread_ids: vec![],
  677. };
  678. if let Some(parent_category_id) = parent_category_id {
  679. // Ensure number of direct subcategories for parent category decremented successfully
  680. assert_eq!(Module::<T>::category_by_id(parent_category_id).num_direct_subcategories, 0);
  681. }
  682. assert_eq!(<Module<T>>::category_counter(), category_counter - T::CategoryId::one());
  683. // Ensure category removed successfully
  684. assert!(!<CategoryById<T>>::contains_key(category_id));
  685. assert_last_event::<T>(
  686. RawEvent::CategoryDeleted(category_id, PrivilegedActor::Lead).into()
  687. );
  688. }
  689. delete_category_moderator {
  690. let lead_id = 0;
  691. let caller_id =
  692. insert_a_leader::<T>(lead_id);
  693. let i in 3 .. (T::MaxCategoryDepth::get() + 1) as u32;
  694. let moderator_id = ModeratorId::<T>::from(lead_id.try_into().unwrap());
  695. // Generate categories tree
  696. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, Some(moderator_id));
  697. let category_counter = <Module<T>>::category_counter();
  698. }: delete_category(RawOrigin::Signed(caller_id), PrivilegedActor::Moderator(moderator_id), category_id)
  699. verify {
  700. let text = vec![0u8].repeat(MAX_BYTES as usize);
  701. let new_category: Category<T::CategoryId, T::ThreadId, <T as frame_system::Trait>::Hash> = Category {
  702. title_hash: T::calculate_hash(text.as_slice()),
  703. description_hash: T::calculate_hash(text.as_slice()),
  704. archived: false,
  705. num_direct_subcategories: 0,
  706. num_direct_threads: 0,
  707. num_direct_moderators: 1,
  708. parent_category_id: None,
  709. sticky_thread_ids: vec![],
  710. };
  711. if let Some(parent_category_id) = parent_category_id {
  712. // Ensure number of direct subcategories for parent category decremented successfully
  713. assert_eq!(Module::<T>::category_by_id(parent_category_id).num_direct_subcategories, 0);
  714. }
  715. assert_eq!(<Module<T>>::category_counter(), category_counter - T::CategoryId::one());
  716. // Ensure category removed successfully
  717. assert!(!<CategoryById<T>>::contains_key(category_id));
  718. assert_last_event::<T>(
  719. RawEvent::CategoryDeleted(category_id, PrivilegedActor::Moderator(moderator_id)).into()
  720. );
  721. }
  722. create_thread {
  723. let forum_user_id = 0;
  724. let caller_id =
  725. insert_a_leader::<T>(forum_user_id);
  726. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  727. let j in 0 .. MAX_BYTES;
  728. let k in 0 .. MAX_BYTES;
  729. let z in 1 .. (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32;
  730. // Generate categories tree
  731. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  732. let mut category = Module::<T>::category_by_id(category_id);
  733. let metadata = vec![0u8].repeat(j as usize);
  734. let text = vec![0u8].repeat(k as usize);
  735. let expiration_diff = 1010u32.into();
  736. let poll_input = if z == 1 {
  737. None
  738. } else {
  739. // min number of poll alternatives is set to 2
  740. Some(generate_poll_input::<T>(expiration_diff, z))
  741. };
  742. let next_thread_id = Module::<T>::next_thread_id();
  743. let next_post_id = Module::<T>::next_post_id();
  744. let initial_balance = Balances::<T>::usable_balance(&caller_id);
  745. }: _ (RawOrigin::Signed(caller_id.clone()), forum_user_id.saturated_into(), category_id, metadata.clone(), text.clone(), poll_input.clone())
  746. verify {
  747. assert_eq!(
  748. Balances::<T>::usable_balance(&caller_id),
  749. initial_balance - T::ThreadDeposit::get() - T::PostDeposit::get(),
  750. );
  751. // Ensure category num_direct_threads updated successfully.
  752. category.num_direct_threads+=1;
  753. assert_eq!(Module::<T>::category_by_id(category_id), category);
  754. // Ensure initial post added successfully
  755. let new_post = Post {
  756. text_hash: T::calculate_hash(&text),
  757. author_id: forum_user_id.saturated_into(),
  758. thread_id: next_thread_id,
  759. last_edited: System::<T>::block_number(),
  760. cleanup_pay_off: T::PostDeposit::get(),
  761. };
  762. // Ensure new thread created successfully
  763. let new_thread = Thread {
  764. category_id,
  765. author_id: forum_user_id.saturated_into(),
  766. poll: poll_input.clone().map(<Module<T>>::from_poll_input),
  767. cleanup_pay_off: T::ThreadDeposit::get(),
  768. number_of_posts: 1,
  769. };
  770. assert_eq!(Module::<T>::thread_by_id(category_id, next_thread_id), new_thread);
  771. assert_eq!(Module::<T>::next_thread_id(), next_thread_id + T::ThreadId::one());
  772. assert_eq!(
  773. Module::<T>::post_by_id(next_thread_id, next_post_id),
  774. new_post
  775. );
  776. assert_eq!(Module::<T>::next_post_id(), next_post_id + T::PostId::one());
  777. assert_last_event::<T>(
  778. RawEvent::ThreadCreated(
  779. category_id,
  780. next_thread_id,
  781. next_post_id,
  782. forum_user_id.saturated_into(),
  783. metadata,
  784. text,
  785. poll_input,
  786. ).into()
  787. );
  788. }
  789. edit_thread_metadata {
  790. let forum_user_id = 0;
  791. let caller_id =
  792. insert_a_leader::<T>(forum_user_id);
  793. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  794. let j in 0 .. MAX_BYTES;
  795. // Generate categories tree
  796. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  797. // Create thread
  798. let thread_id = create_new_thread::<T>(
  799. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  800. vec![1u8].repeat(MAX_BYTES as usize), vec![1u8].repeat(MAX_BYTES as usize), None
  801. );
  802. let thread = Module::<T>::thread_by_id(category_id, thread_id);
  803. let new_metadata = vec![0u8].repeat(j as usize);
  804. }: _ (RawOrigin::Signed(caller_id), forum_user_id.saturated_into(), category_id, thread_id, new_metadata.clone())
  805. verify {
  806. assert_eq!(Module::<T>::thread_by_id(category_id, thread_id), thread);
  807. assert_last_event::<T>(
  808. RawEvent::ThreadMetadataUpdated(
  809. thread_id,
  810. forum_user_id.saturated_into(),
  811. category_id,
  812. new_metadata
  813. ).into()
  814. );
  815. }
  816. delete_thread {
  817. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  818. let hide = false;
  819. let forum_user_id = 0;
  820. let caller_id =
  821. insert_a_leader::<T>(forum_user_id);
  822. // Generate categories tree
  823. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  824. // Create thread
  825. let expiration_diff = 10u32.into();
  826. let poll = Some(
  827. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  828. );
  829. let text = vec![1u8].repeat(MAX_BYTES as usize);
  830. let thread_id = create_new_thread::<T>(
  831. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  832. text.clone(), text, poll
  833. );
  834. // Add poll voting.
  835. for idx in 1..(T::MaxWorkerNumberLimit::get() - 1) {
  836. let member_id = idx.into();
  837. let member_account_id = insert_a_worker::<T>(caller_id.clone(), member_id);
  838. let alternative_idx = 1;
  839. Module::<T>::vote_on_poll(
  840. RawOrigin::Signed(member_account_id.clone()).into(),
  841. member_id.saturated_into(),
  842. category_id,
  843. thread_id,
  844. alternative_idx
  845. ).unwrap();
  846. }
  847. let mut category = Module::<T>::category_by_id(category_id);
  848. let initial_balance = Balances::<T>::usable_balance(&caller_id);
  849. }: _(
  850. RawOrigin::Signed(caller_id.clone()),
  851. forum_user_id.saturated_into(),
  852. category_id,
  853. thread_id,
  854. hide
  855. )
  856. verify {
  857. // Ensure that balance is paid off
  858. assert_eq!(
  859. Balances::<T>::usable_balance(&caller_id),
  860. initial_balance +
  861. T::ThreadDeposit::get()
  862. );
  863. // Ensure category num_direct_threads updated successfully.
  864. category.num_direct_threads-=1;
  865. assert_eq!(Module::<T>::category_by_id(category_id), category);
  866. // Ensure thread was successfully deleted
  867. assert!(!<ThreadById<T>>::contains_key(category_id, thread_id));
  868. assert_eq!(<PollVotes<T>>::iter_prefix_values(&thread_id).count(), 0);
  869. assert_last_event::<T>(
  870. RawEvent::ThreadDeleted(
  871. thread_id,
  872. forum_user_id.saturated_into(),
  873. category_id,
  874. hide
  875. ).into()
  876. );
  877. }
  878. move_thread_to_category_lead {
  879. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  880. let forum_user_id = 0;
  881. let text = vec![1u8].repeat(MAX_BYTES as usize);
  882. let caller_id =
  883. insert_a_leader::<T>(forum_user_id);
  884. // If category depth is less or equal to one, create two separate categories
  885. let (category_id, new_category_id) = if i <= 2 {
  886. let category_id = create_new_category::<T>(
  887. caller_id.clone(),
  888. None,
  889. text.clone(),
  890. text.clone(),
  891. );
  892. let new_category_id = create_new_category::<T>(
  893. caller_id.clone(),
  894. None,
  895. text.clone(),
  896. text.clone(),
  897. );
  898. (category_id, new_category_id)
  899. } else {
  900. // Generate categories tree
  901. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  902. (category_id, parent_category_id.unwrap())
  903. };
  904. // Create thread
  905. let thread_id = create_new_thread::<T>(caller_id.clone(), forum_user_id.saturated_into(), category_id, text.clone(), text, None);
  906. let thread = Module::<T>::thread_by_id(category_id, thread_id);
  907. let mut category = Module::<T>::category_by_id(category_id);
  908. let mut new_category = Module::<T>::category_by_id(new_category_id);
  909. }: move_thread_to_category(RawOrigin::Signed(caller_id), PrivilegedActor::Lead, category_id, thread_id, new_category_id)
  910. verify {
  911. // Ensure thread was successfully moved to the new category
  912. category.num_direct_threads-=1;
  913. new_category.num_direct_threads+=1;
  914. assert_eq!(Module::<T>::category_by_id(category_id), category);
  915. assert_eq!(Module::<T>::category_by_id(new_category_id), new_category);
  916. assert!(!<ThreadById<T>>::contains_key(category_id, thread_id));
  917. assert_eq!(
  918. Module::<T>::thread_by_id(new_category_id, thread_id),
  919. Thread { category_id: new_category_id, ..thread}
  920. );
  921. assert_last_event::<T>(
  922. RawEvent::ThreadMoved(
  923. thread_id,
  924. new_category_id,
  925. PrivilegedActor::Lead,
  926. category_id
  927. ).into()
  928. );
  929. }
  930. move_thread_to_category_moderator {
  931. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  932. let forum_user_id = 0;
  933. let text = vec![1u8].repeat(MAX_BYTES as usize);
  934. let caller_id =
  935. insert_a_leader::<T>(forum_user_id);
  936. // If category depth is less or equal to one, create two separate categories
  937. let (category_id, new_category_id) = if i <= 2 {
  938. let category_id = create_new_category::<T>(
  939. caller_id.clone(),
  940. None,
  941. text.clone(),
  942. text.clone(),
  943. );
  944. let new_category_id = create_new_category::<T>(
  945. caller_id.clone(),
  946. None,
  947. text.clone(),
  948. text.clone(),
  949. );
  950. (category_id, new_category_id)
  951. } else {
  952. // Generate categories tree
  953. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  954. (category_id, parent_category_id.unwrap())
  955. };
  956. // Create thread
  957. let thread_id = create_new_thread::<T>(caller_id.clone(), forum_user_id.saturated_into(), category_id, text.clone(), text, None);
  958. let thread = Module::<T>::thread_by_id(category_id, thread_id);
  959. let moderator_id = ModeratorId::<T>::from(forum_user_id.try_into().unwrap());
  960. // Set up categories membership of moderator.
  961. Module::<T>::update_category_membership_of_moderator(
  962. RawOrigin::Signed(caller_id.clone()).into(), moderator_id, category_id, true
  963. ).unwrap();
  964. // Set up categories membership of moderator.
  965. Module::<T>::update_category_membership_of_moderator(
  966. RawOrigin::Signed(caller_id.clone()).into(), moderator_id, new_category_id, true
  967. ).unwrap();
  968. let mut category = Module::<T>::category_by_id(category_id);
  969. let mut new_category = Module::<T>::category_by_id(new_category_id);
  970. }: move_thread_to_category(RawOrigin::Signed(caller_id), PrivilegedActor::Moderator(moderator_id), category_id, thread_id, new_category_id)
  971. verify {
  972. // Ensure thread was successfully moved to the new category
  973. category.num_direct_threads-=1;
  974. new_category.num_direct_threads+=1;
  975. assert_eq!(Module::<T>::category_by_id(category_id), category);
  976. assert_eq!(Module::<T>::category_by_id(new_category_id), new_category);
  977. assert!(!<ThreadById<T>>::contains_key(category_id, thread_id));
  978. assert_eq!(
  979. Module::<T>::thread_by_id(new_category_id, thread_id),
  980. Thread { category_id: new_category_id, ..thread}
  981. );
  982. assert_last_event::<T>(
  983. RawEvent::ThreadMoved(
  984. thread_id,
  985. new_category_id,
  986. PrivilegedActor::Moderator(moderator_id),
  987. category_id
  988. ).into()
  989. );
  990. }
  991. vote_on_poll {
  992. let forum_user_id = 0;
  993. let caller_id =
  994. insert_a_leader::<T>(forum_user_id);
  995. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  996. let j in 2 .. (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32;
  997. // Generate categories tree
  998. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  999. // Create thread
  1000. let expiration_diff = 10u32.into();
  1001. let poll_input = Some(generate_poll_input::<T>(expiration_diff, j));
  1002. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1003. let thread_id = create_new_thread::<T>(
  1004. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  1005. text.clone(), text, poll_input
  1006. );
  1007. let mut thread = Module::<T>::thread_by_id(category_id, thread_id);
  1008. }: _ (RawOrigin::Signed(caller_id), forum_user_id.saturated_into(), category_id, thread_id, j - 1)
  1009. verify {
  1010. // Store new poll alternative statistics
  1011. if let Some(ref mut poll) = thread.poll {
  1012. let new_poll_alternatives: Vec<PollAlternative<T::Hash>> = poll.poll_alternatives.iter()
  1013. .enumerate()
  1014. .map(|(old_index, old_value)| if (j - 1) as usize == old_index
  1015. { PollAlternative {
  1016. alternative_text_hash: old_value.alternative_text_hash,
  1017. vote_count: old_value.vote_count + 1,
  1018. }
  1019. } else {
  1020. old_value.clone()
  1021. })
  1022. .collect();
  1023. poll.poll_alternatives = new_poll_alternatives;
  1024. }
  1025. assert_eq!(Module::<T>::thread_by_id(category_id, thread_id), thread);
  1026. assert!(<PollVotes<T>>::get(thread_id, forum_user_id.saturated_into::<ForumUserId<T>>()));
  1027. assert_last_event::<T>(
  1028. RawEvent::VoteOnPoll(
  1029. thread_id,
  1030. j - 1,
  1031. forum_user_id.saturated_into(),
  1032. category_id
  1033. ).into()
  1034. );
  1035. }
  1036. moderate_thread_lead {
  1037. let lead_id = 0;
  1038. let caller_id =
  1039. insert_a_leader::<T>(lead_id);
  1040. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1041. let k in 0 .. MAX_BYTES;
  1042. // Generate categories tree
  1043. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1044. // Create thread
  1045. let expiration_diff = 10u32.into();
  1046. let poll = Some(
  1047. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  1048. );
  1049. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1050. let thread_id = create_new_thread::<T>(
  1051. caller_id.clone(), (lead_id as u64).saturated_into(), category_id,
  1052. text.clone(), text, poll
  1053. );
  1054. let mut category = Module::<T>::category_by_id(category_id);
  1055. let rationale = vec![0u8].repeat(k as usize);
  1056. }: moderate_thread(RawOrigin::Signed(caller_id), PrivilegedActor::Lead, category_id, thread_id, rationale.clone())
  1057. verify {
  1058. // Thread balance was correctly slashed
  1059. let thread_account_id = T::ModuleId::get().into_sub_account(thread_id);
  1060. assert_eq!(
  1061. Balances::<T>::free_balance(&thread_account_id),
  1062. T::PostDeposit::get()
  1063. );
  1064. // Ensure category num_direct_threads updated successfully.
  1065. category.num_direct_threads-=1;
  1066. assert_eq!(Module::<T>::category_by_id(category_id), category);
  1067. // Ensure thread was successfully deleted
  1068. assert!(!<ThreadById<T>>::contains_key(category_id, thread_id));
  1069. assert_last_event::<T>(
  1070. RawEvent::ThreadModerated(
  1071. thread_id,
  1072. rationale,
  1073. PrivilegedActor::Lead,
  1074. category_id
  1075. ).into()
  1076. );
  1077. }
  1078. moderate_thread_moderator {
  1079. let lead_id = 0;
  1080. let caller_id =
  1081. insert_a_leader::<T>(lead_id);
  1082. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1083. let k in 0 .. MAX_BYTES;
  1084. // Generate categories tree
  1085. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1086. // Create thread
  1087. let expiration_diff = 10u32.into();
  1088. let poll = Some(
  1089. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  1090. );
  1091. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1092. let thread_id = create_new_thread::<T>(
  1093. caller_id.clone(), (lead_id as u64).saturated_into(), category_id,
  1094. text.clone(), text, poll
  1095. );
  1096. let moderator_id = ModeratorId::<T>::from(lead_id.try_into().unwrap());
  1097. // Set up category membership of moderator.
  1098. Module::<T>::update_category_membership_of_moderator(
  1099. RawOrigin::Signed(caller_id.clone()).into(), moderator_id, category_id, true
  1100. ).unwrap();
  1101. let mut category = Module::<T>::category_by_id(category_id);
  1102. let rationale = vec![0u8].repeat(k as usize);
  1103. }: moderate_thread(RawOrigin::Signed(caller_id), PrivilegedActor::Moderator(moderator_id), category_id, thread_id, rationale.clone())
  1104. verify {
  1105. // Thread balance was correctly slashed
  1106. let thread_account_id = T::ModuleId::get().into_sub_account(thread_id);
  1107. assert_eq!(
  1108. Balances::<T>::free_balance(&thread_account_id),
  1109. T::PostDeposit::get()
  1110. );
  1111. // Ensure category num_direct_threads updated successfully.
  1112. category.num_direct_threads-=1;
  1113. assert_eq!(Module::<T>::category_by_id(category_id), category);
  1114. // Ensure thread was successfully deleted
  1115. assert!(!<ThreadById<T>>::contains_key(category_id, thread_id));
  1116. assert_last_event::<T>(
  1117. RawEvent::ThreadModerated(
  1118. thread_id,
  1119. rationale,
  1120. PrivilegedActor::Moderator(moderator_id),
  1121. category_id
  1122. ).into()
  1123. );
  1124. }
  1125. add_post {
  1126. let forum_user_id = 0;
  1127. let caller_id =
  1128. insert_a_leader::<T>(forum_user_id);
  1129. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1130. let j in 0 .. MAX_BYTES;
  1131. let text = vec![0u8].repeat(j as usize);
  1132. // Generate categories tree
  1133. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1134. // Create thread
  1135. let thread_id = create_new_thread::<T>(
  1136. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  1137. vec![0u8].repeat(MAX_BYTES as usize), vec![0u8].repeat(MAX_BYTES as usize), None
  1138. );
  1139. let thread = Module::<T>::thread_by_id(category_id, thread_id);
  1140. let post_id = Module::<T>::next_post_id();
  1141. let initial_balance = Balances::<T>::usable_balance(&caller_id);
  1142. }: _ (RawOrigin::Signed(caller_id.clone()), forum_user_id.saturated_into(), category_id, thread_id, text.clone(), true)
  1143. verify {
  1144. assert_eq!(
  1145. Balances::<T>::usable_balance(&caller_id),
  1146. initial_balance - T::PostDeposit::get()
  1147. );
  1148. // Ensure initial post added successfully
  1149. let new_post = Post {
  1150. text_hash: T::calculate_hash(&text),
  1151. author_id: forum_user_id.saturated_into(),
  1152. thread_id,
  1153. last_edited: System::<T>::block_number(),
  1154. cleanup_pay_off: T::PostDeposit::get(),
  1155. };
  1156. assert_eq!(Module::<T>::post_by_id(thread_id, post_id), new_post);
  1157. assert_eq!(Module::<T>::next_post_id(), post_id + T::PostId::one());
  1158. assert_last_event::<T>(
  1159. RawEvent::PostAdded(
  1160. post_id,
  1161. forum_user_id.saturated_into(),
  1162. category_id,
  1163. thread_id,
  1164. text,
  1165. true,
  1166. ).into()
  1167. );
  1168. }
  1169. react_post {
  1170. let forum_user_id = 0;
  1171. let caller_id =
  1172. insert_a_leader::<T>(forum_user_id);
  1173. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1174. // Generate categories tree
  1175. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1176. // Create thread
  1177. let expiration_diff = 10u32.into();
  1178. let poll = Some(
  1179. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  1180. );
  1181. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1182. let thread_id = create_new_thread::<T>(
  1183. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  1184. text.clone(), text.clone(), poll
  1185. );
  1186. let post_id = add_thread_post::<T>(caller_id.clone(), forum_user_id.saturated_into(), category_id, thread_id, text);
  1187. let react = T::PostReactionId::one();
  1188. }: _ (RawOrigin::Signed(caller_id), forum_user_id.saturated_into(), category_id, thread_id, post_id, react)
  1189. verify {
  1190. assert_last_event::<T>(
  1191. RawEvent::PostReacted(
  1192. forum_user_id.saturated_into(),
  1193. post_id,
  1194. react,
  1195. category_id,
  1196. thread_id
  1197. ).into()
  1198. );
  1199. }
  1200. edit_post_text {
  1201. let forum_user_id = 0;
  1202. let caller_id =
  1203. insert_a_leader::<T>(forum_user_id);
  1204. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1205. let j in 0 .. MAX_BYTES;
  1206. // Generate categories tree
  1207. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1208. // Create thread
  1209. let expiration_diff = 10u32.into();
  1210. let poll = Some(
  1211. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  1212. );
  1213. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1214. let thread_id = create_new_thread::<T>(
  1215. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  1216. text.clone(), text.clone(), poll
  1217. );
  1218. let post_id = add_thread_post::<T>(caller_id.clone(), forum_user_id.saturated_into(), category_id, thread_id, text);
  1219. let mut post = Module::<T>::post_by_id(thread_id, post_id);
  1220. let new_text = vec![0u8].repeat(j as usize);
  1221. }: _ (RawOrigin::Signed(caller_id), forum_user_id.saturated_into(), category_id, thread_id, post_id, new_text.clone())
  1222. verify {
  1223. // Ensure post text updated successfully.
  1224. post.text_hash = T::calculate_hash(&new_text);
  1225. post.last_edited = System::<T>::block_number();
  1226. assert_eq!(
  1227. Module::<T>::post_by_id(thread_id, post_id),
  1228. post
  1229. );
  1230. assert_last_event::<T>(
  1231. RawEvent::PostTextUpdated(
  1232. post_id,
  1233. forum_user_id.saturated_into(),
  1234. category_id,
  1235. thread_id,
  1236. new_text
  1237. ).into()
  1238. );
  1239. }
  1240. moderate_post_lead {
  1241. let forum_user_id = 0;
  1242. let caller_id =
  1243. insert_a_leader::<T>(forum_user_id);
  1244. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1245. let j in 0 .. MAX_BYTES;
  1246. // Generate categories tree
  1247. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1248. // Create thread
  1249. let expiration_diff = 10u32.into();
  1250. let poll = Some(
  1251. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  1252. );
  1253. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1254. let thread_id = create_new_thread::<T>(
  1255. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  1256. text.clone(), text.clone(), poll
  1257. );
  1258. let post_id = add_thread_post::<T>(caller_id.clone(), forum_user_id.saturated_into(), category_id, thread_id, text);
  1259. let mut thread = Module::<T>::thread_by_id(category_id, thread_id);
  1260. let rationale = vec![0u8].repeat(j as usize);
  1261. }: moderate_post(RawOrigin::Signed(caller_id), PrivilegedActor::Lead, category_id, thread_id, post_id, rationale.clone())
  1262. verify {
  1263. thread.number_of_posts -= 1;
  1264. assert_eq!(Module::<T>::thread_by_id(category_id, thread_id), thread);
  1265. assert!(!<PostById<T>>::contains_key(thread_id, post_id));
  1266. assert_last_event::<T>(
  1267. RawEvent::PostModerated(
  1268. post_id,
  1269. rationale,
  1270. PrivilegedActor::Lead,
  1271. category_id,
  1272. thread_id
  1273. ).into()
  1274. );
  1275. }
  1276. moderate_post_moderator {
  1277. let forum_user_id = 0;
  1278. let caller_id =
  1279. insert_a_leader::<T>(forum_user_id);
  1280. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1281. let j in 0 .. MAX_BYTES;
  1282. // Generate categories tree
  1283. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1284. // Create thread
  1285. let expiration_diff = 10u32.into();
  1286. let poll = Some(
  1287. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  1288. );
  1289. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1290. let thread_id = create_new_thread::<T>(
  1291. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  1292. text.clone(), text.clone(), poll
  1293. );
  1294. let post_id = add_thread_post::<T>(caller_id.clone(), forum_user_id.saturated_into(), category_id, thread_id, text);
  1295. let mut thread = Module::<T>::thread_by_id(category_id, thread_id);
  1296. let moderator_id = ModeratorId::<T>::from(forum_user_id.try_into().unwrap());
  1297. // Set up category membership of moderator.
  1298. Module::<T>::update_category_membership_of_moderator(
  1299. RawOrigin::Signed(caller_id.clone()).into(), moderator_id, category_id, true
  1300. ).unwrap();
  1301. let rationale = vec![0u8].repeat(j as usize);
  1302. }: moderate_post(RawOrigin::Signed(caller_id), PrivilegedActor::Moderator(moderator_id), category_id, thread_id, post_id, rationale.clone())
  1303. verify {
  1304. thread.number_of_posts -= 1;
  1305. assert_eq!(Module::<T>::thread_by_id(category_id, thread_id), thread);
  1306. assert!(!<PostById<T>>::contains_key(thread_id, post_id));
  1307. assert_last_event::<T>(
  1308. RawEvent::PostModerated(
  1309. post_id,
  1310. rationale,
  1311. PrivilegedActor::Moderator(moderator_id),
  1312. category_id,
  1313. thread_id
  1314. ).into()
  1315. );
  1316. }
  1317. delete_posts {
  1318. let forum_user_id = 0;
  1319. let caller_id =
  1320. insert_a_leader::<T>(forum_user_id);
  1321. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1322. let j in 0 .. MAX_BYTES;
  1323. let k in 1 .. MAX_POSTS;
  1324. // Generate categories tree
  1325. let (category_id, _) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1326. // Create thread
  1327. let expiration_diff = 10u32.into();
  1328. let poll = Some(
  1329. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  1330. );
  1331. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1332. let thread_id = create_new_thread::<T>(
  1333. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  1334. text.clone(), text.clone(), poll
  1335. );
  1336. let hide = false;
  1337. let mut posts = BTreeMap::new();
  1338. for _ in 0 .. k {
  1339. posts.insert(
  1340. ExtendedPostIdObject {
  1341. category_id,
  1342. thread_id,
  1343. post_id: add_thread_post::<T>(
  1344. caller_id.clone(),
  1345. forum_user_id.saturated_into(),
  1346. category_id,
  1347. thread_id,
  1348. vec![0u8],
  1349. ),
  1350. },
  1351. hide
  1352. );
  1353. }
  1354. let post_id = add_thread_post::<T>(caller_id.clone(), forum_user_id.saturated_into(), category_id, thread_id, text);
  1355. let mut thread = Module::<T>::thread_by_id(category_id, thread_id);
  1356. let moderator_id = ModeratorId::<T>::from(forum_user_id.try_into().unwrap());
  1357. // Set up category membership of moderator.
  1358. Module::<T>::update_category_membership_of_moderator(
  1359. RawOrigin::Signed(caller_id.clone()).into(), moderator_id, category_id, true
  1360. ).unwrap();
  1361. let rationale = vec![0u8].repeat(j as usize);
  1362. }: _(
  1363. RawOrigin::Signed(caller_id),
  1364. forum_user_id.saturated_into(),
  1365. posts.clone(),
  1366. rationale.clone()
  1367. )
  1368. verify {
  1369. thread.number_of_posts -= k as u64;
  1370. assert_eq!(Module::<T>::thread_by_id(category_id, thread_id), thread);
  1371. for (extended_post, _) in &posts {
  1372. assert!(!<PostById<T>>::contains_key(extended_post.thread_id, extended_post.post_id));
  1373. }
  1374. assert_last_event::<T>(
  1375. RawEvent::PostDeleted(
  1376. rationale,
  1377. forum_user_id.saturated_into(),
  1378. posts,
  1379. ).into()
  1380. );
  1381. }
  1382. set_stickied_threads_lead {
  1383. let forum_user_id = 0;
  1384. let caller_id =
  1385. insert_a_leader::<T>(forum_user_id);
  1386. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1387. let j in 0 .. MAX_THREADS;
  1388. // Generate categories tree
  1389. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1390. // Create threads
  1391. let expiration_diff = 1010u32.into();
  1392. let poll = Some(
  1393. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  1394. );
  1395. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1396. let stickied_ids: Vec<T::ThreadId> = (0..j)
  1397. .into_iter()
  1398. .map(|_| create_new_thread::<T>(
  1399. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  1400. text.clone(), text.clone(), poll.clone()
  1401. )).collect();
  1402. let mut category = Module::<T>::category_by_id(category_id);
  1403. }: set_stickied_threads(RawOrigin::Signed(caller_id), PrivilegedActor::Lead, category_id, stickied_ids.clone())
  1404. verify {
  1405. // Ensure category stickied_ids updated successfully.
  1406. category.sticky_thread_ids = stickied_ids;
  1407. assert_eq!(Module::<T>::category_by_id(category_id), category);
  1408. assert_last_event::<T>(
  1409. RawEvent::CategoryStickyThreadUpdate(
  1410. category_id,
  1411. category.sticky_thread_ids,
  1412. PrivilegedActor::Lead
  1413. ).into()
  1414. );
  1415. }
  1416. set_stickied_threads_moderator {
  1417. let forum_user_id = 0;
  1418. let caller_id =
  1419. insert_a_leader::<T>(forum_user_id);
  1420. let i in 1 .. (T::MaxCategoryDepth::get() + 1) as u32;
  1421. let j in 0 .. MAX_THREADS;
  1422. // Generate categories tree
  1423. let (category_id, parent_category_id) = generate_categories_tree::<T>(caller_id.clone(), i, None);
  1424. // Create threads
  1425. let expiration_diff = 1010u32.into();
  1426. let poll = Some(
  1427. generate_poll_input::<T>(expiration_diff, (<<<T as Trait>::MapLimits as StorageLimits>::MaxPollAlternativesNumber>::get() - 1) as u32)
  1428. );
  1429. let text = vec![1u8].repeat(MAX_BYTES as usize);
  1430. let stickied_ids: Vec<T::ThreadId> = (0..j)
  1431. .into_iter()
  1432. .map(|_| create_new_thread::<T>(
  1433. caller_id.clone(), forum_user_id.saturated_into(), category_id,
  1434. text.clone(), text.clone(), poll.clone()
  1435. )).collect();
  1436. let moderator_id = ModeratorId::<T>::from(forum_user_id.try_into().unwrap());
  1437. // Set up category membership of moderator.
  1438. Module::<T>::update_category_membership_of_moderator(
  1439. RawOrigin::Signed(caller_id.clone()).into(), moderator_id, category_id, true
  1440. ).unwrap();
  1441. let mut category = Module::<T>::category_by_id(category_id);
  1442. }: set_stickied_threads(RawOrigin::Signed(caller_id), PrivilegedActor::Moderator(moderator_id), category_id, stickied_ids.clone())
  1443. verify {
  1444. // Ensure category stickied_ids updated successfully.
  1445. category.sticky_thread_ids = stickied_ids;
  1446. assert_eq!(Module::<T>::category_by_id(category_id), category);
  1447. assert_last_event::<T>(
  1448. RawEvent::CategoryStickyThreadUpdate(
  1449. category_id,
  1450. category.sticky_thread_ids,
  1451. PrivilegedActor::Moderator(moderator_id)
  1452. ).into()
  1453. );
  1454. }
  1455. }
  1456. #[cfg(test)]
  1457. mod tests {
  1458. use super::*;
  1459. use crate::mock::*;
  1460. use frame_support::assert_ok;
  1461. #[test]
  1462. fn test_create_category() {
  1463. with_test_externalities(|| {
  1464. assert_ok!(test_benchmark_create_category::<Runtime>());
  1465. });
  1466. }
  1467. #[test]
  1468. fn test_update_category_membership_of_moderator_new() {
  1469. with_test_externalities(|| {
  1470. assert_ok!(test_benchmark_update_category_membership_of_moderator_new::<Runtime>());
  1471. });
  1472. }
  1473. #[test]
  1474. fn test_update_category_membership_of_moderator_old() {
  1475. with_test_externalities(|| {
  1476. assert_ok!(test_benchmark_update_category_membership_of_moderator_old::<Runtime>());
  1477. });
  1478. }
  1479. #[test]
  1480. fn test_update_category_archival_status_lead() {
  1481. with_test_externalities(|| {
  1482. assert_ok!(test_benchmark_update_category_archival_status_lead::<Runtime>());
  1483. });
  1484. }
  1485. #[test]
  1486. fn test_update_category_archival_status_moderator() {
  1487. with_test_externalities(|| {
  1488. assert_ok!(test_benchmark_update_category_archival_status_moderator::<
  1489. Runtime,
  1490. >());
  1491. });
  1492. }
  1493. #[test]
  1494. fn test_delete_category_lead() {
  1495. with_test_externalities(|| {
  1496. assert_ok!(test_benchmark_delete_category_lead::<Runtime>());
  1497. });
  1498. }
  1499. #[test]
  1500. fn test_delete_category_moderator() {
  1501. with_test_externalities(|| {
  1502. assert_ok!(test_benchmark_delete_category_moderator::<Runtime>());
  1503. });
  1504. }
  1505. #[test]
  1506. fn test_create_thread() {
  1507. with_test_externalities(|| {
  1508. assert_ok!(test_benchmark_create_thread::<Runtime>());
  1509. });
  1510. }
  1511. #[test]
  1512. fn test_edit_thread_metadata() {
  1513. with_test_externalities(|| {
  1514. assert_ok!(test_benchmark_edit_thread_metadata::<Runtime>());
  1515. });
  1516. }
  1517. #[test]
  1518. fn test_delete_thread() {
  1519. with_test_externalities(|| {
  1520. assert_ok!(test_benchmark_delete_thread::<Runtime>());
  1521. });
  1522. }
  1523. #[test]
  1524. fn test_move_thread_to_category_lead() {
  1525. with_test_externalities(|| {
  1526. assert_ok!(test_benchmark_move_thread_to_category_lead::<Runtime>());
  1527. });
  1528. }
  1529. #[test]
  1530. fn test_move_thread_to_category_moderator() {
  1531. with_test_externalities(|| {
  1532. assert_ok!(test_benchmark_move_thread_to_category_moderator::<Runtime>());
  1533. });
  1534. }
  1535. #[test]
  1536. fn test_vote_on_poll() {
  1537. with_test_externalities(|| {
  1538. assert_ok!(test_benchmark_vote_on_poll::<Runtime>());
  1539. });
  1540. }
  1541. #[test]
  1542. fn test_moderate_thread_lead() {
  1543. with_test_externalities(|| {
  1544. assert_ok!(test_benchmark_moderate_thread_lead::<Runtime>());
  1545. });
  1546. }
  1547. #[test]
  1548. fn test_moderate_thread_moderator() {
  1549. with_test_externalities(|| {
  1550. assert_ok!(test_benchmark_moderate_thread_moderator::<Runtime>());
  1551. });
  1552. }
  1553. #[test]
  1554. fn test_add_post() {
  1555. with_test_externalities(|| {
  1556. assert_ok!(test_benchmark_add_post::<Runtime>());
  1557. });
  1558. }
  1559. #[test]
  1560. fn test_react_post() {
  1561. with_test_externalities(|| {
  1562. assert_ok!(test_benchmark_react_post::<Runtime>());
  1563. });
  1564. }
  1565. #[test]
  1566. fn test_edit_post_text() {
  1567. with_test_externalities(|| {
  1568. assert_ok!(test_benchmark_edit_post_text::<Runtime>());
  1569. });
  1570. }
  1571. #[test]
  1572. fn test_moderate_post_lead() {
  1573. with_test_externalities(|| {
  1574. assert_ok!(test_benchmark_moderate_post_lead::<Runtime>());
  1575. });
  1576. }
  1577. #[test]
  1578. fn test_moderate_post_moderator() {
  1579. with_test_externalities(|| {
  1580. assert_ok!(test_benchmark_moderate_post_moderator::<Runtime>());
  1581. });
  1582. }
  1583. #[test]
  1584. fn test_set_stickied_threads_moderator() {
  1585. with_test_externalities(|| {
  1586. assert_ok!(test_benchmark_set_stickied_threads_moderator::<Runtime>());
  1587. });
  1588. }
  1589. #[test]
  1590. fn test_set_stickied_threads_lead() {
  1591. with_test_externalities(|| {
  1592. assert_ok!(test_benchmark_set_stickied_threads_lead::<Runtime>());
  1593. });
  1594. }
  1595. #[test]
  1596. fn test_update_category_title_lead() {
  1597. with_test_externalities(|| {
  1598. assert_ok!(test_benchmark_update_category_title_lead::<Runtime>());
  1599. });
  1600. }
  1601. #[test]
  1602. fn test_update_category_title_moderator() {
  1603. with_test_externalities(|| {
  1604. assert_ok!(test_benchmark_update_category_title_moderator::<Runtime>());
  1605. });
  1606. }
  1607. #[test]
  1608. fn test_update_category_description_lead() {
  1609. with_test_externalities(|| {
  1610. assert_ok!(test_benchmark_update_category_description_lead::<Runtime>());
  1611. });
  1612. }
  1613. #[test]
  1614. fn test_update_category_description_moderator() {
  1615. with_test_externalities(|| {
  1616. assert_ok!(test_benchmark_update_category_description_moderator::<
  1617. Runtime,
  1618. >());
  1619. });
  1620. }
  1621. #[test]
  1622. fn test_delete_posts() {
  1623. with_test_externalities(|| {
  1624. assert_ok!(test_benchmark_delete_posts::<Runtime>());
  1625. });
  1626. }
  1627. }