1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/// Macro to update the ownership of an Abstract contract.
///
/// ```rustignore
/// pub fn execute(deps: DepsMut, env: Env, info: MessageInfo, msg: ExecuteMsg) -> ContractResult {
///     match msg {
///         ...
///         ExecuteMsg::UpdateOwnership(action) => {
///             execute_update_ownership!(ContractResponse, deps, env, info, action)
///         }
///     }
/// }
/// ```
#[macro_export]
macro_rules! execute_update_ownership {
    ($response_type:ident, $deps:expr, $env:expr, $info:expr, $action:expr) => {{
        let ownership = cw_ownable::update_ownership($deps, &$env.block, &$info.sender, $action)?;
        Ok($response_type::new(
            "update_ownership",
            ownership.into_attributes(),
        ))
    }};
}

/// Macro to query the ownership of a contract.
///
/// ```rustignore
/// pub fn query(deps: Deps, env: Env, msg: QueryMsg) -> StdResult<Binary> {
///     match msg {
///         ...
///         QueryMsg::Ownership {} => query_ownership!(deps),
///     }
/// }
/// ```
#[macro_export]
macro_rules! query_ownership {
    ($deps:expr) => {{
        cosmwasm_std::to_binary(&cw_ownable::get_ownership($deps.storage)?)
    }};
}

#[cfg(test)]
mod tests {
    use abstract_macros::abstract_response;
    use cosmwasm_schema::cw_serde;
    use cosmwasm_schema::QueryResponses;
    use cosmwasm_std::{
        from_binary,
        testing::{mock_dependencies, mock_env, mock_info},
        Addr, Binary, StdError, StdResult,
    };

    use cw_ownable::{cw_ownable_execute, cw_ownable_query, Action, OwnershipError};
    use thiserror::Error;

    const MOCK_CONTRACT: &str = "contract";

    #[abstract_response(MOCK_CONTRACT)]
    pub struct MockResponse;

    #[cw_ownable_execute]
    #[cw_serde]
    enum ExecuteMsg {}

    #[cw_ownable_query]
    #[cw_serde]
    #[derive(QueryResponses)]
    enum QueryMsg {}

    #[derive(Error, Debug, PartialEq)]
    pub enum MockError {
        #[error("{0}")]
        Std(#[from] StdError),
        #[error("{0}")]
        Ownership(#[from] cw_ownable::OwnershipError),
    }

    const NEW_OWNER: &str = "new_owner";
    const OLD_OWNER: &str = "old_owner";

    #[test]
    fn test_update_ownership_macro() -> Result<(), MockError> {
        let mut deps = mock_dependencies();

        let env = mock_env();
        let info = mock_info(OLD_OWNER, &[]);

        cw_ownable::initialize_owner(&mut deps.storage, &deps.api, Some(OLD_OWNER))?;

        let mut_deps = deps.as_mut();

        // ExecuteMsg for testing the macro
        let transfer_ownership_action = Action::TransferOwnership {
            new_owner: NEW_OWNER.to_string(),
            expiry: None,
        };

        let ownership_msg = ExecuteMsg::UpdateOwnership(transfer_ownership_action);

        let result: Result<_, OwnershipError> = match ownership_msg {
            ExecuteMsg::UpdateOwnership(action) => {
                execute_update_ownership!(MockResponse, mut_deps, env, info, action)
            }
        };

        let expected_response = MockResponse::new(
            "update_ownership",
            vec![
                ("owner", OLD_OWNER),
                ("pending_owner", NEW_OWNER),
                ("pending_expiry", "none"),
            ],
        );

        assert_eq!(result.unwrap(), expected_response);

        Ok(())
    }

    #[test]
    fn test_query_ownership_macro() -> Result<(), MockError> {
        let mut deps = mock_dependencies();
        let _env = mock_env();

        let old_owner = "owner1";

        cw_ownable::initialize_owner(&mut deps.storage, &deps.api, Some(old_owner))?;

        // Ownership query message for testing the macro
        let ownership_query_msg = QueryMsg::Ownership {};

        let result: StdResult<Binary> = match ownership_query_msg {
            QueryMsg::Ownership {} => query_ownership!(deps.as_ref()),
        };

        let expected = cw_ownable::Ownership {
            owner: Some(Addr::unchecked(old_owner)),
            pending_owner: None,
            pending_expiry: None,
        };

        // Deserialize the query response
        let actual: cw_ownable::Ownership<Addr> = from_binary(&result.unwrap())?;

        assert_eq!(actual, expected);

        Ok(())
    }
}