diff --git a/test-engine/src/call_builder.rs b/test-engine/src/call_builder.rs index 6816b7c..49aa919 100644 --- a/test-engine/src/call_builder.rs +++ b/test-engine/src/call_builder.rs @@ -1,18 +1,14 @@ use crate::account::Account; -use crate::environment::{EnvironmentEncode, Fungible, NonFungible}; +use crate::environment::{Fungible, NonFungible, ToValue}; use crate::internal_prelude::*; use crate::method_call::SimpleMethodCaller; +use crate::receipt_traits::Outcome; use crate::references::{ComponentReference, GlobalReference, ReferenceName, ResourceReference}; use crate::test_engine::TestEngine; use crate::to_id::ToId; use std::collections::BTreeSet; use std::vec::Vec; -struct TransactionManifestData { - transaction_manifest: TransactionManifestV1, - // object_names: KnownManifestObjectNames, -} - pub struct CallBuilder<'a> { caller: Account, manifest_builder: ManifestBuilder, @@ -25,7 +21,7 @@ pub struct CallBuilder<'a> { with_tx_fee: bool, log_title: Option<&'a str>, deposit_destination: ComponentAddress, - manifest_data: Option, + transaction_manifest: Option, } impl<'a> CallBuilder<'a> { @@ -42,7 +38,7 @@ impl<'a> CallBuilder<'a> { output_manifest: None, admin_badge: vec![], with_trace: false, - manifest_data: None, + transaction_manifest: None, with_tx_fee: false, log_title: None, } @@ -69,7 +65,7 @@ impl<'a> CallBuilder<'a> { /// # Arguments /// * `method_name`: name of the method. /// * `args`: environment arguments to call the method. - pub fn call(self, method_name: &str, args: Vec>) -> Self { + pub fn call(self, method_name: &str, args: Vec>) -> Self { let component = *self.test_engine.current_component(); self.call_method_internal(component, method_name, args) } @@ -84,9 +80,10 @@ impl<'a> CallBuilder<'a> { self, entity_name: G, method_name: &str, - args: Vec>, + args: Vec>, ) -> Self { let component = entity_name.address(self.test_engine); + self.call_method_internal(component, method_name, args) } @@ -96,15 +93,13 @@ impl<'a> CallBuilder<'a> { /// * `name`: reference name of the component. pub fn set_current_component(self, name: E) -> Self { self.test_engine.set_current_component(name); + manifest_args!(); self } /// Executes the call. pub fn execute(mut self) -> TransactionReceipt { - self.manifest_data = Some(TransactionManifestData { - // object_names: self.manifest_builder.object_names().clone(), - transaction_manifest: self.manifest_builder.build(), - }); + self.transaction_manifest = Some(self.manifest_builder.build()); self.manifest_builder = ManifestBuilder::new(); @@ -114,7 +109,7 @@ impl<'a> CallBuilder<'a> { self.output_manifest(); let receipt = self.test_engine.execute_call( - self.manifest_data.unwrap().transaction_manifest, + self.transaction_manifest.unwrap(), self.with_trace, btreeset![self.caller.proof()], true, @@ -135,12 +130,16 @@ impl<'a> CallBuilder<'a> { receipt } - pub fn execute_and_expect_success(self) -> CommitResult { - self.execute().expect_commit_success().clone() + pub fn execute_and_expect_success(self) -> TransactionReceipt { + self.execute().assert_is_success() } - pub fn execute_and_expect_failure(self) -> CommitResult { - self.execute().expect_commit_failure().clone() + pub fn execute_and_expect_failure(self) -> TransactionReceipt { + self.execute().assert_failed() + } + + pub fn execute_and_expect_failure_with(self, error: &str) -> TransactionReceipt { + self.execute().assert_failed_with(error) } /// Deposits the batch to the given account. @@ -295,28 +294,21 @@ impl<'a> CallBuilder<'a> { mut self, component: impl ReferencedManifestGlobalAddress, method_name: &str, - args: Vec>, + args: Vec>, ) -> Self { - let mut manifest_builder = self.manifest_builder; - - let mut buf = Vec::new(); - let mut encoder = ManifestEncoder::new(&mut buf, MANIFEST_SBOR_V1_MAX_DEPTH); - encoder - .write_payload_prefix(MANIFEST_SBOR_V1_PAYLOAD_PREFIX) - .unwrap(); - encoder.write_value_kind(ManifestValueKind::Tuple).unwrap(); - encoder.write_size(args.len()).unwrap(); - for arg in args { - manifest_builder = arg.encode( - self.test_engine, - manifest_builder, - &mut encoder, - *self.caller.address(), - ); - } + let manifest_builder = self.manifest_builder; + + let (manifest_builder, values) = args.into_iter().fold( + (manifest_builder, Vec::new()), + |(manifest_builder, mut values), arg| { + let (manifest_builder, encoded) = + arg.to_value(self.test_engine, manifest_builder, *self.caller.address()); + values.push(encoded); + (manifest_builder, values) + }, + ); - let value = manifest_decode(&buf).unwrap(); - let manifest_arg = ManifestArgs::new_from_tuple_or_panic(value); + let manifest_arg = ManifestArgs::new_from_tuple_or_panic(Value::Tuple { fields: values }); let manifest_builder = manifest_builder.call_method(component, method_name, manifest_arg); @@ -326,10 +318,7 @@ impl<'a> CallBuilder<'a> { } pub(crate) fn execute_no_update(mut self) -> TransactionReceipt { - self.manifest_data = Some(TransactionManifestData { - // object_names: self.manifest_builder.object_names().clone(), - transaction_manifest: self.manifest_builder.build(), - }); + self.transaction_manifest = Some(self.manifest_builder.build()); self.manifest_builder = ManifestBuilder::new(); @@ -339,7 +328,7 @@ impl<'a> CallBuilder<'a> { self.output_manifest(); let receipt = self.test_engine.execute_call( - self.manifest_data.unwrap().transaction_manifest, + self.transaction_manifest.unwrap(), self.with_trace, btreeset![self.caller.proof()], false, @@ -365,28 +354,21 @@ impl<'a> CallBuilder<'a> { package_address: PackageAddress, blueprint_name: &str, function_name: &str, - args: Vec>, + args: Vec>, ) -> Self { - let mut manifest_builder = self.manifest_builder; - - let mut buf = Vec::new(); - let mut encoder = ManifestEncoder::new(&mut buf, MANIFEST_SBOR_V1_MAX_DEPTH); - encoder - .write_payload_prefix(MANIFEST_SBOR_V1_PAYLOAD_PREFIX) - .unwrap(); - encoder.write_value_kind(ManifestValueKind::Tuple).unwrap(); - encoder.write_size(args.len()).unwrap(); - for arg in args { - manifest_builder = arg.encode( - self.test_engine, - manifest_builder, - &mut encoder, - *self.caller.address(), - ); - } + let manifest_builder = self.manifest_builder; + + let (manifest_builder, values) = args.into_iter().fold( + (manifest_builder, Vec::new()), + |(manifest_builder, mut values), arg| { + let (manifest_builder, encoded) = + arg.to_value(self.test_engine, manifest_builder, *self.caller.address()); + values.push(encoded); + (manifest_builder, values) + }, + ); - let value = manifest_decode(&buf).unwrap(); - let manifest_arg = ManifestArgs::new_from_tuple_or_panic(value); + let manifest_arg = ManifestArgs::new_from_tuple_or_panic(Value::Tuple { fields: values }); let manifest_builder = manifest_builder.call_function( package_address, @@ -401,7 +383,7 @@ impl<'a> CallBuilder<'a> { } fn write_lock(&mut self) { - let manifest = &mut self.manifest_data.as_mut().unwrap().transaction_manifest; + let manifest = &mut self.transaction_manifest.as_mut().unwrap(); manifest.instructions.insert( 0, @@ -414,7 +396,7 @@ impl<'a> CallBuilder<'a> { } fn write_deposit(&mut self) { - let manifest = &mut self.manifest_data.as_mut().unwrap().transaction_manifest; + let manifest = &mut self.transaction_manifest.as_mut().unwrap(); manifest .instructions @@ -425,7 +407,7 @@ impl<'a> CallBuilder<'a> { })); } fn write_badge(&mut self) { - let manifest = &mut self.manifest_data.as_mut().unwrap().transaction_manifest; + let manifest = &mut self.transaction_manifest.as_mut().unwrap(); for (badge, opt_ids) in &self.admin_badge { if badge.is_fungible() { manifest.instructions.insert( @@ -450,14 +432,13 @@ impl<'a> CallBuilder<'a> { } fn output_manifest(&mut self) { - let manifest = &self.manifest_data.as_mut().unwrap().transaction_manifest; - // let a = manifest.transaction_manifest.clone(); + let manifest = self.transaction_manifest.as_mut().unwrap(); + match &self.output_manifest { None => {} Some((path, name)) => { match dump_manifest_to_file_system( - manifest, //.object_names.clone(), - // &manifest.transaction_manifest, + manifest, path, Some(name), &self.test_engine.network(), @@ -492,11 +473,7 @@ impl<'a> CallBuilder<'a> { } impl SimpleMethodCaller for CallBuilder<'_> { - fn call_method( - self, - method_name: &str, - args: Vec>, - ) -> TransactionReceipt { + fn call_method(self, method_name: &str, args: Vec>) -> TransactionReceipt { let component = *self.test_engine.current_component(); self.call_method_internal(component, method_name, args) .execute() @@ -506,7 +483,7 @@ impl SimpleMethodCaller for CallBuilder<'_> { self, entity_name: G, method_name: &str, - args: Vec>, + args: Vec>, ) -> TransactionReceipt { let component = entity_name.address(self.test_engine); self.call_method_internal(component, method_name, args) @@ -517,7 +494,7 @@ impl SimpleMethodCaller for CallBuilder<'_> { self, method_name: &str, admin_badge: R, - args: Vec>, + args: Vec>, ) -> TransactionReceipt { let component = *self.test_engine.current_component(); self.call_method_internal(component, method_name, args) diff --git a/test-engine/src/engine_interface.rs b/test-engine/src/engine_interface.rs index 237fbae..0f0e099 100644 --- a/test-engine/src/engine_interface.rs +++ b/test-engine/src/engine_interface.rs @@ -11,7 +11,8 @@ pub struct EngineInterface { impl EngineInterface { pub fn new() -> Self { let test_runner_builder = LedgerSimulatorBuilder::new() - .with_custom_genesis(BabylonSettings::test_default()) + // .with_custom_genesis(BabylonSettings::test_default()) + // .with_custom_protocol(|builder| builder.only_babylon()) .without_kernel_trace() .build(); @@ -22,8 +23,11 @@ impl EngineInterface { pub fn new_with_custom_genesis(genesis: BabylonSettings) -> Self { let test_runner_builder = LedgerSimulatorBuilder::new() - .with_custom_genesis(genesis) - .without_kernel_trace() + .with_custom_protocol(|builder| { + builder + .configure_babylon(|_| genesis) + .from_bootstrap_to_latest() + }) .build(); Self { simulator: test_runner_builder, diff --git a/test-engine/src/environment.rs b/test-engine/src/environment.rs index 5a1fe60..090ef6f 100644 --- a/test-engine/src/environment.rs +++ b/test-engine/src/environment.rs @@ -3,28 +3,54 @@ use crate::references::{ReferenceName, ResourceReference}; use crate::test_engine::TestEngine; use std::vec::Vec; -pub trait ToEncode { - fn to_encode<'a>( +pub trait ToValue { + fn to_value<'a>( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, caller: ComponentAddress, - ) -> ( - ManifestBuilder, - Box>>, - ); + ) -> (ManifestBuilder, ManifestValue); } -pub trait EnvironmentEncode { - fn encode( - &self, - test_engine: &mut TestEngine, - manifest_builder: ManifestBuilder, - encoder: &mut ManifestEncoder, - caller: ComponentAddress, - ) -> ManifestBuilder; +// ! Refs + +// macro to implement ToValue of env reference types +macro_rules! env_to_value_impl { + ($name:ident, $getter:ident) => { + impl ToValue for $name { + fn to_value<'a>( + &self, + test_engine: &mut TestEngine, + manifest_builder: ManifestBuilder, + _caller: ComponentAddress, + ) -> (ManifestBuilder, ManifestValue) { + let address = test_engine.$getter(self.0.clone()); + ( + manifest_builder, + Value::Custom { + value: ManifestCustomValue::Address((address.clone()).into()), + }, + ) + } + } + }; } +#[derive(Clone, Debug)] +pub struct EnvResource(pub N); +env_to_value_impl!(EnvResource, get_resource); + +#[derive(Clone, Debug)] +pub struct EnvAccount(pub N); +env_to_value_impl!(EnvAccount, get_account); + +#[derive(Clone, Debug)] +pub struct EnvComponent(pub N); +env_to_value_impl!(EnvComponent, get_component); + +pub struct EnvPackage(pub N); +env_to_value_impl!(EnvPackage, get_package); + pub enum Environment { Account(N), Component(N), @@ -32,53 +58,35 @@ pub enum Environment { Resource(N), } -impl ToEncode for Environment { - fn to_encode<'a>( +impl ToValue for Environment { + fn to_value<'a>( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, _caller: ComponentAddress, - ) -> ( - ManifestBuilder, - Box>>, - ) { - match self { + ) -> (ManifestBuilder, ManifestValue) { + let value = match self { Environment::Resource(resource) => { - let resource_address = test_engine.get_resource(resource.clone()); - (manifest_builder, Box::new(resource_address)) + ManifestCustomValue::Address(test_engine.get_resource(resource.clone()).into()) } Environment::Account(address) => { - let account = *test_engine.get_account(address.clone()); - (manifest_builder, Box::new(account)) + ManifestCustomValue::Address((*test_engine.get_account(address.clone())).into()) } Environment::Component(address) => { - let component = test_engine.get_component(address.clone()); - (manifest_builder, Box::new(component)) + ManifestCustomValue::Address(test_engine.get_component(address.clone()).into()) } Environment::Package(address) => { - let package = test_engine.get_package(address.clone()); - (manifest_builder, Box::new(package)) + ManifestCustomValue::Address(test_engine.get_package(address.clone()).into()) } - } - } -} + }; -impl EnvironmentEncode for Environment { - fn encode( - &self, - test_engine: &mut TestEngine, - manifest_builder: ManifestBuilder, - encoder: &mut ManifestEncoder, - caller: ComponentAddress, - ) -> ManifestBuilder { - let (manifest_builder, encoded) = self.to_encode(test_engine, manifest_builder, caller); - encoder.encode(encoded.as_ref()).expect("Could not encode"); - manifest_builder + (manifest_builder, Value::Custom { value }) } } -// Fungible +// ! Fungible +#[derive(Clone, Debug)] pub enum Fungible { FromAccount(R, Decimal), FromWorkTop(R, Decimal), @@ -86,16 +94,13 @@ pub enum Fungible { AllFromWorktop(R), } -impl ToEncode for Fungible { - fn to_encode<'a>( +impl Fungible { + pub fn to_manifest_bucket<'a>( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, caller: ComponentAddress, - ) -> ( - ManifestBuilder, - Box>>, - ) { + ) -> (ManifestBuilder, ManifestBucket) { match self { Fungible::FromAccount(resource, amount) => { let resource_address = resource.address(test_engine); @@ -112,19 +117,20 @@ impl ToEncode for Fungible { amount, }), ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + (manifest_builder, bucket.new_bucket.unwrap()) } Fungible::FromWorkTop(resource, amount) => { let resource_address = resource.address(test_engine); let amount = *amount; - let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( + let (manifest_builder, symbols) = manifest_builder.add_instruction_advanced( InstructionV1::TakeFromWorktop(TakeFromWorktop { resource_address, amount, }), ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + + (manifest_builder, symbols.new_bucket.unwrap()) } Fungible::AllFromAccount(resource) => { let amount_owned = test_engine.current_balance(resource.clone()); @@ -141,7 +147,7 @@ impl ToEncode for Fungible { amount: amount_owned, }), ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + (manifest_builder, bucket.new_bucket.unwrap()) } Fungible::AllFromWorktop(resource) => { let resource_address = resource.address(test_engine); @@ -149,27 +155,31 @@ impl ToEncode for Fungible { let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( InstructionV1::TakeAllFromWorktop(TakeAllFromWorktop { resource_address }), ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + (manifest_builder, bucket.new_bucket.unwrap()) } } } } -impl EnvironmentEncode for Fungible { - fn encode( +impl ToValue for Fungible { + fn to_value<'a>( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, - encoder: &mut ManifestEncoder, caller: ComponentAddress, - ) -> ManifestBuilder { - let (manifest_builder, encoded) = self.to_encode(test_engine, manifest_builder, caller); - encoder.encode(encoded.as_ref()).expect("Could not encode"); - manifest_builder + ) -> (ManifestBuilder, ManifestValue) { + let manifest_bucket = self.to_manifest_bucket(test_engine, manifest_builder, caller); + + ( + manifest_bucket.0, + Value::Custom { + value: ManifestCustomValue::Bucket(manifest_bucket.1), + }, + ) } } -// Non Fungible +// ! Non Fungible pub enum NonFungible { FromAccount(R, Vec), @@ -178,16 +188,13 @@ pub enum NonFungible { AllFromWorktop(R), } -impl ToEncode for NonFungible { - fn to_encode<'a>( +impl NonFungible { + fn to_manifest_bucket<'a>( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, caller: ComponentAddress, - ) -> ( - ManifestBuilder, - Box>>, - ) { + ) -> (ManifestBuilder, ManifestBucket) { match self { NonFungible::FromAccount(resource, ids) => { let resource_address = resource.address(test_engine); @@ -203,7 +210,7 @@ impl ToEncode for NonFungible { ids: ids.clone(), }), ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + (manifest_builder, bucket.new_bucket.unwrap()) } NonFungible::FromWorktop(resource, ids) => { let resource_address = resource.address(test_engine); @@ -213,7 +220,7 @@ impl ToEncode for NonFungible { ids: ids.clone(), }), ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + (manifest_builder, bucket.new_bucket.unwrap()) } NonFungible::AllFromAccount(resource) => { @@ -231,7 +238,7 @@ impl ToEncode for NonFungible { ids: ids_owned, }), ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + (manifest_builder, bucket.new_bucket.unwrap()) } NonFungible::AllFromWorktop(resource) => { let resource_address = resource.address(test_engine); @@ -239,27 +246,31 @@ impl ToEncode for NonFungible { let (manifest_builder, bucket) = manifest_builder.add_instruction_advanced( InstructionV1::TakeAllFromWorktop(TakeAllFromWorktop { resource_address }), ); - (manifest_builder, Box::new(bucket.new_bucket.unwrap())) + (manifest_builder, bucket.new_bucket.unwrap()) } } } } -impl EnvironmentEncode for NonFungible { - fn encode( +impl ToValue for NonFungible { + fn to_value<'a>( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, - encoder: &mut ManifestEncoder, caller: ComponentAddress, - ) -> ManifestBuilder { - let (manifest_builder, encoded) = self.to_encode(test_engine, manifest_builder, caller); - encoder.encode(encoded.as_ref()).expect("Could not encode"); - manifest_builder + ) -> (ManifestBuilder, ManifestValue) { + let manifest_bucket = self.to_manifest_bucket(test_engine, manifest_builder, caller); + + ( + manifest_bucket.0, + Value::Custom { + value: ManifestCustomValue::Bucket(manifest_bucket.1), + }, + ) } } -// Proofs +// ! Proofs pub enum ProofOf { FungibleFromAccount(R, Decimal), @@ -268,17 +279,14 @@ pub enum ProofOf { NonFungibleFromAuthZone(R, Vec), } -impl ToEncode for ProofOf { - fn to_encode<'a>( +impl ToValue for ProofOf { + fn to_value<'a>( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, caller: ComponentAddress, - ) -> ( - ManifestBuilder, - Box>>, - ) { - match self { + ) -> (ManifestBuilder, ManifestValue) { + let (manifest_builder, proof) = match self { ProofOf::FungibleFromAccount(resource, amount) => { let resource_address = resource.address(test_engine); let amount = *amount; @@ -289,24 +297,22 @@ impl ToEncode for ProofOf { manifest_args!(resource_address, amount), ); - let (manifest_builder, proof) = manifest_builder - .add_instruction_advanced(InstructionV1::PopFromAuthZone(PopFromAuthZone)); - - (manifest_builder, Box::new(proof.new_proof.unwrap())) + manifest_builder + .add_instruction_advanced(InstructionV1::PopFromAuthZone(PopFromAuthZone)) } + ProofOf::FungibleFromAuthZone(resource, amount) => { let resource_address = resource.address(test_engine); let amount = *amount; - let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( + manifest_builder.add_instruction_advanced( InstructionV1::CreateProofFromAuthZoneOfAmount( CreateProofFromAuthZoneOfAmount { resource_address, amount, }, ), - ); - (manifest_builder, Box::new(proof.new_proof.unwrap())) + ) } ProofOf::NonFungibleFromAccount(resource, ids) => { let resource_address = resource.address(test_engine); @@ -316,133 +322,295 @@ impl ToEncode for ProofOf { manifest_args!(resource_address, ids.clone()), ); - let (manifest_builder, proof) = manifest_builder - .add_instruction_advanced(InstructionV1::PopFromAuthZone(PopFromAuthZone)); - - (manifest_builder, Box::new(proof.new_proof.unwrap())) + manifest_builder + .add_instruction_advanced(InstructionV1::PopFromAuthZone(PopFromAuthZone)) } ProofOf::NonFungibleFromAuthZone(resource, ids) => { let resource_address = resource.address(test_engine); - let (manifest_builder, proof) = manifest_builder.add_instruction_advanced( + manifest_builder.add_instruction_advanced( InstructionV1::CreateProofFromAuthZoneOfNonFungibles( CreateProofFromAuthZoneOfNonFungibles { resource_address, ids: ids.clone(), }, ), - ); - (manifest_builder, Box::new(proof.new_proof.unwrap())) + ) } + }; + + ( + manifest_builder, + Value::Custom { + value: ManifestCustomValue::Proof(proof.new_proof.unwrap()), + }, + ) + } +} + +// ! Env Vec + +pub struct EnvVec { + value_kind: ManifestValueKind, + elements: Vec>, +} + +impl EnvVec { + pub fn from_vec(value_kind: ManifestValueKind, elements: Vec>) -> Self { + Self { + value_kind, + elements, } } + + pub fn new(value_kind: ManifestValueKind) -> Self { + Self { + value_kind, + elements: Vec::new(), + } + } + + pub fn extend(&mut self, elements: EnvVec) { + self.elements.extend(elements.elements); + } + + pub fn push(&mut self, element: Box) { + self.elements.push(element); + } + + pub fn pop(&mut self) -> Option> { + self.elements.pop() + } +} + +impl Iterator for EnvVec { + type Item = Box; + + fn next(&mut self) -> Option { + self.elements.pop() + } } -impl EnvironmentEncode for ProofOf { - fn encode( +impl ToValue for EnvVec { + fn to_value<'a>( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, - encoder: &mut ManifestEncoder, caller: ComponentAddress, - ) -> ManifestBuilder { - let (manifest_builder, encoded) = self.to_encode(test_engine, manifest_builder, caller); - encoder.encode(encoded.as_ref()).expect("Could not encode"); - manifest_builder + ) -> (ManifestBuilder, ManifestValue) { + let (manifest_builder, vec) = self.elements.iter().fold( + (manifest_builder, Vec::new()), + |(manifest_builder, mut vec), element| { + let (manifest_builder, element_value) = + element.to_value(test_engine, manifest_builder, caller); + + vec.push(element_value); + + (manifest_builder, vec) + }, + ); + + let value_kind = if let Some(first) = vec.first() { + get_value_kind(first) + } else { + self.value_kind + }; + + let value = Value::Array { + element_value_kind: value_kind, + elements: vec, + }; + + (manifest_builder, value) } } -// Env Vec +// ! Env Tuple -pub struct EnvVec { - elements: Vec>, +pub struct EnvTuple { + elements: Vec>, } -impl EnvVec { - pub fn from_vec(elements: Vec>) -> Self { +impl EnvTuple { + pub fn from_vec(elements: Vec>) -> Self { Self { elements } } + + pub fn new() -> Self { + Self { + elements: Vec::new(), + } + } } -impl EnvironmentEncode for EnvVec { - fn encode( +impl ToValue for EnvTuple { + fn to_value<'a>( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, - encoder: &mut ManifestEncoder, caller: ComponentAddress, - ) -> ManifestBuilder { - let mut manifest_builder = manifest_builder; - - encoder.write_value_kind(ValueKind::Array).expect(""); - let size = self.elements.len(); - let mut encoded = Vec::new(); - for elem in &self.elements { - let (mb, encode) = elem.to_encode(test_engine, manifest_builder, caller); - manifest_builder = mb; - encoded.push(encode); - } + ) -> (ManifestBuilder, ManifestValue) { + let (manifest_builder, tuple) = self.elements.iter().fold( + (manifest_builder, Vec::new()), + |(manifest_builder, mut tuple), element| { + let (manifest_builder, element_value) = + element.to_value(test_engine, manifest_builder, caller); + tuple.push(element_value); + (manifest_builder, tuple) + }, + ); + + let value = Value::Tuple { fields: tuple }; + + (manifest_builder, value) + } +} - let mut encoded = encoded.iter(); - match encoded.next() { - None => { - encoder.write_value_kind(ValueKind::I8).unwrap(); - encoder.write_size(size).expect(""); - } - Some(elem) => { - let encode = elem.as_ref(); - encode.encode_value_kind(encoder).expect("Error"); - encoder.write_size(size).expect(""); - encoder.encode_deeper_body(encode).expect(""); - } +// ! Env map + +pub struct EnvMap { + key_kind: ManifestValueKind, + value_kind: ManifestValueKind, + elements: Vec<(Box, Box)>, +} + +impl EnvMap { + pub fn from_vec( + key_kind: ManifestValueKind, + value_kind: ManifestValueKind, + elements: Vec<(Box, Box)>, + ) -> Self { + Self { + key_kind, + value_kind, + elements, } + } - for elem in encoded { - encoder.encode_deeper_body(elem.as_ref()).expect("OK"); + pub fn new(key_kind: ManifestValueKind, value_kind: ManifestValueKind) -> Self { + Self { + key_kind, + value_kind, + elements: Vec::new(), } - manifest_builder } } -pub struct EnvSome { - element: Box, +impl ToValue for EnvMap { + fn to_value( + &self, + test_engine: &mut TestEngine, + manifest_builder: ManifestBuilder, + caller: ComponentAddress, + ) -> (ManifestBuilder, ManifestValue) { + let (manifest_builder, entries) = self.elements.iter().fold( + (manifest_builder, Vec::new()), + |(manifest_builder, mut entries), (key, value)| { + let (manifest_builder, key_value) = + key.to_value(test_engine, manifest_builder, caller); + let (manifest_builder, value_value) = + value.to_value(test_engine, manifest_builder, caller); + entries.push((key_value, value_value)); + (manifest_builder, entries) + }, + ); + + let (key_kind, value_kind) = if let Some(first) = entries.first() { + (get_value_kind(&first.0), get_value_kind(&first.1)) + } else { + (self.key_kind, self.value_kind) + }; + + let value = Value::Map { + key_value_kind: key_kind, + value_value_kind: value_kind, + entries, + }; + + (manifest_builder, value) + } } -impl EnvSome { - pub fn new(element: Box) -> Self { - Self { element } - } +// ! Env Option + +pub enum EnvOption { + None, + Some(Box), } -impl EnvironmentEncode for EnvSome { - fn encode( +impl ToValue for EnvOption { + fn to_value( &self, test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, - encoder: &mut ManifestEncoder, caller: ComponentAddress, - ) -> ManifestBuilder { - let (mb, encode) = self - .element - .to_encode(test_engine, manifest_builder, caller); - - encoder.write_value_kind(ValueKind::Enum).expect(""); - encoder.write_discriminator(OPTION_VARIANT_SOME).expect(""); - encoder.write_size(1).expect(""); - encoder.encode(encode.as_ref()).expect(""); - - mb + ) -> (ManifestBuilder, ManifestValue) { + let (manifest_builder, value) = match self { + EnvOption::Some(element) => { + let (manifest_builder, inner_value) = + element.to_value(test_engine, manifest_builder, caller); + + ( + manifest_builder, + Value::Enum { + discriminator: 1, + fields: vec![inner_value], + }, + ) + } + EnvOption::None => ( + manifest_builder, + Value::Enum { + discriminator: 0, + fields: vec![], + }, + ), + }; + + (manifest_builder, value) } } -impl Encode>> EnvironmentEncode for T { - fn encode( +// Other encoding types + +impl Encode> + ?Sized> ToValue for T { + fn to_value( &self, _test_engine: &mut TestEngine, manifest_builder: ManifestBuilder, - encoder: &mut ManifestEncoder, _caller: ComponentAddress, - ) -> ManifestBuilder { + ) -> (ManifestBuilder, ManifestValue) { + let mut buf = sbor::rust::vec::Vec::new(); + let mut encoder = ManifestEncoder::new(&mut buf, MANIFEST_SBOR_V1_MAX_DEPTH); + encoder + .write_payload_prefix(MANIFEST_SBOR_V1_PAYLOAD_PREFIX) + .unwrap(); + encoder.encode(&self).unwrap(); - manifest_builder + + let value = manifest_decode(&buf).unwrap(); + + (manifest_builder, value) + } +} + +fn get_value_kind(value: &ManifestValue) -> ManifestValueKind { + match value { + Value::Bool { .. } => ValueKind::Bool, + Value::I8 { .. } => ValueKind::I8, + Value::I16 { .. } => ValueKind::I16, + Value::I32 { .. } => ValueKind::I32, + Value::I64 { .. } => ValueKind::I64, + Value::I128 { .. } => ValueKind::I128, + Value::U8 { .. } => ValueKind::U8, + Value::U16 { .. } => ValueKind::U16, + Value::U32 { .. } => ValueKind::U32, + Value::U64 { .. } => ValueKind::U64, + Value::U128 { .. } => ValueKind::U128, + Value::String { .. } => ValueKind::String, + Value::Enum { .. } => ValueKind::Enum, + Value::Array { .. } => ValueKind::Array, + Value::Tuple { .. } => ValueKind::Tuple, + Value::Map { .. } => ValueKind::Map, + Value::Custom { value } => ValueKind::Custom(value.get_custom_value_kind()), } } diff --git a/test-engine/src/from_instruction.rs b/test-engine/src/from_instruction.rs deleted file mode 100644 index 8b607de..0000000 --- a/test-engine/src/from_instruction.rs +++ /dev/null @@ -1,18 +0,0 @@ -use crate::internal_prelude::*; - -pub trait FromInstruction { - fn from(instructions: Vec) -> Self; -} - -impl FromInstruction for T { - fn from(mut instructions: Vec) -> Self { - instructions.pop(); - let bytes = match instructions.pop().unwrap() { - InstructionOutput::None => { - panic!("The method does not return anything") - } - InstructionOutput::CallReturn(bytes) => bytes, - }; - scrypto_decode::(&bytes).expect("Could not parse method return into given type 2") - } -} diff --git a/test-engine/src/lib.rs b/test-engine/src/lib.rs index 35de8dc..d38bb62 100644 --- a/test-engine/src/lib.rs +++ b/test-engine/src/lib.rs @@ -1,6 +1,5 @@ mod account; mod engine_interface; -mod from_instruction; mod references; mod call_builder; @@ -8,8 +7,9 @@ mod environment; mod internal_prelude; mod macros; mod method_call; -pub mod prelude; -pub(crate) mod receipt_traits; +mod receipt_traits; mod test_engine; mod to_id; mod utils; + +pub mod prelude; diff --git a/test-engine/src/macros.rs b/test-engine/src/macros.rs index 64f40aa..cdf69f0 100644 --- a/test-engine/src/macros.rs +++ b/test-engine/src/macros.rs @@ -7,43 +7,86 @@ macro_rules! env_args { ($( $x:expr ),*) => {{ use test_engine::prelude::*; - let mut temp_vec: Vec> = vec![]; + let mut temp_vec: Vec> = vec![]; $( temp_vec.push(Box::new($x)); )* temp_vec }}; + } #[macro_export] -macro_rules! env_vec { +macro_rules! env_tuple{ () => ( - vec![] + EnvTuple::new() ); ($( $x:expr ),*) => {{ use test_engine::prelude::*; - let mut temp_vec: Vec> = vec![]; + let mut temp_vec: Vec> = vec![]; $( temp_vec.push(Box::new($x)); )* - EnvVec::from_vec(temp_vec) + EnvTuple::from_vec(temp_vec) }}; } #[macro_export] -macro_rules! global_package { - ($name:ident, $path:expr) => { +macro_rules! env_vec { + (@empty $kind:expr) => {{ use test_engine::prelude::*; - lazy_static! { - static ref $name: (Vec, PackageDefinition) = - { PackagePublishingSource::from($path).code_and_definition() }; - } + EnvVec::from_vec($kind,vec![]) + }}; + + ($x0:expr $(, $x:expr)* $(,)?) => {{ + use test_engine::prelude::*; + + let mut temp_vec: Vec> = vec![Box::new($x0)]; + $( + temp_vec.push(Box::new($x)); + )* + EnvVec::from_vec(ManifestValueKind::Bool, temp_vec) + }}; +} + +#[macro_export] +macro_rules! some { + ($x:expr) => {{ + use test_engine::prelude::*; + + EnvOption::Some(Box::new($x)) + }}; +} + +#[macro_export] +macro_rules! none { + () => { + EnvOption::None }; } +#[macro_export] +macro_rules! env_map { + (@empty $key_kind:expr , $value_kind:expr) => {{ + use test_engine::prelude::*; + + EnvMap::new($key_kind, $value_kind) + }}; + + ($($key:expr => $value:expr),*) => {{ + use test_engine::prelude::*; + + let mut temp_vec:Vec<(Box, Box)> = vec![]; + $( + temp_vec.push((Box::new($key), Box::new($value))); + )* + EnvMap::from_vec(ManifestValueKind::Bool, ManifestValueKind::Bool, temp_vec) + }}; +} + #[macro_export] macro_rules! nf_ids { () => ( @@ -62,17 +105,55 @@ macro_rules! nf_ids { } #[macro_export] -macro_rules! some { - ($x:expr) => {{ +macro_rules! global_package { + ($name:ident, $path:expr) => { use test_engine::prelude::*; - EnvSome::new(Box::new($x)) - }}; + + lazy_static! { + static ref $name: (Vec, PackageDefinition) = + { PackagePublishingSource::from($path).code_and_definition() }; + } + }; } #[macro_export] -macro_rules! none { - () => { - None:: +macro_rules! global_package_from_binary { + ($name:ident, $release_path:expr, $package_name:expr) => { + lazy_static! { + static ref $name: (Vec, PackageDefinition) = { + let package_test_dir = PathBuf::from_str(env!("CARGO_MANIFEST_DIR")).unwrap(); + let release_dir = package_test_dir.join($release_path); + let package_name = if $package_name == "" { + env!("CARGO_PKG_NAME") + } else { + $package_name + }; + + let wasm_path = release_dir.join(format!("{}.wasm", package_name)); + + let definition_path = release_dir.join(format!("{}.rpd", package_name)); + + let code = std::fs::read(&wasm_path).unwrap_or_else(|err| { + panic!( + "Failed to read built WASM from path {:?} - {:?}", + &wasm_path, err + ) + }); + let definition = std::fs::read(&definition_path).unwrap_or_else(|err| { + panic!( + "Failed to read package definition from path {:?} - {:?}", + &definition_path, err + ) + }); + let definition = manifest_decode(&definition).unwrap_or_else(|err| { + panic!( + "Failed to parse package definition from path {:?} - {:?}", + &definition_path, err + ) + }); + (code, definition) + }; + } }; } diff --git a/test-engine/src/method_call.rs b/test-engine/src/method_call.rs index bdd7334..2fa7711 100644 --- a/test-engine/src/method_call.rs +++ b/test-engine/src/method_call.rs @@ -1,5 +1,5 @@ use crate::call_builder::CallBuilder; -use crate::environment::EnvironmentEncode; +use crate::environment::ToValue; use crate::internal_prelude::*; use crate::references::{GlobalReference, ResourceReference}; @@ -9,11 +9,7 @@ pub trait SimpleMethodCaller { /// # Arguments /// * `method_name`: name of the method. /// * `args`: environment arguments to call the method. - fn call_method( - self, - method_name: &str, - args: Vec>, - ) -> TransactionReceipt; + fn call_method(self, method_name: &str, args: Vec>) -> TransactionReceipt; /// Makes a simple call to a method of a given entity. /// @@ -25,7 +21,7 @@ pub trait SimpleMethodCaller { self, global_address: G, method_name: &str, - args: Vec>, + args: Vec>, ) -> TransactionReceipt; /// Calls a method of the current component with a given admin badge. @@ -38,7 +34,7 @@ pub trait SimpleMethodCaller { self, method_name: &str, admin_badge: R, - args: Vec>, + args: Vec>, ) -> TransactionReceipt; } @@ -51,32 +47,32 @@ pub trait ComplexMethodCaller { /// # Arguments /// * `method_name`: name of the method. /// * `args`: environment arguments to call the method. - fn call(&mut self, method_name: &str, args: Vec>) -> CallBuilder; + fn call(&mut self, method_name: &str, args: Vec>) -> CallBuilder; - /// Returns a call builder with an initial method call with a given admin badge. + /// Returns a call builder with an initial method call to a given entity. /// /// # Arguments + /// * `global_address`: reference or address of the entity to call. /// * `method_name`: name of the method. - /// * `admin_badge`: reference name or address of the resource to use as an admin badge. /// * `args`: environment arguments to call the method. - fn call_with_badge( + fn call_from( &mut self, + global_address: G, method_name: &str, - admin_badge: R, - args: Vec>, + args: Vec>, ) -> CallBuilder; - /// Returns a call builder with an initial method call to a given entity. + /// Returns a call builder with an initial method call with a given admin badge. /// /// # Arguments - /// * `global_address`: reference or address of the entity to call. /// * `method_name`: name of the method. + /// * `admin_badge`: reference name or address of the resource to use as an admin badge. /// * `args`: environment arguments to call the method. - fn call_from( + fn call_with_badge( &mut self, - global_address: G, method_name: &str, - args: Vec>, + admin_badge: R, + args: Vec>, ) -> CallBuilder; fn with_manifest_builder(&mut self, f: F) -> CallBuilder diff --git a/test-engine/src/prelude.rs b/test-engine/src/prelude.rs index 92a53a4..d307d0a 100644 --- a/test-engine/src/prelude.rs +++ b/test-engine/src/prelude.rs @@ -9,7 +9,11 @@ pub use crate::call_builder::*; pub use crate::environment::*; pub use crate::method_call::*; pub use crate::receipt_traits::*; +pub use crate::references::*; pub use crate::test_engine::*; pub use crate::to_id::ToId; pub use crate::utils::*; -pub use crate::{env_args, env_vec, global_package, global_package_advanced, nf_ids, none, some}; +pub use crate::{ + env_args, env_map, env_tuple, env_vec, global_package, global_package_advanced, + global_package_from_binary, nf_ids, none, some, +}; diff --git a/test-engine/src/receipt_traits.rs b/test-engine/src/receipt_traits.rs index 60dca83..a7b6e5d 100644 --- a/test-engine/src/receipt_traits.rs +++ b/test-engine/src/receipt_traits.rs @@ -1,8 +1,8 @@ -use crate::from_instruction::FromInstruction; use crate::internal_prelude::*; pub trait Outcome { fn assert_is_success(self) -> Self; + fn assert_failed(self) -> Self; fn assert_failed_with(self, error: &str) -> Self; } @@ -26,6 +26,23 @@ impl Outcome for TransactionReceipt { } } + fn assert_failed(self) -> Self { + match &self.result { + TransactionResult::Commit(commit) => match &commit.outcome { + TransactionOutcome::Success(_) => { + panic!("Transaction succeeded !"); + } + TransactionOutcome::Failure(_) => self, + }, + TransactionResult::Reject(reject) => { + panic!("Transaction rejected with: {:?}", reject.reason); + } + TransactionResult::Abort(abort) => { + panic!("Transaction aborted with: {}", abort.reason); + } + } + } + /// Asserts that the transaction failed with a given message. /// Panics if the transaction succeeded or was rejected/aborted. /// @@ -60,19 +77,22 @@ impl Outcome for TransactionReceipt { } } -pub trait GetReturn { - fn get_return(&self) -> T; +pub trait GetReturn { + fn get_return(&self, index: usize) -> T; } -impl GetReturn for TransactionReceipt -where - T: FromInstruction, -{ +impl GetReturn for TransactionReceipt { /// Returns the method's return from a receipt. - fn get_return(&self) -> T { + fn get_return(&self, index: usize) -> T { match &self.result { TransactionResult::Commit(commit) => match &commit.outcome { - TransactionOutcome::Success(output) => T::from(output.clone()), + TransactionOutcome::Success(output) => T::from( + output + .get(index) + .expect(&format!("No return at index {}", index)) + .clone(), + ), + TransactionOutcome::Failure(failure) => { panic!("Transaction failed with: {:?}", failure); } @@ -86,3 +106,19 @@ where } } } + +pub trait FromInstruction { + fn from(instructions: InstructionOutput) -> Self; +} + +impl FromInstruction for T { + fn from(instructions: InstructionOutput) -> Self { + let bytes = match instructions { + InstructionOutput::None => { + panic!("The method does not return anything") + } + InstructionOutput::CallReturn(bytes) => bytes, + }; + scrypto_decode::(&bytes).expect("Could not parse method return into given type 2") + } +} diff --git a/test-engine/src/test_engine.rs b/test-engine/src/test_engine.rs index 4302d9b..eea1ee1 100644 --- a/test-engine/src/test_engine.rs +++ b/test-engine/src/test_engine.rs @@ -1,7 +1,7 @@ use crate::account::Account; use crate::call_builder::CallBuilder; use crate::engine_interface::EngineInterface; -use crate::environment::EnvironmentEncode; +use crate::environment::ToValue; use crate::method_call::{ComplexMethodCaller, SimpleMethodCaller}; use crate::receipt_traits::Outcome; use crate::references::{ComponentReference, GlobalReference, ReferenceName, ResourceReference}; @@ -158,7 +158,7 @@ impl TestEngine { component_name: N, blueprint_name: &str, instantiation_function: &str, - args: Vec>, + args: Vec>, ) -> TransactionReceipt { self.create_component( component_name, @@ -183,7 +183,7 @@ impl TestEngine { blueprint_name: &str, instantiation_function: &str, badge: R, - args: Vec>, + args: Vec>, ) -> TransactionReceipt { self.create_component( component_name, @@ -207,7 +207,7 @@ impl TestEngine { component_name: N, blueprint_name: &str, instantiation_function: &str, - args: Vec>, + args: Vec>, callback: impl FnOnce(CallBuilder) -> CallBuilder, ) -> TransactionReceipt { self.create_component( @@ -612,11 +612,11 @@ impl TestEngine { resource: R1, id: T, field_name: &str, - mut data: Vec>, + mut data: Vec>, badge: R2, ) -> TransactionReceipt { let resource = resource.address(self); - let mut args: Vec> = + let mut args: Vec> = vec![Box::new(id.to_id()), Box::new(field_name.to_string())]; args.append(&mut data); CallBuilder::new(self) @@ -821,7 +821,7 @@ impl TestEngine { component_name: N, blueprint_name: &str, instantiation_function: &str, - args: Vec>, + args: Vec>, callback: impl FnOnce(CallBuilder) -> CallBuilder, ) -> TransactionReceipt { // let caller = self.current_account().clone(); @@ -940,11 +940,7 @@ impl Default for TestEngine { } impl<'a> SimpleMethodCaller for &'a mut TestEngine { - fn call_method( - self, - method_name: &str, - args: Vec>, - ) -> TransactionReceipt { + fn call_method(self, method_name: &str, args: Vec>) -> TransactionReceipt { let component = *self.current_component(); self.call_method_from(component, method_name, args) } @@ -953,7 +949,7 @@ impl<'a> SimpleMethodCaller for &'a mut TestEngine { self, global_address: G, method_name: &str, - args: Vec>, + args: Vec>, ) -> TransactionReceipt { self.call_from(global_address, method_name, args).execute() } @@ -962,7 +958,7 @@ impl<'a> SimpleMethodCaller for &'a mut TestEngine { self, method_name: &str, admin_badge: R, - args: Vec>, + args: Vec>, ) -> TransactionReceipt { self.call(method_name, args) .with_badge(admin_badge) @@ -975,7 +971,7 @@ impl ComplexMethodCaller for TestEngine { CallBuilder::new(self) } - fn call(&mut self, method_name: &str, args: Vec>) -> CallBuilder { + fn call(&mut self, method_name: &str, args: Vec>) -> CallBuilder { let component = *self.current_component(); self.call_from(component, method_name, args) } @@ -983,7 +979,7 @@ impl ComplexMethodCaller for TestEngine { &mut self, method_name: &str, admin_badge: R, - args: Vec>, + args: Vec>, ) -> CallBuilder { let component = *self.current_component(); self.call_from(component, method_name, args) @@ -994,7 +990,7 @@ impl ComplexMethodCaller for TestEngine { &mut self, global_address: G, method_name: &str, - args: Vec>, + args: Vec>, ) -> CallBuilder { let address = global_address.address(self); CallBuilder::new(self).call_method_internal(address, method_name, args) diff --git a/test-engine/tests/general/mod.rs b/test-engine/tests/general/mod.rs index ce3ffff..ac9b4ad 100644 --- a/test-engine/tests/general/mod.rs +++ b/test-engine/tests/general/mod.rs @@ -32,16 +32,18 @@ fn test_transfer() { test_engine .transfer("Recipient", "Test token", dec!(10)) .assert_is_success(); + assert_eq!(test_engine.balance_of("Recipient", "Test token"), dec!(10)); } #[test] fn test_bug() { let mut simulator = LedgerSimulatorBuilder::new() - .with_custom_genesis(BabylonSettings::test_default( - // Epoch::of(1), - // BabylonSettings::default_consensus_manager_config(), - )) + // .with_custom_genesis(BabylonSettings::test_default( + // Epoch::of(1), + // BabylonSettings::default_consensus_manager_config(), + // )) + .with_custom_protocol(|builder| builder.only_babylon()) .without_kernel_trace() .build(); diff --git a/test-engine/tests/gumball_machine/unit_tests.rs b/test-engine/tests/gumball_machine/unit_tests.rs index 9d20dd6..adfe495 100644 --- a/test-engine/tests/gumball_machine/unit_tests.rs +++ b/test-engine/tests/gumball_machine/unit_tests.rs @@ -43,7 +43,7 @@ mod gumball_machine_tests { fn test_get_price() { let mut test_engine = instantiate_gumball(); let receipt = test_engine.call_method("get_price", env_args!()); - let price: Decimal = receipt.get_return(); + let price: Decimal = receipt.get_return(1); assert_eq!(price, dec!(5)); } }