sentry_options/
testing.rs1use std::cell::RefCell;
20use std::collections::HashMap;
21
22use serde_json::Value;
23
24use crate::{GLOBAL_OPTIONS, OptionsError, Result};
25
26pub fn ensure_initialized() -> Result<()> {
48 match crate::init() {
49 Ok(()) => Ok(()),
50 Err(OptionsError::AlreadyInitialized) => Ok(()),
51 Err(e) => Err(e),
52 }
53}
54
55thread_local! {
56 static OVERRIDES: RefCell<HashMap<String, HashMap<String, Value>>> = RefCell::new(HashMap::new());
57}
58
59pub fn set_override(namespace: &str, key: &str, value: Value) {
61 OVERRIDES.with(|o| {
62 o.borrow_mut()
63 .entry(namespace.to_string())
64 .or_default()
65 .insert(key.to_string(), value);
66 });
67}
68
69pub fn get_override(namespace: &str, key: &str) -> Option<Value> {
71 OVERRIDES.with(|o| {
72 o.borrow()
73 .get(namespace)
74 .and_then(|ns| ns.get(key).cloned())
75 })
76}
77
78pub fn clear_override(namespace: &str, key: &str) {
80 OVERRIDES.with(|o| {
81 if let Some(ns_map) = o.borrow_mut().get_mut(namespace) {
82 ns_map.remove(key);
83 }
84 });
85}
86
87pub struct OverrideGuard {
89 previous: Vec<(String, String, Option<Value>)>,
90}
91
92impl Drop for OverrideGuard {
93 fn drop(&mut self) {
94 OVERRIDES.with(|o| {
95 let mut map = o.borrow_mut();
96 for (ns, key, prev_value) in self.previous.drain(..) {
97 match prev_value {
98 Some(v) => {
99 map.entry(ns).or_default().insert(key, v);
100 }
101 None => {
102 if let Some(ns_map) = map.get_mut(&ns) {
103 ns_map.remove(&key);
104 }
105 }
106 }
107 }
108 });
109 }
110}
111
112pub fn override_options(overrides: &[(&str, &str, Value)]) -> Result<OverrideGuard> {
149 let opts = GLOBAL_OPTIONS
151 .get()
152 .expect("options not initialized - call init() or ensure_initialized() first");
153 for (ns, key, value) in overrides {
154 opts.validate_override(ns, key, value)?;
155 }
156
157 let mut previous = Vec::with_capacity(overrides.len());
158
159 OVERRIDES.with(|o| {
160 let mut map = o.borrow_mut();
161 for (ns, key, value) in overrides {
162 let prev = map.get(*ns).and_then(|m| m.get(*key).cloned());
163 previous.push((ns.to_string(), key.to_string(), prev));
164 map.entry(ns.to_string())
165 .or_default()
166 .insert(key.to_string(), value.clone());
167 }
168 });
169
170 Ok(OverrideGuard { previous })
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176 use serde_json::json;
177
178 #[test]
179 fn test_set_get_clear_override() {
180 set_override("ns", "key", json!(true));
181 assert_eq!(get_override("ns", "key"), Some(json!(true)));
182 clear_override("ns", "key");
183 assert_eq!(get_override("ns", "key"), None);
184 }
185
186 #[test]
187 fn test_override_guard_restores() {
188 ensure_initialized().unwrap();
189 set_override("sentry-options-testing", "int-option", json!(1));
190
191 {
192 let _guard =
193 override_options(&[("sentry-options-testing", "int-option", json!(2))]).unwrap();
194 assert_eq!(
195 get_override("sentry-options-testing", "int-option"),
196 Some(json!(2))
197 );
198 }
199
200 assert_eq!(
201 get_override("sentry-options-testing", "int-option"),
202 Some(json!(1))
203 );
204 clear_override("sentry-options-testing", "int-option");
205 }
206
207 #[test]
208 fn test_override_guard_clears_new_key() {
209 ensure_initialized().unwrap();
210 assert_eq!(get_override("sentry-options-testing", "bool-option"), None);
211
212 {
213 let _guard =
214 override_options(&[("sentry-options-testing", "bool-option", json!(true))])
215 .unwrap();
216 assert_eq!(
217 get_override("sentry-options-testing", "bool-option"),
218 Some(json!(true))
219 );
220 }
221
222 assert_eq!(get_override("sentry-options-testing", "bool-option"), None);
223 }
224
225 #[test]
226 fn test_nested_overrides() {
227 ensure_initialized().unwrap();
228 {
229 let _outer =
230 override_options(&[("sentry-options-testing", "int-option", json!(100))]).unwrap();
231 assert_eq!(
232 get_override("sentry-options-testing", "int-option"),
233 Some(json!(100))
234 );
235
236 {
237 let _inner =
238 override_options(&[("sentry-options-testing", "int-option", json!(200))])
239 .unwrap();
240 assert_eq!(
241 get_override("sentry-options-testing", "int-option"),
242 Some(json!(200))
243 );
244 }
245
246 assert_eq!(
247 get_override("sentry-options-testing", "int-option"),
248 Some(json!(100))
249 );
250 }
251
252 assert_eq!(get_override("sentry-options-testing", "int-option"), None);
253 }
254}