Implements mocking of runtime apis (#5448)

* Implements mocking of runtime apis

This pr adds support for easily mock runtime api implementations for
tests by using the `mock_impl_runtime_apis!` macro. The syntax is
similar to `impl_runtime_apis!`. The mocked implementation automatically
implements `ApiExt`, `ApiErrorExt` and `Core` as these are required by
the runtime api traits, but not required in tests or only a subset of them.

* Fix warnings

* Update primitives/api/proc-macro/src/utils.rs

Co-Authored-By: Nikolay Volf <nikvolf@gmail.com>

* Review feedback

Co-authored-by: Nikolay Volf <nikvolf@gmail.com>
This commit is contained in:
Bastian Köcher
2020-03-31 13:46:07 +02:00
committed by GitHub
parent b4d83a4b54
commit 954dca689d
19 changed files with 899 additions and 258 deletions
@@ -0,0 +1,19 @@
use substrate_test_runtime_client::runtime::Block;
sp_api::decl_runtime_apis! {
pub trait Api {
fn test(data: u64);
}
}
struct MockApi;
sp_api::mock_impl_runtime_apis! {
impl Api<Block> for MockApi {
type OtherData = u32;
fn test(data: u64) {}
}
}
fn main() {}
@@ -0,0 +1,5 @@
error: Only associated type with name `Error` is allowed
--> $DIR/mock_only_error_associated_type.rs:13:3
|
13 | type OtherData = u32;
| ^^^^
@@ -0,0 +1,27 @@
use substrate_test_runtime_client::runtime::Block;
struct Block2;
sp_api::decl_runtime_apis! {
pub trait Api {
fn test(data: u64);
}
pub trait Api2 {
fn test(data: u64);
}
}
struct MockApi;
sp_api::mock_impl_runtime_apis! {
impl Api<Block> for MockApi {
fn test(data: u64) {}
}
impl Api2<Block2> for MockApi {
fn test(data: u64) {}
}
}
fn main() {}
@@ -0,0 +1,19 @@
error: Block type should be the same between all runtime apis.
--> $DIR/mock_only_one_block_type.rs:22:12
|
22 | impl Api2<Block2> for MockApi {
| ^^^^^^
error: First block type found here
--> $DIR/mock_only_one_block_type.rs:18:11
|
18 | impl Api<Block> for MockApi {
| ^^^^^
warning: unused import: `substrate_test_runtime_client::runtime::Block`
--> $DIR/mock_only_one_block_type.rs:1:5
|
1 | use substrate_test_runtime_client::runtime::Block;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
@@ -0,0 +1,29 @@
use substrate_test_runtime_client::runtime::Block;
sp_api::decl_runtime_apis! {
pub trait Api {
fn test(data: u64);
}
pub trait Api2 {
fn test(data: u64);
}
}
struct MockApi;
sp_api::mock_impl_runtime_apis! {
impl Api<Block> for MockApi {
type Error = u32;
fn test(data: u64) {}
}
impl Api2<Block> for MockApi {
type Error = u64;
fn test(data: u64) {}
}
}
fn main() {}
@@ -0,0 +1,27 @@
error: Error type can not change between runtime apis
--> $DIR/mock_only_one_error_type.rs:23:3
|
23 | type Error = u64;
| ^^^^
error[E0277]: the trait bound `u32: std::convert::From<std::string::String>` is not satisfied
--> $DIR/mock_only_one_error_type.rs:15:1
|
15 | / sp_api::mock_impl_runtime_apis! {
16 | | impl Api<Block> for MockApi {
17 | | type Error = u32;
18 | |
... |
26 | | }
27 | | }
| | ^
| | |
| |_the trait `std::convert::From<std::string::String>` is not implemented for `u32`
| in this macro invocation
|
= help: the following implementations were found:
<u32 as std::convert::From<bool>>
<u32 as std::convert::From<char>>
<u32 as std::convert::From<h2::frame::reason::Reason>>
<u32 as std::convert::From<h2::frame::stream_id::StreamId>>
and 16 others
@@ -0,0 +1,26 @@
use substrate_test_runtime_client::runtime::Block;
sp_api::decl_runtime_apis! {
pub trait Api {
fn test(data: u64);
}
pub trait Api2 {
fn test(data: u64);
}
}
struct MockApi;
struct MockApi2;
sp_api::mock_impl_runtime_apis! {
impl Api<Block> for MockApi {
fn test(data: u64) {}
}
impl Api2<Block> for MockApi2 {
fn test(data: u64) {}
}
}
fn main() {}
@@ -0,0 +1,19 @@
error: Self type should not change between runtime apis
--> $DIR/mock_only_one_self_type.rs:21:23
|
21 | impl Api2<Block> for MockApi2 {
| ^^^^^^^^
error: First self type found here
--> $DIR/mock_only_one_self_type.rs:17:22
|
17 | impl Api<Block> for MockApi {
| ^^^^^^^
warning: unused import: `substrate_test_runtime_client::runtime::Block`
--> $DIR/mock_only_one_self_type.rs:1:5
|
1 | use substrate_test_runtime_client::runtime::Block;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `#[warn(unused_imports)]` on by default
@@ -0,0 +1,20 @@
use substrate_test_runtime_client::runtime::Block;
sp_api::decl_runtime_apis! {
pub trait Api {
fn test(data: u64);
fn test2(data: u64);
}
}
struct MockApi;
sp_api::mock_impl_runtime_apis! {
impl Api<Block> for MockApi {
fn test(self, data: u64) {}
fn test2(&mut self, data: u64) {}
}
}
fn main() {}
@@ -0,0 +1,65 @@
error: Only `&self` is supported!
--> $DIR/mock_only_self_reference.rs:14:11
|
14 | fn test(self, data: u64) {}
| ^^^^
error: Only `&self` is supported!
--> $DIR/mock_only_self_reference.rs:16:12
|
16 | fn test2(&mut self, data: u64) {}
| ^
error[E0053]: method `Api_test_runtime_api_impl` has an incompatible type for trait
--> $DIR/mock_only_self_reference.rs:12:1
|
3 | / sp_api::decl_runtime_apis! {
4 | | pub trait Api {
5 | | fn test(data: u64);
6 | | fn test2(data: u64);
7 | | }
8 | | }
| |_- type in trait
...
12 | sp_api::mock_impl_runtime_apis! {
| -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| _expected `u64`, found `()`
| |
13 | | impl Api<Block> for MockApi {
14 | | fn test(self, data: u64) {}
15 | |
16 | | fn test2(&mut self, data: u64) {}
17 | | }
18 | | }
| |_- in this macro invocation
|
= note: expected fn pointer `fn(&MockApi, &sp_api_hidden_includes_DECL_RUNTIME_APIS::sp_api::BlockId<sp_runtime::generic::block::Block<sp_runtime::generic::header::Header<u64, sp_runtime::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>, sp_api_hidden_includes_DECL_RUNTIME_APIS::sp_api::ExecutionContext, std::option::Option<u64>, std::vec::Vec<_>) -> std::result::Result<_, _>`
found fn pointer `fn(&MockApi, &sp_api_hidden_includes_DECL_RUNTIME_APIS::sp_api::BlockId<sp_runtime::generic::block::Block<sp_runtime::generic::header::Header<u64, sp_runtime::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>, sp_api_hidden_includes_DECL_RUNTIME_APIS::sp_api::ExecutionContext, std::option::Option<()>, std::vec::Vec<_>) -> std::result::Result<_, _>`
error[E0053]: method `Api_test2_runtime_api_impl` has an incompatible type for trait
--> $DIR/mock_only_self_reference.rs:12:1
|
3 | / sp_api::decl_runtime_apis! {
4 | | pub trait Api {
5 | | fn test(data: u64);
6 | | fn test2(data: u64);
7 | | }
8 | | }
| |_- type in trait
...
12 | sp_api::mock_impl_runtime_apis! {
| -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| _expected `u64`, found `()`
| |
13 | | impl Api<Block> for MockApi {
14 | | fn test(self, data: u64) {}
15 | |
16 | | fn test2(&mut self, data: u64) {}
17 | | }
18 | | }
| |_- in this macro invocation
|
= note: expected fn pointer `fn(&MockApi, &sp_api_hidden_includes_DECL_RUNTIME_APIS::sp_api::BlockId<sp_runtime::generic::block::Block<sp_runtime::generic::header::Header<u64, sp_runtime::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>, sp_api_hidden_includes_DECL_RUNTIME_APIS::sp_api::ExecutionContext, std::option::Option<u64>, std::vec::Vec<_>) -> std::result::Result<_, _>`
found fn pointer `fn(&MockApi, &sp_api_hidden_includes_DECL_RUNTIME_APIS::sp_api::BlockId<sp_runtime::generic::block::Block<sp_runtime::generic::header::Header<u64, sp_runtime::traits::BlakeTwo256>, substrate_test_runtime::Extrinsic>>, sp_api_hidden_includes_DECL_RUNTIME_APIS::sp_api::ExecutionContext, std::option::Option<()>, std::vec::Vec<_>) -> std::result::Result<_, _>`