Skip to main content

ic_testkit/pic/
standalone.rs

1use candid::{CandidType, Principal, utils::ArgumentEncoder};
2use pocket_ic::PocketIc;
3use serde::de::DeserializeOwned;
4
5use super::{
6    CandidCallError, CandidCallExt, CanisterInstallExt, InstallSpec, StandaloneCanisterInstallError,
7};
8
9///
10/// StandaloneCanisterFixture
11///
12
13pub struct StandaloneCanisterFixture {
14    pocket_ic: PocketIc,
15    canister_id: Principal,
16}
17
18impl StandaloneCanisterFixture {
19    /// Install one canister into a caller-configured PocketIC instance.
20    #[must_use]
21    pub fn install(pocket_ic: PocketIc, spec: InstallSpec) -> Self {
22        Self::try_install(pocket_ic, spec)
23            .unwrap_or_else(|err| panic!("failed to install standalone canister fixture: {err}"))
24    }
25
26    /// Fallible counterpart to [`install`](Self::install).
27    ///
28    /// On failure, the error retains both the caller's PocketIC instance and
29    /// the structured install failure.
30    pub fn try_install(
31        pocket_ic: PocketIc,
32        spec: InstallSpec,
33    ) -> Result<Self, StandaloneCanisterInstallError> {
34        let canister_id = match pocket_ic.try_create_and_install(spec) {
35            Ok(canister_id) => canister_id,
36            Err(error) => return Err(StandaloneCanisterInstallError::new(pocket_ic, error)),
37        };
38
39        Ok(Self {
40            pocket_ic,
41            canister_id,
42        })
43    }
44
45    /// Borrow the PocketIC instance that owns this standalone fixture.
46    #[must_use]
47    pub const fn pocket_ic(&self) -> &PocketIc {
48        &self.pocket_ic
49    }
50
51    /// Read the installed canister id for this standalone fixture.
52    #[must_use]
53    pub const fn canister_id(&self) -> Principal {
54        self.canister_id
55    }
56
57    /// Consume the fixture and return the owned PocketIC instance and canister id.
58    #[must_use]
59    pub fn into_parts(self) -> (PocketIc, Principal) {
60        (self.pocket_ic, self.canister_id)
61    }
62
63    /// Forward one typed update call to this fixture's canister id.
64    pub fn update_call<T, A>(&self, method: &str, args: A) -> Result<T, CandidCallError>
65    where
66        T: CandidType + DeserializeOwned,
67        A: ArgumentEncoder,
68    {
69        self.pocket_ic.update_candid(self.canister_id, method, args)
70    }
71
72    /// Forward one typed update call to this fixture's canister id, panicking
73    /// on rejection or Candid codec failure.
74    ///
75    /// This does not unwrap application-level results. For example,
76    /// `update_call_or_panic::<Result<T, E>, _>(...)` returns `Result<T, E>`.
77    #[track_caller]
78    pub fn update_call_or_panic<T, A>(&self, method: &str, args: A) -> T
79    where
80        T: CandidType + DeserializeOwned,
81        A: ArgumentEncoder,
82    {
83        self.pocket_ic
84            .update_candid_or_panic(self.canister_id, method, args)
85    }
86
87    /// Forward one typed update call with an explicit caller to this fixture's canister id.
88    pub fn update_call_as<T, A>(
89        &self,
90        caller: Principal,
91        method: &str,
92        args: A,
93    ) -> Result<T, CandidCallError>
94    where
95        T: CandidType + DeserializeOwned,
96        A: ArgumentEncoder,
97    {
98        self.pocket_ic
99            .update_candid_as(self.canister_id, caller, method, args)
100    }
101
102    /// Forward one typed update call with an explicit caller to this fixture's
103    /// canister id, panicking on rejection or Candid codec failure.
104    ///
105    /// This does not unwrap application-level results. For example,
106    /// `update_call_as_or_panic::<Result<T, E>, _>(...)` returns `Result<T, E>`.
107    #[track_caller]
108    pub fn update_call_as_or_panic<T, A>(&self, caller: Principal, method: &str, args: A) -> T
109    where
110        T: CandidType + DeserializeOwned,
111        A: ArgumentEncoder,
112    {
113        self.pocket_ic
114            .update_candid_as_or_panic(self.canister_id, caller, method, args)
115    }
116
117    /// Forward one typed query call to this fixture's canister id.
118    pub fn query_call<T, A>(&self, method: &str, args: A) -> Result<T, CandidCallError>
119    where
120        T: CandidType + DeserializeOwned,
121        A: ArgumentEncoder,
122    {
123        self.pocket_ic.query_candid(self.canister_id, method, args)
124    }
125
126    /// Forward one typed query call to this fixture's canister id, panicking on
127    /// rejection or Candid codec failure.
128    ///
129    /// This does not unwrap application-level results. For example,
130    /// `query_call_or_panic::<Result<T, E>, _>(...)` returns `Result<T, E>`.
131    #[track_caller]
132    pub fn query_call_or_panic<T, A>(&self, method: &str, args: A) -> T
133    where
134        T: CandidType + DeserializeOwned,
135        A: ArgumentEncoder,
136    {
137        self.pocket_ic
138            .query_candid_or_panic(self.canister_id, method, args)
139    }
140
141    /// Forward one typed query call with an explicit caller to this fixture's canister id.
142    pub fn query_call_as<T, A>(
143        &self,
144        caller: Principal,
145        method: &str,
146        args: A,
147    ) -> Result<T, CandidCallError>
148    where
149        T: CandidType + DeserializeOwned,
150        A: ArgumentEncoder,
151    {
152        self.pocket_ic
153            .query_candid_as(self.canister_id, caller, method, args)
154    }
155
156    /// Forward one typed query call with an explicit caller to this fixture's
157    /// canister id, panicking on rejection or Candid codec failure.
158    ///
159    /// This does not unwrap application-level results. For example,
160    /// `query_call_as_or_panic::<Result<T, E>, _>(...)` returns `Result<T, E>`.
161    #[track_caller]
162    pub fn query_call_as_or_panic<T, A>(&self, caller: Principal, method: &str, args: A) -> T
163    where
164        T: CandidType + DeserializeOwned,
165        A: ArgumentEncoder,
166    {
167        self.pocket_ic
168            .query_candid_as_or_panic(self.canister_id, caller, method, args)
169    }
170}