mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-23 06:08:01 +00:00
26b8a81c17
* Preserve attrs on codegen and ignore all clippy on generated code * tweak and test attr preservation
144 lines
4.9 KiB
Rust
144 lines
4.9 KiB
Rust
// Copyright 2019-2022 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,
|
|
};
|
|
|
|
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) => v14,
|
|
_ => 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) -> 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);
|
|
generator
|
|
.generate_runtime(item_mod, derives, crate_path)
|
|
.to_string()
|
|
}
|
|
|
|
fn interface_docs() -> 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());
|
|
|
|
// 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();
|
|
|
|
for raw in raw_docs.iter() {
|
|
assert!(
|
|
runtime_docs.contains(raw),
|
|
"Documentation not 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 generated_code = generator
|
|
.generate_runtime(item_mod, derives, CratePath::default())
|
|
.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);
|
|
}
|