From f97efdd9ab349d15ddb2fa2847a6884b3eea91c5 Mon Sep 17 00:00:00 2001 From: Vadim Obradovich Date: Thu, 25 Jul 2024 11:09:59 +0200 Subject: [PATCH] feat(sails, lient-gen): Support mocking generated client (#397) --- Cargo.lock | 85 ++++++- Cargo.toml | 1 + examples/demo/client/Cargo.toml | 4 + examples/demo/client/build.rs | 1 + examples/no-svcs-prog/wasm/build.rs | 1 + examples/proxy/Cargo.toml | 4 + examples/proxy/proxy.idl | 7 +- examples/proxy/src/this_that/mod.rs | 84 ++++++- examples/rmrk/resource/app/Cargo.toml | 11 +- examples/rmrk/resource/app/build.rs | 3 +- examples/rmrk/resource/app/src/lib.rs | 4 + .../rmrk/resource/app/src/services/errors.rs | 6 +- .../rmrk/resource/app/src/services/mod.rs | 230 +++--------------- .../resource/app/src/services/resources.rs | 8 + examples/rmrk/resource/wasm/build.rs | 2 +- rs/Cargo.toml | 4 + rs/client-gen/src/lib.rs | 13 +- rs/client-gen/src/mock_generator.rs | 65 +++++ rs/client-gen/src/root_generator.rs | 37 ++- rs/client-gen/src/service_generators.rs | 2 +- rs/client-gen/src/type_generators.rs | 6 +- rs/client-gen/tests/generator.rs | 2 +- .../snapshots/generator__basic_works.snap | 21 +- .../snapshots/generator__events_works.snap | 17 +- .../tests/snapshots/generator__full.snap | 29 ++- .../generator__multiple_services.snap | 18 +- .../snapshots/generator__nonzero_works.snap | 17 +- .../snapshots/generator__rmrk_works.snap | 33 ++- rs/src/calls.rs | 10 +- rs/src/lib.rs | 7 + rs/src/mockall.rs | 77 ++++++ 31 files changed, 553 insertions(+), 256 deletions(-) create mode 100644 rs/client-gen/src/mock_generator.rs create mode 100644 rs/src/mockall.rs diff --git a/Cargo.lock b/Cargo.lock index 39482399..3afb987b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -143,6 +143,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + [[package]] name = "anyhow" version = "1.0.86" @@ -1441,6 +1447,7 @@ name = "demo-client" version = "0.1.0" dependencies = [ "demo", + "mockall", "sails-client-gen", "sails-idl-gen", "sails-rs", @@ -1569,6 +1576,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "downcast-rs" version = "1.2.1" @@ -1969,6 +1982,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "frame-metadata" version = "15.1.0" @@ -4048,6 +4067,33 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "mockall" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43766c2b5203b10de348ffe19f7e54564b64f3d6018ff7648d1e2d6d3a0f0a48" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7cbce79ec385a1d4f54baa90a76401eb15d9cab93685f62e7e9f942aa00ae2" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.72", +] + [[package]] name = "more-asserts" version = "0.2.2" @@ -4589,6 +4635,32 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +[[package]] +name = "predicates" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + [[package]] name = "prettyplease" version = "0.2.20" @@ -4682,6 +4754,7 @@ dependencies = [ "demo-client", "sails-idl-gen", "sails-rs", + "tokio", ] [[package]] @@ -5034,10 +5107,11 @@ version = "0.1.0" dependencies = [ "git-download", "gstd", - "parity-scale-codec", + "mockall", + "rmrk-resource-app", "sails-client-gen", "sails-rs", - "scale-info", + "tokio", ] [[package]] @@ -5252,6 +5326,7 @@ dependencies = [ "gtest", "hashbrown 0.14.5", "hex", + "mockall", "parity-scale-codec", "primitive-types", "sails-macros", @@ -6623,6 +6698,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + [[package]] name = "thiserror" version = "1.0.63" diff --git a/Cargo.toml b/Cargo.toml index a25b650c..1b2a9a7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,7 @@ itertools = "0.12" lalrpop = { version = "0.20", default-features = false } lalrpop-util = "0.20" logos = "0.13" +mockall = "0.12" parity-scale-codec = { version = "3.6", default-features = false } prettyplease = "0.2" primitive-types = { version = "0.12", default-features = false } diff --git a/examples/demo/client/Cargo.toml b/examples/demo/client/Cargo.toml index 8098ceff..982240b1 100644 --- a/examples/demo/client/Cargo.toml +++ b/examples/demo/client/Cargo.toml @@ -4,9 +4,13 @@ version = "0.1.0" edition = "2021" [dependencies] +mockall = { workspace = true, optional = true } sails-rs.workspace = true [build-dependencies] demo = { path = "../app" } sails-client-gen.workspace = true sails-idl-gen.workspace = true + +[features] +with_mocks = ["sails-rs/mockall", "dep:mockall"] diff --git a/examples/demo/client/build.rs b/examples/demo/client/build.rs index 0859dd1e..5c363c1c 100644 --- a/examples/demo/client/build.rs +++ b/examples/demo/client/build.rs @@ -11,6 +11,7 @@ fn main() { sails_client_gen::generate_client_from_idl( &idl_file_path, PathBuf::from(env::var("OUT_DIR").unwrap()).join("demo_client.rs"), + Some("with_mocks"), ) .unwrap(); } diff --git a/examples/no-svcs-prog/wasm/build.rs b/examples/no-svcs-prog/wasm/build.rs index 61818cb4..e3b4fc89 100644 --- a/examples/no-svcs-prog/wasm/build.rs +++ b/examples/no-svcs-prog/wasm/build.rs @@ -12,6 +12,7 @@ fn main() { sails_client_gen::generate_client_from_idl( &idl_file_path, PathBuf::from(env::var("OUT_DIR").unwrap()).join("no_svcs_prog.rs"), + None, ) .unwrap(); } diff --git a/examples/proxy/Cargo.toml b/examples/proxy/Cargo.toml index ad5f6137..24f908a4 100644 --- a/examples/proxy/Cargo.toml +++ b/examples/proxy/Cargo.toml @@ -16,5 +16,9 @@ demo-client = { path = "../demo/client" } sails-idl-gen = { workspace = true, optional = true } sails-rs.workspace = true +[dev-dependencies] +demo-client = { path = "../demo/client", features = ["with_mocks"] } +tokio = { workspace = true, features = ["rt", "macros"] } + [features] idl-gen = ["sails-idl-gen"] diff --git a/examples/proxy/proxy.idl b/examples/proxy/proxy.idl index d59eee4e..1e088c0e 100644 --- a/examples/proxy/proxy.idl +++ b/examples/proxy/proxy.idl @@ -1,8 +1,13 @@ +type TupleStruct = struct { + bool, +}; + constructor { New : (); }; service ThisThatCaller { - CallThis : (this_that_addr: actor_id) -> u32; + CallDoThis : (p1: u32, p2: str, p3: struct { opt h160, nat8 }, p4: TupleStruct, this_that_addr: actor_id) -> struct { str, u32 }; + query QueryThis : (this_that_addr: actor_id) -> u32; }; diff --git a/examples/proxy/src/this_that/mod.rs b/examples/proxy/src/this_that/mod.rs index 828d4f7b..cfc69b5b 100644 --- a/examples/proxy/src/this_that/mod.rs +++ b/examples/proxy/src/this_that/mod.rs @@ -1,5 +1,5 @@ -use demo_client::traits::ThisThat; -use sails_rs::{calls::Query, prelude::*}; +use demo_client::{traits::ThisThat, TupleStruct}; +use sails_rs::{calls::*, prelude::*}; #[derive(Clone)] pub struct ThisThatCaller { @@ -15,7 +15,85 @@ where Self { this_that } } - pub async fn call_this(&mut self, this_that_addr: ActorId) -> u32 { + pub async fn call_do_this( + &mut self, + p1: u32, + p2: String, + p3: (Option, NonZeroU8), + p4: TupleStruct, + this_that_addr: ActorId, + ) -> (String, u32) { + self.this_that + .do_this(p1, p2, p3, p4) + .send_recv(this_that_addr) + .await + .unwrap() + } + + pub async fn query_this(&self, this_that_addr: ActorId) -> u32 { self.this_that.this().recv(this_that_addr).await.unwrap() } } + +#[cfg(test)] +mod tests { + use super::*; + use demo_client::mockall::MockThisThat; + use sails_rs::mockall::*; + + #[tokio::test] + async fn this_that_caller_query_this() { + // arrange + const ACTOR_ID: u64 = 11; + let mut mock_this_that = MockThisThat::<()>::new(); + mock_this_that.expect_this().returning(|| { + let mut mock_query_this = MockQuery::new(); + mock_query_this + .expect_recv() + .with(predicate::eq(ActorId::from(ACTOR_ID))) + .times(1) + .returning(move |_| Ok(42)); + mock_query_this + }); + + // act + let this_that_caller = ThisThatCaller::new(mock_this_that); + let resp = this_that_caller.query_this(ACTOR_ID.into()).await; + + // assert + assert_eq!(42, resp); + } + + #[tokio::test] + async fn this_that_caller_call_do_this() { + // arrange + const ACTOR_ID: u64 = 11; + let mut mock_this_that = MockThisThat::<()>::new(); + mock_this_that + .expect_do_this() + .returning(move |p1, p2, _p3, _p4| { + let mut mock_call_do_this = MockCall::new(); + mock_call_do_this + .expect_send_recv() + .with(predicate::eq(ActorId::from(ACTOR_ID))) + .times(1) + .returning(move |_| Ok((p2.clone(), p1))); + mock_call_do_this + }); + + // act + let mut this_that_caller = ThisThatCaller::new(mock_this_that); + let resp = this_that_caller + .call_do_this( + 42, + "test".to_owned(), + (None, NonZeroU8::MAX), + TupleStruct(true), + ACTOR_ID.into(), + ) + .await; + + // assert + assert_eq!(("test".to_owned(), 42), resp); + } +} diff --git a/examples/rmrk/resource/app/Cargo.toml b/examples/rmrk/resource/app/Cargo.toml index 70dba094..acb54b53 100644 --- a/examples/rmrk/resource/app/Cargo.toml +++ b/examples/rmrk/resource/app/Cargo.toml @@ -2,13 +2,20 @@ name = "rmrk-resource-app" version = "0.1.0" edition = "2021" +resolver = "2" [dependencies] gstd.workspace = true -parity-scale-codec = { workspace = true, features = ["derive"] } +mockall = { workspace = true, optional = true } sails-rs.workspace = true -scale-info = { workspace = true, features = ["derive"] } [build-dependencies] git-download.workspace = true sails-client-gen.workspace = true + +[dev-dependencies] +rmrk-resource-app = { path = ".", features = ["mockall"] } +tokio = { workspace = true, features = ["rt", "macros"] } + +[features] +mockall = ["sails-rs/mockall", "dep:mockall"] diff --git a/examples/rmrk/resource/app/build.rs b/examples/rmrk/resource/app/build.rs index f23a4f19..809804d8 100644 --- a/examples/rmrk/resource/app/build.rs +++ b/examples/rmrk/resource/app/build.rs @@ -21,5 +21,6 @@ fn main() { let idl_file_path = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) .join("..\\..\\catalog\\wasm\\rmrk-catalog.idl"); - sails_client_gen::generate_client_from_idl(idl_file_path, client_rs_file_path).unwrap(); + sails_client_gen::generate_client_from_idl(idl_file_path, client_rs_file_path, Some("mockall")) + .unwrap(); } diff --git a/examples/rmrk/resource/app/src/lib.rs b/examples/rmrk/resource/app/src/lib.rs index 8ba14162..bf937062 100644 --- a/examples/rmrk/resource/app/src/lib.rs +++ b/examples/rmrk/resource/app/src/lib.rs @@ -1,5 +1,9 @@ #![no_std] +#[cfg(feature = "mockall")] +#[cfg(not(target_arch = "wasm32"))] +pub extern crate std; + use sails_rs::gstd::{calls::GStdRemoting, gprogram, groute, GStdExecContext}; use services::ResourceStorage; diff --git a/examples/rmrk/resource/app/src/services/errors.rs b/examples/rmrk/resource/app/src/services/errors.rs index b8947306..2a86219d 100644 --- a/examples/rmrk/resource/app/src/services/errors.rs +++ b/examples/rmrk/resource/app/src/services/errors.rs @@ -1,8 +1,10 @@ -use sails_rs::{Decode, Encode, Result as RtlResult, TypeInfo}; +use sails_rs::prelude::*; -pub type Result = RtlResult; +pub type Result = sails_rs::Result; #[derive(Encode, Decode, TypeInfo, Debug)] +#[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub enum Error { NotAuthorized, ZeroResourceId, diff --git a/examples/rmrk/resource/app/src/services/mod.rs b/examples/rmrk/resource/app/src/services/mod.rs index 1edc8126..733cd98c 100644 --- a/examples/rmrk/resource/app/src/services/mod.rs +++ b/examples/rmrk/resource/app/src/services/mod.rs @@ -22,6 +22,8 @@ struct ResourceStorageData { // Service event type definition #[derive(TypeInfo, Encode)] +#[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub enum ResourceStorageEvent { ResourceAdded { resource_id: ResourceId, @@ -165,43 +167,57 @@ fn resource_storage_admin() -> ActorId { #[cfg(test)] mod tests { - use core::marker::PhantomData; - use super::*; - use crate::catalogs::{Error, Part}; - use resources::BasicResource; - use sails_rs::{ - calls::{Action, Call, Remoting, Reply}, - collections::BTreeMap, - gstd::calls::GStdRemoting, - ActorId, - }; - - #[test] - fn test_add_resource_entry() { - ResourceStorage::>::seed( - ExecContextMock { - actor_id: 1.into(), - message_id: 1.into(), - }, - ); + use crate::catalogs::{mockall::MockRmrkCatalog, FixedPart, Part}; + use resources::ComposedResource; + use sails_rs::{gstd::calls::GStdArgs, mockall::MockQuery, ActorId}; + + #[tokio::test] + async fn test_add_resource_entry() { + ResourceStorage::>::seed(ExecContextMock { + actor_id: 1.into(), + message_id: 1.into(), + }); let mut resource_storage = ResourceStorage::new( ExecContextMock { actor_id: 1.into(), message_id: 1.into(), }, - MockCatalogClient:: { _r: PhantomData }, + MockRmrkCatalog::::new(), ); - let resource = Resource::Basic(BasicResource { + + let resource = Resource::Composed(ComposedResource { src: "src".to_string(), - thumb: None, + thumb: "thumb".to_string(), metadata_uri: "metadata_uri".to_string(), + base: 1.into(), + parts: vec![], }); let (actual_resource_id, actual_resource) = resource_storage .add_resource_entry(1, resource.clone()) .unwrap(); assert_eq!(actual_resource_id, 1); assert_eq!(actual_resource, resource); + + // add_part_to_resource + let mut part_query = MockQuery::new(); + part_query.expect_recv().returning(move |_| { + Ok(Some(Part::Fixed(FixedPart { + z: None, + metadata_uri: "metadata_uri".to_string(), + }))) + }); + resource_storage + .catalog_client + .expect_part() + .with(mockall::predicate::eq(1)) + .return_once(|_| part_query); + + let actual_part_id = resource_storage + .add_part_to_resource(actual_resource_id, 1) + .await + .unwrap(); + assert_eq!(actual_part_id, 1); } struct ExecContextMock { @@ -218,174 +234,4 @@ mod tests { self.message_id } } - - struct MockCatalogClient { - _r: PhantomData, - } - - struct MockCall { - _r: PhantomData, - _a: PhantomData, - } - - impl MockCall { - pub fn new() -> Self { - Self { - _r: PhantomData, - _a: PhantomData, - } - } - } - - impl Call for MockCall { - type Output = R; - - async fn send( - self, - _target: ActorId, - ) -> sails_rs::errors::Result> { - Ok(MockReply::::new()) - } - } - - impl Action for MockCall { - type Args = A; - - fn with_value(self, _value: ValueUnit) -> Self { - todo!() - } - - fn with_args(self, _args: A) -> Self { - todo!() - } - - fn value(&self) -> ValueUnit { - todo!() - } - - fn args(&self) -> &A { - todo!() - } - } - - struct MockReply { - _r: PhantomData, - } - - impl MockReply { - pub fn new() -> Self { - Self { _r: PhantomData } - } - } - - impl Reply for MockReply { - type Output = R; - - async fn recv(self) -> sails_rs::errors::Result { - unimplemented!() - } - } - - #[derive(Default)] - struct MockQuery { - _r: PhantomData, - _a: PhantomData, - } - - impl MockQuery { - pub fn new() -> Self { - Self { - _r: PhantomData, - _a: PhantomData, - } - } - } - - impl Query for MockQuery { - async fn recv(self, _target: ActorId) -> sails_rs::errors::Result { - unimplemented!() - } - - type Output = R; - } - - impl Action for MockQuery { - fn with_value(self, _value: ValueUnit) -> Self { - todo!() - } - - fn with_args(self, _args: A) -> Self { - todo!() - } - - fn value(&self) -> ValueUnit { - todo!() - } - - fn args(&self) -> &A { - todo!() - } - - type Args = A; - } - - impl RmrkCatalog for MockCatalogClient { - type Args = R::Args; - - fn add_parts( - &mut self, - _parts: BTreeMap, - ) -> impl Call, Error>, Args = R::Args> { - MockCall::new() - } - - fn remove_parts( - &mut self, - _part_ids: Vec, - ) -> impl Call, Error>, Args = R::Args> { - MockCall::new() - } - - fn add_equippables( - &mut self, - _part_id: u32, - _collection_ids: Vec, - ) -> impl Call), Error>, Args = R::Args> { - MockCall::new() - } - - fn remove_equippable( - &mut self, - _part_id: u32, - _collection_id: ActorId, - ) -> impl Call, Args = R::Args> { - MockCall::new() - } - - fn reset_equippables( - &mut self, - _part_id: u32, - ) -> impl Call, Args = R::Args> { - MockCall::new() - } - - fn set_equippables_to_all( - &mut self, - _part_id: u32, - ) -> impl Call, Args = R::Args> { - MockCall::new() - } - - fn part(&self, _part_id: u32) -> impl Query, Args = R::Args> { - MockQuery::new() - } - - fn equippable( - &self, - _part_id: u32, - _collection_id: ActorId, - ) -> impl Query, Args = R::Args> { - MockQuery::new() - } - } } diff --git a/examples/rmrk/resource/app/src/services/resources.rs b/examples/rmrk/resource/app/src/services/resources.rs index 6a625ce0..20468dc6 100644 --- a/examples/rmrk/resource/app/src/services/resources.rs +++ b/examples/rmrk/resource/app/src/services/resources.rs @@ -5,6 +5,8 @@ pub type PartId = u32; pub type ResourceId = u8; #[derive(Decode, Encode, TypeInfo, Clone, Debug, PartialEq, Eq)] +#[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub enum Resource { Basic(BasicResource), Slot(SlotResource), @@ -12,6 +14,8 @@ pub enum Resource { } #[derive(Decode, Encode, TypeInfo, Clone, Debug, PartialEq, Eq)] +#[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct BasicResource { /// URI like IPFS hash pub src: String, @@ -25,6 +29,8 @@ pub struct BasicResource { } #[derive(Decode, Encode, TypeInfo, Clone, Debug, PartialEq, Eq)] +#[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct ComposedResource { /// URI like ipfs hash pub src: String, @@ -44,6 +50,8 @@ pub struct ComposedResource { } #[derive(Decode, Encode, TypeInfo, Clone, Debug, PartialEq, Eq)] +#[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct SlotResource { /// URI like ipfs hash pub src: String, diff --git a/examples/rmrk/resource/wasm/build.rs b/examples/rmrk/resource/wasm/build.rs index 0ec114ea..84d7df97 100644 --- a/examples/rmrk/resource/wasm/build.rs +++ b/examples/rmrk/resource/wasm/build.rs @@ -12,5 +12,5 @@ fn main() { let out_dir_path = PathBuf::from(env::var("OUT_DIR").unwrap()); let client_rs_file_path = out_dir_path.join("rmrk_resource.rs"); - sails_client_gen::generate_client_from_idl(idl_file_path, client_rs_file_path).unwrap(); + sails_client_gen::generate_client_from_idl(idl_file_path, client_rs_file_path, None).unwrap(); } diff --git a/rs/Cargo.toml b/rs/Cargo.toml index d45bf48c..2313d9e2 100644 --- a/rs/Cargo.toml +++ b/rs/Cargo.toml @@ -16,6 +16,7 @@ gprimitives.workspace = true gstd.workspace = true hashbrown.workspace = true hex.workspace = true +mockall = { workspace = true, optional = true } parity-scale-codec = { workspace = true, features = ["derive"] } primitive-types.workspace = true sails-macros.workspace = true @@ -26,3 +27,6 @@ thiserror-no-std.workspace = true [target.'cfg(not(target_arch = "wasm32"))'.dependencies] gclient.workspace = true gtest.workspace = true + +[features] +mockall = ["dep:mockall"] diff --git a/rs/client-gen/src/lib.rs b/rs/client-gen/src/lib.rs index 8ad77aa4..4a8e51dd 100644 --- a/rs/client-gen/src/lib.rs +++ b/rs/client-gen/src/lib.rs @@ -2,6 +2,7 @@ mod ctor_generators; mod events_generator; mod helpers; mod io_generators; +mod mock_generator; mod root_generator; mod service_generators; mod type_generators; @@ -16,6 +17,7 @@ use std::{ffi::OsStr, fs, io::Write, path::Path}; pub fn generate_client_from_idl( idl_path: impl AsRef, out_path: impl AsRef, + mocks_feature_name: Option<&str>, ) -> Result<()> { let idl_path = idl_path.as_ref(); let out_path = out_path.as_ref(); @@ -34,7 +36,8 @@ pub fn generate_client_from_idl( let file_name = idl_path.file_stem().unwrap_or(OsStr::new("service")); let service_name = file_name.to_string_lossy().to_case(Case::Pascal); - let buf = generate(program, &service_name).context("failed to generate client")?; + let buf = generate(program, &service_name, mocks_feature_name) + .context("failed to generate client")?; fs::write(out_path, buf) .with_context(|| format!("Failed to write generated client to {}", out_path.display()))?; @@ -42,8 +45,12 @@ pub fn generate_client_from_idl( Ok(()) } -pub fn generate(program: Program, anonymous_service_name: &str) -> Result { - let mut generator = RootGenerator::new(anonymous_service_name); +pub fn generate( + program: Program, + anonymous_service_name: &str, + mocks_feature_name: Option<&str>, +) -> Result { + let mut generator = RootGenerator::new(anonymous_service_name, mocks_feature_name); visitor::accept_program(&program, &mut generator); let code = generator.finalize(); diff --git a/rs/client-gen/src/mock_generator.rs b/rs/client-gen/src/mock_generator.rs new file mode 100644 index 00000000..f5450ee8 --- /dev/null +++ b/rs/client-gen/src/mock_generator.rs @@ -0,0 +1,65 @@ +use convert_case::{Case, Casing}; +use genco::prelude::*; +use rust::Tokens; +use sails_idl_parser::{ast::visitor, ast::visitor::Visitor, ast::*}; + +use crate::type_generators::generate_type_decl_code; + +pub(crate) struct MockGenerator { + service_name: String, + tokens: rust::Tokens, +} + +impl MockGenerator { + pub(crate) fn new(service_name: String) -> Self { + Self { + service_name, + tokens: rust::Tokens::new(), + } + } + + pub(crate) fn finalize(self) -> rust::Tokens { + quote! { + mock! { + pub $(&self.service_name) {} + + #[allow(refining_impl_trait)] + #[allow(clippy::type_complexity)] + impl traits::$(&self.service_name) for $(&self.service_name) { + type Args = A; + $(self.tokens) + } + } + } + } +} + +impl<'ast> Visitor<'ast> for MockGenerator { + fn visit_service(&mut self, service: &'ast Service) { + visitor::accept_service(service, self); + } + + fn visit_service_func(&mut self, func: &'ast ServiceFunc) { + let mutability = if func.is_query() { "" } else { "mut" }; + let fn_name = func.name().to_case(Case::Snake); + + let mut params_tokens = Tokens::new(); + for param in func.params() { + let type_decl_code = generate_type_decl_code(param.type_decl()); + quote_in! {params_tokens => + $(param.name()): $(type_decl_code), + }; + } + + let output_type_decl_code = generate_type_decl_code(func.output()); + let output_mock = if func.is_query() { + "MockQuery" + } else { + "MockCall" + }; + + quote_in! { self.tokens=> + fn $fn_name (&$mutability self, $params_tokens) -> $output_mock; + }; + } +} diff --git a/rs/client-gen/src/root_generator.rs b/rs/client-gen/src/root_generator.rs index f0bf0c27..a43cfa0e 100644 --- a/rs/client-gen/src/root_generator.rs +++ b/rs/client-gen/src/root_generator.rs @@ -1,6 +1,6 @@ use crate::{ - ctor_generators::*, events_generator::*, io_generators::*, service_generators::*, - type_generators::*, + ctor_generators::*, events_generator::*, io_generators::*, mock_generator::MockGenerator, + service_generators::*, type_generators::*, }; use convert_case::{Case, Casing}; use genco::prelude::*; @@ -10,11 +10,16 @@ use sails_idl_parser::{ast::visitor::Visitor, ast::*}; pub(crate) struct RootGenerator<'a> { tokens: Tokens, traits_tokens: Tokens, + mocks_tokens: Tokens, anonymous_service_name: &'a str, + mocks_feature_name: Option<&'a str>, } impl<'a> RootGenerator<'a> { - pub(crate) fn new(anonymous_service_name: &'a str) -> Self { + pub(crate) fn new( + anonymous_service_name: &'a str, + mocks_feature_name: Option<&'a str>, + ) -> Self { let tokens = quote! { #[allow(unused_imports)] use sails_rs::{prelude::*, String, calls::{Activation, Call, Query, Remoting, RemotingAction}}; @@ -26,10 +31,30 @@ impl<'a> RootGenerator<'a> { anonymous_service_name, tokens, traits_tokens: Tokens::new(), + mocks_tokens: Tokens::new(), + mocks_feature_name, } } pub(crate) fn finalize(self) -> String { + let mocks_tokens = if let Some(mocks_feature_name) = self.mocks_feature_name { + quote! { + #[cfg(feature = $(quoted(mocks_feature_name)))] + #[cfg(not(target_arch = "wasm32"))] + extern crate std; + + #[cfg(feature = $(quoted(mocks_feature_name)))] + #[cfg(not(target_arch = "wasm32"))] + pub mod mockall { + use super::*; + use sails_rs::mockall::*; + $(self.mocks_tokens) + } + } + } else { + Tokens::new() + }; + let result: Tokens = quote! { $(self.tokens) @@ -37,6 +62,8 @@ impl<'a> RootGenerator<'a> { use super::*; $(self.traits_tokens) } + + $mocks_tokens }; let mut result = result.to_file_string().unwrap(); @@ -96,6 +123,10 @@ impl<'a, 'ast> Visitor<'ast> for RootGenerator<'a> { $(service_tokens) } } + + let mut mock_gen: MockGenerator = MockGenerator::new(service_name.to_owned()); + mock_gen.visit_service(service); + self.mocks_tokens.extend(mock_gen.finalize()); } fn visit_type(&mut self, t: &'ast Type) { diff --git a/rs/client-gen/src/service_generators.rs b/rs/client-gen/src/service_generators.rs index cadc2364..a0bc0b1c 100644 --- a/rs/client-gen/src/service_generators.rs +++ b/rs/client-gen/src/service_generators.rs @@ -22,6 +22,7 @@ impl ServiceTraitGenerator { pub(crate) fn finalize(self) -> Tokens { quote! { + #[allow(clippy::type_complexity)] pub trait $(&self.service_name) { type Args; $(self.tokens) @@ -51,7 +52,6 @@ impl<'ast> Visitor<'ast> for ServiceTraitGenerator { let output_trait = if func.is_query() { "Query" } else { "Call" }; quote_in! { self.tokens=> - #[allow(clippy::type_complexity)] fn $fn_name (&$mutability self, $params_tokens) -> impl $output_trait; }; } diff --git a/rs/client-gen/src/type_generators.rs b/rs/client-gen/src/type_generators.rs index 7b8f60f3..a92dcbb3 100644 --- a/rs/client-gen/src/type_generators.rs +++ b/rs/client-gen/src/type_generators.rs @@ -47,8 +47,9 @@ impl<'a, 'ast> Visitor<'ast> for TopLevelTypeGenerator<'a> { }; quote_in!(self.tokens => - #[derive(PartialEq, Debug, Encode, Decode)] + #[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] + #[scale_info(crate = sails_rs::scale_info)] pub struct $(self.type_name) $(struct_def_generator.code) $(semi) ); } @@ -58,8 +59,9 @@ impl<'a, 'ast> Visitor<'ast> for TopLevelTypeGenerator<'a> { enum_def_generator.visit_enum_def(enum_def); quote_in!(self.tokens => - #[derive(PartialEq, Debug, Encode, Decode)] + #[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] + #[scale_info(crate = sails_rs::scale_info)] pub enum $(self.type_name) $(enum_def_generator.code) ); } diff --git a/rs/client-gen/tests/generator.rs b/rs/client-gen/tests/generator.rs index 3852e0a2..4d143eb5 100644 --- a/rs/client-gen/tests/generator.rs +++ b/rs/client-gen/tests/generator.rs @@ -130,5 +130,5 @@ fn test_events_works() { fn gen(program: &str, service_name: &str) -> String { let program = sails_idl_parser::ast::parse_idl(program).expect("parse IDL"); - sails_client_gen::generate(program, service_name).expect("generate client") + sails_client_gen::generate(program, service_name, Some("with_mocks")).expect("generate client") } diff --git a/rs/client-gen/tests/snapshots/generator__basic_works.snap b/rs/client-gen/tests/snapshots/generator__basic_works.snap index f9852243..2221bdb1 100644 --- a/rs/client-gen/tests/snapshots/generator__basic_works.snap +++ b/rs/client-gen/tests/snapshots/generator__basic_works.snap @@ -1,5 +1,5 @@ --- -source: sails/client-gen/tests/generator.rs +source: rs/client-gen/tests/generator.rs expression: "gen(idl, \"Basic\")" --- // Code generated by sails-client-gen. DO NOT EDIT. @@ -59,15 +59,17 @@ pub mod basic { } } } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct MyParam { pub f1: u32, pub f2: Vec, pub f3: Option<(u8, u32)>, } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub enum MyParam2 { Variant1, Variant2(u32), @@ -77,11 +79,20 @@ pub enum MyParam2 { } pub mod traits { use super::*; + #[allow(clippy::type_complexity)] pub trait Basic { type Args; - #[allow(clippy::type_complexity)] fn do_this(&mut self, p1: u32, p2: MyParam) -> impl Call; - #[allow(clippy::type_complexity)] fn do_that(&mut self, p1: (u8, u32)) -> impl Call; } } +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +extern crate std; +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +pub mod mockall { + use super::*; + use sails_rs::mockall::*; + mock! { pub Basic {} #[allow(refining_impl_trait)] #[allow(clippy::type_complexity)] impl traits::Basic for Basic { type Args = A; fn do_this (&mut self, p1: u32,p2: MyParam,) -> MockCall;fn do_that (&mut self, p1: (u8,u32,),) -> MockCall; } } +} diff --git a/rs/client-gen/tests/snapshots/generator__events_works.snap b/rs/client-gen/tests/snapshots/generator__events_works.snap index 33f9a52d..b0293fc7 100644 --- a/rs/client-gen/tests/snapshots/generator__events_works.snap +++ b/rs/client-gen/tests/snapshots/generator__events_works.snap @@ -1,5 +1,5 @@ --- -source: sails/client-gen/tests/generator.rs +source: rs/client-gen/tests/generator.rs expression: "gen(idl, \"ServiceWithEvents\")" --- // Code generated by sails-client-gen. DO NOT EDIT. @@ -77,8 +77,9 @@ pub mod service_with_events { } } } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct MyParam { pub f1: NonZeroU256, pub f2: Vec, @@ -86,9 +87,9 @@ pub struct MyParam { } pub mod traits { use super::*; + #[allow(clippy::type_complexity)] pub trait ServiceWithEvents { type Args; - #[allow(clippy::type_complexity)] fn do_this( &mut self, p1: NonZeroU256, @@ -96,3 +97,13 @@ pub mod traits { ) -> impl Call; } } +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +extern crate std; +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +pub mod mockall { + use super::*; + use sails_rs::mockall::*; + mock! { pub ServiceWithEvents {} #[allow(refining_impl_trait)] #[allow(clippy::type_complexity)] impl traits::ServiceWithEvents for ServiceWithEvents { type Args = A; fn do_this (&mut self, p1: NonZeroU256,p2: MyParam,) -> MockCall; } } +} diff --git a/rs/client-gen/tests/snapshots/generator__full.snap b/rs/client-gen/tests/snapshots/generator__full.snap index 612e1e07..abbe374a 100644 --- a/rs/client-gen/tests/snapshots/generator__full.snap +++ b/rs/client-gen/tests/snapshots/generator__full.snap @@ -1,5 +1,5 @@ --- -source: sails/client-gen/tests/generator.rs +source: rs/client-gen/tests/generator.rs expression: "gen(IDL, \"Service\")" --- // Code generated by sails-client-gen. DO NOT EDIT. @@ -142,18 +142,21 @@ pub mod service { } } } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct ThisThatSvcAppTupleStruct(pub bool); -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct ThisThatSvcAppDoThatParam { pub p1: u32, pub p2: String, pub p3: ThisThatSvcAppManyVariants, } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub enum ThisThatSvcAppManyVariants { One, Two(u32), @@ -162,8 +165,9 @@ pub enum ThisThatSvcAppManyVariants { Five((String, u32)), Six((u32,)), } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub enum T { One, } @@ -176,9 +180,9 @@ pub mod traits { #[allow(clippy::wrong_self_convention)] fn new(&self, a: u32) -> impl Activation; } + #[allow(clippy::type_complexity)] pub trait Service { type Args; - #[allow(clippy::type_complexity)] fn do_this( &mut self, p1: u32, @@ -186,14 +190,21 @@ pub mod traits { p3: (Option, u8), p4: ThisThatSvcAppTupleStruct, ) -> impl Call; - #[allow(clippy::type_complexity)] fn do_that( &mut self, param: ThisThatSvcAppDoThatParam, ) -> impl Call, Args = Self::Args>; - #[allow(clippy::type_complexity)] fn this(&self, v1: Vec) -> impl Query; - #[allow(clippy::type_complexity)] fn that(&self, v1: ()) -> impl Query, Args = Self::Args>; } } +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +extern crate std; +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +pub mod mockall { + use super::*; + use sails_rs::mockall::*; + mock! { pub Service {} #[allow(refining_impl_trait)] #[allow(clippy::type_complexity)] impl traits::Service for Service { type Args = A; fn do_this (&mut self, p1: u32,p2: String,p3: (Option,u8,),p4: ThisThatSvcAppTupleStruct,) -> MockCall;fn do_that (&mut self, param: ThisThatSvcAppDoThatParam,) -> MockCall>;fn this (& self, v1: Vec,) -> MockQuery;fn that (& self, v1: (),) -> MockQuery>; } } +} diff --git a/rs/client-gen/tests/snapshots/generator__multiple_services.snap b/rs/client-gen/tests/snapshots/generator__multiple_services.snap index 8edbfac4..f352bd13 100644 --- a/rs/client-gen/tests/snapshots/generator__multiple_services.snap +++ b/rs/client-gen/tests/snapshots/generator__multiple_services.snap @@ -1,5 +1,5 @@ --- -source: sails/client-gen/tests/generator.rs +source: rs/client-gen/tests/generator.rs expression: "gen(idl, \"Multiple\")" --- // Code generated by sails-client-gen. DO NOT EDIT. @@ -94,16 +94,26 @@ pub mod named { } pub mod traits { use super::*; + #[allow(clippy::type_complexity)] pub trait Multiple { type Args; - #[allow(clippy::type_complexity)] fn do_this(&mut self, p1: u32, p2: MyParam) -> impl Call; - #[allow(clippy::type_complexity)] fn do_that(&mut self, p1: (u8, u32)) -> impl Call; } + #[allow(clippy::type_complexity)] pub trait Named { type Args; - #[allow(clippy::type_complexity)] fn that(&self, p1: u32) -> impl Query; } } +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +extern crate std; +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +pub mod mockall { + use super::*; + use sails_rs::mockall::*; + mock! { pub Multiple {} #[allow(refining_impl_trait)] #[allow(clippy::type_complexity)] impl traits::Multiple for Multiple { type Args = A; fn do_this (&mut self, p1: u32,p2: MyParam,) -> MockCall;fn do_that (&mut self, p1: (u8,u32,),) -> MockCall; } } + mock! { pub Named {} #[allow(refining_impl_trait)] #[allow(clippy::type_complexity)] impl traits::Named for Named { type Args = A; fn that (& self, p1: u32,) -> MockQuery; } } +} diff --git a/rs/client-gen/tests/snapshots/generator__nonzero_works.snap b/rs/client-gen/tests/snapshots/generator__nonzero_works.snap index 843dc976..47cef5e7 100644 --- a/rs/client-gen/tests/snapshots/generator__nonzero_works.snap +++ b/rs/client-gen/tests/snapshots/generator__nonzero_works.snap @@ -1,5 +1,5 @@ --- -source: sails/client-gen/tests/generator.rs +source: rs/client-gen/tests/generator.rs expression: "gen(idl, \"NonZeroParams\")" --- // Code generated by sails-client-gen. DO NOT EDIT. @@ -48,8 +48,9 @@ pub mod non_zero_params { } } } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct MyParam { pub f1: NonZeroU256, pub f2: Vec, @@ -57,9 +58,9 @@ pub struct MyParam { } pub mod traits { use super::*; + #[allow(clippy::type_complexity)] pub trait NonZeroParams { type Args; - #[allow(clippy::type_complexity)] fn do_this( &mut self, p1: NonZeroU256, @@ -67,3 +68,13 @@ pub mod traits { ) -> impl Call; } } +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +extern crate std; +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +pub mod mockall { + use super::*; + use sails_rs::mockall::*; + mock! { pub NonZeroParams {} #[allow(refining_impl_trait)] #[allow(clippy::type_complexity)] impl traits::NonZeroParams for NonZeroParams { type Args = A; fn do_this (&mut self, p1: NonZeroU256,p2: MyParam,) -> MockCall; } } +} diff --git a/rs/client-gen/tests/snapshots/generator__rmrk_works.snap b/rs/client-gen/tests/snapshots/generator__rmrk_works.snap index 77ab26b4..5b9c3e00 100644 --- a/rs/client-gen/tests/snapshots/generator__rmrk_works.snap +++ b/rs/client-gen/tests/snapshots/generator__rmrk_works.snap @@ -1,5 +1,5 @@ --- -source: sails/client-gen/tests/generator.rs +source: rs/client-gen/tests/generator.rs expression: "gen(idl, \"RmrkCatalog\")" --- // Code generated by sails-client-gen. DO NOT EDIT. @@ -242,8 +242,9 @@ pub mod rmrk_catalog { } } } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub enum Error { PartIdCantBeZero, BadConfig, @@ -253,20 +254,23 @@ pub enum Error { WrongPartFormat, NotAllowedToCall, } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub enum Part { Fixed(FixedPart), Slot(SlotPart), } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct FixedPart { pub z: Option, pub metadata_uri: String, } -#[derive(PartialEq, Debug, Encode, Decode)] +#[derive(PartialEq, Debug, Encode, Decode, TypeInfo)] #[codec(crate = sails_rs::scale_codec)] +#[scale_info(crate = sails_rs::scale_info)] pub struct SlotPart { pub equippable: Vec, pub z: Option, @@ -281,47 +285,50 @@ pub mod traits { #[allow(clippy::wrong_self_convention)] fn new(&self) -> impl Activation; } + #[allow(clippy::type_complexity)] pub trait RmrkCatalog { type Args; - #[allow(clippy::type_complexity)] fn add_equippables( &mut self, part_id: u32, collection_ids: Vec, ) -> impl Call), Error>, Args = Self::Args>; - #[allow(clippy::type_complexity)] fn add_parts( &mut self, parts: BTreeMap, ) -> impl Call, Error>, Args = Self::Args>; - #[allow(clippy::type_complexity)] fn remove_equippable( &mut self, part_id: u32, collection_id: ActorId, ) -> impl Call, Args = Self::Args>; - #[allow(clippy::type_complexity)] fn remove_parts( &mut self, part_ids: Vec, ) -> impl Call, Error>, Args = Self::Args>; - #[allow(clippy::type_complexity)] fn reset_equippables( &mut self, part_id: u32, ) -> impl Call, Args = Self::Args>; - #[allow(clippy::type_complexity)] fn set_equippables_to_all( &mut self, part_id: u32, ) -> impl Call, Args = Self::Args>; - #[allow(clippy::type_complexity)] fn equippable( &self, part_id: u32, collection_id: ActorId, ) -> impl Query, Args = Self::Args>; - #[allow(clippy::type_complexity)] fn part(&self, part_id: u32) -> impl Query, Args = Self::Args>; } } +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +extern crate std; +#[cfg(feature = "with_mocks")] +#[cfg(not(target_arch = "wasm32"))] +pub mod mockall { + use super::*; + use sails_rs::mockall::*; + mock! { pub RmrkCatalog {} #[allow(refining_impl_trait)] #[allow(clippy::type_complexity)] impl traits::RmrkCatalog for RmrkCatalog { type Args = A; fn add_equippables (&mut self, part_id: u32,collection_ids: Vec,) -> MockCall,), Error>>;fn add_parts (&mut self, parts: BTreeMap,) -> MockCall, Error>>;fn remove_equippable (&mut self, part_id: u32,collection_id: ActorId,) -> MockCall>;fn remove_parts (&mut self, part_ids: Vec,) -> MockCall, Error>>;fn reset_equippables (&mut self, part_id: u32,) -> MockCall>;fn set_equippables_to_all (&mut self, part_id: u32,) -> MockCall>;fn equippable (& self, part_id: u32,collection_id: ActorId,) -> MockQuery>;fn part (& self, part_id: u32,) -> MockQuery>; } } +} diff --git a/rs/src/calls.rs b/rs/src/calls.rs index e487bcd5..9ac6713b 100644 --- a/rs/src/calls.rs +++ b/rs/src/calls.rs @@ -32,13 +32,13 @@ pub trait Call: Action { #[allow(async_fn_in_trait)] pub trait Activation: Action { - async fn send( + async fn send>( self, code_id: CodeId, - salt: impl AsRef<[u8]>, + salt: S, ) -> Result>; - async fn send_recv(self, code_id: CodeId, salt: impl AsRef<[u8]>) -> Result + async fn send_recv>(self, code_id: CodeId, salt: S) -> Result where Self: Sized, { @@ -205,10 +205,10 @@ where TRemoting: Remoting, TActionIo: ActionIo, { - async fn send( + async fn send>( self, code_id: CodeId, - salt: impl AsRef<[u8]>, + salt: S, ) -> Result> { let payload = TActionIo::encode_call(&self.params); let reply_future = self diff --git a/rs/src/lib.rs b/rs/src/lib.rs index 90488290..a1262af9 100644 --- a/rs/src/lib.rs +++ b/rs/src/lib.rs @@ -1,5 +1,9 @@ #![no_std] +#[cfg(feature = "mockall")] +#[cfg(not(target_arch = "wasm32"))] +extern crate std; + pub use hex::{self}; pub use prelude::*; pub use spin::{self}; @@ -13,6 +17,9 @@ pub mod gsdk; pub mod gstd; #[cfg(not(target_arch = "wasm32"))] pub mod gtest; +#[cfg(feature = "mockall")] +#[cfg(not(target_arch = "wasm32"))] +pub mod mockall; pub mod prelude; mod types; diff --git a/rs/src/mockall.rs b/rs/src/mockall.rs new file mode 100644 index 00000000..91e610ec --- /dev/null +++ b/rs/src/mockall.rs @@ -0,0 +1,77 @@ +use crate::{calls::*, errors::Result, prelude::*}; + +pub use mockall::*; + +mock! { + pub Activation {} + + impl Action for Activation { + type Args = A; + + fn with_value(self, value: ValueUnit) -> Self; + fn with_args(self, args: A) -> Self; + fn value(&self) -> ValueUnit; + fn args(&self) -> &A; + } + + impl Activation for Activation + { + #[allow(refining_impl_trait)] + #[mockall::concretize] + async fn send>(self, code_id: CodeId, salt: S) -> Result>; + #[mockall::concretize] + async fn send_recv>(self, d: CodeId, salt: S) -> Result; + } +} + +mock! { + pub Call {} + + impl Action for Call { + type Args = A; + + fn with_value(self, value: ValueUnit) -> Self; + fn with_args(self, args: A) -> Self; + fn value(&self) -> ValueUnit; + fn args(&self) -> &A; + } + + impl Call for Call + { + type Output = O; + + #[allow(refining_impl_trait)] + async fn send(self, target: ActorId) -> Result>; + async fn send_recv(self, target: ActorId) -> Result; + } +} + +mock! { + pub Query {} + + impl Action for Query { + type Args = A; + + fn with_value(self, value: ValueUnit) -> Self; + fn with_args(self, args: A) -> Self; + fn value(&self) -> ValueUnit; + fn args(&self) -> &A; + } + + impl Query for Query { + type Output = O; + + async fn recv(self, target: ActorId) -> Result; + } +} + +mock! { + pub Reply {} + + impl Reply for Reply + { + type Output = O; + + async fn recv(self) -> Result; + } +}