From 76340e96a56fa197d9ee6203f2e9194556383471 Mon Sep 17 00:00:00 2001 From: Nikita Khateev Date: Thu, 19 Dec 2024 15:46:18 +0400 Subject: [PATCH] Add unit tests (#382) --- .gitignore | 2 + .../runtime/src/configs/asset_config.rs | 164 +++++++++++++++++ .../runtime/src/configs/governance/origins.rs | 169 ++++++++++++++++++ .../runtime/src/configs/governance/tracks.rs | 135 ++++++++++++++ generic-template/runtime/src/lib.rs | 24 +++ generic-template/runtime/src/types.rs | 63 +++++++ 6 files changed, 557 insertions(+) diff --git a/.gitignore b/.gitignore index 5eec1af6..5c161235 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ docs/build **/zombienet-linux-arm64 **/zombienet-linux-x64 **/bin-* + +coverage \ No newline at end of file diff --git a/generic-template/runtime/src/configs/asset_config.rs b/generic-template/runtime/src/configs/asset_config.rs index 65b98866..3c495e49 100644 --- a/generic-template/runtime/src/configs/asset_config.rs +++ b/generic-template/runtime/src/configs/asset_config.rs @@ -158,3 +158,167 @@ impl pallet_asset_manager::AssetRegistrar for AssetRegistrar { .weight } } + +#[cfg(test)] +mod tests { + mod asset_registrar { + use pallet_asset_manager::AssetRegistrar; + use sp_io::TestExternalities; + + use crate::{ + configs::{AssetRegistrar as Registrar, AssetRegistrarMetadata}, + types::AssetId, + AssetManager, Assets, Runtime, RuntimeOrigin, + }; + + #[test] + fn test_destroy_asset_dispatch_info_weight() { + let asset_id: AssetId = 1; + let _ = >::destroy_asset_dispatch_info_weight( + asset_id, + ); + } + + #[test] + fn test_destroy_foreign_asset() { + TestExternalities::default().execute_with(|| { + let asset_id: AssetId = 1; + let _ = Assets::force_create( + RuntimeOrigin::root(), + asset_id.into(), + sp_runtime::MultiAddress::Id(AssetManager::account_id()), + true, + 1, + ); + let res = >::destroy_foreign_asset(asset_id); + assert!(res.is_ok()); + }); + } + + #[test] + fn test_create_foreign_asset() { + TestExternalities::default().execute_with(|| { + let asset_id = 1; + let res = >::create_foreign_asset( + asset_id, + 1, + AssetRegistrarMetadata { + name: vec![0, 1, 2, 3], + symbol: vec![4, 5, 6, 7], + decimals: 6, + is_frozen: false, + }, + false, + ); + assert!(res.is_ok()); + }); + } + } + + mod account_asset_id_conversion { + use sp_runtime::AccountId32; + + use crate::{ + configs::{ + asset_config::FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, AccountIdAssetIdConversion, + }, + types::AssetId, + AccountId, Runtime, + }; + + #[test] + fn test_account_to_asset_id_success() { + let expected_asset_id: AssetId = 1; + let mut data = [0u8; 32]; + data[0..28].copy_from_slice(FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX); + data[28..32].copy_from_slice(&expected_asset_id.to_be_bytes()); + let account_id = AccountId::from(data); + let (prefix, asset_id) = Runtime::account_to_asset_id(account_id) + .expect("Account to asset id conversion failed"); + assert_eq!(prefix, FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX); + assert_eq!(asset_id, expected_asset_id); + } + + #[test] + fn test_account_to_asset_id_error() { + let expected_asset_id: AssetId = 1; + let mut data = [0u8; 32]; + data[0..27].copy_from_slice(&FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX[0..27]); + data[27..28].copy_from_slice(&[0]); + data[28..32].copy_from_slice(&expected_asset_id.to_be_bytes()); + let account_id = AccountId::from(data); + let res = Runtime::account_to_asset_id(account_id); + assert_eq!(res, None); + } + + #[test] + fn test_asset_id_to_account() { + let expected = AccountId32::new([ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 1, + ]); + let asset_id = 1; + let result = + Runtime::asset_id_to_account(FOREIGN_ASSET_PRECOMPILE_ADDRESS_PREFIX, asset_id); + assert_eq!(result, expected); + } + } + + mod asset_type { + use crate::{configs::AssetType, types::AssetId}; + + #[test] + fn test_asset_type_default() { + let default_asset_type = AssetType::default(); + assert_eq!( + default_asset_type, + AssetType::Xcm(xcm::v3::Location { + parents: 0, + interior: xcm::v3::Junctions::Here + }) + ); + } + + #[test] + fn test_asset_type_from_location_v3() { + let location = xcm::v3::Location { + parents: 0, + interior: xcm::v3::Junctions::X1(xcm::v3::Junction::OnlyChild), + }; + let asset_type = AssetType::from(location); + + assert_eq!(asset_type, AssetType::Xcm(location)); + } + + #[test] + fn test_asset_type_try_from_location_v4() { + let location = + xcm::latest::Location { parents: 0, interior: xcm::latest::Junctions::Here }; + let old_location: xcm::v3::Location = + xcm::v3::Location { parents: 0, interior: xcm::v3::Junctions::Here }; + let asset_type = AssetType::try_from(location) + .expect("AssetType conversion from location v4 failed"); + + assert_eq!(asset_type, AssetType::Xcm(old_location)); + } + + #[test] + fn test_asset_type_into_location() { + let location = xcm::v3::Location { parents: 0, interior: xcm::v3::Junctions::Here }; + let asset_type = AssetType::Xcm(location); + let converted: Option = asset_type.into(); + assert_eq!(converted, Some(location)); + } + + #[test] + fn test_asset_type_into_asset_id() { + let location = xcm::v3::Location { parents: 0, interior: xcm::v3::Junctions::Here }; + let expected_asset_id: u32 = 3068126878; + let asset_type = AssetType::Xcm(location); + + let asset_id = AssetId::from(asset_type); + + assert_eq!(asset_id, expected_asset_id); + } + } +} diff --git a/generic-template/runtime/src/configs/governance/origins.rs b/generic-template/runtime/src/configs/governance/origins.rs index 03b878cf..fa6c1bb0 100644 --- a/generic-template/runtime/src/configs/governance/origins.rs +++ b/generic-template/runtime/src/configs/governance/origins.rs @@ -113,3 +113,172 @@ pub mod pallet_custom_origins { } } } + +#[cfg(test)] +mod tests { + use frame_support::traits::EnsureOrigin; + + use crate::{ + configs::{governance::Spender, pallet_custom_origins::Origin}, + constants::currency::{CENTS, GRAND}, + Balance, + }; + + #[derive(Debug, PartialEq)] + enum TestOrigin { + SmallTipper, + SmallSpender, + Treasurer, + BigTipper, + MediumSpender, + BigSpender, + WhitelistedCaller, + ReferendumCanceller, + ReferendumKiller, + } + + impl From for Result { + fn from(value: TestOrigin) -> Self { + match value { + TestOrigin::SmallTipper => Ok(Origin::SmallTipper), + TestOrigin::SmallSpender => Ok(Origin::SmallSpender), + TestOrigin::Treasurer => Ok(Origin::Treasurer), + TestOrigin::ReferendumCanceller => Ok(Origin::ReferendumCanceller), + TestOrigin::ReferendumKiller => Ok(Origin::ReferendumKiller), + TestOrigin::BigTipper => Ok(Origin::BigTipper), + TestOrigin::MediumSpender => Ok(Origin::MediumSpender), + TestOrigin::BigSpender => Ok(Origin::BigSpender), + TestOrigin::WhitelistedCaller => Ok(Origin::WhitelistedCaller), + } + } + } + + impl From for TestOrigin { + fn from(value: Origin) -> Self { + match value { + Origin::SmallTipper => TestOrigin::SmallTipper, + Origin::SmallSpender => TestOrigin::SmallSpender, + Origin::Treasurer => TestOrigin::Treasurer, + Origin::ReferendumCanceller => TestOrigin::ReferendumCanceller, + Origin::ReferendumKiller => TestOrigin::ReferendumKiller, + Origin::BigTipper => TestOrigin::BigTipper, + Origin::MediumSpender => TestOrigin::MediumSpender, + Origin::BigSpender => TestOrigin::BigSpender, + Origin::WhitelistedCaller => TestOrigin::WhitelistedCaller, + } + } + } + mod spender { + use super::*; + + #[test] + fn test_small_tipper() { + let a: Balance = + Spender::try_origin(TestOrigin::SmallTipper).expect("SmallTipper misconfigured"); + assert_eq!(a, 250 * 3 * CENTS); + } + + #[test] + fn test_small_spender() { + let a: Balance = + Spender::try_origin(TestOrigin::SmallSpender).expect("SmallSpender misconfigured"); + assert_eq!(a, 10 * GRAND); + } + + #[test] + fn test_big_tipper() { + let a: Balance = + Spender::try_origin(TestOrigin::BigTipper).expect("BigTipper misconfigured"); + assert_eq!(a, GRAND); + } + + #[test] + fn test_medium_spender() { + let a: Balance = Spender::try_origin(TestOrigin::MediumSpender) + .expect("MediumSpender misconfigured"); + assert_eq!(a, 100 * GRAND); + } + + #[test] + fn test_big_spender() { + let a: Balance = + Spender::try_origin(TestOrigin::BigSpender).expect("BigSpender misconfigured"); + assert_eq!(a, 1_000 * GRAND); + } + + #[test] + fn test_treasurer() { + let a: Balance = + Spender::try_origin(TestOrigin::Treasurer).expect("Treasurer misconfigured"); + assert_eq!(a, 10_000 * GRAND); + } + + #[test] + fn test_referendum_killer() { + let a: TestOrigin = Spender::try_origin(TestOrigin::ReferendumKiller) + .expect_err("ReferendumKiller misconfigured"); + assert_eq!(a, TestOrigin::ReferendumKiller); + } + + #[test] + fn test_referendum_canceller() { + let a: TestOrigin = Spender::try_origin(TestOrigin::ReferendumCanceller) + .expect_err("ReferendumCanceller misconfigured"); + assert_eq!(a, TestOrigin::ReferendumCanceller); + } + + #[test] + fn test_whitelisted_caller() { + let a: TestOrigin = Spender::try_origin(TestOrigin::WhitelistedCaller) + .expect_err("WhitelistedCaller misconfigured"); + assert_eq!(a, TestOrigin::WhitelistedCaller); + } + + #[test] + #[cfg(feature = "runtime-benchmarks")] + fn test_try_successful_origin() { + let a: TestOrigin = Spender::try_successful_origin().expect("incorrect setup"); + assert_eq!(a, TestOrigin::Treasurer); + } + } + + mod treasurer { + use super::*; + use crate::configs::pallet_custom_origins::Treasurer; + + #[test] + pub fn test_treasurer_try_origin() { + let () = Treasurer::try_origin(TestOrigin::Treasurer).expect("incorrect configuration"); + let a = Treasurer::try_origin(TestOrigin::MediumSpender).expect_err("should be err"); + assert_eq!(a, TestOrigin::MediumSpender) + } + + #[test] + #[cfg(feature = "runtime-benchmarks")] + fn test_treasurer_try_successful_origin() { + let a: Result = Treasurer::try_successful_origin(); + assert_eq!(a, Ok(TestOrigin::Treasurer)); + } + } + + mod referendum_canceller { + use super::*; + use crate::configs::pallet_custom_origins::ReferendumCanceller; + + #[test] + pub fn test_referendum_canceller_try_origin() { + let () = ReferendumCanceller::try_origin(TestOrigin::ReferendumCanceller) + .expect("incorrect configuration"); + let a = ReferendumCanceller::try_origin(TestOrigin::MediumSpender) + .expect_err("should be err"); + assert_eq!(a, TestOrigin::MediumSpender) + } + + #[test] + #[cfg(feature = "runtime-benchmarks")] + fn test_treasurer_try_successful_origin() { + let a: Result = ReferendumCanceller::try_successful_origin(); + assert_eq!(a, Ok(TestOrigin::ReferendumCanceller)); + } + } +} diff --git a/generic-template/runtime/src/configs/governance/tracks.rs b/generic-template/runtime/src/configs/governance/tracks.rs index 3ec4b6e8..57b0e9d7 100644 --- a/generic-template/runtime/src/configs/governance/tracks.rs +++ b/generic-template/runtime/src/configs/governance/tracks.rs @@ -212,3 +212,138 @@ impl pallet_referenda::TracksInfo for TracksInfo { } } pallet_referenda::impl_tracksinfo_get!(TracksInfo, Balance, BlockNumber); + +#[cfg(test)] +mod tests { + use super::origins; + use crate::{Balance, BlockNumber, OriginCaller}; + + #[test] + fn test_track_system_origin() { + let track = + >::track_for(&OriginCaller::system(frame_system::RawOrigin::Root)) + .expect("incorrect config"); + assert_eq!(track, 0); + } + + #[test] + fn test_track_system_origin_error() { + let () = >::track_for(&OriginCaller::system(frame_system::RawOrigin::None)) + .expect_err("incorrect config"); + } + + #[test] + fn test_track_custom_origin_whitelisted_caller() { + let track = + >::track_for(&OriginCaller::Origins(origins::Origin::WhitelistedCaller)) + .expect("incorrect config"); + assert_eq!(track, 1); + } + + #[test] + fn test_track_custom_origin_treasurer() { + let track = + >::track_for(&OriginCaller::Origins(origins::Origin::Treasurer)) + .expect("incorrect config"); + assert_eq!(track, 11); + } + + #[test] + fn test_track_custom_origin_referendum_canceller() { + let track = + >::track_for(&OriginCaller::Origins(origins::Origin::ReferendumCanceller)) + .expect("incorrect config"); + assert_eq!(track, 20); + } + + #[test] + fn test_track_custom_origin_referendum_killer() { + let track = + >::track_for(&OriginCaller::Origins(origins::Origin::ReferendumKiller)) + .expect("incorrect config"); + assert_eq!(track, 21); + } + + #[test] + fn test_track_custom_origin_small_tipper() { + let track = + >::track_for(&OriginCaller::Origins(origins::Origin::SmallTipper)) + .expect("incorrect config"); + assert_eq!(track, 30); + } + + #[test] + fn test_track_custom_origin_big_tipper() { + let track = + >::track_for(&OriginCaller::Origins(origins::Origin::BigTipper)) + .expect("incorrect config"); + assert_eq!(track, 31); + } + + #[test] + fn test_track_custom_origin_small_spender() { + let track = + >::track_for(&OriginCaller::Origins(origins::Origin::SmallSpender)) + .expect("incorrect config"); + assert_eq!(track, 32); + } + + #[test] + fn test_track_custom_origin_medium_spender() { + let track = + >::track_for(&OriginCaller::Origins(origins::Origin::MediumSpender)) + .expect("incorrect config"); + assert_eq!(track, 33); + } + + #[test] + fn test_track_custom_origin_big_spender() { + let track = + >::track_for(&OriginCaller::Origins(origins::Origin::BigSpender)) + .expect("incorrect config"); + assert_eq!(track, 34); + } + + #[test] + fn test_track_error() { + let () = + >::track_for(&OriginCaller::CumulusXcm(cumulus_pallet_xcm::Origin::Relay)) + .expect_err("incorrect config"); + } +} diff --git a/generic-template/runtime/src/lib.rs b/generic-template/runtime/src/lib.rs index 71a743ab..c5de0281 100644 --- a/generic-template/runtime/src/lib.rs +++ b/generic-template/runtime/src/lib.rs @@ -124,5 +124,29 @@ mod runtime { struct Governance; } +#[cfg(test)] +mod test { + use frame_support::weights::WeightToFeePolynomial; + + use crate::{ + constants::{POLY_DEGREE, VERSION}, + native_version, WeightToFee, + }; + + #[test] + fn test_native_version() { + let version = native_version(); + assert_eq!(version.runtime_version, VERSION); + } + + #[test] + fn test_weight_to_fee() { + let mut fee = WeightToFee::polynomial(); + let coef = fee.pop().expect("no coef"); + assert!(!coef.negative); + assert_eq!(coef.degree, POLY_DEGREE); + } +} + #[cfg(feature = "runtime-benchmarks")] mod benchmark; diff --git a/generic-template/runtime/src/types.rs b/generic-template/runtime/src/types.rs index ac31594a..c58bbe6f 100644 --- a/generic-template/runtime/src/types.rs +++ b/generic-template/runtime/src/types.rs @@ -193,3 +193,66 @@ parameter_types! { pub TreasuryInteriorLocation: InteriorLocation = PalletInstance(13).into(); pub MessageQueueServiceWeight: Weight = Perbill::from_percent(35) * RuntimeBlockWeights::get().max_block; } + +#[cfg(test)] +mod test { + mod filter { + use frame_support::traits::InstanceFilter; + use sp_core::H256; + + use crate::{types::ProxyType, AssetManager, RuntimeCall}; + + #[test] + fn test_filter_any() { + let call = RuntimeCall::CollatorSelection( + pallet_collator_selection::Call::set_desired_candidates { max: 10 }, + ); + let proxy_type = ProxyType::Any; + assert!(proxy_type.filter(&call)); + } + + #[test] + fn test_filter_nontransfer() { + let proxy_type = ProxyType::NonTransfer; + let valid_call = RuntimeCall::CollatorSelection( + pallet_collator_selection::Call::set_desired_candidates { max: 10 }, + ); + assert!(proxy_type.filter(&valid_call)); + let invalid_call = + RuntimeCall::Balances(pallet_balances::Call::burn { value: 1, keep_alive: true }); + assert!(!proxy_type.filter(&invalid_call)); + } + + #[test] + fn test_filter_cancel_proxy() { + let proxy_type = ProxyType::CancelProxy; + let invalid_call = RuntimeCall::CollatorSelection( + pallet_collator_selection::Call::set_desired_candidates { max: 10 }, + ); + assert!(!proxy_type.filter(&invalid_call)); + let valid_call = RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { + delegate: sp_runtime::MultiAddress::Id(AssetManager::account_id()), + call_hash: H256::zero(), + }); + assert!(proxy_type.filter(&valid_call)); + } + + #[test] + fn test_filter_collator() { + let proxy_type = ProxyType::Collator; + let valid_call = RuntimeCall::CollatorSelection( + pallet_collator_selection::Call::set_desired_candidates { max: 10 }, + ); + assert!(proxy_type.filter(&valid_call)); + let invalid_call = + RuntimeCall::Balances(pallet_balances::Call::burn { value: 1, keep_alive: true }); + assert!(!proxy_type.filter(&invalid_call)); + } + + #[test] + fn test_filter_default() { + let expected = ProxyType::Any; + assert_eq!(expected, ProxyType::default()); + } + } +}