瀏覽代碼

runtime: bounty: Add tests.

Shamil Gadelshin 4 年之前
父節點
當前提交
e6a2930982

+ 3 - 0
Cargo.lock

@@ -3744,6 +3744,9 @@ dependencies = [
  "parity-scale-codec",
  "serde",
  "sp-arithmetic",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
  "sp-std",
 ]
 

+ 6 - 0
runtime-modules/bounty/Cargo.toml

@@ -13,6 +13,12 @@ frame-support = { package = 'frame-support', default-features = false, git = 'ht
 frame-system = { package = 'frame-system', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 balances = { package = 'pallet-balances', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
 
+[dev-dependencies]
+sp-io = { package = 'sp-io', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+sp-core = { package = 'sp-core', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+sp-runtime = { package = 'sp-runtime', default-features = false, git = 'https://github.com/paritytech/substrate.git', rev = 'a200cdb93c6af5763b9c7bf313fa708764ac88ca'}
+
+
 [features]
 default = ['std']
 std = [

+ 6 - 4
runtime-modules/bounty/src/lib.rs

@@ -1,6 +1,9 @@
 // Ensure we're `no_std` when compiling for Wasm.
 #![cfg_attr(not(feature = "std"), no_std)]
 
+#[cfg(test)]
+pub(crate) mod tests;
+
 use frame_support::{decl_event, decl_module, decl_storage, Parameter};
 use frame_system::ensure_signed;
 use sp_arithmetic::traits::Zero;
@@ -88,9 +91,6 @@ decl_module! {
         fn create_bounty(origin, params: BountyCreationParameters<T::AccountId, BalanceOf<T>, T::BlockNumber>) {
             ensure_signed(origin)?;
 
-            // ensure!(!<balances::Module<T>>::total_balance(&sender).is_zero(), "account must have a balance");
-            // ensure!(memo.len() as u32 <= Self::max_memo_length(), "memo too long");
-
             let next_bounty_count_value = Self::bounty_count() + 1;
             let bounty_id = T::BountyId::from(next_bounty_count_value);
 
@@ -103,7 +103,9 @@ decl_module! {
             //
 
             <Bounties<T>>::insert(bounty_id, bounty);
-            BountyCount::mutate(|count| *count + 1);
+            BountyCount::mutate(|count| {
+                *count = *count + 1
+            });
             Self::deposit_event(RawEvent::BountyCreated(bounty_id));
         }
     }

+ 81 - 0
runtime-modules/bounty/src/tests/fixtures.rs

@@ -0,0 +1,81 @@
+use frame_support::dispatch::DispatchResult;
+use frame_support::storage::StorageMap;
+use frame_support::traits::{OnFinalize, OnInitialize};
+use frame_system::{EventRecord, Phase, RawOrigin};
+
+use super::mocks::{Bounty, System, Test, TestEvent};
+use crate::{BountyCreationParameters, RawEvent};
+
+// Recommendation from Parity on testing on_finalize
+// https://substrate.dev/docs/en/next/development/module/tests
+pub fn run_to_block(n: u64) {
+    while System::block_number() < n {
+        <System as OnFinalize<u64>>::on_finalize(System::block_number());
+        <Bounty as OnFinalize<u64>>::on_finalize(System::block_number());
+        System::set_block_number(System::block_number() + 1);
+        <System as OnInitialize<u64>>::on_initialize(System::block_number());
+        <Bounty as OnInitialize<u64>>::on_initialize(System::block_number());
+    }
+}
+
+pub struct EventFixture;
+impl EventFixture {
+    pub fn assert_last_crate_event(expected_raw_event: RawEvent<u64>) {
+        let converted_event = TestEvent::bounty(expected_raw_event);
+
+        Self::assert_last_global_event(converted_event)
+    }
+
+    pub fn assert_last_global_event(expected_event: TestEvent) {
+        let expected_event = EventRecord {
+            phase: Phase::Initialization,
+            event: expected_event,
+            topics: vec![],
+        };
+
+        assert_eq!(System::events().pop().unwrap(), expected_event);
+    }
+}
+
+pub struct CreateBountyFixture {
+    origin: RawOrigin<u64>,
+    metadata: Vec<u8>,
+}
+
+impl CreateBountyFixture {
+    pub fn default() -> Self {
+        Self {
+            origin: RawOrigin::Signed(1),
+            metadata: Vec::new(),
+        }
+    }
+    pub fn with_origin(self, origin: RawOrigin<u64>) -> Self {
+        Self { origin, ..self }
+    }
+
+    pub fn with_metadata(self, metadata: Vec<u8>) -> Self {
+        Self { metadata, ..self }
+    }
+
+    pub fn call_and_assert(&self, expected_result: DispatchResult) {
+        let params = BountyCreationParameters {
+            metadata: self.metadata.clone(),
+            ..BountyCreationParameters::default()
+        };
+
+        let next_bounty_count_value = Bounty::bounty_count() + 1;
+        let bounty_id: u64 = next_bounty_count_value.into();
+
+        let actual_result = Bounty::create_bounty(self.origin.clone().into(), params);
+
+        assert_eq!(actual_result, expected_result);
+
+        if actual_result.is_ok() {
+            assert_eq!(next_bounty_count_value, Bounty::bounty_count());
+            assert!(<crate::Bounties<Test>>::contains_key(&bounty_id));
+        } else {
+            assert_eq!(next_bounty_count_value - 1, Bounty::bounty_count());
+            assert!(!<crate::Bounties<Test>>::contains_key(&bounty_id));
+        }
+    }
+}

+ 94 - 0
runtime-modules/bounty/src/tests/mocks.rs

@@ -0,0 +1,94 @@
+#![cfg(test)]
+
+use crate::{Module, Trait};
+use frame_support::{impl_outer_event, impl_outer_origin, parameter_types};
+use sp_core::H256;
+use sp_runtime::{
+    testing::Header,
+    traits::{BlakeTwo256, IdentityLookup},
+    Perbill,
+};
+
+impl_outer_origin! {
+    pub enum Origin for Test {}
+}
+
+mod bounty {
+    pub use crate::Event;
+}
+
+impl_outer_event! {
+    pub enum TestEvent for Test {
+        bounty<T>,
+        frame_system<T>,
+        balances<T>,
+    }
+}
+
+// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted.
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct Test;
+parameter_types! {
+    pub const BlockHashCount: u64 = 250;
+    pub const MaximumBlockWeight: u32 = 1024;
+    pub const MaximumBlockLength: u32 = 2 * 1024;
+    pub const AvailableBlockRatio: Perbill = Perbill::one();
+}
+
+impl frame_system::Trait for Test {
+    type BaseCallFilter = ();
+    type Origin = Origin;
+    type Call = ();
+    type Index = u64;
+    type BlockNumber = u64;
+    type Hash = H256;
+    type Hashing = BlakeTwo256;
+    type AccountId = u64;
+    type Lookup = IdentityLookup<Self::AccountId>;
+    type Header = Header;
+    type Event = TestEvent;
+    type BlockHashCount = BlockHashCount;
+    type MaximumBlockWeight = MaximumBlockWeight;
+    type DbWeight = ();
+    type BlockExecutionWeight = ();
+    type ExtrinsicBaseWeight = ();
+    type MaximumExtrinsicWeight = ();
+    type MaximumBlockLength = MaximumBlockLength;
+    type AvailableBlockRatio = AvailableBlockRatio;
+    type Version = ();
+    type AccountData = balances::AccountData<u64>;
+    type OnNewAccount = ();
+    type OnKilledAccount = ();
+    type PalletInfo = ();
+    type SystemWeightInfo = ();
+}
+
+impl Trait for Test {
+    type Event = TestEvent;
+    type BountyId = u64;
+}
+
+parameter_types! {
+    pub const ExistentialDeposit: u32 = 0;
+}
+
+impl balances::Trait for Test {
+    type Balance = u64;
+    type DustRemoval = ();
+    type Event = TestEvent;
+    type ExistentialDeposit = ExistentialDeposit;
+    type AccountStore = System;
+    type WeightInfo = ();
+    type MaxLocks = ();
+}
+
+pub fn build_test_externalities() -> sp_io::TestExternalities {
+    let t = frame_system::GenesisConfig::default()
+        .build_storage::<Test>()
+        .unwrap();
+
+    t.into()
+}
+
+pub type System = frame_system::Module<Test>;
+pub type Bounty = Module<Test>;

+ 36 - 0
runtime-modules/bounty/src/tests/mod.rs

@@ -0,0 +1,36 @@
+#![cfg(test)]
+
+pub(crate) mod fixtures;
+pub(crate) mod mocks;
+
+use frame_system::RawOrigin;
+use sp_runtime::DispatchError;
+
+use crate::RawEvent;
+use fixtures::{run_to_block, CreateBountyFixture, EventFixture};
+use mocks::build_test_externalities;
+
+#[test]
+fn create_bounty_succeeds() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let text = b"Bounty text".to_vec();
+
+        let create_bounty_fixture = CreateBountyFixture::default().with_metadata(text);
+        create_bounty_fixture.call_and_assert(Ok(()));
+
+        let bounty_id = 1u64;
+
+        EventFixture::assert_last_crate_event(RawEvent::BountyCreated(bounty_id));
+    });
+}
+
+#[test]
+fn create_bounty_fails_with_invalid_origin() {
+    build_test_externalities().execute_with(|| {
+        let create_bounty_fixture = CreateBountyFixture::default().with_origin(RawOrigin::None);
+        create_bounty_fixture.call_and_assert(Err(DispatchError::BadOrigin));
+    });
+}