From e5751557a7b32afd5348a5923f709976be4996c8 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 15 Jun 2022 14:36:55 +0100 Subject: [PATCH 01/10] move test crates into a testing folder and add a ui test and helpers --- Cargo.toml | 5 +- testing/integration-tests/Cargo.toml | 33 ++ testing/integration-tests/src/client/mod.rs | 230 ++++++++++++ .../integration-tests}/src/codegen/mod.rs | 0 .../src/codegen/polkadot.rs | 0 .../integration-tests}/src/events/mod.rs | 0 .../integration-tests}/src/frame/balances.rs | 0 .../integration-tests}/src/frame/contracts.rs | 0 .../integration-tests}/src/frame/mod.rs | 0 .../integration-tests}/src/frame/staking.rs | 0 .../integration-tests}/src/frame/sudo.rs | 0 .../integration-tests}/src/frame/system.rs | 0 .../integration-tests}/src/frame/timestamp.rs | 0 testing/integration-tests/src/lib.rs | 38 ++ .../integration-tests}/src/metadata/mod.rs | 0 .../src/metadata/validation.rs | 340 ++++++++++++++++++ .../integration-tests}/src/storage/mod.rs | 0 .../integration-tests}/src/utils/context.rs | 0 .../integration-tests}/src/utils/mod.rs | 0 .../integration-tests}/src/utils/node_proc.rs | 0 .../test-runtime}/Cargo.toml | 4 +- .../test-runtime}/README.md | 0 .../test-runtime}/build.rs | 0 .../test-runtime}/src/lib.rs | 0 testing/ui-tests/Cargo.toml | 15 + testing/ui-tests/src/lib.rs | 19 + testing/ui-tests/src/storage.rs | 78 ++++ testing/ui-tests/src/utils/dispatch_error.rs | 41 +++ .../src/utils/metadata_test_runner.rs | 81 +++++ testing/ui-tests/src/utils/mod.rs | 65 ++++ 30 files changed, 945 insertions(+), 4 deletions(-) create mode 100644 testing/integration-tests/Cargo.toml create mode 100644 testing/integration-tests/src/client/mod.rs rename {integration-tests => testing/integration-tests}/src/codegen/mod.rs (100%) rename {integration-tests => testing/integration-tests}/src/codegen/polkadot.rs (100%) rename {integration-tests => testing/integration-tests}/src/events/mod.rs (100%) rename {integration-tests => testing/integration-tests}/src/frame/balances.rs (100%) rename {integration-tests => testing/integration-tests}/src/frame/contracts.rs (100%) rename {integration-tests => testing/integration-tests}/src/frame/mod.rs (100%) rename {integration-tests => testing/integration-tests}/src/frame/staking.rs (100%) rename {integration-tests => testing/integration-tests}/src/frame/sudo.rs (100%) rename {integration-tests => testing/integration-tests}/src/frame/system.rs (100%) rename {integration-tests => testing/integration-tests}/src/frame/timestamp.rs (100%) create mode 100644 testing/integration-tests/src/lib.rs rename {integration-tests => testing/integration-tests}/src/metadata/mod.rs (100%) create mode 100644 testing/integration-tests/src/metadata/validation.rs rename {integration-tests => testing/integration-tests}/src/storage/mod.rs (100%) rename {integration-tests => testing/integration-tests}/src/utils/context.rs (100%) rename {integration-tests => testing/integration-tests}/src/utils/mod.rs (100%) rename {integration-tests => testing/integration-tests}/src/utils/node_proc.rs (100%) rename {test-runtime => testing/test-runtime}/Cargo.toml (84%) rename {test-runtime => testing/test-runtime}/README.md (100%) rename {test-runtime => testing/test-runtime}/build.rs (100%) rename {test-runtime => testing/test-runtime}/src/lib.rs (100%) create mode 100644 testing/ui-tests/Cargo.toml create mode 100644 testing/ui-tests/src/lib.rs create mode 100644 testing/ui-tests/src/storage.rs create mode 100644 testing/ui-tests/src/utils/dispatch_error.rs create mode 100644 testing/ui-tests/src/utils/metadata_test_runner.rs create mode 100644 testing/ui-tests/src/utils/mod.rs diff --git a/Cargo.toml b/Cargo.toml index c40d47f125..f69ba5d891 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,9 +4,10 @@ members = [ "cli", "codegen", "examples", - "integration-tests", + "testing/test-runtime", + "testing/integration-tests", + "testing/ui-tests", "macro", "metadata", "subxt", - "test-runtime" ] diff --git a/testing/integration-tests/Cargo.toml b/testing/integration-tests/Cargo.toml new file mode 100644 index 0000000000..a8a50c96d8 --- /dev/null +++ b/testing/integration-tests/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "subxt-integration" +version = "0.21.0" +authors = ["Parity Technologies "] +edition = "2021" + +license = "GPL-3.0" +readme = "../README.md" +repository = "https://github.com/paritytech/subxt" +documentation = "https://docs.rs/subxt" +homepage = "https://www.parity.io/" +description = "Subxt integration tests that rely on the Substrate binary" + +[features] +default = ["subxt/integration-tests"] + +[dev-dependencies] +assert_matches = "1.5.0" +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "full", "bit-vec"] } +frame-metadata = "15.0.0" +futures = "0.3.13" +hex = "0.4.3" +scale-info = { version = "2.0.0", features = ["bit-vec"] } +sp-core = { version = "6.0.0", default-features = false } +sp-keyring = "6.0.0" +sp-runtime = "6.0.0" +subxt = { version = "0.21.0", path = "../../subxt" } +test-runtime = { path = "../test-runtime" } +tokio = { version = "1.8", features = ["macros", "time"] } +tracing = "0.1.34" +tracing-subscriber = "0.3.11" +wabt = "0.10.0" +which = "4.0.2" diff --git a/testing/integration-tests/src/client/mod.rs b/testing/integration-tests/src/client/mod.rs new file mode 100644 index 0000000000..657ec56bb3 --- /dev/null +++ b/testing/integration-tests/src/client/mod.rs @@ -0,0 +1,230 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . + +use crate::{ + test_node_process, + test_node_process_with, + utils::{ + node_runtime::system, + pair_signer, + test_context, + }, +}; + +use sp_core::{ + sr25519::Pair, + storage::{ + well_known_keys, + StorageKey, + }, + Pair as _, +}; +use sp_keyring::AccountKeyring; +use sp_runtime::DispatchOutcome; +use subxt::Error; + +#[tokio::test] +async fn insert_key() { + let test_node_process = test_node_process_with(AccountKeyring::Bob).await; + let client = test_node_process.client(); + let public = AccountKeyring::Alice.public().as_array_ref().to_vec(); + client + .rpc() + .insert_key( + "aura".to_string(), + "//Alice".to_string(), + public.clone().into(), + ) + .await + .unwrap(); + assert!(client + .rpc() + .has_key(public.clone().into(), "aura".to_string()) + .await + .unwrap()); +} + +#[tokio::test] +async fn fetch_block_hash() { + let node_process = test_node_process().await; + node_process.client().rpc().block_hash(None).await.unwrap(); +} + +#[tokio::test] +async fn fetch_block() { + let node_process = test_node_process().await; + let client = node_process.client(); + let block_hash = client.rpc().block_hash(None).await.unwrap(); + client.rpc().block(block_hash).await.unwrap(); +} + +#[tokio::test] +async fn fetch_read_proof() { + let node_process = test_node_process().await; + let client = node_process.client(); + let block_hash = client.rpc().block_hash(None).await.unwrap(); + client + .rpc() + .read_proof( + vec![ + StorageKey(well_known_keys::HEAP_PAGES.to_vec()), + StorageKey(well_known_keys::EXTRINSIC_INDEX.to_vec()), + ], + block_hash, + ) + .await + .unwrap(); +} + +#[tokio::test] +async fn chain_subscribe_blocks() { + let node_process = test_node_process().await; + let client = node_process.client(); + let mut blocks = client.rpc().subscribe_blocks().await.unwrap(); + blocks.next().await.unwrap().unwrap(); +} + +#[tokio::test] +async fn chain_subscribe_finalized_blocks() { + let node_process = test_node_process().await; + let client = node_process.client(); + let mut blocks = client.rpc().subscribe_finalized_blocks().await.unwrap(); + blocks.next().await.unwrap().unwrap(); +} + +#[tokio::test] +async fn fetch_keys() { + let node_process = test_node_process().await; + let client = node_process.client(); + let keys = client + .storage() + .fetch_keys::(4, None, None) + .await + .unwrap(); + assert_eq!(keys.len(), 4) +} + +#[tokio::test] +async fn test_iter() { + let node_process = test_node_process().await; + let client = node_process.client(); + let mut iter = client + .storage() + .iter::(None) + .await + .unwrap(); + let mut i = 0; + while iter.next().await.unwrap().is_some() { + i += 1; + } + assert_eq!(i, 13); +} + +#[tokio::test] +async fn fetch_system_info() { + let node_process = test_node_process().await; + let client = node_process.client(); + assert_eq!(client.rpc().system_chain().await.unwrap(), "Development"); + assert_eq!(client.rpc().system_name().await.unwrap(), "Substrate Node"); + assert!(!client.rpc().system_version().await.unwrap().is_empty()); +} + +#[tokio::test] +async fn dry_run_passes() { + let node_process = test_node_process().await; + let client = node_process.client(); + + let alice = pair_signer(AccountKeyring::Alice.pair()); + let bob = pair_signer(AccountKeyring::Bob.pair()); + let bob_address = bob.account_id().clone().into(); + let cxt = test_context().await; + let api = &cxt.api; + + let signed_extrinsic = api + .tx() + .balances() + .transfer(bob_address, 10_000) + .unwrap() + .create_signed(&alice, Default::default()) + .await + .unwrap(); + + client + .rpc() + .dry_run(&signed_extrinsic, None) + .await + .expect("dryrunning failed") + .expect("expected dryrunning to be successful") + .unwrap(); + signed_extrinsic + .submit_and_watch() + .await + .unwrap() + .wait_for_finalized_success() + .await + .unwrap(); +} + +#[tokio::test] +async fn dry_run_fails() { + let node_process = test_node_process().await; + let client = node_process.client(); + + let alice = pair_signer(AccountKeyring::Alice.pair()); + let hans = pair_signer(Pair::generate().0); + let hans_address = hans.account_id().clone().into(); + let cxt = test_context().await; + let api = &cxt.api; + + let signed_extrinsic = api + .tx() + .balances() + .transfer( + hans_address, + 100_000_000_000_000_000_000_000_000_000_000_000, + ) + .unwrap() + .create_signed(&alice, Default::default()) + .await + .unwrap(); + + let dry_run_res: DispatchOutcome = client + .rpc() + .dry_run(&signed_extrinsic, None) + .await + .expect("dryrunning failed") + .expect("expected dryrun transaction to be valid"); + if let Err(sp_runtime::DispatchError::Module(module_error)) = dry_run_res { + assert_eq!(module_error.index, 6); + assert_eq!(module_error.error, 2); + } else { + panic!("expected a module error when dryrunning"); + } + + let res = signed_extrinsic + .submit_and_watch() + .await + .unwrap() + .wait_for_finalized_success() + .await; + + if let Err(Error::Module(err)) = res { + assert_eq!(err.pallet, "Balances"); + assert_eq!(err.error, "InsufficientBalance"); + } else { + panic!("expected a runtime module error"); + } +} diff --git a/integration-tests/src/codegen/mod.rs b/testing/integration-tests/src/codegen/mod.rs similarity index 100% rename from integration-tests/src/codegen/mod.rs rename to testing/integration-tests/src/codegen/mod.rs diff --git a/integration-tests/src/codegen/polkadot.rs b/testing/integration-tests/src/codegen/polkadot.rs similarity index 100% rename from integration-tests/src/codegen/polkadot.rs rename to testing/integration-tests/src/codegen/polkadot.rs diff --git a/integration-tests/src/events/mod.rs b/testing/integration-tests/src/events/mod.rs similarity index 100% rename from integration-tests/src/events/mod.rs rename to testing/integration-tests/src/events/mod.rs diff --git a/integration-tests/src/frame/balances.rs b/testing/integration-tests/src/frame/balances.rs similarity index 100% rename from integration-tests/src/frame/balances.rs rename to testing/integration-tests/src/frame/balances.rs diff --git a/integration-tests/src/frame/contracts.rs b/testing/integration-tests/src/frame/contracts.rs similarity index 100% rename from integration-tests/src/frame/contracts.rs rename to testing/integration-tests/src/frame/contracts.rs diff --git a/integration-tests/src/frame/mod.rs b/testing/integration-tests/src/frame/mod.rs similarity index 100% rename from integration-tests/src/frame/mod.rs rename to testing/integration-tests/src/frame/mod.rs diff --git a/integration-tests/src/frame/staking.rs b/testing/integration-tests/src/frame/staking.rs similarity index 100% rename from integration-tests/src/frame/staking.rs rename to testing/integration-tests/src/frame/staking.rs diff --git a/integration-tests/src/frame/sudo.rs b/testing/integration-tests/src/frame/sudo.rs similarity index 100% rename from integration-tests/src/frame/sudo.rs rename to testing/integration-tests/src/frame/sudo.rs diff --git a/integration-tests/src/frame/system.rs b/testing/integration-tests/src/frame/system.rs similarity index 100% rename from integration-tests/src/frame/system.rs rename to testing/integration-tests/src/frame/system.rs diff --git a/integration-tests/src/frame/timestamp.rs b/testing/integration-tests/src/frame/timestamp.rs similarity index 100% rename from integration-tests/src/frame/timestamp.rs rename to testing/integration-tests/src/frame/timestamp.rs diff --git a/testing/integration-tests/src/lib.rs b/testing/integration-tests/src/lib.rs new file mode 100644 index 0000000000..64c30c83eb --- /dev/null +++ b/testing/integration-tests/src/lib.rs @@ -0,0 +1,38 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . + +#![deny(unused_crate_dependencies)] + +#[cfg(test)] +mod codegen; +#[cfg(test)] +mod utils; + +#[cfg(test)] +mod client; +#[cfg(test)] +mod events; +#[cfg(test)] +mod frame; +#[cfg(test)] +mod metadata; +#[cfg(test)] +mod storage; + +#[cfg(test)] +use test_runtime::node_runtime; +#[cfg(test)] +use utils::*; diff --git a/integration-tests/src/metadata/mod.rs b/testing/integration-tests/src/metadata/mod.rs similarity index 100% rename from integration-tests/src/metadata/mod.rs rename to testing/integration-tests/src/metadata/mod.rs diff --git a/testing/integration-tests/src/metadata/validation.rs b/testing/integration-tests/src/metadata/validation.rs new file mode 100644 index 0000000000..47a2eb034c --- /dev/null +++ b/testing/integration-tests/src/metadata/validation.rs @@ -0,0 +1,340 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . + +use crate::{ + test_context, + TestContext, +}; +use frame_metadata::{ + ExtrinsicMetadata, + PalletCallMetadata, + PalletMetadata, + PalletStorageMetadata, + RuntimeMetadataPrefixed, + RuntimeMetadataV14, + StorageEntryMetadata, + StorageEntryModifier, + StorageEntryType, +}; +use scale_info::{ + build::{ + Fields, + Variants, + }, + meta_type, + Path, + Type, + TypeInfo, +}; +use subxt::{ + ClientBuilder, + DefaultConfig, + Metadata, + SubstrateExtrinsicParams, +}; + +use crate::utils::node_runtime; + +type RuntimeApi = + node_runtime::RuntimeApi>; + +async fn metadata_to_api(metadata: RuntimeMetadataV14, cxt: &TestContext) -> RuntimeApi { + let prefixed = RuntimeMetadataPrefixed::from(metadata); + let metadata = Metadata::try_from(prefixed).unwrap(); + + ClientBuilder::new() + .set_url(cxt.node_proc.ws_url().to_string()) + .set_metadata(metadata) + .build() + .await + .unwrap() + .to_runtime_api::, + >>() +} + +#[tokio::test] +async fn full_metadata_check() { + let cxt = test_context().await; + let api = &cxt.api; + + // Runtime metadata is identical to the metadata used during API generation. + assert!(api.validate_metadata().is_ok()); + + // Modify the metadata. + let mut metadata: RuntimeMetadataV14 = { + let locked_client_metadata = api.client.metadata(); + let client_metadata = locked_client_metadata.read(); + client_metadata.runtime_metadata().clone() + }; + metadata.pallets[0].name = "NewPallet".to_string(); + + let new_api = metadata_to_api(metadata, &cxt).await; + assert_eq!( + new_api + .validate_metadata() + .err() + .expect("Validation should fail for incompatible metadata"), + ::subxt::MetadataError::IncompatibleMetadata + ); +} + +#[tokio::test] +async fn constants_check() { + let cxt = test_context().await; + let api = &cxt.api; + + // Ensure that `ExistentialDeposit` is compatible before altering the metadata. + assert!(cxt.api.constants().balances().existential_deposit().is_ok()); + + // Modify the metadata. + let mut metadata: RuntimeMetadataV14 = { + let locked_client_metadata = api.client.metadata(); + let client_metadata = locked_client_metadata.read(); + client_metadata.runtime_metadata().clone() + }; + + let mut existential = metadata + .pallets + .iter_mut() + .find(|pallet| pallet.name == "Balances") + .expect("Metadata must contain Balances pallet") + .constants + .iter_mut() + .find(|constant| constant.name == "ExistentialDeposit") + .expect("ExistentialDeposit constant must be present"); + existential.value = vec![0u8; 32]; + + let new_api = metadata_to_api(metadata, &cxt).await; + + assert!(new_api.validate_metadata().is_err()); + assert!(new_api + .constants() + .balances() + .existential_deposit() + .is_err()); + + // Other constant validation should not be impacted. + assert!(new_api.constants().balances().max_locks().is_ok()); +} + +fn default_pallet() -> PalletMetadata { + PalletMetadata { + name: "Test", + storage: None, + calls: None, + event: None, + constants: vec![], + error: None, + index: 0, + } +} + +fn pallets_to_metadata(pallets: Vec) -> RuntimeMetadataV14 { + RuntimeMetadataV14::new( + pallets, + ExtrinsicMetadata { + ty: meta_type::<()>(), + version: 0, + signed_extensions: vec![], + }, + meta_type::<()>(), + ) +} + +#[tokio::test] +async fn calls_check() { + let cxt = test_context().await; + + // Ensure that `Unbond` and `WinthdrawUnbonded` calls are compatible before altering the metadata. + assert!(cxt.api.tx().staking().unbond(123_456_789_012_345).is_ok()); + assert!(cxt.api.tx().staking().withdraw_unbonded(10).is_ok()); + + // Reconstruct the `Staking` call as is. + struct CallRec; + impl TypeInfo for CallRec { + type Identity = Self; + fn type_info() -> Type { + Type::builder() + .path(Path::new("Call", "pallet_staking::pallet::pallet")) + .variant( + Variants::new() + .variant("unbond", |v| { + v.index(0).fields(Fields::named().field(|f| { + f.compact::() + .name("value") + .type_name("BalanceOf") + })) + }) + .variant("withdraw_unbonded", |v| { + v.index(1).fields(Fields::named().field(|f| { + f.ty::().name("num_slashing_spans").type_name("u32") + })) + }), + ) + } + } + let pallet = PalletMetadata { + name: "Staking", + calls: Some(PalletCallMetadata { + ty: meta_type::(), + }), + ..default_pallet() + }; + let metadata = pallets_to_metadata(vec![pallet]); + let new_api = metadata_to_api(metadata, &cxt).await; + assert!(new_api.tx().staking().unbond(123_456_789_012_345).is_ok()); + assert!(new_api.tx().staking().withdraw_unbonded(10).is_ok()); + + // Change `Unbond` call but leave the rest as is. + struct CallRecSecond; + impl TypeInfo for CallRecSecond { + type Identity = Self; + fn type_info() -> Type { + Type::builder() + .path(Path::new("Call", "pallet_staking::pallet::pallet")) + .variant( + Variants::new() + .variant("unbond", |v| { + v.index(0).fields(Fields::named().field(|f| { + // Is of type u32 instead of u128. + f.compact::().name("value").type_name("BalanceOf") + })) + }) + .variant("withdraw_unbonded", |v| { + v.index(1).fields(Fields::named().field(|f| { + f.ty::().name("num_slashing_spans").type_name("u32") + })) + }), + ) + } + } + let pallet = PalletMetadata { + name: "Staking", + calls: Some(PalletCallMetadata { + ty: meta_type::(), + }), + ..default_pallet() + }; + let metadata = pallets_to_metadata(vec![pallet]); + let new_api = metadata_to_api(metadata, &cxt).await; + // Unbond call should fail, while withdraw_unbonded remains compatible. + assert!(new_api.tx().staking().unbond(123_456_789_012_345).is_err()); + assert!(new_api.tx().staking().withdraw_unbonded(10).is_ok()); +} + +#[tokio::test] +async fn storage_check() { + let cxt = test_context().await; + + // Ensure that `ExtrinsicCount` and `EventCount` storages are compatible before altering the metadata. + assert!(cxt + .api + .storage() + .system() + .extrinsic_count(None) + .await + .is_ok()); + assert!(cxt + .api + .storage() + .system() + .all_extrinsics_len(None) + .await + .is_ok()); + + // Reconstruct the storage. + let storage = PalletStorageMetadata { + prefix: "System", + entries: vec![ + StorageEntryMetadata { + name: "ExtrinsicCount", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(meta_type::()), + default: vec![0], + docs: vec![], + }, + StorageEntryMetadata { + name: "AllExtrinsicsLen", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(meta_type::()), + default: vec![0], + docs: vec![], + }, + ], + }; + let pallet = PalletMetadata { + name: "System", + storage: Some(storage), + ..default_pallet() + }; + let metadata = pallets_to_metadata(vec![pallet]); + let new_api = metadata_to_api(metadata, &cxt).await; + assert!(new_api + .storage() + .system() + .extrinsic_count(None) + .await + .is_ok()); + assert!(new_api + .storage() + .system() + .all_extrinsics_len(None) + .await + .is_ok()); + + // Reconstruct the storage while modifying ExtrinsicCount. + let storage = PalletStorageMetadata { + prefix: "System", + entries: vec![ + StorageEntryMetadata { + name: "ExtrinsicCount", + modifier: StorageEntryModifier::Optional, + // Previously was u32. + ty: StorageEntryType::Plain(meta_type::()), + default: vec![0], + docs: vec![], + }, + StorageEntryMetadata { + name: "AllExtrinsicsLen", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Plain(meta_type::()), + default: vec![0], + docs: vec![], + }, + ], + }; + let pallet = PalletMetadata { + name: "System", + storage: Some(storage), + ..default_pallet() + }; + let metadata = pallets_to_metadata(vec![pallet]); + let new_api = metadata_to_api(metadata, &cxt).await; + assert!(new_api + .storage() + .system() + .extrinsic_count(None) + .await + .is_err()); + assert!(new_api + .storage() + .system() + .all_extrinsics_len(None) + .await + .is_ok()); +} diff --git a/integration-tests/src/storage/mod.rs b/testing/integration-tests/src/storage/mod.rs similarity index 100% rename from integration-tests/src/storage/mod.rs rename to testing/integration-tests/src/storage/mod.rs diff --git a/integration-tests/src/utils/context.rs b/testing/integration-tests/src/utils/context.rs similarity index 100% rename from integration-tests/src/utils/context.rs rename to testing/integration-tests/src/utils/context.rs diff --git a/integration-tests/src/utils/mod.rs b/testing/integration-tests/src/utils/mod.rs similarity index 100% rename from integration-tests/src/utils/mod.rs rename to testing/integration-tests/src/utils/mod.rs diff --git a/integration-tests/src/utils/node_proc.rs b/testing/integration-tests/src/utils/node_proc.rs similarity index 100% rename from integration-tests/src/utils/node_proc.rs rename to testing/integration-tests/src/utils/node_proc.rs diff --git a/test-runtime/Cargo.toml b/testing/test-runtime/Cargo.toml similarity index 84% rename from test-runtime/Cargo.toml rename to testing/test-runtime/Cargo.toml index fe163e76a2..a10addd4c5 100644 --- a/test-runtime/Cargo.toml +++ b/testing/test-runtime/Cargo.toml @@ -4,12 +4,12 @@ version = "0.21.0" edition = "2021" [dependencies] -subxt = { path = "../subxt" } +subxt = { path = "../../subxt" } sp-runtime = "6.0.0" codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "full", "bit-vec"] } [build-dependencies] -subxt = { path = "../subxt" } +subxt = { path = "../../subxt" } sp-core = "6.0.0" tokio = { version = "1.8", features = ["macros", "rt-multi-thread"] } which = "4.2.2" diff --git a/test-runtime/README.md b/testing/test-runtime/README.md similarity index 100% rename from test-runtime/README.md rename to testing/test-runtime/README.md diff --git a/test-runtime/build.rs b/testing/test-runtime/build.rs similarity index 100% rename from test-runtime/build.rs rename to testing/test-runtime/build.rs diff --git a/test-runtime/src/lib.rs b/testing/test-runtime/src/lib.rs similarity index 100% rename from test-runtime/src/lib.rs rename to testing/test-runtime/src/lib.rs diff --git a/testing/ui-tests/Cargo.toml b/testing/ui-tests/Cargo.toml new file mode 100644 index 0000000000..1627720582 --- /dev/null +++ b/testing/ui-tests/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "ui-tests" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[dev-dependencies] +trybuild = "1.0.63" +scale-info = { version = "2.0.0", features = ["bit-vec"] } +frame-metadata = "15.0.0" +codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["derive", "full", "bit-vec"] } +subxt = { path = "../../subxt" } \ No newline at end of file diff --git a/testing/ui-tests/src/lib.rs b/testing/ui-tests/src/lib.rs new file mode 100644 index 0000000000..e68d9f0a26 --- /dev/null +++ b/testing/ui-tests/src/lib.rs @@ -0,0 +1,19 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . +#![cfg(test)] + +mod utils; +mod storage; \ No newline at end of file diff --git a/testing/ui-tests/src/storage.rs b/testing/ui-tests/src/storage.rs new file mode 100644 index 0000000000..cdfc88467a --- /dev/null +++ b/testing/ui-tests/src/storage.rs @@ -0,0 +1,78 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . + +use frame_metadata::{ + RuntimeMetadataPrefixed, +}; +use frame_metadata::{ + PalletStorageMetadata, + StorageEntryModifier, + StorageEntryType, + PalletMetadata, + StorageEntryMetadata, +}; +use scale_info::{ + meta_type, +}; + +use crate::utils::{ + MetadataTestRunner, + generate_metadata_from_pallets +}; + +/// Generate metadata which contains a `Map` storage entry with no hashers/values. +/// This is a bit of an odd case, but it was raised in https://github.com/paritytech/subxt/issues/552, +/// and this test will fail before the fix and should pass once the fix is applied. +fn metadata_storage_item_no_values() -> RuntimeMetadataPrefixed { + let storage = PalletStorageMetadata { + prefix: "System".into(), + entries: vec![ + StorageEntryMetadata { + name: "Map".into(), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + hashers: vec![], + key: meta_type::<()>(), + value: meta_type::() + }, + default: vec![0], + docs: vec![], + } + ], + }; + + let pallet = PalletMetadata { + index: 0, + name: "System".into(), + storage: Some(storage), + constants: vec![], + calls: None, + event: None, + error: None, + }; + + generate_metadata_from_pallets(vec![pallet]) +} + +#[test] +fn ui_tests() { + let mut m = MetadataTestRunner::default(); + let t = trybuild::TestCases::new(); + + t.pass(&m.path_to_ui_test_for_metadata( + metadata_storage_item_no_values() + )); +} diff --git a/testing/ui-tests/src/utils/dispatch_error.rs b/testing/ui-tests/src/utils/dispatch_error.rs new file mode 100644 index 0000000000..d2100c92f3 --- /dev/null +++ b/testing/ui-tests/src/utils/dispatch_error.rs @@ -0,0 +1,41 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . + +/// This type has TypeInfo compatible with the (old version of) the DispatchError +/// type (or at least, is defined enough to allow the subxt macro to generate +/// proper code if this exists in the metadata type registry). +pub enum DispatchError {} +impl scale_info::TypeInfo for DispatchError { + type Identity = Self; + fn type_info() -> scale_info::Type { + scale_info::Type::builder() + .path(scale_info::Path::new("DispatchError", "sp_runtime")) + .variant(scale_info::build::Variants::new() + .variant("Module", |builder| { + builder + .fields( + scale_info::build::FieldsBuilder::::default() + .field(|b| { + b.name("error").ty::() + }) + .field(|b| { + b.name("index").ty::() + }) + ) + .index(0) + })) + } +} \ No newline at end of file diff --git a/testing/ui-tests/src/utils/metadata_test_runner.rs b/testing/ui-tests/src/utils/metadata_test_runner.rs new file mode 100644 index 0000000000..6a276dcc09 --- /dev/null +++ b/testing/ui-tests/src/utils/metadata_test_runner.rs @@ -0,0 +1,81 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . + +use frame_metadata::{ + RuntimeMetadataPrefixed, +}; +use codec::{ + Encode, +}; + +static TEST_DIR_PREFIX: &str = "subxt_generated_ui_tests_"; + +#[derive(Default)] +pub struct MetadataTestRunner { + index: usize +} + +impl MetadataTestRunner { + pub fn path_to_ui_test_for_metadata(&mut self, metadata: RuntimeMetadataPrefixed) -> String { + // increment test index to avoid overlaps. + let index = self.index; + self.index += 1; + + let mut tmp_dir = std::env::temp_dir(); + tmp_dir.push(format!("{TEST_DIR_PREFIX}{index}")); + + let tmp_metadata_path = { + let mut t = tmp_dir.clone(); + t.push("metadata.scale"); + t.to_string_lossy().into_owned() + }; + let tmp_rust_path = { + let mut t = tmp_dir.clone(); + t.push("code.rs"); + t.to_string_lossy().into_owned() + }; + + let encoded_metadata = metadata.encode(); + let rust_file = format!(r#" + use subxt; + + #[subxt::subxt(runtime_metadata_path = "{tmp_metadata_path}")] + pub mod polkadot {{}} + + fn main() {{}} + "#); + + std::fs::create_dir_all(&tmp_dir).expect("could not create tmp ui test dir"); + // Write metadata to tmp folder: + std::fs::write(&tmp_metadata_path, &encoded_metadata).unwrap(); + // Write test file to tmp folder (it'll be moved by trybuild): + std::fs::write(&tmp_rust_path, &rust_file).unwrap(); + + tmp_rust_path + } +} + +// `trybuild` runs all tests once it's dropped. So, we defer all cleanup until we +// are dropped too, to make sure that cleanup happens after tests are ran. +impl Drop for MetadataTestRunner { + fn drop(&mut self) { + for i in 0..self.index { + let mut tmp_dir = std::env::temp_dir(); + tmp_dir.push(format!("{TEST_DIR_PREFIX}{i}")); + std::fs::remove_dir_all(tmp_dir).expect("cannot cleanup temp files"); + } + } +} \ No newline at end of file diff --git a/testing/ui-tests/src/utils/mod.rs b/testing/ui-tests/src/utils/mod.rs new file mode 100644 index 0000000000..b3b14cda2c --- /dev/null +++ b/testing/ui-tests/src/utils/mod.rs @@ -0,0 +1,65 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . + +mod dispatch_error; +mod metadata_test_runner; + +use frame_metadata::{ + RuntimeMetadataPrefixed, + v14::RuntimeMetadataV14 +}; +use frame_metadata::{ + ExtrinsicMetadata, + PalletMetadata, +}; +use scale_info::{ + meta_type, + IntoPortable, +}; +use dispatch_error::DispatchError; + +pub use metadata_test_runner::MetadataTestRunner; + +/// Given some pallet metadata, generate a [`RuntimeMetadataPrefixed`] struct. +/// We default to a duff extrinsic type, and register a fake `DispatchError` type +/// so that codegen is happy with the metadata generated. +pub fn generate_metadata_from_pallets(pallets: Vec) -> RuntimeMetadataPrefixed { + // We don't care about the extrinsic type. + let extrinsic = ExtrinsicMetadata { + ty: meta_type::<()>(), + version: 0, + signed_extensions: vec![], + }; + + // Construct metadata manually from our types (See `RuntimeMetadataV14::new()`). + // Add any extra types we need to the registry. + let mut registry = scale_info::Registry::new(); + let pallets = registry.map_into_portable(pallets); + let extrinsic = extrinsic.into_portable(&mut registry); + let ty = registry.register_type(&meta_type::<()>()); + + // Metadata needs to contain this DispatchError, since codegen looks for it. + registry.register_type(&meta_type::()); + + let metadata = RuntimeMetadataV14 { + types: registry.into(), + pallets, + extrinsic, + ty, + }; + + RuntimeMetadataPrefixed::from(metadata) +} \ No newline at end of file From 61083fb67f1978358cc290d86ad74836e1d4c580 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 15 Jun 2022 14:43:40 +0100 Subject: [PATCH 02/10] undo wee mixup with another PR --- testing/integration-tests/src/client/mod.rs | 105 +------------------- 1 file changed, 4 insertions(+), 101 deletions(-) diff --git a/testing/integration-tests/src/client/mod.rs b/testing/integration-tests/src/client/mod.rs index 657ec56bb3..050ef2e32b 100644 --- a/testing/integration-tests/src/client/mod.rs +++ b/testing/integration-tests/src/client/mod.rs @@ -17,24 +17,14 @@ use crate::{ test_node_process, test_node_process_with, - utils::{ - node_runtime::system, - pair_signer, - test_context, - }, + utils::node_runtime::system, }; -use sp_core::{ - sr25519::Pair, - storage::{ - well_known_keys, - StorageKey, - }, - Pair as _, +use sp_core::storage::{ + well_known_keys, + StorageKey, }; use sp_keyring::AccountKeyring; -use sp_runtime::DispatchOutcome; -use subxt::Error; #[tokio::test] async fn insert_key() { @@ -141,90 +131,3 @@ async fn fetch_system_info() { assert_eq!(client.rpc().system_name().await.unwrap(), "Substrate Node"); assert!(!client.rpc().system_version().await.unwrap().is_empty()); } - -#[tokio::test] -async fn dry_run_passes() { - let node_process = test_node_process().await; - let client = node_process.client(); - - let alice = pair_signer(AccountKeyring::Alice.pair()); - let bob = pair_signer(AccountKeyring::Bob.pair()); - let bob_address = bob.account_id().clone().into(); - let cxt = test_context().await; - let api = &cxt.api; - - let signed_extrinsic = api - .tx() - .balances() - .transfer(bob_address, 10_000) - .unwrap() - .create_signed(&alice, Default::default()) - .await - .unwrap(); - - client - .rpc() - .dry_run(&signed_extrinsic, None) - .await - .expect("dryrunning failed") - .expect("expected dryrunning to be successful") - .unwrap(); - signed_extrinsic - .submit_and_watch() - .await - .unwrap() - .wait_for_finalized_success() - .await - .unwrap(); -} - -#[tokio::test] -async fn dry_run_fails() { - let node_process = test_node_process().await; - let client = node_process.client(); - - let alice = pair_signer(AccountKeyring::Alice.pair()); - let hans = pair_signer(Pair::generate().0); - let hans_address = hans.account_id().clone().into(); - let cxt = test_context().await; - let api = &cxt.api; - - let signed_extrinsic = api - .tx() - .balances() - .transfer( - hans_address, - 100_000_000_000_000_000_000_000_000_000_000_000, - ) - .unwrap() - .create_signed(&alice, Default::default()) - .await - .unwrap(); - - let dry_run_res: DispatchOutcome = client - .rpc() - .dry_run(&signed_extrinsic, None) - .await - .expect("dryrunning failed") - .expect("expected dryrun transaction to be valid"); - if let Err(sp_runtime::DispatchError::Module(module_error)) = dry_run_res { - assert_eq!(module_error.index, 6); - assert_eq!(module_error.error, 2); - } else { - panic!("expected a module error when dryrunning"); - } - - let res = signed_extrinsic - .submit_and_watch() - .await - .unwrap() - .wait_for_finalized_success() - .await; - - if let Err(Error::Module(err)) = res { - assert_eq!(err.pallet, "Balances"); - assert_eq!(err.error, "InsufficientBalance"); - } else { - panic!("expected a runtime module error"); - } -} From 455b4ab42ed4bf942adac635043964b34f54615b Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 15 Jun 2022 14:43:57 +0100 Subject: [PATCH 03/10] cargo fmt --- testing/ui-tests/src/lib.rs | 2 +- testing/ui-tests/src/storage.rs | 42 ++++++++----------- testing/ui-tests/src/utils/dispatch_error.rs | 21 +++++----- .../src/utils/metadata_test_runner.rs | 23 +++++----- testing/ui-tests/src/utils/mod.rs | 14 +++---- 5 files changed, 47 insertions(+), 55 deletions(-) diff --git a/testing/ui-tests/src/lib.rs b/testing/ui-tests/src/lib.rs index e68d9f0a26..b952e6bbad 100644 --- a/testing/ui-tests/src/lib.rs +++ b/testing/ui-tests/src/lib.rs @@ -15,5 +15,5 @@ // along with subxt. If not, see . #![cfg(test)] +mod storage; mod utils; -mod storage; \ No newline at end of file diff --git a/testing/ui-tests/src/storage.rs b/testing/ui-tests/src/storage.rs index cdfc88467a..df53a2e4dd 100644 --- a/testing/ui-tests/src/storage.rs +++ b/testing/ui-tests/src/storage.rs @@ -15,22 +15,18 @@ // along with subxt. If not, see . use frame_metadata::{ - RuntimeMetadataPrefixed, -}; -use frame_metadata::{ + PalletMetadata, PalletStorageMetadata, + RuntimeMetadataPrefixed, + StorageEntryMetadata, StorageEntryModifier, StorageEntryType, - PalletMetadata, - StorageEntryMetadata, -}; -use scale_info::{ - meta_type, }; +use scale_info::meta_type; use crate::utils::{ + generate_metadata_from_pallets, MetadataTestRunner, - generate_metadata_from_pallets }; /// Generate metadata which contains a `Map` storage entry with no hashers/values. @@ -39,19 +35,17 @@ use crate::utils::{ fn metadata_storage_item_no_values() -> RuntimeMetadataPrefixed { let storage = PalletStorageMetadata { prefix: "System".into(), - entries: vec![ - StorageEntryMetadata { - name: "Map".into(), - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![], - key: meta_type::<()>(), - value: meta_type::() - }, - default: vec![0], - docs: vec![], - } - ], + entries: vec![StorageEntryMetadata { + name: "Map".into(), + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + hashers: vec![], + key: meta_type::<()>(), + value: meta_type::(), + }, + default: vec![0], + docs: vec![], + }], }; let pallet = PalletMetadata { @@ -72,7 +66,5 @@ fn ui_tests() { let mut m = MetadataTestRunner::default(); let t = trybuild::TestCases::new(); - t.pass(&m.path_to_ui_test_for_metadata( - metadata_storage_item_no_values() - )); + t.pass(&m.path_to_ui_test_for_metadata(metadata_storage_item_no_values())); } diff --git a/testing/ui-tests/src/utils/dispatch_error.rs b/testing/ui-tests/src/utils/dispatch_error.rs index d2100c92f3..003ef6d280 100644 --- a/testing/ui-tests/src/utils/dispatch_error.rs +++ b/testing/ui-tests/src/utils/dispatch_error.rs @@ -23,19 +23,18 @@ impl scale_info::TypeInfo for DispatchError { fn type_info() -> scale_info::Type { scale_info::Type::builder() .path(scale_info::Path::new("DispatchError", "sp_runtime")) - .variant(scale_info::build::Variants::new() - .variant("Module", |builder| { + .variant( + scale_info::build::Variants::new().variant("Module", |builder| { builder .fields( - scale_info::build::FieldsBuilder::::default() - .field(|b| { - b.name("error").ty::() - }) - .field(|b| { - b.name("index").ty::() - }) + scale_info::build::FieldsBuilder::< + scale_info::build::NamedFields, + >::default() + .field(|b| b.name("error").ty::()) + .field(|b| b.name("index").ty::()), ) .index(0) - })) + }), + ) } -} \ No newline at end of file +} diff --git a/testing/ui-tests/src/utils/metadata_test_runner.rs b/testing/ui-tests/src/utils/metadata_test_runner.rs index 6a276dcc09..b98c64479d 100644 --- a/testing/ui-tests/src/utils/metadata_test_runner.rs +++ b/testing/ui-tests/src/utils/metadata_test_runner.rs @@ -14,22 +14,21 @@ // You should have received a copy of the GNU General Public License // along with subxt. If not, see . -use frame_metadata::{ - RuntimeMetadataPrefixed, -}; -use codec::{ - Encode, -}; +use codec::Encode; +use frame_metadata::RuntimeMetadataPrefixed; static TEST_DIR_PREFIX: &str = "subxt_generated_ui_tests_"; #[derive(Default)] pub struct MetadataTestRunner { - index: usize + index: usize, } impl MetadataTestRunner { - pub fn path_to_ui_test_for_metadata(&mut self, metadata: RuntimeMetadataPrefixed) -> String { + pub fn path_to_ui_test_for_metadata( + &mut self, + metadata: RuntimeMetadataPrefixed, + ) -> String { // increment test index to avoid overlaps. let index = self.index; self.index += 1; @@ -49,14 +48,16 @@ impl MetadataTestRunner { }; let encoded_metadata = metadata.encode(); - let rust_file = format!(r#" + let rust_file = format!( + r#" use subxt; #[subxt::subxt(runtime_metadata_path = "{tmp_metadata_path}")] pub mod polkadot {{}} fn main() {{}} - "#); + "# + ); std::fs::create_dir_all(&tmp_dir).expect("could not create tmp ui test dir"); // Write metadata to tmp folder: @@ -78,4 +79,4 @@ impl Drop for MetadataTestRunner { std::fs::remove_dir_all(tmp_dir).expect("cannot cleanup temp files"); } } -} \ No newline at end of file +} diff --git a/testing/ui-tests/src/utils/mod.rs b/testing/ui-tests/src/utils/mod.rs index b3b14cda2c..9b6fa8bdba 100644 --- a/testing/ui-tests/src/utils/mod.rs +++ b/testing/ui-tests/src/utils/mod.rs @@ -17,26 +17,26 @@ mod dispatch_error; mod metadata_test_runner; +use dispatch_error::DispatchError; use frame_metadata::{ - RuntimeMetadataPrefixed, - v14::RuntimeMetadataV14 -}; -use frame_metadata::{ + v14::RuntimeMetadataV14, ExtrinsicMetadata, PalletMetadata, + RuntimeMetadataPrefixed, }; use scale_info::{ meta_type, IntoPortable, }; -use dispatch_error::DispatchError; pub use metadata_test_runner::MetadataTestRunner; /// Given some pallet metadata, generate a [`RuntimeMetadataPrefixed`] struct. /// We default to a duff extrinsic type, and register a fake `DispatchError` type /// so that codegen is happy with the metadata generated. -pub fn generate_metadata_from_pallets(pallets: Vec) -> RuntimeMetadataPrefixed { +pub fn generate_metadata_from_pallets( + pallets: Vec, +) -> RuntimeMetadataPrefixed { // We don't care about the extrinsic type. let extrinsic = ExtrinsicMetadata { ty: meta_type::<()>(), @@ -62,4 +62,4 @@ pub fn generate_metadata_from_pallets(pallets: Vec) -> RuntimeMe }; RuntimeMetadataPrefixed::from(metadata) -} \ No newline at end of file +} From 8acc7c1a36b48be332f1cbd531cbbde7d6b844c4 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 15 Jun 2022 14:51:15 +0100 Subject: [PATCH 04/10] clippy --- testing/ui-tests/src/storage.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testing/ui-tests/src/storage.rs b/testing/ui-tests/src/storage.rs index df53a2e4dd..5858b4e786 100644 --- a/testing/ui-tests/src/storage.rs +++ b/testing/ui-tests/src/storage.rs @@ -34,9 +34,9 @@ use crate::utils::{ /// and this test will fail before the fix and should pass once the fix is applied. fn metadata_storage_item_no_values() -> RuntimeMetadataPrefixed { let storage = PalletStorageMetadata { - prefix: "System".into(), + prefix: "System", entries: vec![StorageEntryMetadata { - name: "Map".into(), + name: "Map", modifier: StorageEntryModifier::Optional, ty: StorageEntryType::Map { hashers: vec![], @@ -50,7 +50,7 @@ fn metadata_storage_item_no_values() -> RuntimeMetadataPrefixed { let pallet = PalletMetadata { index: 0, - name: "System".into(), + name: "System", storage: Some(storage), constants: vec![], calls: None, From 8a2c011280dcc1b51d270530906658e518e757df Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 15 Jun 2022 17:17:09 +0100 Subject: [PATCH 05/10] tidy ui-tests a little --- testing/ui-tests/src/storage.rs | 45 ++++++++++--------------------- testing/ui-tests/src/utils/mod.rs | 26 ++++++++++++++++++ 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/testing/ui-tests/src/storage.rs b/testing/ui-tests/src/storage.rs index 5858b4e786..4aa007cf4c 100644 --- a/testing/ui-tests/src/storage.rs +++ b/testing/ui-tests/src/storage.rs @@ -15,8 +15,6 @@ // along with subxt. If not, see . use frame_metadata::{ - PalletMetadata, - PalletStorageMetadata, RuntimeMetadataPrefixed, StorageEntryMetadata, StorageEntryModifier, @@ -25,40 +23,25 @@ use frame_metadata::{ use scale_info::meta_type; use crate::utils::{ - generate_metadata_from_pallets, + generate_metadata_from_storage_entries, MetadataTestRunner, }; /// Generate metadata which contains a `Map` storage entry with no hashers/values. /// This is a bit of an odd case, but it was raised in https://github.com/paritytech/subxt/issues/552, /// and this test will fail before the fix and should pass once the fix is applied. -fn metadata_storage_item_no_values() -> RuntimeMetadataPrefixed { - let storage = PalletStorageMetadata { - prefix: "System", - entries: vec![StorageEntryMetadata { - name: "Map", - modifier: StorageEntryModifier::Optional, - ty: StorageEntryType::Map { - hashers: vec![], - key: meta_type::<()>(), - value: meta_type::(), - }, - default: vec![0], - docs: vec![], - }], - }; - - let pallet = PalletMetadata { - index: 0, - name: "System", - storage: Some(storage), - constants: vec![], - calls: None, - event: None, - error: None, - }; - - generate_metadata_from_pallets(vec![pallet]) +fn metadata_storage_map_no_keys() -> RuntimeMetadataPrefixed { + generate_metadata_from_storage_entries(vec![StorageEntryMetadata { + name: "MapWithNoKeys", + modifier: StorageEntryModifier::Optional, + ty: StorageEntryType::Map { + hashers: vec![], + key: meta_type::<()>(), + value: meta_type::(), + }, + default: vec![0], + docs: vec![], + }]) } #[test] @@ -66,5 +49,5 @@ fn ui_tests() { let mut m = MetadataTestRunner::default(); let t = trybuild::TestCases::new(); - t.pass(&m.path_to_ui_test_for_metadata(metadata_storage_item_no_values())); + t.pass(&m.path_to_ui_test_for_metadata(metadata_storage_map_no_keys())); } diff --git a/testing/ui-tests/src/utils/mod.rs b/testing/ui-tests/src/utils/mod.rs index 9b6fa8bdba..10c4f7b510 100644 --- a/testing/ui-tests/src/utils/mod.rs +++ b/testing/ui-tests/src/utils/mod.rs @@ -22,7 +22,9 @@ use frame_metadata::{ v14::RuntimeMetadataV14, ExtrinsicMetadata, PalletMetadata, + PalletStorageMetadata, RuntimeMetadataPrefixed, + StorageEntryMetadata, }; use scale_info::{ meta_type, @@ -63,3 +65,27 @@ pub fn generate_metadata_from_pallets( RuntimeMetadataPrefixed::from(metadata) } + +/// Given some storage entries, generate a [`RuntimeMetadataPrefixed`] struct. +/// We default to a duff extrinsic type, mock a pallet out, and register a +/// fake `DispatchError` type so that codegen is happy with the metadata generated. +pub fn generate_metadata_from_storage_entries( + storage_entries: Vec, +) -> RuntimeMetadataPrefixed { + let storage = PalletStorageMetadata { + prefix: "System", + entries: storage_entries, + }; + + let pallet = PalletMetadata { + index: 0, + name: "System", + storage: Some(storage), + constants: vec![], + calls: None, + event: None, + error: None, + }; + + generate_metadata_from_pallets(vec![pallet]) +} From 6ae6aaad1c284d9f6d74035b9dd8f19ccb269e7c Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 15 Jun 2022 18:16:52 +0100 Subject: [PATCH 06/10] test different DispatchError types --- testing/ui-tests/src/lib.rs | 39 ++++++ testing/ui-tests/src/storage.rs | 15 +-- testing/ui-tests/src/utils/dispatch_error.rs | 118 ++++++++++++++++--- testing/ui-tests/src/utils/mod.rs | 21 +++- 4 files changed, 157 insertions(+), 36 deletions(-) diff --git a/testing/ui-tests/src/lib.rs b/testing/ui-tests/src/lib.rs index b952e6bbad..887f461cf2 100644 --- a/testing/ui-tests/src/lib.rs +++ b/testing/ui-tests/src/lib.rs @@ -17,3 +17,42 @@ mod storage; mod utils; + +use crate::utils::{ + dispatch_error::{ + ArrayDispatchError, + LegacyDispatchError, + NamedFieldDispatchError, + }, + generate_metadata_from_pallets_custom_dispatch_error, + MetadataTestRunner, +}; + +// Each of these tests leads to some rust code being compiled and +// executed to test that compilation is successful (or errors in the +// way that we'd expect). +#[test] +fn ui_tests() { + let mut m = MetadataTestRunner::default(); + let t = trybuild::TestCases::new(); + + // Check that storage maps with no keys are handled properly. + t.pass(&m.path_to_ui_test_for_metadata(storage::metadata_storage_map_no_keys())); + + // Test that the codegen can handle the different types of DispatchError. + t.pass(&m.path_to_ui_test_for_metadata( + generate_metadata_from_pallets_custom_dispatch_error::( + vec![], + ), + )); + t.pass(&m.path_to_ui_test_for_metadata( + generate_metadata_from_pallets_custom_dispatch_error::( + vec![], + ), + )); + t.pass(&m.path_to_ui_test_for_metadata( + generate_metadata_from_pallets_custom_dispatch_error::( + vec![], + ), + )); +} diff --git a/testing/ui-tests/src/storage.rs b/testing/ui-tests/src/storage.rs index 4aa007cf4c..f6816bcdf3 100644 --- a/testing/ui-tests/src/storage.rs +++ b/testing/ui-tests/src/storage.rs @@ -22,15 +22,12 @@ use frame_metadata::{ }; use scale_info::meta_type; -use crate::utils::{ - generate_metadata_from_storage_entries, - MetadataTestRunner, -}; +use crate::utils::generate_metadata_from_storage_entries; /// Generate metadata which contains a `Map` storage entry with no hashers/values. /// This is a bit of an odd case, but it was raised in https://github.com/paritytech/subxt/issues/552, /// and this test will fail before the fix and should pass once the fix is applied. -fn metadata_storage_map_no_keys() -> RuntimeMetadataPrefixed { +pub fn metadata_storage_map_no_keys() -> RuntimeMetadataPrefixed { generate_metadata_from_storage_entries(vec![StorageEntryMetadata { name: "MapWithNoKeys", modifier: StorageEntryModifier::Optional, @@ -43,11 +40,3 @@ fn metadata_storage_map_no_keys() -> RuntimeMetadataPrefixed { docs: vec![], }]) } - -#[test] -fn ui_tests() { - let mut m = MetadataTestRunner::default(); - let t = trybuild::TestCases::new(); - - t.pass(&m.path_to_ui_test_for_metadata(metadata_storage_map_no_keys())); -} diff --git a/testing/ui-tests/src/utils/dispatch_error.rs b/testing/ui-tests/src/utils/dispatch_error.rs index 003ef6d280..ba291df15e 100644 --- a/testing/ui-tests/src/utils/dispatch_error.rs +++ b/testing/ui-tests/src/utils/dispatch_error.rs @@ -14,27 +14,107 @@ // You should have received a copy of the GNU General Public License // along with subxt. If not, see . -/// This type has TypeInfo compatible with the (old version of) the DispatchError -/// type (or at least, is defined enough to allow the subxt macro to generate -/// proper code if this exists in the metadata type registry). -pub enum DispatchError {} -impl scale_info::TypeInfo for DispatchError { +use scale_info::{ + build::{ + FieldsBuilder, + NamedFields, + UnnamedFields, + Variants, + }, + Path, + Type, + TypeInfo, +}; + +/// See the `ModuleErrorType` in `subxt_codegen` for more info on the different DispatchError +/// types that we've encountered. We need the path to match `sp_runtime::DispatchError`, otherwise +/// we could just implement roughly the correct types and derive TypeInfo on them. + +/// This type has TypeInfo compatible with the `NamedField` version of the DispatchError. +/// This is the oldest version that subxt supports: +/// `DispatchError::Module { index: u8, error: u8 }` +pub enum NamedFieldDispatchError {} +impl TypeInfo for NamedFieldDispatchError { type Identity = Self; - fn type_info() -> scale_info::Type { - scale_info::Type::builder() - .path(scale_info::Path::new("DispatchError", "sp_runtime")) - .variant( - scale_info::build::Variants::new().variant("Module", |builder| { - builder - .fields( - scale_info::build::FieldsBuilder::< - scale_info::build::NamedFields, - >::default() + fn type_info() -> Type { + Type::builder() + .path(Path::new("DispatchError", "sp_runtime")) + .variant(Variants::new().variant("Module", |builder| { + builder + .fields( + FieldsBuilder::::default() .field(|b| b.name("error").ty::()) .field(|b| b.name("index").ty::()), - ) - .index(0) - }), - ) + ) + .index(0) + })) + } +} + +/// This type has TypeInfo compatible with the `LegacyError` version of the DispatchError. +/// This is the version wasn't around for long: +/// `DispatchError::Module ( sp_runtime::ModuleError { index: u8, error: u8 } )` +pub enum LegacyDispatchError {} +impl TypeInfo for LegacyDispatchError { + type Identity = Self; + fn type_info() -> Type { + struct ModuleError; + impl TypeInfo for ModuleError { + type Identity = Self; + fn type_info() -> Type { + Type::builder() + .path(Path::new("ModuleError", "sp_runtime")) + .composite( + FieldsBuilder::::default() + .field(|b| b.name("index").ty::()) + .field(|b| b.name("error").ty::()), + ) + } + } + + Type::builder() + .path(Path::new("DispatchError", "sp_runtime")) + .variant(Variants::new().variant("Module", |builder| { + builder + .fields( + FieldsBuilder::::default() + .field(|b| b.ty::()), + ) + .index(0) + })) + } +} + +/// This type has TypeInfo compatible with the `ArrayError` version of the DispatchError. +/// This is the current version: +/// `DispatchError::Module ( sp_runtime::ModuleError { index: u8, error: [u8; 4] } )` +pub enum ArrayDispatchError {} +impl TypeInfo for ArrayDispatchError { + type Identity = Self; + fn type_info() -> Type { + struct ModuleError; + impl TypeInfo for ModuleError { + type Identity = Self; + fn type_info() -> Type { + Type::builder() + .path(Path::new("ModuleError", "sp_runtime")) + .composite( + FieldsBuilder::::default() + .field(|b| b.name("index").ty::()) + .field(|b| b.name("error").ty::<[u8; 4]>()), + ) + } + } + + Type::builder() + .path(Path::new("DispatchError", "sp_runtime")) + .variant(Variants::new().variant("Module", |builder| { + builder + .fields( + FieldsBuilder::::default() + .field(|b| b.ty::()), + ) + .index(0) + })) } } diff --git a/testing/ui-tests/src/utils/mod.rs b/testing/ui-tests/src/utils/mod.rs index 10c4f7b510..871d55904d 100644 --- a/testing/ui-tests/src/utils/mod.rs +++ b/testing/ui-tests/src/utils/mod.rs @@ -14,10 +14,9 @@ // You should have received a copy of the GNU General Public License // along with subxt. If not, see . -mod dispatch_error; +pub mod dispatch_error; mod metadata_test_runner; -use dispatch_error::DispatchError; use frame_metadata::{ v14::RuntimeMetadataV14, ExtrinsicMetadata, @@ -29,14 +28,17 @@ use frame_metadata::{ use scale_info::{ meta_type, IntoPortable, + TypeInfo, }; pub use metadata_test_runner::MetadataTestRunner; /// Given some pallet metadata, generate a [`RuntimeMetadataPrefixed`] struct. /// We default to a duff extrinsic type, and register a fake `DispatchError` type -/// so that codegen is happy with the metadata generated. -pub fn generate_metadata_from_pallets( +/// matching the generic type param provided. +pub fn generate_metadata_from_pallets_custom_dispatch_error< + DispatchError: TypeInfo + 'static, +>( pallets: Vec, ) -> RuntimeMetadataPrefixed { // We don't care about the extrinsic type. @@ -66,6 +68,17 @@ pub fn generate_metadata_from_pallets( RuntimeMetadataPrefixed::from(metadata) } +/// Given some pallet metadata, generate a [`RuntimeMetadataPrefixed`] struct. +/// We default to a duff extrinsic type, and register a fake `DispatchError` type +/// so that codegen is happy with the metadata generated. +pub fn generate_metadata_from_pallets( + pallets: Vec, +) -> RuntimeMetadataPrefixed { + generate_metadata_from_pallets_custom_dispatch_error::< + dispatch_error::ArrayDispatchError, + >(pallets) +} + /// Given some storage entries, generate a [`RuntimeMetadataPrefixed`] struct. /// We default to a duff extrinsic type, mock a pallet out, and register a /// fake `DispatchError` type so that codegen is happy with the metadata generated. From 94e7be7d15f9d51ab02a3b7b9d1cd173bfb75e18 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 15 Jun 2022 18:25:53 +0100 Subject: [PATCH 07/10] refactor dispatch error stuff --- testing/ui-tests/src/dispatch_errors.rs | 39 +++++++++++++++++++++++++ testing/ui-tests/src/lib.rs | 27 +++++------------ 2 files changed, 46 insertions(+), 20 deletions(-) create mode 100644 testing/ui-tests/src/dispatch_errors.rs diff --git a/testing/ui-tests/src/dispatch_errors.rs b/testing/ui-tests/src/dispatch_errors.rs new file mode 100644 index 0000000000..8dca723c82 --- /dev/null +++ b/testing/ui-tests/src/dispatch_errors.rs @@ -0,0 +1,39 @@ +// Copyright 2019-2022 Parity Technologies (UK) Ltd. +// This file is part of subxt. +// +// subxt is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// subxt is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with subxt. If not, see . + +use crate::utils::{ + dispatch_error::{ + ArrayDispatchError, + LegacyDispatchError, + NamedFieldDispatchError, + }, + generate_metadata_from_pallets_custom_dispatch_error, +}; +use frame_metadata::RuntimeMetadataPrefixed; + +pub fn metadata_array_dispatch_error() -> RuntimeMetadataPrefixed { + generate_metadata_from_pallets_custom_dispatch_error::(vec![]) +} + +pub fn metadata_legacy_dispatch_error() -> RuntimeMetadataPrefixed { + generate_metadata_from_pallets_custom_dispatch_error::(vec![]) +} + +pub fn metadata_named_field_dispatch_error() -> RuntimeMetadataPrefixed { + generate_metadata_from_pallets_custom_dispatch_error::( + vec![], + ) +} diff --git a/testing/ui-tests/src/lib.rs b/testing/ui-tests/src/lib.rs index 887f461cf2..adf08b3ab0 100644 --- a/testing/ui-tests/src/lib.rs +++ b/testing/ui-tests/src/lib.rs @@ -15,18 +15,11 @@ // along with subxt. If not, see . #![cfg(test)] +mod dispatch_errors; mod storage; mod utils; -use crate::utils::{ - dispatch_error::{ - ArrayDispatchError, - LegacyDispatchError, - NamedFieldDispatchError, - }, - generate_metadata_from_pallets_custom_dispatch_error, - MetadataTestRunner, -}; +use crate::utils::MetadataTestRunner; // Each of these tests leads to some rust code being compiled and // executed to test that compilation is successful (or errors in the @@ -41,18 +34,12 @@ fn ui_tests() { // Test that the codegen can handle the different types of DispatchError. t.pass(&m.path_to_ui_test_for_metadata( - generate_metadata_from_pallets_custom_dispatch_error::( - vec![], - ), + dispatch_errors::metadata_named_field_dispatch_error(), )); t.pass(&m.path_to_ui_test_for_metadata( - generate_metadata_from_pallets_custom_dispatch_error::( - vec![], - ), - )); - t.pass(&m.path_to_ui_test_for_metadata( - generate_metadata_from_pallets_custom_dispatch_error::( - vec![], - ), + dispatch_errors::metadata_legacy_dispatch_error() )); + t.pass( + &m.path_to_ui_test_for_metadata(dispatch_errors::metadata_array_dispatch_error()), + ); } From 92ecd0857463c32550246ebcb2d6d295a898e333 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Wed, 15 Jun 2022 18:34:54 +0100 Subject: [PATCH 08/10] name ui tests --- testing/ui-tests/src/lib.rs | 16 +++++++++++----- .../ui-tests/src/utils/metadata_test_runner.rs | 5 ++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/testing/ui-tests/src/lib.rs b/testing/ui-tests/src/lib.rs index adf08b3ab0..bced80fc0c 100644 --- a/testing/ui-tests/src/lib.rs +++ b/testing/ui-tests/src/lib.rs @@ -30,16 +30,22 @@ fn ui_tests() { let t = trybuild::TestCases::new(); // Check that storage maps with no keys are handled properly. - t.pass(&m.path_to_ui_test_for_metadata(storage::metadata_storage_map_no_keys())); + t.pass(&m.path_to_ui_test_for_metadata( + "storage_map_no_keys", + storage::metadata_storage_map_no_keys(), + )); // Test that the codegen can handle the different types of DispatchError. t.pass(&m.path_to_ui_test_for_metadata( + "named_field_dispatch_error", dispatch_errors::metadata_named_field_dispatch_error(), )); t.pass(&m.path_to_ui_test_for_metadata( - dispatch_errors::metadata_legacy_dispatch_error() + "legacy_dispatch_error", + dispatch_errors::metadata_legacy_dispatch_error(), + )); + t.pass(&m.path_to_ui_test_for_metadata( + "array_dispatch_error", + dispatch_errors::metadata_array_dispatch_error(), )); - t.pass( - &m.path_to_ui_test_for_metadata(dispatch_errors::metadata_array_dispatch_error()), - ); } diff --git a/testing/ui-tests/src/utils/metadata_test_runner.rs b/testing/ui-tests/src/utils/metadata_test_runner.rs index b98c64479d..7c1de6affd 100644 --- a/testing/ui-tests/src/utils/metadata_test_runner.rs +++ b/testing/ui-tests/src/utils/metadata_test_runner.rs @@ -27,8 +27,11 @@ pub struct MetadataTestRunner { impl MetadataTestRunner { pub fn path_to_ui_test_for_metadata( &mut self, + name: impl AsRef, metadata: RuntimeMetadataPrefixed, ) -> String { + let test_name = name.as_ref(); + // increment test index to avoid overlaps. let index = self.index; self.index += 1; @@ -43,7 +46,7 @@ impl MetadataTestRunner { }; let tmp_rust_path = { let mut t = tmp_dir.clone(); - t.push("code.rs"); + t.push(format!("{test_name}.rs")); t.to_string_lossy().into_owned() }; From f7ed4ca9384cb47a1c1969cee3edf8a1cb326eb5 Mon Sep 17 00:00:00 2001 From: James Wilson Date: Thu, 16 Jun 2022 16:51:40 +0100 Subject: [PATCH 09/10] duff => useless --- testing/ui-tests/src/utils/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/testing/ui-tests/src/utils/mod.rs b/testing/ui-tests/src/utils/mod.rs index 871d55904d..f68823d41b 100644 --- a/testing/ui-tests/src/utils/mod.rs +++ b/testing/ui-tests/src/utils/mod.rs @@ -34,8 +34,8 @@ use scale_info::{ pub use metadata_test_runner::MetadataTestRunner; /// Given some pallet metadata, generate a [`RuntimeMetadataPrefixed`] struct. -/// We default to a duff extrinsic type, and register a fake `DispatchError` type -/// matching the generic type param provided. +/// We default to a useless extrinsic type, and register a fake `DispatchError` +/// type matching the generic type param provided. pub fn generate_metadata_from_pallets_custom_dispatch_error< DispatchError: TypeInfo + 'static, >( @@ -69,8 +69,8 @@ pub fn generate_metadata_from_pallets_custom_dispatch_error< } /// Given some pallet metadata, generate a [`RuntimeMetadataPrefixed`] struct. -/// We default to a duff extrinsic type, and register a fake `DispatchError` type -/// so that codegen is happy with the metadata generated. +/// We default to a useless extrinsic type, and register a fake `DispatchError` +/// type so that codegen is happy with the metadata generated. pub fn generate_metadata_from_pallets( pallets: Vec, ) -> RuntimeMetadataPrefixed { @@ -80,7 +80,7 @@ pub fn generate_metadata_from_pallets( } /// Given some storage entries, generate a [`RuntimeMetadataPrefixed`] struct. -/// We default to a duff extrinsic type, mock a pallet out, and register a +/// We default to a useless extrinsic type, mock a pallet out, and register a /// fake `DispatchError` type so that codegen is happy with the metadata generated. pub fn generate_metadata_from_storage_entries( storage_entries: Vec, From 2ae1e6aab31757897d9c788599d822eeac4b89ea Mon Sep 17 00:00:00 2001 From: James Wilson Date: Fri, 17 Jun 2022 13:58:43 +0100 Subject: [PATCH 10/10] align versions and cargo fmt --- testing/integration-tests/Cargo.toml | 2 +- testing/ui-tests/Cargo.toml | 2 +- testing/ui-tests/src/utils/mod.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/integration-tests/Cargo.toml b/testing/integration-tests/Cargo.toml index a8a50c96d8..e17299c889 100644 --- a/testing/integration-tests/Cargo.toml +++ b/testing/integration-tests/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "subxt-integration" +name = "integration-tests" version = "0.21.0" authors = ["Parity Technologies "] edition = "2021" diff --git a/testing/ui-tests/Cargo.toml b/testing/ui-tests/Cargo.toml index 1627720582..08f16a66af 100644 --- a/testing/ui-tests/Cargo.toml +++ b/testing/ui-tests/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ui-tests" -version = "0.1.0" +version = "0.21.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/testing/ui-tests/src/utils/mod.rs b/testing/ui-tests/src/utils/mod.rs index f68823d41b..d0eacd266a 100644 --- a/testing/ui-tests/src/utils/mod.rs +++ b/testing/ui-tests/src/utils/mod.rs @@ -34,7 +34,7 @@ use scale_info::{ pub use metadata_test_runner::MetadataTestRunner; /// Given some pallet metadata, generate a [`RuntimeMetadataPrefixed`] struct. -/// We default to a useless extrinsic type, and register a fake `DispatchError` +/// We default to a useless extrinsic type, and register a fake `DispatchError` /// type matching the generic type param provided. pub fn generate_metadata_from_pallets_custom_dispatch_error< DispatchError: TypeInfo + 'static, @@ -69,7 +69,7 @@ pub fn generate_metadata_from_pallets_custom_dispatch_error< } /// Given some pallet metadata, generate a [`RuntimeMetadataPrefixed`] struct. -/// We default to a useless extrinsic type, and register a fake `DispatchError` +/// We default to a useless extrinsic type, and register a fake `DispatchError` /// type so that codegen is happy with the metadata generated. pub fn generate_metadata_from_pallets( pallets: Vec,