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 Backend::RuntimeOnly(args) => {
82 let runtime: syn::Path = args.runtime_path();
83 let client: syn::Path = args.client_path();
84 build_runtime_client(exec_build_contracts, runtime, client)
85 }
86 };
87
88 let parser = syn::Attribute::parse_outer;
89 use syn::parse::Parser;
90 let chosen_test_attr = parser
91 .parse_str(&chosen_test_attr)
92 .expect("Failed to parse attribute");
93
94 quote! {
95 #( #attrs )*
96 #( #chosen_test_attr )*
97 #vis fn #fn_name (#possibly_fn_input) #ret {
98 use ::ink_e2e::log_info;
99 ::ink_e2e::LOG_PREFIX.with(|log_prefix| {
100 let str = format!("test: {}", stringify!(#fn_name));
101 *log_prefix.borrow_mut() = String::from(str);
102 });
103 log_info("setting up e2e test");
104
105 ::ink_e2e::INIT.call_once(|| {
106 let _ = ::ink_e2e::tracing_subscriber::fmt::try_init();
108 });
109
110 log_info("creating new client");
111
112 let run = async {
113 #client_building
114
115 let __ret = {
116 #block
117 };
118 __ret
119 };
120
121 {
122 return ::ink_e2e::tokio::runtime::Builder::new_current_thread()
123 .enable_all()
124 .build()
125 .unwrap_or_else(|err| panic!("Failed building the Runtime: {err}"))
126 .block_on(run);
127 }
128 }
129 }
130 }
131}
132
133fn build_full_client(
134 environment: &syn::Path,
135 contracts: TokenStream2,
136 node_config: Node,
137) -> TokenStream2 {
138 match node_config.url() {
139 Some(url) => {
140 quote! {
141 let contracts = #contracts;
142 let rpc = ::ink_e2e::RpcClient::from_url(#url)
143 .await
144 .unwrap_or_else(|err|
145 ::core::panic!("Error connecting to node at {}: {err:?}", #url)
146 );
147 let mut client = ::ink_e2e::Client::<
148 ::ink_e2e::PolkadotConfig,
149 #environment
150 >::new(rpc, contracts, #url.to_string()).await
151 .expect("Failed creating Client");
152 }
153 }
154 None => {
155 quote! {
156 let contracts = #contracts;
157 let node_rpc = ::ink_e2e::TestNodeProcess::<::ink_e2e::PolkadotConfig>
158 ::build_with_env_or_default()
159 .spawn()
160 .await
161 .unwrap_or_else(|err|
162 ::core::panic!("Error spawning ink-node: {err:?}")
163 );
164 let mut client = ::ink_e2e::Client::<
165 ::ink_e2e::PolkadotConfig,
166 #environment
167 >::new(node_rpc.rpc(), contracts, node_rpc.url().to_string()).await
168 .expect("Failed creating Client");
169 }
170 }
171 }
172}
173
174fn build_runtime_client(
175 contracts: TokenStream2,
176 runtime: syn::Path,
177 client: syn::Path,
178) -> TokenStream2 {
179 quote! {
180 let contracts = #contracts;
181 let mut client = #client::<_, #runtime>::new(contracts);
182 }
183}