mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 02:57:57 +00:00
59d195d4ad
* Update frame-metadata to v15.1.0 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Enable V15 unstable metadata in frame-metadata Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Move validation hashing to dedicated file Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Use sp-metadata-ir from substrate to work with metadata Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Revert using sp-metadata-ir in favor of conversion to v15 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Convert v14 to v15 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Use v15 for validation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * codegen: Use v15 for codegen Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata/bench: Use v15 Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust to v15 metadata Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Adjust testing Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * Improve documentation Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * force CI Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Address feedback Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Use HASH_LEN Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadta: Remove `LatestRuntimeMetadata` type alias Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> * metadata: Remove `metadata_to_latest` to avoid pancis Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io> --------- Signed-off-by: Alexandru Vasile <alexandru.vasile@parity.io>
172 lines
5.9 KiB
Rust
172 lines
5.9 KiB
Rust
// Copyright 2019-2023 Parity Technologies (UK) Ltd.
|
|
// This file is dual-licensed as Apache-2.0 or GPL-3.0.
|
|
// see LICENSE for license details.
|
|
|
|
use regex::Regex;
|
|
use subxt_codegen::{CratePath, DerivesRegistry, RuntimeGenerator, TypeSubstitutes};
|
|
|
|
fn load_test_metadata() -> frame_metadata::RuntimeMetadataPrefixed {
|
|
let bytes = test_runtime::METADATA;
|
|
codec::Decode::decode(&mut &*bytes).expect("Cannot decode scale metadata")
|
|
}
|
|
|
|
fn metadata_docs() -> Vec<String> {
|
|
// Load the runtime metadata downloaded from a node via `test-runtime`.
|
|
let meta = load_test_metadata();
|
|
let metadata = match meta.1 {
|
|
frame_metadata::RuntimeMetadata::V14(v14) => subxt_metadata::metadata_v14_to_latest(v14),
|
|
frame_metadata::RuntimeMetadata::V15(v15) => v15,
|
|
_ => panic!("Unsupported metadata version {:?}", meta.1),
|
|
};
|
|
|
|
// Inspect the metadata types and collect the documentation.
|
|
let mut docs = Vec::new();
|
|
for ty in &metadata.types.types {
|
|
docs.extend_from_slice(&ty.ty.docs);
|
|
}
|
|
|
|
for pallet in metadata.pallets {
|
|
if let Some(storage) = pallet.storage {
|
|
for entry in storage.entries {
|
|
docs.extend(entry.docs);
|
|
}
|
|
}
|
|
// Note: Calls, Events and Errors are deduced directly to
|
|
// PortableTypes which are handled above.
|
|
for constant in pallet.constants {
|
|
docs.extend(constant.docs);
|
|
}
|
|
}
|
|
// Note: Extrinsics do not have associated documentation, but is implied by
|
|
// associated Type.
|
|
|
|
docs
|
|
}
|
|
|
|
fn generate_runtime_interface(crate_path: CratePath, should_gen_docs: bool) -> String {
|
|
// Load the runtime metadata downloaded from a node via `test-runtime`.
|
|
let metadata = load_test_metadata();
|
|
|
|
// Generate a runtime interface from the provided metadata.
|
|
let generator = RuntimeGenerator::new(metadata);
|
|
let item_mod = syn::parse_quote!(
|
|
pub mod api {}
|
|
);
|
|
let derives = DerivesRegistry::new(&crate_path);
|
|
let type_substitutes = TypeSubstitutes::new(&crate_path);
|
|
generator
|
|
.generate_runtime(
|
|
item_mod,
|
|
derives,
|
|
type_substitutes,
|
|
crate_path,
|
|
should_gen_docs,
|
|
)
|
|
.expect("API generation must be valid")
|
|
.to_string()
|
|
}
|
|
|
|
fn interface_docs(should_gen_docs: bool) -> Vec<String> {
|
|
// Generate the runtime interface from the node's metadata.
|
|
// Note: the API is generated on a single line.
|
|
let runtime_api = generate_runtime_interface(CratePath::default(), should_gen_docs);
|
|
|
|
// Documentation lines have the following format:
|
|
// # [ doc = "Upward message is invalid XCM."]
|
|
// Given the API is generated on a single line, the regex matching
|
|
// must be lazy hence the `?` in the matched group `(.*?)`.
|
|
//
|
|
// The greedy `non-?` matching would lead to one single match
|
|
// from the beginning of the first documentation tag, containing everything up to
|
|
// the last documentation tag
|
|
// `# [ doc = "msg"] # [ doc = "msg2"] ... api ... # [ doc = "msgN" ]`
|
|
//
|
|
// The `(.*?)` stands for match any character zero or more times lazily.
|
|
let re = Regex::new(r#"\# \[doc = "(.*?)"\]"#).unwrap();
|
|
re.captures_iter(&runtime_api)
|
|
.filter_map(|capture| {
|
|
// Get the matched group (ie index 1).
|
|
capture.get(1).as_ref().map(|doc| {
|
|
// Generated documentation will escape special characters.
|
|
// Replace escaped characters with unescaped variants for
|
|
// exact matching on the raw metadata documentation.
|
|
doc.as_str()
|
|
.replace("\\n", "\n")
|
|
.replace("\\t", "\t")
|
|
.replace("\\\"", "\"")
|
|
})
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
#[test]
|
|
fn check_documentation() {
|
|
// Inspect metadata recursively and obtain all associated documentation.
|
|
let raw_docs = metadata_docs();
|
|
// Obtain documentation from the generated API.
|
|
let runtime_docs = interface_docs(true);
|
|
|
|
for raw in raw_docs.iter() {
|
|
assert!(
|
|
runtime_docs.contains(raw),
|
|
"Documentation not present in runtime API: {raw}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn check_no_documentation() {
|
|
// Inspect metadata recursively and obtain all associated documentation.
|
|
let raw_docs = metadata_docs();
|
|
// Obtain documentation from the generated API.
|
|
let runtime_docs = interface_docs(false);
|
|
|
|
for raw in raw_docs.iter() {
|
|
assert!(
|
|
!runtime_docs.contains(raw),
|
|
"Documentation should not be present in runtime API: {raw}"
|
|
);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn check_root_attrs_preserved() {
|
|
let metadata = load_test_metadata();
|
|
|
|
// Test that the root docs/attr are preserved.
|
|
let item_mod = syn::parse_quote!(
|
|
/// Some root level documentation
|
|
#[some_root_attribute]
|
|
pub mod api {}
|
|
);
|
|
|
|
// Generate a runtime interface from the provided metadata.
|
|
let generator = RuntimeGenerator::new(metadata);
|
|
let derives = DerivesRegistry::new(&CratePath::default());
|
|
let type_substitutes = TypeSubstitutes::new(&CratePath::default());
|
|
let generated_code = generator
|
|
.generate_runtime(
|
|
item_mod,
|
|
derives,
|
|
type_substitutes,
|
|
CratePath::default(),
|
|
true,
|
|
)
|
|
.expect("API generation must be valid")
|
|
.to_string();
|
|
|
|
let doc_str_loc = generated_code
|
|
.find("Some root level documentation")
|
|
.expect("root docs should be preserved");
|
|
let attr_loc = generated_code
|
|
.find("some_root_attribute") // '#' is space separated in generated output.
|
|
.expect("root attr should be preserved");
|
|
let mod_start = generated_code
|
|
.find("pub mod api")
|
|
.expect("'pub mod api' expected");
|
|
|
|
// These things should be before the mod start
|
|
assert!(doc_str_loc < mod_start);
|
|
assert!(attr_loc < mod_start);
|
|
}
|