#![allow(clippy::deprecated_semver)]
use super::*;
use sp_io::{MultiRemovalResults, TestExternalities};
use sp_metadata_ir::{
PalletStorageMetadataIR, StorageEntryMetadataIR, StorageEntryModifierIR, StorageEntryTypeIR,
StorageHasherIR,
};
use sp_runtime::{generic, traits::BlakeTwo256, BuildStorage};
pub use self::frame_system::{pallet_prelude::*, Config, Pallet};
mod storage_alias;
#[pallet]
pub mod frame_system {
#[allow(unused)]
use super::{frame_system, frame_system::pallet_prelude::*};
pub use crate::dispatch::RawOrigin;
use crate::{pallet_prelude::*, traits::tasks::Task as TaskTrait};
pub mod config_preludes {
use super::{inject_runtime_type, DefaultConfig};
pub struct TestDefaultConfig;
#[crate::register_default_impl(TestDefaultConfig)]
impl DefaultConfig for TestDefaultConfig {
type AccountId = u64;
type BaseCallFilter = frame_support::traits::Everything;
#[inject_runtime_type]
type RuntimeOrigin = ();
#[inject_runtime_type]
type RuntimeCall = ();
#[inject_runtime_type]
type PalletInfo = ();
#[inject_runtime_type]
type RuntimeTask = ();
type DbWeight = ();
}
}
#[pallet::pallet]
pub struct Pallet<T>(_);
#[pallet::config(with_default, frame_system_config)]
#[pallet::disable_frame_system_supertrait_check]
pub trait Config: 'static {
#[pallet::no_default]
type Block: Parameter + sp_runtime::traits::Block;
type AccountId;
#[pallet::no_default_bounds]
type BaseCallFilter: crate::traits::Contains<Self::RuntimeCall>;
#[pallet::no_default_bounds]
type RuntimeOrigin;
#[pallet::no_default_bounds]
type RuntimeCall;
#[pallet::no_default_bounds]
type RuntimeTask: crate::traits::tasks::Task;
#[pallet::no_default_bounds]
type PalletInfo: crate::traits::PalletInfo;
type DbWeight: Get<crate::weights::RuntimeDbWeight>;
#[pallet::constant]
#[pallet::no_default]
#[deprecated = "this constant is deprecated"]
#[allow(deprecated)]
type ExampleConstant: Get<()>;
}
#[pallet::error]
pub enum Error<T> {
CallFiltered,
NotFound,
InvalidTask,
FailedTask,
}
#[pallet::origin]
pub type Origin<T> = RawOrigin<<T as Config>::AccountId>;
#[pallet::call]
impl<T: Config> Pallet<T> {
#[pallet::call_index(0)]
#[pallet::weight(task.weight())]
pub fn do_task(_origin: OriginFor<T>, task: T::RuntimeTask) -> DispatchResultWithPostInfo {
if !task.is_valid() {
return Err(Error::<T>::InvalidTask.into());
}
if let Err(_err) = task.run() {
return Err(Error::<T>::FailedTask.into());
}
Ok(().into())
}
}
#[pallet::storage]
#[deprecated]
#[allow(deprecated)]
pub type Data<T> = StorageMap<_, Twox64Concat, u32, u64, ValueQuery>;
#[pallet::storage]
#[deprecated(note = "test")]
#[allow(deprecated)]
pub type OptionLinkedMap<T> = StorageMap<_, Blake2_128Concat, u32, u32, OptionQuery>;
#[pallet::storage]
#[pallet::getter(fn generic_data)]
#[deprecated(note = "test", since = "test")]
#[allow(deprecated)]
pub type GenericData<T: Config> =
StorageMap<_, Identity, BlockNumberFor<T>, BlockNumberFor<T>, ValueQuery>;
#[pallet::storage]
#[pallet::getter(fn generic_data2)]
#[deprecated = "test"]
#[allow(deprecated)]
pub type GenericData2<T: Config> =
StorageMap<_, Blake2_128Concat, BlockNumberFor<T>, BlockNumberFor<T>, OptionQuery>;
#[pallet::storage]
pub type DataDM<T> =
StorageDoubleMap<_, Twox64Concat, u32, Blake2_128Concat, u32, u64, ValueQuery>;
#[pallet::storage]
pub type GenericDataDM<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
BlockNumberFor<T>,
Identity,
BlockNumberFor<T>,
BlockNumberFor<T>,
ValueQuery,
>;
#[pallet::storage]
pub type GenericData2DM<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
BlockNumberFor<T>,
Twox64Concat,
BlockNumberFor<T>,
BlockNumberFor<T>,
OptionQuery,
>;
#[pallet::storage]
#[pallet::unbounded]
pub type AppendableDM<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
u32,
Blake2_128Concat,
BlockNumberFor<T>,
Vec<u32>,
ValueQuery,
>;
#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
pub data: Vec<(u32, u64)>,
pub test_config: Vec<(u32, u32, u64)>,
#[serde(skip)]
pub _config: core::marker::PhantomData<T>,
}
impl<T: Config> Default for GenesisConfig<T> {
fn default() -> Self {
Self {
_config: Default::default(),
data: vec![(15u32, 42u64)],
test_config: vec![(15u32, 16u32, 42u64)],
}
}
}
#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
#[allow(deprecated)]
fn build(&self) {
for (k, v) in &self.data {
<Data<T>>::insert(k, v);
}
for (k1, k2, v) in &self.test_config {
<DataDM<T>>::insert(k1, k2, v);
}
}
}
#[pallet::storage]
pub type Total<T: Config> = StorageValue<_, (u32, u32), ValueQuery>;
#[pallet::storage]
pub type Numbers<T: Config> = StorageMap<_, Twox64Concat, u32, u32, OptionQuery>;
pub mod pallet_prelude {
pub type OriginFor<T> = <T as super::Config>::RuntimeOrigin;
pub type HeaderFor<T> =
<<T as super::Config>::Block as sp_runtime::traits::HeaderProvider>::HeaderT;
pub type BlockNumberFor<T> = <HeaderFor<T> as sp_runtime::traits::Header>::Number;
}
}
type BlockNumber = u32;
type AccountId = u32;
type Header = generic::Header<BlockNumber, BlakeTwo256>;
type UncheckedExtrinsic = generic::UncheckedExtrinsic<u32, RuntimeCall, (), ()>;
type Block = generic::Block<Header, UncheckedExtrinsic>;
#[crate::runtime]
mod runtime {
#[runtime::runtime]
#[runtime::derive(
RuntimeCall,
RuntimeEvent,
RuntimeError,
RuntimeOrigin,
RuntimeFreezeReason,
RuntimeHoldReason,
RuntimeSlashReason,
RuntimeLockId,
RuntimeTask,
RuntimeViewFunction
)]
pub struct Runtime;
#[runtime::pallet_index(0)]
pub type System = self::frame_system;
}
#[crate::derive_impl(self::frame_system::config_preludes::TestDefaultConfig as self::frame_system::DefaultConfig)]
impl Config for Runtime {
type Block = Block;
type AccountId = AccountId;
type ExampleConstant = ();
}
fn new_test_ext() -> TestExternalities {
RuntimeGenesisConfig::default().build_storage().unwrap().into()
}
trait Sorted {
fn sorted(self) -> Self;
}
impl<T: Ord> Sorted for Vec<T> {
fn sorted(mut self) -> Self {
self.sort();
self
}
}
#[test]
fn map_issue_3318() {
new_test_ext().execute_with(|| {
#[allow(deprecated)]
type OptionLinkedMap = self::frame_system::OptionLinkedMap<Runtime>;
OptionLinkedMap::insert(1, 1);
assert_eq!(OptionLinkedMap::get(1), Some(1));
OptionLinkedMap::insert(1, 2);
assert_eq!(OptionLinkedMap::get(1), Some(2));
});
}
#[test]
fn map_swap_works() {
new_test_ext().execute_with(|| {
#[allow(deprecated)]
type OptionLinkedMap = self::frame_system::OptionLinkedMap<Runtime>;
OptionLinkedMap::insert(0, 0);
OptionLinkedMap::insert(1, 1);
OptionLinkedMap::insert(2, 2);
OptionLinkedMap::insert(3, 3);
let collect = || OptionLinkedMap::iter().collect::<Vec<_>>().sorted();
assert_eq!(collect(), vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
OptionLinkedMap::swap(1, 2);
assert_eq!(collect(), vec![(0, 0), (1, 2), (2, 1), (3, 3)]);
OptionLinkedMap::swap(2, 1);
assert_eq!(collect(), vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
OptionLinkedMap::swap(2, 5);
assert_eq!(collect(), vec![(0, 0), (1, 1), (3, 3), (5, 2)]);
OptionLinkedMap::swap(5, 2);
assert_eq!(collect(), vec![(0, 0), (1, 1), (2, 2), (3, 3)]);
});
}
#[test]
fn double_map_swap_works() {
new_test_ext().execute_with(|| {
#[allow(deprecated)]
type DataDM = self::frame_system::DataDM<Runtime>;
DataDM::insert(0, 1, 1);
DataDM::insert(1, 0, 2);
DataDM::insert(1, 1, 3);
let get_all = || {
vec![
DataDM::get(0, 1),
DataDM::get(1, 0),
DataDM::get(1, 1),
DataDM::get(2, 0),
DataDM::get(2, 1),
]
};
assert_eq!(get_all(), vec![1, 2, 3, 0, 0]);
DataDM::swap(0, 1, 1, 0);
assert_eq!(get_all(), vec![2, 1, 3, 0, 0]);
DataDM::swap(1, 0, 2, 0);
assert_eq!(get_all(), vec![2, 0, 3, 1, 0]);
DataDM::swap(2, 1, 1, 1);
assert_eq!(get_all(), vec![2, 0, 0, 1, 3]);
});
}
#[test]
fn map_basic_insert_remove_should_work() {
new_test_ext().execute_with(|| {
#[allow(deprecated)]
type Map = self::frame_system::Data<Runtime>;
assert_eq!(Map::get(&15u32), 42u64);
let key = 17u32;
assert_eq!(Map::get(&key), 0u64);
Map::insert(key, 4u64);
assert_eq!(Map::get(&key), 4u64);
assert_eq!(Map::take(&key), 4u64);
assert_eq!(Map::get(&key), 0u64);
Map::mutate(&key, |val| {
*val = 15;
});
assert_eq!(Map::get(&key), 15u64);
Map::remove(&key);
assert_eq!(Map::get(&key), 0u64);
});
}
#[test]
fn map_iteration_should_work() {
new_test_ext().execute_with(|| {
#[allow(deprecated)]
type Map = self::frame_system::Data<Runtime>;
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(15, 42)]);
let key = 17u32;
Map::insert(key, 4u64);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(15, 42), (key, 4)]);
assert_eq!(Map::take(&15), 42u64);
assert_eq!(Map::take(&key), 4u64);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![]);
Map::insert(key, 42u64);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key, 42)]);
Map::insert(key + 1, 43u64);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key, 42), (key + 1, 43)]);
let key = key + 2;
Map::mutate(&key, |val| {
*val = 15;
});
assert_eq!(
Map::iter().collect::<Vec<_>>().sorted(),
vec![(key - 2, 42), (key - 1, 43), (key, 15)]
);
Map::mutate(&key, |val| {
*val = 17;
});
assert_eq!(
Map::iter().collect::<Vec<_>>().sorted(),
vec![(key - 2, 42), (key - 1, 43), (key, 17)]
);
Map::remove(&key);
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key - 2, 42), (key - 1, 43)]);
Map::remove(&(key - 2));
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![(key - 1, 43)]);
Map::remove(&(key - 1));
assert_eq!(Map::iter().collect::<Vec<_>>().sorted(), vec![]);
});
}
#[test]
fn double_map_basic_insert_remove_remove_prefix_with_commit_should_work() {
let key1 = 17u32;
let key2 = 18u32;
type DoubleMap = self::frame_system::DataDM<Runtime>;
let mut e = new_test_ext();
e.execute_with(|| {
assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64);
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
DoubleMap::insert(&key1, &key2, &4u64);
assert_eq!(DoubleMap::get(&key1, &key2), 4u64);
assert_eq!(DoubleMap::take(&key1, &key2), 4u64);
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
DoubleMap::mutate(&key1, &key2, |val| *val = 15);
assert_eq!(DoubleMap::get(&key1, &key2), 15u64);
DoubleMap::remove(&key1, &key2);
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
DoubleMap::insert(&key1, &key2, &4u64);
DoubleMap::insert(&key1, &(key2 + 1), &4u64);
DoubleMap::insert(&(key1 + 1), &key2, &4u64);
DoubleMap::insert(&(key1 + 1), &(key2 + 1), &4u64);
});
e.commit_all().unwrap();
e.execute_with(|| {
assert!(matches!(
DoubleMap::clear_prefix(&key1, u32::max_value(), None),
MultiRemovalResults { maybe_cursor: None, backend: 2, unique: 2, loops: 2 }
));
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
assert_eq!(DoubleMap::get(&key1, &(key2 + 1)), 0u64);
assert_eq!(DoubleMap::get(&(key1 + 1), &key2), 4u64);
assert_eq!(DoubleMap::get(&(key1 + 1), &(key2 + 1)), 4u64);
});
}
#[test]
fn double_map_basic_insert_remove_remove_prefix_should_work() {
new_test_ext().execute_with(|| {
let key1 = 17u32;
let key2 = 18u32;
type DoubleMap = self::frame_system::DataDM<Runtime>;
assert_eq!(DoubleMap::get(&15u32, &16u32), 42u64);
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
DoubleMap::insert(&key1, &key2, &4u64);
assert_eq!(DoubleMap::get(&key1, &key2), 4u64);
assert_eq!(DoubleMap::take(&key1, &key2), 4u64);
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
DoubleMap::mutate(&key1, &key2, |val| *val = 15);
assert_eq!(DoubleMap::get(&key1, &key2), 15u64);
DoubleMap::remove(&key1, &key2);
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
DoubleMap::insert(&key1, &key2, &4u64);
DoubleMap::insert(&key1, &(key2 + 1), &4u64);
DoubleMap::insert(&(key1 + 1), &key2, &4u64);
DoubleMap::insert(&(key1 + 1), &(key2 + 1), &4u64);
assert!(matches!(
DoubleMap::clear_prefix(&key1, u32::max_value(), None),
MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 }
));
assert!(matches!(
DoubleMap::clear_prefix(&key1, u32::max_value(), None),
MultiRemovalResults { maybe_cursor: None, backend: 0, unique: 0, loops: 0 }
));
assert_eq!(DoubleMap::get(&key1, &key2), 0u64);
assert_eq!(DoubleMap::get(&key1, &(key2 + 1)), 0u64);
assert_eq!(DoubleMap::get(&(key1 + 1), &key2), 4u64);
assert_eq!(DoubleMap::get(&(key1 + 1), &(key2 + 1)), 4u64);
});
}
#[test]
fn double_map_append_should_work() {
new_test_ext().execute_with(|| {
type DoubleMap = self::frame_system::AppendableDM<Runtime>;
let key1 = 17u32;
let key2 = 18u32;
DoubleMap::insert(&key1, &key2, &vec![1]);
DoubleMap::append(&key1, &key2, 2);
assert_eq!(DoubleMap::get(&key1, &key2), &[1, 2]);
});
}
#[test]
fn double_map_mutate_exists_should_work() {
new_test_ext().execute_with(|| {
type DoubleMap = self::frame_system::DataDM<Runtime>;
let (key1, key2) = (11, 13);
DoubleMap::mutate_exists(key1, key2, |v| *v = Some(1));
assert_eq!(DoubleMap::get(&key1, key2), 1);
DoubleMap::mutate_exists(key1, key2, |v| *v = None);
assert!(!DoubleMap::contains_key(&key1, key2));
});
}
#[test]
fn double_map_try_mutate_exists_should_work() {
new_test_ext().execute_with(|| {
type DoubleMap = self::frame_system::DataDM<Runtime>;
type TestResult = Result<(), &'static str>;
let (key1, key2) = (11, 13);
assert_ok!(DoubleMap::try_mutate_exists(key1, key2, |v| -> TestResult {
*v = Some(1);
Ok(())
}));
assert_eq!(DoubleMap::get(&key1, key2), 1);
assert_noop!(
DoubleMap::try_mutate_exists(key1, key2, |v| -> TestResult {
*v = Some(2);
Err("nah")
}),
"nah"
);
assert_ok!(DoubleMap::try_mutate_exists(key1, key2, |v| -> TestResult {
*v = None;
Ok(())
}));
assert!(!DoubleMap::contains_key(&key1, key2));
});
}
fn expected_metadata() -> PalletStorageMetadataIR {
PalletStorageMetadataIR {
prefix: "System",
entries: vec![
StorageEntryMetadataIR {
name: "Data",
modifier: StorageEntryModifierIR::Default,
ty: StorageEntryTypeIR::Map {
hashers: vec![StorageHasherIR::Twox64Concat],
key: scale_info::meta_type::<u32>(),
value: scale_info::meta_type::<u64>(),
},
default: vec![0, 0, 0, 0, 0, 0, 0, 0],
docs: vec![],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::DeprecatedWithoutNote,
},
StorageEntryMetadataIR {
name: "OptionLinkedMap",
modifier: StorageEntryModifierIR::Optional,
ty: StorageEntryTypeIR::Map {
hashers: vec![StorageHasherIR::Blake2_128Concat],
key: scale_info::meta_type::<u32>(),
value: scale_info::meta_type::<u32>(),
},
default: vec![0],
docs: vec![],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::Deprecated {
note: "test",
since: None,
},
},
StorageEntryMetadataIR {
name: "GenericData",
modifier: StorageEntryModifierIR::Default,
ty: StorageEntryTypeIR::Map {
hashers: vec![StorageHasherIR::Identity],
key: scale_info::meta_type::<u32>(),
value: scale_info::meta_type::<u32>(),
},
default: vec![0, 0, 0, 0],
docs: vec![],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::Deprecated {
note: "test",
since: Some("test"),
},
},
StorageEntryMetadataIR {
name: "GenericData2",
modifier: StorageEntryModifierIR::Optional,
ty: StorageEntryTypeIR::Map {
hashers: vec![StorageHasherIR::Blake2_128Concat],
key: scale_info::meta_type::<u32>(),
value: scale_info::meta_type::<u32>(),
},
default: vec![0],
docs: vec![],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::Deprecated {
note: "test",
since: None,
},
},
StorageEntryMetadataIR {
name: "DataDM",
modifier: StorageEntryModifierIR::Default,
ty: StorageEntryTypeIR::Map {
hashers: vec![StorageHasherIR::Twox64Concat, StorageHasherIR::Blake2_128Concat],
key: scale_info::meta_type::<(u32, u32)>(),
value: scale_info::meta_type::<u64>(),
},
default: vec![0, 0, 0, 0, 0, 0, 0, 0],
docs: vec![],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
},
StorageEntryMetadataIR {
name: "GenericDataDM",
modifier: StorageEntryModifierIR::Default,
ty: StorageEntryTypeIR::Map {
hashers: vec![StorageHasherIR::Blake2_128Concat, StorageHasherIR::Identity],
key: scale_info::meta_type::<(u32, u32)>(),
value: scale_info::meta_type::<u32>(),
},
default: vec![0, 0, 0, 0],
docs: vec![],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
},
StorageEntryMetadataIR {
name: "GenericData2DM",
modifier: StorageEntryModifierIR::Optional,
ty: StorageEntryTypeIR::Map {
hashers: vec![StorageHasherIR::Blake2_128Concat, StorageHasherIR::Twox64Concat],
key: scale_info::meta_type::<(u32, u32)>(),
value: scale_info::meta_type::<u32>(),
},
default: vec![0],
docs: vec![],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
},
StorageEntryMetadataIR {
name: "AppendableDM",
modifier: StorageEntryModifierIR::Default,
ty: StorageEntryTypeIR::Map {
hashers: vec![
StorageHasherIR::Blake2_128Concat,
StorageHasherIR::Blake2_128Concat,
],
key: scale_info::meta_type::<(u32, u32)>(),
value: scale_info::meta_type::<Vec<u32>>(),
},
default: vec![0],
docs: vec![],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
},
StorageEntryMetadataIR {
name: "Total",
modifier: StorageEntryModifierIR::Default,
ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<(u32, u32)>()),
default: vec![0, 0, 0, 0, 0, 0, 0, 0],
docs: vec![" Some running total."],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
},
StorageEntryMetadataIR {
name: "Numbers",
modifier: StorageEntryModifierIR::Optional,
ty: StorageEntryTypeIR::Map {
hashers: vec![StorageHasherIR::Twox64Concat],
key: scale_info::meta_type::<u32>(),
value: scale_info::meta_type::<u32>(),
},
default: vec![0],
docs: vec![" Numbers to be added into the total."],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
},
],
}
}
#[test]
fn store_metadata() {
let metadata = Pallet::<Runtime>::storage_metadata();
pretty_assertions::assert_eq!(expected_metadata(), metadata);
}
#[test]
fn constant_metadata() {
let metadata: Vec<sp_metadata_ir::PalletConstantMetadataIR> =
Pallet::<Runtime>::pallet_constants_metadata();
pretty_assertions::assert_eq!(
metadata,
vec![sp_metadata_ir::PalletConstantMetadataIR {
name: "ExampleConstant",
ty: scale_info::meta_type::<()>(),
value: vec![],
docs: vec![],
deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::Deprecated {
note: "this constant is deprecated",
since: None
}
},]
);
}
parameter_types! {
storage StorageParameter: u64 = 10;
}
#[test]
fn check_storage_parameter_type_works() {
TestExternalities::default().execute_with(|| {
assert_eq!(sp_io::hashing::twox_128(b":StorageParameter:"), StorageParameter::key());
assert_eq!(10, StorageParameter::get());
StorageParameter::set(&300);
assert_eq!(300, StorageParameter::get());
})
}
#[test]
fn derive_partial_eq_no_bound_core_mod() {
mod core {}
#[derive(
crate::PartialEqNoBound,
crate::CloneNoBound,
crate::DebugNoBound,
crate::DefaultNoBound,
crate::EqNoBound,
)]
#[allow(dead_code)]
struct Test;
}