Browse Source

runtime: constitution: Add mocks and tests.

Shamil Gadelshin 4 years ago
parent
commit
4d3acab6d8

+ 2 - 0
Cargo.lock

@@ -3314,6 +3314,8 @@ dependencies = [
  "frame-system",
  "parity-scale-codec",
  "serde",
+ "sp-core",
+ "sp-io",
  "sp-runtime",
  "sp-std",
 ]

+ 5 - 0
runtime-modules/constitution/Cargo.toml

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

+ 4 - 1
runtime-modules/constitution/src/lib.rs

@@ -7,6 +7,9 @@
 // Ensure we're `no_std` when compiling for Wasm.
 #![cfg_attr(not(feature = "std"), no_std)]
 
+#[cfg(test)]
+mod tests;
+
 use codec::{Decode, Encode};
 use frame_support::{decl_event, decl_module, decl_storage};
 #[cfg(feature = "std")]
@@ -54,7 +57,7 @@ decl_module! {
         /// Sets the current constitution hash.It also sets the amendment number for the
         /// constitution and increment it for the next amendment. Requires root origin.
         #[weight = 10_000_000] // TODO: adjust weight
-        fn amend_contitution(origin, constitution_text: Vec<u8>) {
+        fn amend_constitution(origin, constitution_text: Vec<u8>) {
             ensure_root(origin)?;
 
             //

+ 77 - 0
runtime-modules/constitution/src/tests/mocks.rs

@@ -0,0 +1,77 @@
+#![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 constitution {
+    pub use crate::Event;
+}
+
+impl_outer_event! {
+    pub enum TestEvent for Test {
+        constitution,
+        system<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 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 ModuleToIndex = ();
+    type AccountData = ();
+    type OnNewAccount = ();
+    type OnKilledAccount = ();
+}
+
+impl Trait for Test {
+    type Event = TestEvent;
+}
+
+pub fn build_test_externalities() -> sp_io::TestExternalities {
+    let t = system::GenesisConfig::default()
+        .build_storage::<Test>()
+        .unwrap();
+
+    t.into()
+}
+
+pub type System = system::Module<Test>;
+pub type Constitution = Module<Test>;

+ 119 - 0
runtime-modules/constitution/src/tests/mod.rs

@@ -0,0 +1,119 @@
+#![cfg(test)]
+
+mod mocks;
+
+use crate::{ConstitutionInfo, Event};
+use frame_support::dispatch::DispatchResult;
+use frame_support::traits::{OnFinalize, OnInitialize};
+use mocks::{build_test_externalities, Constitution, System, Test, TestEvent};
+use sp_runtime::traits::Hash;
+use sp_runtime::DispatchError;
+use system::{EventRecord, Phase, RawOrigin};
+
+// Recommendation from Parity on testing on_finalize
+// https://substrate.dev/docs/en/next/development/module/tests
+fn run_to_block(n: u64) {
+    while System::block_number() < n {
+        <System as OnFinalize<u64>>::on_finalize(System::block_number());
+        <Constitution 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());
+        <Constitution as OnInitialize<u64>>::on_initialize(System::block_number());
+    }
+}
+
+pub struct EventFixture;
+impl EventFixture {
+    pub fn assert_last_crate_event(expected_raw_event: Event) {
+        let converted_event = TestEvent::constitution(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 AmendConstitutionFixture {
+    origin: RawOrigin<u64>,
+    text: Vec<u8>,
+}
+
+impl AmendConstitutionFixture {
+    pub fn default() -> Self {
+        Self {
+            origin: RawOrigin::Root,
+            text: Vec::new(),
+        }
+    }
+    pub fn with_origin(self, origin: RawOrigin<u64>) -> Self {
+        Self { origin, ..self }
+    }
+
+    pub fn with_text(self, text: Vec<u8>) -> Self {
+        Self { text, ..self }
+    }
+
+    pub fn call_and_assert(&self, expected_result: DispatchResult) {
+        let old_constitution = Constitution::constitution();
+        let old_next_amendment_number = Constitution::next_amendment_number();
+
+        let actual_result =
+            Constitution::amend_constitution(self.origin.clone().into(), self.text.clone());
+
+        assert_eq!(actual_result, expected_result);
+
+        let new_constitution = Constitution::constitution();
+        if actual_result.is_ok() {
+            let new_next_amendment_number = Constitution::next_amendment_number();
+            assert_eq!(new_next_amendment_number, old_next_amendment_number + 1);
+
+            let hashed = <Test as system::Trait>::Hashing::hash(&self.text);
+            let hash = hashed.as_ref().to_vec();
+
+            assert_eq!(
+                new_constitution,
+                ConstitutionInfo {
+                    text_hash: hash,
+                    amendment_number: old_next_amendment_number,
+                }
+            );
+        } else {
+            assert_eq!(old_constitution, new_constitution);
+        }
+    }
+}
+
+#[test]
+fn amend_contitution_succeeds() {
+    build_test_externalities().execute_with(|| {
+        let starting_block = 1;
+        run_to_block(starting_block);
+
+        let text = b"Constitution text".to_vec();
+
+        let hashed = <Test as system::Trait>::Hashing::hash(&text);
+        let hash = hashed.as_ref().to_vec();
+
+        let amend_constitution_fixture = AmendConstitutionFixture::default().with_text(text);
+        amend_constitution_fixture.call_and_assert(Ok(()));
+
+        EventFixture::assert_last_crate_event(Event::ConstutionAmended(hash, 0));
+    });
+}
+
+#[test]
+fn amend_contitution_fais_with_invalid_origin() {
+    build_test_externalities().execute_with(|| {
+        let amend_constitution_fixture =
+            AmendConstitutionFixture::default().with_origin(RawOrigin::None);
+        amend_constitution_fixture.call_and_assert(Err(DispatchError::BadOrigin));
+    });
+}