1use crate::{
16 config::{
17 Backend,
18 Node,
19 },
20 ir,
21};
22use derive_more::From;
23use proc_macro2::TokenStream as TokenStream2;
24use quote::quote;
25
26#[derive(From)]
28pub struct InkE2ETest {
29 test: ir::InkE2ETest,
31}
32
33impl InkE2ETest {
34 pub fn generate_code(&self) -> TokenStream2 {
36 #[cfg(clippy)]
37 if true {
38 return quote! {};
39 }
40
41 let item_fn = &self.test.item_fn.item_fn;
42 let fn_name = &item_fn.sig.ident;
43 let block = &item_fn.block;
44 let fn_return_type = &item_fn.sig.output;
45 let vis = &item_fn.vis;
46 let attrs = &item_fn.attrs;
47 let ret = match fn_return_type {
48 syn::ReturnType::Default => quote! {},
49 syn::ReturnType::Type(rarrow, ret_type) => quote! { #rarrow #ret_type },
50 };
51
52 let environment = self
53 .test
54 .config
55 .environment()
56 .unwrap_or_else(|| syn::parse_quote! { ::ink::env::DefaultEnvironment });
57
58 let chosen_test_attr = self
59 .test
60 .config
61 .replace_test_attr()
62 .unwrap_or_else(|| "#[test]".to_string());
63 let possibly_fn_input = if chosen_test_attr == "#[test]" {
64 quote! {}
65 } else {
66 let inputs = &item_fn.sig.inputs;
67 quote! { #inputs }
68 };
69
70 let features = self.test.config.features();
71 let exec_build_contracts = quote! {
72 ::ink_e2e::build_root_and_contract_dependencies(
73 vec![#( #features.to_string() ),*]
74 )
75 };
76
77 let client_building = match self.test.config.backend() {
78 Backend::Node(node_config) => {
79 build_full_client(&environment, exec_build_contracts, node_config)
80 }
81 #[cfg(any(test, feature = "sandbox"))]
82 Backend::RuntimeOnly(runtime) => {
83 build_runtime_client(exec_build_contracts, runtime.into())
84 }
85 };
86
87 let parser = syn::Attribute::parse_outer;
88 use syn::parse::Parser;
89 let chosen_test_attr = parser
90 .parse_str(&chosen_test_attr)
91 .expect("Failed to parse attribute");
92
93 quote! {
94 #( #attrs )*
95 #( #chosen_test_attr )*
96 #vis fn #fn_name (#possibly_fn_input) #ret {
97 use ::ink_e2e::log_info;
98 ::ink_e2e::LOG_PREFIX.with(|log_prefix| {
99 let str = format!("test: {}", stringify!(#fn_name));
100 *log_prefix.borrow_mut() = String::from(str);
101 });
102 log_info("setting up e2e test");
103
104 ::ink_e2e::INIT.call_once(|| {
105 let _ = ::ink_e2e::tracing_subscriber::fmt::try_init();
107 });
108
109 log_info("creating new client");
110
111 let run = async {
112 #client_building
113
114 let __ret = {
115 #block
116 };
117 __ret
118 };
119
120 {
121 return ::ink_e2e::tokio::runtime::Builder::new_current_thread()
122 .enable_all()
123 .build()
124 .unwrap_or_else(|err| panic!("Failed building the Runtime: {err}"))
125 .block_on(run);
126 }
127 }
128 }
129 }
130}
131
132fn build_full_client(
133 environment: &syn::Path,
134 contracts: TokenStream2,
135 node_config: Node,
136) -> TokenStream2 {
137 match node_config.url() {
138 Some(url) => {
139 quote! {
140 let contracts = #contracts;
141 let rpc = ::ink_e2e::RpcClient::from_url(#url)
142 .await
143 .unwrap_or_else(|err|
144 ::core::panic!("Error connecting to node at {}: {err:?}", #url)
145 );
146 let mut client = ::ink_e2e::Client::<
147 ::ink_e2e::PolkadotConfig,
148 #environment
149 >::new(rpc, contracts, #url.to_string()).await
150 .expect("Failed creating Client");
151 }
152 }
153 None => {
154 quote! {
155 let contracts = #contracts;
156 let node_rpc = ::ink_e2e::TestNodeProcess::<::ink_e2e::PolkadotConfig>
157 ::build_with_env_or_default()
158 .spawn()
159 .await
160 .unwrap_or_else(|err|
161 ::core::panic!("Error spawning ink-node: {err:?}")
162 );
163 let mut client = ::ink_e2e::Client::<
164 ::ink_e2e::PolkadotConfig,
165 #environment
166 >::new(node_rpc.rpc(), contracts, node_rpc.url().to_string()).await
167 .expect("Failed creating Client");
168 }
169 }
170 }
171}
172
173#[cfg(any(test, feature = "sandbox"))]
174fn build_runtime_client(contracts: TokenStream2, runtime: syn::Path) -> TokenStream2 {
175 quote! {
176 let contracts = #contracts;
177 let mut client = ::ink_e2e::SandboxClient::<_, #runtime>::new(contracts);
178 }
179}