From 246cba34a4377f8d207341425454e12551a96047 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Wo=C5=BAniak?= <jnwznk@gmail.com>
Date: Wed, 11 Oct 2023 10:50:11 +0200
Subject: [PATCH] test: Multiple generic interfaces

---
 sylvia/tests/generics.rs | 170 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 168 insertions(+), 2 deletions(-)

diff --git a/sylvia/tests/generics.rs b/sylvia/tests/generics.rs
index 7551600e..73f36fd4 100644
--- a/sylvia/tests/generics.rs
+++ b/sylvia/tests/generics.rs
@@ -13,7 +13,7 @@ pub mod cw1 {
     where
         for<'msg_de> Msg: CustomMsg + Deserialize<'msg_de>,
         Param: sylvia::types::CustomMsg,
-        for<'msg_de> QueryRet: CustomQuery + DeserializeOwned,
+        QueryRet: CustomQuery + DeserializeOwned,
     {
         type Error: From<StdError>;
 
@@ -29,6 +29,56 @@ pub mod cw1 {
     }
 }
 
+pub mod whitelist {
+    use cosmwasm_std::{CosmosMsg, CustomMsg, CustomQuery, Response, StdError};
+
+    use serde::de::DeserializeOwned;
+    use serde::Deserialize;
+    use sylvia::types::{ExecCtx, QueryCtx};
+    use sylvia_derive::interface;
+
+    #[interface(module=msg)]
+    pub trait Whitelist<Msg, QueryRet>
+    where
+        for<'msg_de> Msg: CustomMsg + Deserialize<'msg_de>,
+        for<'msg_de> QueryRet: CustomQuery + DeserializeOwned,
+    {
+        type Error: From<StdError>;
+
+        #[msg(exec)]
+        fn update_admins(
+            &self,
+            ctx: ExecCtx,
+            msgs: Vec<CosmosMsg<Msg>>,
+        ) -> Result<Response, Self::Error>;
+
+        #[msg(query)]
+        fn admins_list(&self, ctx: QueryCtx) -> Result<QueryRet, Self::Error>;
+    }
+}
+
+pub mod non_generic {
+    use cosmwasm_std::{CosmosMsg, Empty, Response, StdError};
+
+    use sylvia::types::{ExecCtx, QueryCtx};
+    use sylvia_derive::interface;
+
+    #[interface(module=msg)]
+    pub trait NonGeneric {
+        type Error: From<StdError>;
+
+        #[msg(exec)]
+        fn non_generic_exec(
+            &self,
+            ctx: ExecCtx,
+            msgs: Vec<CosmosMsg<Empty>>,
+        ) -> Result<Response, Self::Error>;
+
+        #[msg(query)]
+        fn non_generic_query(&self, ctx: QueryCtx) -> Result<Response, Self::Error>;
+    }
+}
+
 pub mod cw1_contract {
     use cosmwasm_std::{Response, StdResult};
     use sylvia::types::InstantiateCtx;
@@ -40,6 +90,8 @@ pub mod cw1_contract {
 
     #[contract]
     #[messages(crate::cw1<ExternalMsg, ExternalMsg, ExternalQuery> as Cw1)]
+    #[messages(crate::whitelist<ExternalMsg, ExternalQuery> as Whitelist: custom(msg))]
+    #[messages(crate::non_generic as NonGeneric: custom(msg))]
     /// Required if interface returns generic `Response`
     #[sv::custom(msg=ExternalMsg)]
     impl Cw1Contract {
@@ -54,6 +106,66 @@ pub mod cw1_contract {
     }
 }
 
+pub mod impl_non_generic {
+    use crate::cw1_contract::Cw1Contract;
+    use crate::non_generic::NonGeneric;
+    use cosmwasm_std::{CosmosMsg, Empty, Response, StdError};
+    use sylvia::types::{ExecCtx, QueryCtx};
+    use sylvia_derive::contract;
+
+    #[contract(module = crate::cw1_contract)]
+    #[messages(crate::non_generic as NonGeneric)]
+    #[sv::custom(msg=crate::ExternalMsg)]
+    impl NonGeneric for Cw1Contract {
+        type Error = StdError;
+
+        #[msg(exec)]
+        fn non_generic_exec(
+            &self,
+            _ctx: ExecCtx,
+            _msgs: Vec<CosmosMsg<Empty>>,
+        ) -> Result<Response, Self::Error> {
+            Ok(Response::new())
+        }
+
+        #[msg(query)]
+        fn non_generic_query(&self, _ctx: QueryCtx) -> Result<Response, Self::Error> {
+            Ok(Response::default())
+        }
+    }
+}
+
+pub mod impl_whitelist {
+    use cosmwasm_std::{CosmosMsg, Response, StdError};
+    use sylvia::types::{ExecCtx, QueryCtx};
+    use sylvia_derive::contract;
+
+    use crate::cw1_contract::Cw1Contract;
+    use crate::whitelist::Whitelist;
+    use crate::{ExternalMsg, ExternalQuery};
+
+    #[contract(module = crate::cw1_contract)]
+    #[messages(crate::whitelist as Whitelist)]
+    #[sv::custom(msg=ExternalMsg)]
+    impl Whitelist<ExternalMsg, ExternalQuery> for Cw1Contract {
+        type Error = StdError;
+
+        #[msg(exec)]
+        fn update_admins(
+            &self,
+            _ctx: ExecCtx,
+            _msgs: Vec<CosmosMsg<ExternalMsg>>,
+        ) -> Result<Response, Self::Error> {
+            Ok(Response::new())
+        }
+
+        #[msg(query)]
+        fn admins_list(&self, _ctx: QueryCtx) -> Result<ExternalQuery, Self::Error> {
+            Ok(ExternalQuery {})
+        }
+    }
+}
+
 pub mod impl_cw1 {
     use cosmwasm_std::{CosmosMsg, Response, StdError};
     use sylvia::types::{ExecCtx, QueryCtx};
@@ -63,6 +175,7 @@ pub mod impl_cw1 {
 
     #[contract(module = crate::cw1_contract)]
     #[messages(crate::cw1 as Cw1)]
+    #[sv::custom(msg=ExternalMsg)]
     impl Cw1<ExternalMsg, crate::ExternalMsg, crate::ExternalQuery> for Cw1Contract {
         type Error = StdError;
 
@@ -93,22 +206,38 @@ impl cosmwasm_std::CustomMsg for ExternalMsg {}
 #[cw_serde]
 pub struct ExternalQuery;
 impl cosmwasm_std::CustomQuery for ExternalQuery {}
-
 #[cfg(all(test, feature = "mt"))]
 mod tests {
     use crate::cw1::{InterfaceTypes, Querier as Cw1Querier};
+    use crate::cw1_contract::Cw1Contract;
+    use crate::impl_cw1::test_utils::Cw1;
+    use crate::impl_non_generic::test_utils::NonGeneric;
+    use crate::impl_whitelist::test_utils::Whitelist;
+    use crate::non_generic::Querier as NonGenericQuerier;
+    use crate::whitelist::Querier as WhitelistQuerier;
     use crate::{ExternalMsg, ExternalQuery};
     use cosmwasm_std::{testing::mock_dependencies, Addr, CosmosMsg, Empty, QuerierWrapper};
+    use sylvia::multitest::App;
     use sylvia::types::InterfaceMessages;
 
     #[test]
     fn construct_messages() {
         let contract = Addr::unchecked("contract");
 
+        // Direct message construction
+        // cw1
         let _ = crate::cw1::QueryMsg::<_, Empty>::some_query(ExternalMsg {});
         let _ = crate::cw1::ExecMsg::execute(vec![CosmosMsg::Custom(ExternalMsg {})]);
         let _ = crate::cw1::ExecMsg::execute(vec![CosmosMsg::Custom(Empty {})]);
 
+        // whitelist
+        let _ = crate::whitelist::QueryMsg::<ExternalQuery>::admins_list();
+        let _ = crate::whitelist::ExecMsg::update_admins(vec![CosmosMsg::Custom(ExternalMsg {})]);
+
+        // non_generic
+        let _ = crate::non_generic::QueryMsg::non_generic_query();
+        let _ = crate::non_generic::ExecMsg::non_generic_exec(vec![]);
+
         // Generic Querier
         let deps = mock_dependencies();
         let querier: QuerierWrapper<ExternalQuery> = QuerierWrapper::new(&deps.querier);
@@ -120,6 +249,8 @@ mod tests {
 
         let contract_querier = crate::cw1_contract::BoundQuerier::borrowed(&contract, &querier);
         let _: Result<ExternalQuery, _> = contract_querier.some_query(ExternalMsg {});
+        let _: Result<ExternalQuery, _> = contract_querier.admins_list();
+        let _ = contract_querier.non_generic_query();
 
         // Construct messages with Interface extension
         let _ =
@@ -131,4 +262,39 @@ mod tests {
                 CosmosMsg::Custom(ExternalMsg {}),
             ]);
     }
+
+    #[test]
+    fn mt_helpers() {
+        let _ = Cw1Contract::new();
+        let app = App::<cw_multi_test::BasicApp<ExternalMsg>>::custom(|_, _, _| {});
+        let code_id = crate::cw1_contract::multitest_utils::CodeId::store_code(&app);
+
+        let owner = "owner";
+
+        let contract = code_id
+            .instantiate()
+            .with_label("Cw1Contract")
+            .call(owner)
+            .unwrap();
+
+        // CustomMsg generic Interface
+        contract.cw1_proxy().some_query(ExternalMsg {}).unwrap();
+        contract.cw1_proxy().execute(vec![]).call(owner).unwrap();
+
+        // Non-CustomMsg generic Interface
+        contract.whitelist_proxy().admins_list().unwrap();
+        contract
+            .whitelist_proxy()
+            .update_admins(vec![])
+            .call(owner)
+            .unwrap();
+
+        // Non-CustomMsg non-generic Interface
+        contract.non_generic_proxy().non_generic_query().unwrap();
+        contract
+            .non_generic_proxy()
+            .non_generic_exec(vec![])
+            .call(owner)
+            .unwrap();
+    }
 }