tet_core/
testing.rs

1// This file is part of Tetcore.
2
3// Copyright (C) 2019-2021 Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Types that should only be used for testing!
19
20use crate::crypto::KeyTypeId;
21
22/// Key type for generic Ed25519 key.
23pub const ED25519: KeyTypeId = KeyTypeId(*b"ed25");
24/// Key type for generic Sr 25519 key.
25pub const SR25519: KeyTypeId = KeyTypeId(*b"sr25");
26/// Key type for generic Sr 25519 key.
27pub const ECDSA: KeyTypeId = KeyTypeId(*b"ecds");
28
29/// Macro for exporting functions from wasm in with the expected signature for using it with the
30/// wasm executor. This is useful for tests where you need to call a function in wasm.
31///
32/// The input parameters are expected to be SCALE encoded and will be automatically decoded for you.
33/// The output value is also SCALE encoded when returned back to the host.
34///
35/// The functions are feature-gated with `#[cfg(not(feature = "std"))]`, so they are only available
36/// from within wasm.
37///
38/// # Example
39///
40/// ```
41/// # use tet_core::wasm_export_functions;
42///
43/// wasm_export_functions! {
44///     fn test_in_wasm(value: bool, another_value: Vec<u8>) -> bool {
45///         value && another_value.is_empty()
46///     }
47///
48///     fn without_return_value() {
49///         // do something
50///     }
51/// }
52/// ```
53#[macro_export]
54macro_rules! wasm_export_functions {
55	(
56		$(
57			fn $name:ident (
58				$( $arg_name:ident: $arg_ty:ty ),* $(,)?
59			) $( -> $ret_ty:ty )? { $( $fn_impl:tt )* }
60		)*
61	) => {
62		$(
63			$crate::wasm_export_functions! {
64				@IMPL
65				fn $name (
66					$( $arg_name: $arg_ty ),*
67				) $( -> $ret_ty )? { $( $fn_impl )* }
68			}
69		)*
70	};
71	(@IMPL
72		fn $name:ident (
73				$( $arg_name:ident: $arg_ty:ty ),*
74		) { $( $fn_impl:tt )* }
75	) => {
76		#[no_mangle]
77		#[allow(unreachable_code)]
78		#[cfg(not(feature = "std"))]
79		pub fn $name(input_data: *mut u8, input_len: usize) -> u64 {
80			let input: &[u8] = if input_len == 0 {
81				&[0u8; 0]
82			} else {
83				unsafe {
84					$crate::tetcore_std::slice::from_raw_parts(input_data, input_len)
85				}
86			};
87
88			{
89				let ($( $arg_name ),*) : ($( $arg_ty ),*) = $crate::Decode::decode(
90					&mut &input[..],
91				).expect("Input data is correctly encoded");
92
93				$( $fn_impl )*
94			}
95
96			$crate::to_tetcore_wasm_fn_return_value(&())
97		}
98	};
99	(@IMPL
100		fn $name:ident (
101				$( $arg_name:ident: $arg_ty:ty ),*
102		) $( -> $ret_ty:ty )? { $( $fn_impl:tt )* }
103	) => {
104		#[no_mangle]
105		#[allow(unreachable_code)]
106		#[cfg(not(feature = "std"))]
107		pub fn $name(input_data: *mut u8, input_len: usize) -> u64 {
108			let input: &[u8] = if input_len == 0 {
109				&[0u8; 0]
110			} else {
111				unsafe {
112					$crate::tetcore_std::slice::from_raw_parts(input_data, input_len)
113				}
114			};
115
116			let output $( : $ret_ty )? = {
117				let ($( $arg_name ),*) : ($( $arg_ty ),*) = $crate::Decode::decode(
118					&mut &input[..],
119				).expect("Input data is correctly encoded");
120
121				$( $fn_impl )*
122			};
123
124			$crate::to_tetcore_wasm_fn_return_value(&output)
125		}
126	};
127}
128
129/// A task executor that can be used in tests.
130///
131/// Internally this just wraps a `ThreadPool` with a pool size of `8`. This
132/// should ensure that we have enough threads in tests for spawning blocking futures.
133#[cfg(feature = "std")]
134#[derive(Clone)]
135pub struct TaskExecutor(futures::executor::ThreadPool);
136
137#[cfg(feature = "std")]
138impl TaskExecutor {
139	/// Create a new instance of `Self`.
140	pub fn new() -> Self {
141		let mut builder = futures::executor::ThreadPoolBuilder::new();
142		Self(builder.pool_size(8).create().expect("Failed to create thread pool"))
143	}
144}
145
146#[cfg(feature = "std")]
147impl crate::traits::SpawnNamed for TaskExecutor {
148	fn spawn_blocking(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) {
149		self.0.spawn_ok(future);
150	}
151	fn spawn(&self, _: &'static str, future: futures::future::BoxFuture<'static, ()>) {
152		self.0.spawn_ok(future);
153	}
154}