Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Add tests and filter out mut keyword
  • Loading branch information
SkymanOne committed Nov 23, 2023
commit ffb5081954dc6385ffb2f69f77151d406b6802e5
19 changes: 18 additions & 1 deletion crates/ink/codegen/src/generator/arg_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ pub fn output_ident(message_name: &syn::Ident) -> syn::Ident {
format_ident!("{}Output", message_name.to_string().to_lower_camel_case())
}

/// Returns the sequence of artificial input parameter bindings for the message.
/// Returns the sequence of artificial input parameter bindings
/// for the message or constructor.
///
/// # Note
///
Expand All @@ -46,6 +47,22 @@ pub fn input_types(inputs: ir::InputsIter) -> Vec<&syn::Type> {
inputs.map(|pat_type| &*pat_type.ty).collect::<Vec<_>>()
}

/// Returns the sequence of input idents for the message.
pub fn input_message_idents(inputs: ir::InputsIter) -> Vec<&syn::Ident> {
inputs
.map(|input| {
match &*input.pat {
syn::Pat::Ident(ident) => &ident.ident,
_ => {
unreachable!(
"encountered ink! dispatch input with missing identifier"
)
}
}
})
.collect::<Vec<_>>()
}

/// Returns a tuple type representing the types yielded by the input types.
pub fn input_types_tuple(inputs: ir::InputsIter) -> TokenStream2 {
let input_types = input_types(inputs);
Expand Down
16 changes: 8 additions & 8 deletions crates/ink/codegen/src/generator/as_dependency/contract_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ impl ContractRef<'_> {
ir::Receiver::RefMut => quote! { forward_mut },
};
let mut_token = message.receiver().is_ref_mut().then(|| quote! { mut });
let input_bindings = message.inputs().map(|input| &input.pat).collect::<Vec<_>>();
let input_idents = generator::input_message_idents(message.inputs());
let input_types = message.inputs().map(|input| &input.ty).collect::<Vec<_>>();
let cfg_attrs = message.get_cfg_attrs(span);
quote_spanned!(span=>
Expand All @@ -301,13 +301,13 @@ impl ContractRef<'_> {
#( #cfg_attrs )*
fn #message_ident(
& #mut_token self
#( , #input_bindings : #input_types )*
#( , #input_idents : #input_types )*
) -> Self::#output_ident {
<_ as #trait_path>::#message_ident(
<_ as ::ink::codegen::TraitCallForwarderFor<{#trait_info_id}>>::#forward_operator(
<Self as ::ink::codegen::TraitCallBuilder>::#call_operator(self),
)
#( , #input_bindings )*
#( , #input_idents )*
)
}
)
Expand Down Expand Up @@ -384,7 +384,7 @@ impl ContractRef<'_> {
ir::Receiver::RefMut => quote! { call_mut },
};
let mut_token = message.receiver().is_ref_mut().then(|| quote! { mut });
let input_bindings = message.inputs().map(|input| &input.pat).collect::<Vec<_>>();
let input_idents = generator::input_message_idents(message.inputs());
let input_types = message.inputs().map(|input| &input.ty).collect::<Vec<_>>();
let output_type = message.output().map(|ty| quote! { -> #ty });
let wrapped_output_type = message.wrapped_output();
Expand All @@ -393,9 +393,9 @@ impl ContractRef<'_> {
#[inline]
pub fn #message_ident(
& #mut_token self
#( , #input_bindings : #input_types )*
#( , #input_idents : #input_types )*
) #output_type {
self.#try_message_ident( #( #input_bindings, )* )
self.#try_message_ident( #( #input_idents, )* )
.unwrap_or_else(|error| ::core::panic!(
"encountered error while calling {}::{}: {:?}",
::core::stringify!(#storage_ident),
Expand All @@ -408,10 +408,10 @@ impl ContractRef<'_> {
#[inline]
pub fn #try_message_ident(
& #mut_token self
#( , #input_bindings : #input_types )*
#( , #input_idents : #input_types )*
) -> #wrapped_output_type {
<Self as ::ink::codegen::TraitCallBuilder>::#call_operator(self)
.#message_ident( #( #input_bindings ),* )
.#message_ident( #( #input_idents ),* )
.try_invoke()
.unwrap_or_else(|error| ::core::panic!(
"encountered error while calling {}::{}: {:?}",
Expand Down
1 change: 1 addition & 0 deletions crates/ink/codegen/src/generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ pub use self::{
generate_reference_to_trait_info,
input_bindings,
input_bindings_tuple,
input_message_idents,
input_types,
input_types_tuple,
output_ident,
Expand Down
6 changes: 0 additions & 6 deletions integration-tests/flipper/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@ pub mod flipper {
pub fn get(&self) -> bool {
self.value
}

/// Returns the current value of the Flipper's boolean.
#[ink(message)]
pub fn set(&mut self, mut b: bool) {
self.value = b;
}
}

#[cfg(test)]
Expand Down
9 changes: 9 additions & 0 deletions integration-tests/incrementer-mut/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Ignore build artifacts from the local tests sub-crate.
/target/

# Ignore backup files creates by cargo fmt.
**/*.rs.bk

# Remove Cargo.lock when creating an executable, leave it for libraries
# More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock
Cargo.lock
23 changes: 23 additions & 0 deletions integration-tests/incrementer-mut/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "incrementer_mut"
version = "5.0.0-alpha"
authors = ["Parity Technologies <[email protected]>"]
edition = "2021"
publish = false

[dependencies]
ink = { path = "../../crates/ink", default-features = false }

[dev-dependencies]
ink_e2e = { path = "../../crates/e2e" }

[lib]
path = "lib.rs"

[features]
default = ["std"]
std = [
"ink/std",
]
ink-as-dependency = []
e2e-tests = []
136 changes: 136 additions & 0 deletions integration-tests/incrementer-mut/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#![cfg_attr(not(feature = "std"), no_std, no_main)]

//! A simple incrementer contract
//! demonstrating the internal mutability of message parameters.

pub use self::incrementer_mut::{
Incrementer,
IncrementerRef,
};

#[ink::contract]
mod incrementer_mut {
#[ink(storage)]
pub struct Incrementer {
value: i32,
}

impl Incrementer {
/// Create a new contract with the specified counter value.
/// If it is below 0, it is set to 0
#[ink(constructor)]
pub fn new(mut init_value: i32) -> Self {
if init_value < 0 {
init_value = 0;
}
Self { value: init_value }
}

#[ink(constructor)]
pub fn new_default() -> Self {
Self::new(Default::default())
}

#[ink(message)]
pub fn inc(&mut self, by: i32) {
self.value = self.value.checked_add(by).unwrap();
}

/// Update the counter with the specified value.
/// If it is above 100, we set it to 0.
#[ink(message)]
pub fn update(&mut self, mut value: i32) {
if value > 100 {
value = 0;
}
self.value = value;
}

#[ink(message)]
pub fn get(&self) -> i32 {
self.value
}
}

#[cfg(test)]
mod tests {
use super::*;

#[ink::test]
fn default_works() {
let contract = Incrementer::new_default();
assert_eq!(contract.get(), 0);
}

#[ink::test]
fn it_works() {
let mut contract = Incrementer::new(42);
assert_eq!(contract.get(), 42);
contract.inc(5);
assert_eq!(contract.get(), 47);
contract.inc(-50);
assert_eq!(contract.get(), -3);
}
#[ink::test]
fn mutability_works() {
let mut contract = Incrementer::new(-5);
assert_eq!(contract.get(), 0);
contract.update(80);
assert_eq!(contract.get(), 80);
contract.update(120);
assert_eq!(contract.get(), 0);
}
}

#[cfg(all(test, feature = "e2e-tests"))]
mod e2e_tests {
use super::*;
use ink_e2e::ContractsBackend;

type E2EResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;

#[ink_e2e::test]
async fn it_works<Client: E2EBackend>(mut client: Client) -> E2EResult<()> {
// given
let mut constructor = IncrementerRef::new(-2);
let contract = client
.instantiate("incrementer_mut", &ink_e2e::alice(), &mut constructor)
.submit()
.await
.expect("instantiate failed");
let mut call = contract.call::<Incrementer>();

let get = call.get();
let get_res = client.call(&ink_e2e::bob(), &get).dry_run().await?;
assert!(matches!(get_res.return_value(), 0));

// when
let flip = call.update(50);
let _flip_res = client
.call(&ink_e2e::bob(), &flip)
.submit()
.await
.expect("update failed");

// then
let get = call.get();
let get_res = client.call(&ink_e2e::bob(), &get).dry_run().await?;
assert!(matches!(get_res.return_value(), 50));

// when
let flip = call.update(150);
let _flip_res = client
.call(&ink_e2e::bob(), &flip)
.submit()
.await
.expect("update failed");

// then
let get = call.get();
let get_res = client.call(&ink_e2e::bob(), &get).dry_run().await?;
assert!(matches!(get_res.return_value(), 0));

Ok(())
}
}
}