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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
use candid::{CandidType, Principal, utils::ArgumentEncoder};
use pocket_ic::PocketIc;
use serde::de::DeserializeOwned;
use super::{
CandidCallError, CandidCallExt, CanisterInstallExt, InstallSpec, StandaloneCanisterInstallError,
};
///
/// StandaloneCanisterFixture
///
pub struct StandaloneCanisterFixture {
pocket_ic: PocketIc,
canister_id: Principal,
}
impl StandaloneCanisterFixture {
/// Install one canister into a caller-configured PocketIC instance.
#[must_use]
pub fn install(pocket_ic: PocketIc, spec: InstallSpec) -> Self {
Self::try_install(pocket_ic, spec)
.unwrap_or_else(|err| panic!("failed to install standalone canister fixture: {err}"))
}
/// Fallible counterpart to [`install`](Self::install).
///
/// On failure, the error retains both the caller's PocketIC instance and
/// the structured install failure.
pub fn try_install(
pocket_ic: PocketIc,
spec: InstallSpec,
) -> Result<Self, StandaloneCanisterInstallError> {
let canister_id = match pocket_ic.try_create_and_install(spec) {
Ok(canister_id) => canister_id,
Err(error) => return Err(StandaloneCanisterInstallError::new(pocket_ic, error)),
};
Ok(Self {
pocket_ic,
canister_id,
})
}
/// Borrow the PocketIC instance that owns this standalone fixture.
#[must_use]
pub const fn pocket_ic(&self) -> &PocketIc {
&self.pocket_ic
}
/// Read the installed canister id for this standalone fixture.
#[must_use]
pub const fn canister_id(&self) -> Principal {
self.canister_id
}
/// Consume the fixture and return the owned PocketIC instance and canister id.
#[must_use]
pub fn into_parts(self) -> (PocketIc, Principal) {
(self.pocket_ic, self.canister_id)
}
/// Forward one typed update call to this fixture's canister id.
pub fn update_call<T, A>(&self, method: &str, args: A) -> Result<T, CandidCallError>
where
T: CandidType + DeserializeOwned,
A: ArgumentEncoder,
{
self.pocket_ic.update_candid(self.canister_id, method, args)
}
/// Forward one typed update call to this fixture's canister id, panicking
/// on rejection or Candid codec failure.
///
/// This does not unwrap application-level results. For example,
/// `update_call_or_panic::<Result<T, E>, _>(...)` returns `Result<T, E>`.
#[track_caller]
pub fn update_call_or_panic<T, A>(&self, method: &str, args: A) -> T
where
T: CandidType + DeserializeOwned,
A: ArgumentEncoder,
{
self.pocket_ic
.update_candid_or_panic(self.canister_id, method, args)
}
/// Forward one typed update call with an explicit caller to this fixture's canister id.
pub fn update_call_as<T, A>(
&self,
caller: Principal,
method: &str,
args: A,
) -> Result<T, CandidCallError>
where
T: CandidType + DeserializeOwned,
A: ArgumentEncoder,
{
self.pocket_ic
.update_candid_as(self.canister_id, caller, method, args)
}
/// Forward one typed update call with an explicit caller to this fixture's
/// canister id, panicking on rejection or Candid codec failure.
///
/// This does not unwrap application-level results. For example,
/// `update_call_as_or_panic::<Result<T, E>, _>(...)` returns `Result<T, E>`.
#[track_caller]
pub fn update_call_as_or_panic<T, A>(&self, caller: Principal, method: &str, args: A) -> T
where
T: CandidType + DeserializeOwned,
A: ArgumentEncoder,
{
self.pocket_ic
.update_candid_as_or_panic(self.canister_id, caller, method, args)
}
/// Forward one typed query call to this fixture's canister id.
pub fn query_call<T, A>(&self, method: &str, args: A) -> Result<T, CandidCallError>
where
T: CandidType + DeserializeOwned,
A: ArgumentEncoder,
{
self.pocket_ic.query_candid(self.canister_id, method, args)
}
/// Forward one typed query call to this fixture's canister id, panicking on
/// rejection or Candid codec failure.
///
/// This does not unwrap application-level results. For example,
/// `query_call_or_panic::<Result<T, E>, _>(...)` returns `Result<T, E>`.
#[track_caller]
pub fn query_call_or_panic<T, A>(&self, method: &str, args: A) -> T
where
T: CandidType + DeserializeOwned,
A: ArgumentEncoder,
{
self.pocket_ic
.query_candid_or_panic(self.canister_id, method, args)
}
/// Forward one typed query call with an explicit caller to this fixture's canister id.
pub fn query_call_as<T, A>(
&self,
caller: Principal,
method: &str,
args: A,
) -> Result<T, CandidCallError>
where
T: CandidType + DeserializeOwned,
A: ArgumentEncoder,
{
self.pocket_ic
.query_candid_as(self.canister_id, caller, method, args)
}
/// Forward one typed query call with an explicit caller to this fixture's
/// canister id, panicking on rejection or Candid codec failure.
///
/// This does not unwrap application-level results. For example,
/// `query_call_as_or_panic::<Result<T, E>, _>(...)` returns `Result<T, E>`.
#[track_caller]
pub fn query_call_as_or_panic<T, A>(&self, caller: Principal, method: &str, args: A) -> T
where
T: CandidType + DeserializeOwned,
A: ArgumentEncoder,
{
self.pocket_ic
.query_candid_as_or_panic(self.canister_id, caller, method, args)
}
}