1#[cfg(feature = "json")]
2use serde_json::Value as JsonValue;
3use std::borrow::Borrow;
4use std::convert::TryFrom;
5use std::iter::FromIterator;
6
7use std::collections::BTreeMap;
8#[cfg(feature = "json")]
9use std::convert::TryInto;
10
11use crate::value_map::ValueMapHelper;
12use crate::{Error, Identifier, Value};
13
14pub trait BTreeValueMapPathHelper {
15 fn get_at_path(&self, path: &str) -> Result<&Value, Error>;
16 fn get_optional_at_path(&self, path: &str) -> Result<Option<&Value>, Error>;
17 fn get_optional_identifier_at_path(&self, path: &str) -> Result<Option<[u8; 32]>, Error>;
18 fn get_identifier_at_path(&self, path: &str) -> Result<[u8; 32], Error>;
19 fn get_optional_string_at_path(&self, path: &str) -> Result<Option<String>, Error>;
20 fn get_string_at_path(&self, path: &str) -> Result<String, Error>;
21 fn get_optional_str_at_path(&self, path: &str) -> Result<Option<&str>, Error>;
22 fn get_str_at_path(&self, path: &str) -> Result<&str, Error>;
23 fn get_optional_float_at_path(&self, path: &str) -> Result<Option<f64>, Error>;
24 fn get_float_at_path(&self, path: &str) -> Result<f64, Error>;
25 fn get_optional_integer_at_path<T>(&self, path: &str) -> Result<Option<T>, Error>
26 where
27 T: TryFrom<i128>
28 + TryFrom<u128>
29 + TryFrom<u64>
30 + TryFrom<i64>
31 + TryFrom<u32>
32 + TryFrom<i32>
33 + TryFrom<u16>
34 + TryFrom<i16>
35 + TryFrom<u8>
36 + TryFrom<i8>;
37 fn get_integer_at_path<T>(&self, path: &str) -> Result<T, Error>
38 where
39 T: TryFrom<i128>
40 + TryFrom<u128>
41 + TryFrom<u64>
42 + TryFrom<i64>
43 + TryFrom<u32>
44 + TryFrom<i32>
45 + TryFrom<u16>
46 + TryFrom<i16>
47 + TryFrom<u8>
48 + TryFrom<i8>;
49 fn get_optional_bool_at_path(&self, path: &str) -> Result<Option<bool>, Error>;
50 fn get_bool_at_path(&self, path: &str) -> Result<bool, Error>;
51 fn get_optional_inner_value_array_at_path<'a, I: FromIterator<&'a Value>>(
52 &'a self,
53 path: &str,
54 ) -> Result<Option<I>, Error>;
55 fn get_inner_value_array_at_path<'a, I: FromIterator<&'a Value>>(
56 &'a self,
57 path: &str,
58 ) -> Result<I, Error>;
59 fn get_optional_inner_string_array_at_path<I: FromIterator<String>>(
60 &self,
61 path: &str,
62 ) -> Result<Option<I>, Error>;
63 fn get_inner_string_array_at_path<I: FromIterator<String>>(
64 &self,
65 path: &str,
66 ) -> Result<I, Error>;
67 fn get_optional_inner_borrowed_map_at_path(
68 &self,
69 path: &str,
70 ) -> Result<Option<&Vec<(Value, Value)>>, Error>;
71 fn get_optional_inner_borrowed_str_value_map_at_path<'a, I: FromIterator<(String, &'a Value)>>(
72 &'a self,
73 path: &str,
74 ) -> Result<Option<I>, Error>;
75 fn get_inner_borrowed_str_value_map_at_path<'a, I: FromIterator<(String, &'a Value)>>(
76 &'a self,
77 path: &str,
78 ) -> Result<I, Error>;
79 #[cfg(feature = "json")]
80 fn get_optional_inner_str_json_value_map_at_path<I: FromIterator<(String, JsonValue)>>(
81 &self,
82 path: &str,
83 ) -> Result<Option<I>, Error>;
84 #[cfg(feature = "json")]
85 fn get_inner_str_json_value_map_at_path<I: FromIterator<(String, JsonValue)>>(
86 &self,
87 path: &str,
88 ) -> Result<I, Error>;
89 fn get_optional_hash256_bytes_at_path(&self, path: &str) -> Result<Option<[u8; 32]>, Error>;
90 fn get_hash256_bytes_at_path(&self, path: &str) -> Result<[u8; 32], Error>;
91 fn get_optional_identifier_bytes_at_path(&self, path: &str) -> Result<Option<Vec<u8>>, Error>;
92 fn get_identifier_bytes_at_path(&self, path: &str) -> Result<Vec<u8>, Error>;
93 fn remove_optional_string_at_path(&mut self, path: &str) -> Result<Option<String>, Error>;
94 fn remove_string_at_path(&mut self, path: &str) -> Result<String, Error>;
95 fn remove_optional_float_at_path(&mut self, path: &str) -> Result<Option<f64>, Error>;
96 fn remove_float_at_path(&mut self, path: &str) -> Result<f64, Error>;
97 fn remove_optional_integer_at_path<T>(&mut self, path: &str) -> Result<Option<T>, Error>
98 where
99 T: TryFrom<i128>
100 + TryFrom<u128>
101 + TryFrom<u64>
102 + TryFrom<i64>
103 + TryFrom<u32>
104 + TryFrom<i32>
105 + TryFrom<u16>
106 + TryFrom<i16>
107 + TryFrom<u8>
108 + TryFrom<i8>;
109 fn remove_integer_at_path<T>(&mut self, path: &str) -> Result<T, Error>
110 where
111 T: TryFrom<i128>
112 + TryFrom<u128>
113 + TryFrom<u64>
114 + TryFrom<i64>
115 + TryFrom<u32>
116 + TryFrom<i32>
117 + TryFrom<u16>
118 + TryFrom<i16>
119 + TryFrom<u8>
120 + TryFrom<i8>;
121 fn remove_optional_hash256_bytes_at_path(
122 &mut self,
123 path: &str,
124 ) -> Result<Option<[u8; 32]>, Error>;
125 fn remove_hash256_bytes_at_path(&mut self, path: &str) -> Result<[u8; 32], Error>;
126 fn remove_optional_identifier_at_path(
127 &mut self,
128 path: &str,
129 ) -> Result<Option<Identifier>, Error>;
130 fn remove_identifier_at_path(&mut self, path: &str) -> Result<Identifier, Error>;
131 fn get_optional_bytes_at_path(&self, path: &str) -> Result<Option<Vec<u8>>, Error>;
132 fn get_bytes_at_path(&self, path: &str) -> Result<Vec<u8>, Error>;
133 fn get_optional_binary_bytes_at_path(&self, path: &str) -> Result<Option<Vec<u8>>, Error>;
134 fn get_binary_bytes_at_path(&self, path: &str) -> Result<Vec<u8>, Error>;
135}
136
137impl<V> BTreeValueMapPathHelper for BTreeMap<String, V>
138where
139 V: Borrow<Value>,
140{
141 fn get_at_path(&self, path: &str) -> Result<&Value, Error> {
142 let mut split = path.split('.');
143 let first = split.next();
144 let Some(first_path_component) = first else {
145 return Err(Error::PathError("path was empty".to_string()));
146 };
147 let mut current_value = self
148 .get(first_path_component)
149 .ok_or_else(|| {
150 Error::StructureError(format!(
151 "unable to get property {first_path_component} in {path}"
152 ))
153 })?
154 .borrow();
155 for path_component in split {
156 let map = current_value.to_map_ref()?;
157 current_value = map.get_optional_key(path_component).ok_or_else(|| {
158 Error::StructureError(format!(
159 "unable to get property at path {path_component} in {path}"
160 ))
161 })?;
162 }
163 Ok(current_value)
164 }
165
166 fn get_optional_at_path(&self, path: &str) -> Result<Option<&Value>, Error> {
167 let mut split = path.split('.');
168 let first = split.next();
169 let Some(first_path_component) = first else {
170 return Err(Error::PathError("path was empty".to_string()));
171 };
172 let Some(mut current_value) = self.get(first_path_component).map(|v| v.borrow()) else {
173 return Ok(None);
174 };
175 for path_component in split {
176 let map = current_value.to_map_ref()?;
177 let Some(new_value) = map.get_optional_key(path_component) else {
178 return Ok(None);
179 };
180 current_value = new_value;
181 }
182 Ok(Some(current_value))
183 }
184
185 fn get_optional_identifier_at_path(&self, path: &str) -> Result<Option<[u8; 32]>, Error> {
186 self.get_optional_at_path(path)?
187 .map(|v| v.to_hash256())
188 .transpose()
189 }
190
191 fn get_identifier_at_path(&self, path: &str) -> Result<[u8; 32], Error> {
192 self.get_optional_identifier_at_path(path)?.ok_or_else(|| {
193 Error::StructureError(format!("unable to get identifier property {path}"))
194 })
195 }
196
197 fn get_optional_string_at_path(&self, path: &str) -> Result<Option<String>, Error> {
198 self.get_optional_at_path(path)?
199 .map(|v| {
200 v.as_text()
201 .map(|str| str.to_string())
202 .ok_or_else(|| Error::StructureError(format!("{path} must be a string")))
203 })
204 .transpose()
205 }
206
207 fn get_string_at_path(&self, path: &str) -> Result<String, Error> {
208 self.get_optional_string_at_path(path)?
209 .ok_or_else(|| Error::StructureError(format!("unable to get string property {path}")))
210 }
211
212 fn get_optional_str_at_path(&self, path: &str) -> Result<Option<&str>, Error> {
213 self.get_optional_at_path(path)?
214 .map(|v| {
215 v.as_text()
216 .ok_or_else(|| Error::StructureError(format!("{path} must be a string")))
217 })
218 .transpose()
219 }
220
221 fn get_str_at_path(&self, path: &str) -> Result<&str, Error> {
222 self.get_optional_str_at_path(path)?
223 .ok_or_else(|| Error::StructureError(format!("unable to get str property {path}")))
224 }
225
226 fn get_optional_integer_at_path<T>(&self, path: &str) -> Result<Option<T>, Error>
227 where
228 T: TryFrom<i128>
229 + TryFrom<u128>
230 + TryFrom<u64>
231 + TryFrom<i64>
232 + TryFrom<u32>
233 + TryFrom<i32>
234 + TryFrom<u16>
235 + TryFrom<i16>
236 + TryFrom<u8>
237 + TryFrom<i8>,
238 {
239 self.get_optional_at_path(path)?
240 .and_then(|v| {
241 if v.is_null() {
242 None
243 } else {
244 Some(v.to_integer())
245 }
246 })
247 .transpose()
248 }
249
250 fn get_integer_at_path<T>(&self, path: &str) -> Result<T, Error>
251 where
252 T: TryFrom<i128>
253 + TryFrom<u128>
254 + TryFrom<u64>
255 + TryFrom<i64>
256 + TryFrom<u32>
257 + TryFrom<i32>
258 + TryFrom<u16>
259 + TryFrom<i16>
260 + TryFrom<u8>
261 + TryFrom<i8>,
262 {
263 self.get_optional_integer_at_path(path)?
264 .ok_or_else(|| Error::StructureError(format!("unable to get integer property {path}")))
265 }
266
267 fn remove_optional_integer_at_path<T>(&mut self, path: &str) -> Result<Option<T>, Error>
268 where
269 T: TryFrom<i128>
270 + TryFrom<u128>
271 + TryFrom<u64>
272 + TryFrom<i64>
273 + TryFrom<u32>
274 + TryFrom<i32>
275 + TryFrom<u16>
276 + TryFrom<i16>
277 + TryFrom<u8>
278 + TryFrom<i8>,
279 {
280 self.remove(path)
281 .and_then(|v| {
282 let borrowed = v.borrow();
283 if borrowed.is_null() {
284 None
285 } else {
286 Some(v.borrow().to_integer())
287 }
288 })
289 .transpose()
290 }
291
292 fn remove_integer_at_path<T>(&mut self, path: &str) -> Result<T, Error>
293 where
294 T: TryFrom<i128>
295 + TryFrom<u128>
296 + TryFrom<u64>
297 + TryFrom<i64>
298 + TryFrom<u32>
299 + TryFrom<i32>
300 + TryFrom<u16>
301 + TryFrom<i16>
302 + TryFrom<u8>
303 + TryFrom<i8>,
304 {
305 self.remove_optional_integer_at_path(path)?.ok_or_else(|| {
306 Error::StructureError(format!("unable to remove integer property {path}"))
307 })
308 }
309
310 fn get_optional_bool_at_path(&self, path: &str) -> Result<Option<bool>, Error> {
311 self.get_optional_at_path(path)?
312 .and_then(|v| if v.is_null() { None } else { Some(v.to_bool()) })
313 .transpose()
314 }
315
316 fn get_bool_at_path(&self, path: &str) -> Result<bool, Error> {
317 self.get_optional_bool_at_path(path)?
318 .ok_or_else(|| Error::StructureError(format!("unable to get bool property {path}")))
319 }
320
321 fn get_optional_inner_value_array_at_path<'a, I: FromIterator<&'a Value>>(
322 &'a self,
323 path: &str,
324 ) -> Result<Option<I>, Error> {
325 self.get_optional_at_path(path)?
326 .map(|v| {
327 v.as_array()
328 .map(|vec| vec.iter().collect())
329 .ok_or_else(|| Error::StructureError(format!("{path} must be a bool")))
330 })
331 .transpose()
332 }
333
334 fn get_inner_value_array_at_path<'a, I: FromIterator<&'a Value>>(
335 &'a self,
336 path: &str,
337 ) -> Result<I, Error> {
338 self.get_optional_inner_value_array_at_path(path)?
339 .ok_or_else(|| {
340 Error::StructureError(format!("unable to get inner value array property {path}"))
341 })
342 }
343
344 fn get_optional_inner_string_array_at_path<I: FromIterator<String>>(
345 &self,
346 path: &str,
347 ) -> Result<Option<I>, Error> {
348 self.get_optional_at_path(path)?
349 .map(|v| {
350 v.as_array()
351 .map(|inner| {
352 inner
353 .iter()
354 .map(|v| {
355 let Some(str) = v.as_text() else {
356 return Err(Error::StructureError(format!(
357 "{path} must be an string"
358 )));
359 };
360 Ok(str.to_string())
361 })
362 .collect::<Result<I, Error>>()
363 })
364 .transpose()?
365 .ok_or_else(|| Error::StructureError(format!("{path} must be a bool")))
366 })
367 .transpose()
368 }
369
370 fn get_inner_string_array_at_path<I: FromIterator<String>>(
371 &self,
372 path: &str,
373 ) -> Result<I, Error> {
374 self.get_optional_inner_string_array_at_path(path)?
375 .ok_or_else(|| {
376 Error::StructureError(format!("unable to get inner string property {path}"))
377 })
378 }
379
380 fn get_optional_inner_borrowed_map_at_path(
381 &self,
382 path: &str,
383 ) -> Result<Option<&Vec<(Value, Value)>>, Error> {
384 self.get_optional_at_path(path)?
385 .map(|v| {
386 v.as_map()
387 .ok_or_else(|| Error::StructureError(format!("{path} must be a map")))
388 })
389 .transpose()
390 }
391
392 fn get_optional_inner_borrowed_str_value_map_at_path<
393 'a,
394 I: FromIterator<(String, &'a Value)>,
395 >(
396 &'a self,
397 path: &str,
398 ) -> Result<Option<I>, Error> {
399 self.get_optional_at_path(path)?
400 .map(|v| {
401 v.as_map()
402 .map(|inner| {
403 inner
404 .iter()
405 .map(|(k, v)| Ok((k.to_text()?, v)))
406 .collect::<Result<I, Error>>()
407 })
408 .transpose()?
409 .ok_or_else(|| Error::StructureError(format!("{path} must be a bool")))
410 })
411 .transpose()
412 }
413
414 fn get_inner_borrowed_str_value_map_at_path<'a, I: FromIterator<(String, &'a Value)>>(
415 &'a self,
416 path: &str,
417 ) -> Result<I, Error> {
418 self.get_optional_inner_borrowed_str_value_map_at_path(path)?
419 .ok_or_else(|| {
420 Error::StructureError(format!(
421 "unable to get borrowed str value map property {path}"
422 ))
423 })
424 }
425
426 #[cfg(feature = "json")]
427 fn get_optional_inner_str_json_value_map_at_path<I: FromIterator<(String, JsonValue)>>(
428 &self,
429 path: &str,
430 ) -> Result<Option<I>, Error> {
431 self.get_optional_at_path(path)?
432 .map(|v| {
433 v.as_map()
434 .map(|inner| {
435 inner
436 .iter()
437 .map(|(k, v)| Ok((k.to_text()?, v.clone().try_into()?)))
438 .collect::<Result<I, Error>>()
439 })
440 .transpose()?
441 .ok_or_else(|| Error::StructureError(format!("{path} must be a bool")))
442 })
443 .transpose()
444 }
445
446 #[cfg(feature = "json")]
447 fn get_inner_str_json_value_map_at_path<I: FromIterator<(String, JsonValue)>>(
448 &self,
449 path: &str,
450 ) -> Result<I, Error> {
451 self.get_optional_inner_str_json_value_map_at_path(path)?
452 .ok_or_else(|| {
453 Error::StructureError(format!(
454 "unable to get borrowed str json value map property {path}"
455 ))
456 })
457 }
458
459 fn get_optional_hash256_bytes_at_path(&self, path: &str) -> Result<Option<[u8; 32]>, Error> {
460 self.get_optional_at_path(path)?
461 .map(|v| v.to_hash256())
462 .transpose()
463 }
464
465 fn get_hash256_bytes_at_path(&self, path: &str) -> Result<[u8; 32], Error> {
466 self.get_optional_hash256_bytes_at_path(path)?
467 .ok_or_else(|| Error::StructureError(format!("unable to get hash256 property {path}")))
468 }
469
470 fn get_optional_bytes_at_path(&self, path: &str) -> Result<Option<Vec<u8>>, Error> {
471 self.get_optional_at_path(path)?
472 .map(|v| v.to_bytes())
473 .transpose()
474 }
475
476 fn get_bytes_at_path(&self, path: &str) -> Result<Vec<u8>, Error> {
477 self.get_optional_bytes_at_path(path)?.ok_or_else(|| {
478 Error::StructureError(format!("unable to get system bytes property {path}"))
479 })
480 }
481
482 fn get_optional_identifier_bytes_at_path(&self, path: &str) -> Result<Option<Vec<u8>>, Error> {
483 self.get_optional_at_path(path)?
484 .map(|v| v.to_identifier_bytes())
485 .transpose()
486 }
487
488 fn get_identifier_bytes_at_path(&self, path: &str) -> Result<Vec<u8>, Error> {
489 self.get_optional_identifier_bytes_at_path(path)?
490 .ok_or_else(|| {
491 Error::StructureError(format!("unable to get system bytes property {path}"))
492 })
493 }
494
495 fn get_optional_binary_bytes_at_path(&self, path: &str) -> Result<Option<Vec<u8>>, Error> {
496 self.get_optional_at_path(path)?
497 .map(|v| v.to_binary_bytes())
498 .transpose()
499 }
500
501 fn get_binary_bytes_at_path(&self, path: &str) -> Result<Vec<u8>, Error> {
502 self.get_optional_binary_bytes_at_path(path)?
503 .ok_or_else(|| {
504 Error::StructureError(format!("unable to get system bytes property {path}"))
505 })
506 }
507
508 fn remove_optional_hash256_bytes_at_path(
509 &mut self,
510 path: &str,
511 ) -> Result<Option<[u8; 32]>, Error> {
512 self.remove(path)
513 .map(|v| v.borrow().to_hash256())
514 .transpose()
515 }
516
517 fn remove_hash256_bytes_at_path(&mut self, path: &str) -> Result<[u8; 32], Error> {
518 self.remove_optional_hash256_bytes_at_path(path)?
519 .ok_or_else(|| {
520 Error::StructureError(format!("unable to remove hash256 property {path}"))
521 })
522 }
523
524 fn remove_optional_identifier_at_path(
525 &mut self,
526 path: &str,
527 ) -> Result<Option<Identifier>, Error> {
528 self.remove(path)
529 .map(|v| v.borrow().to_identifier())
530 .transpose()
531 }
532
533 fn remove_identifier_at_path(&mut self, path: &str) -> Result<Identifier, Error> {
534 self.remove_optional_identifier_at_path(path)?
535 .ok_or_else(|| {
536 Error::StructureError(format!("unable to remove system bytes property {path}"))
537 })
538 }
539
540 fn remove_optional_string_at_path(&mut self, path: &str) -> Result<Option<String>, Error> {
541 self.remove(path).map(|v| v.borrow().to_text()).transpose()
542 }
543
544 fn remove_string_at_path(&mut self, path: &str) -> Result<String, Error> {
545 self.remove_optional_string_at_path(path)?.ok_or_else(|| {
546 Error::StructureError(format!("unable to remove string property {path}"))
547 })
548 }
549
550 fn remove_optional_float_at_path(&mut self, path: &str) -> Result<Option<f64>, Error> {
551 self.remove(path)
552 .and_then(|v| {
553 let borrowed = v.borrow();
554 if borrowed.is_null() {
555 None
556 } else {
557 Some(v.borrow().to_float())
558 }
559 })
560 .transpose()
561 }
562
563 fn remove_float_at_path(&mut self, path: &str) -> Result<f64, Error> {
564 self.remove_optional_float_at_path(path)?
565 .ok_or_else(|| Error::StructureError(format!("unable to remove float property {path}")))
566 }
567
568 fn get_optional_float_at_path(&self, path: &str) -> Result<Option<f64>, Error> {
569 self.get_optional_at_path(path)?
570 .and_then(|v| {
571 if v.is_null() {
572 None
573 } else {
574 Some(v.to_float())
575 }
576 })
577 .transpose()
578 }
579
580 fn get_float_at_path(&self, path: &str) -> Result<f64, Error> {
581 self.get_optional_float_at_path(path)?
582 .ok_or_else(|| Error::StructureError(format!("unable to get float property {path}")))
583 }
584}
585
586#[cfg(test)]
587mod tests {
588 use super::*;
589 use crate::{Identifier, Value};
590 use std::collections::BTreeMap;
591
592 fn map_with(entries: Vec<(&str, Value)>) -> BTreeMap<String, Value> {
597 entries
598 .into_iter()
599 .map(|(k, v)| (k.to_string(), v))
600 .collect()
601 }
602
603 fn nested_value_map(entries: Vec<(&str, Value)>) -> Value {
605 Value::Map(
606 entries
607 .into_iter()
608 .map(|(k, v)| (Value::Text(k.to_string()), v))
609 .collect(),
610 )
611 }
612
613 #[test]
618 fn get_at_path_single_level() {
619 let map = map_with(vec![("name", Value::Text("alice".to_string()))]);
620 let result = map.get_at_path("name").unwrap();
621 assert_eq!(result, &Value::Text("alice".to_string()));
622 }
623
624 #[test]
625 fn get_at_path_nested() {
626 let inner = nested_value_map(vec![("city", Value::Text("NYC".to_string()))]);
627 let map = map_with(vec![("address", inner)]);
628 let result = map.get_at_path("address.city").unwrap();
629 assert_eq!(result, &Value::Text("NYC".to_string()));
630 }
631
632 #[test]
633 fn get_at_path_deeply_nested() {
634 let deep = nested_value_map(vec![("z", Value::U64(42))]);
635 let mid = nested_value_map(vec![("y", deep)]);
636 let map = map_with(vec![("x", mid)]);
637 let result = map.get_at_path("x.y.z").unwrap();
638 assert_eq!(result, &Value::U64(42));
639 }
640
641 #[test]
642 fn get_at_path_missing_top_level_errors() {
643 let map: BTreeMap<String, Value> = BTreeMap::new();
644 assert!(map.get_at_path("missing").is_err());
645 }
646
647 #[test]
648 fn get_at_path_missing_nested_key_errors() {
649 let inner = nested_value_map(vec![("a", Value::U64(1))]);
650 let map = map_with(vec![("top", inner)]);
651 assert!(map.get_at_path("top.nonexistent").is_err());
652 }
653
654 #[test]
655 fn get_at_path_empty_path_errors() {
656 let map = map_with(vec![("a", Value::U64(1))]);
657 assert!(map.get_at_path("").is_err());
661 }
662
663 #[test]
664 fn get_optional_at_path_returns_some() {
665 let map = map_with(vec![("key", Value::Bool(true))]);
666 let result = map.get_optional_at_path("key").unwrap();
667 assert_eq!(result, Some(&Value::Bool(true)));
668 }
669
670 #[test]
671 fn get_optional_at_path_returns_none_for_missing_top_level() {
672 let map: BTreeMap<String, Value> = BTreeMap::new();
673 let result = map.get_optional_at_path("missing").unwrap();
674 assert_eq!(result, None);
675 }
676
677 #[test]
678 fn get_optional_at_path_returns_none_for_missing_nested() {
679 let inner = nested_value_map(vec![("a", Value::U64(1))]);
680 let map = map_with(vec![("top", inner)]);
681 let result = map.get_optional_at_path("top.missing").unwrap();
682 assert_eq!(result, None);
683 }
684
685 #[test]
686 fn get_optional_at_path_nested_returns_some() {
687 let inner = nested_value_map(vec![("val", Value::Float(9.9))]);
688 let map = map_with(vec![("nested", inner)]);
689 let result = map.get_optional_at_path("nested.val").unwrap();
690 assert_eq!(result, Some(&Value::Float(9.9)));
691 }
692
693 #[test]
698 fn get_identifier_at_path_success() {
699 let id = [1u8; 32];
700 let map = map_with(vec![("id", Value::Bytes32(id))]);
701 let result = map.get_identifier_at_path("id").unwrap();
702 assert_eq!(result, id);
703 }
704
705 #[test]
706 fn get_identifier_at_path_missing_errors() {
707 let map: BTreeMap<String, Value> = BTreeMap::new();
708 assert!(map.get_identifier_at_path("id").is_err());
709 }
710
711 #[test]
712 fn get_optional_identifier_at_path_returns_some() {
713 let id = [2u8; 32];
714 let map = map_with(vec![("id", Value::Bytes32(id))]);
715 let result = map.get_optional_identifier_at_path("id").unwrap();
716 assert_eq!(result, Some(id));
717 }
718
719 #[test]
720 fn get_optional_identifier_at_path_returns_none_for_missing() {
721 let map: BTreeMap<String, Value> = BTreeMap::new();
722 let result = map.get_optional_identifier_at_path("id").unwrap();
723 assert_eq!(result, None);
724 }
725
726 #[test]
731 fn get_string_at_path_success() {
732 let map = map_with(vec![("s", Value::Text("hello".to_string()))]);
733 let result = map.get_string_at_path("s").unwrap();
734 assert_eq!(result, "hello");
735 }
736
737 #[test]
738 fn get_string_at_path_missing_errors() {
739 let map: BTreeMap<String, Value> = BTreeMap::new();
740 assert!(map.get_string_at_path("s").is_err());
741 }
742
743 #[test]
744 fn get_optional_string_at_path_returns_some() {
745 let map = map_with(vec![("s", Value::Text("world".to_string()))]);
746 let result = map.get_optional_string_at_path("s").unwrap();
747 assert_eq!(result, Some("world".to_string()));
748 }
749
750 #[test]
751 fn get_optional_string_at_path_returns_none() {
752 let map: BTreeMap<String, Value> = BTreeMap::new();
753 let result = map.get_optional_string_at_path("s").unwrap();
754 assert_eq!(result, None);
755 }
756
757 #[test]
758 fn get_optional_string_at_path_wrong_type_errors() {
759 let map = map_with(vec![("s", Value::U64(42))]);
760 assert!(map.get_optional_string_at_path("s").is_err());
761 }
762
763 #[test]
768 fn get_str_at_path_success() {
769 let map = map_with(vec![("s", Value::Text("borrow_me".to_string()))]);
770 let result = map.get_str_at_path("s").unwrap();
771 assert_eq!(result, "borrow_me");
772 }
773
774 #[test]
775 fn get_str_at_path_missing_errors() {
776 let map: BTreeMap<String, Value> = BTreeMap::new();
777 assert!(map.get_str_at_path("s").is_err());
778 }
779
780 #[test]
781 fn get_optional_str_at_path_returns_some() {
782 let map = map_with(vec![("s", Value::Text("ref".to_string()))]);
783 let result = map.get_optional_str_at_path("s").unwrap();
784 assert_eq!(result, Some("ref"));
785 }
786
787 #[test]
788 fn get_optional_str_at_path_returns_none() {
789 let map: BTreeMap<String, Value> = BTreeMap::new();
790 let result = map.get_optional_str_at_path("s").unwrap();
791 assert_eq!(result, None);
792 }
793
794 #[test]
799 fn get_integer_at_path_success() {
800 let map = map_with(vec![("num", Value::U64(100))]);
801 let result: u64 = map.get_integer_at_path("num").unwrap();
802 assert_eq!(result, 100);
803 }
804
805 #[test]
806 fn get_integer_at_path_nested() {
807 let inner = nested_value_map(vec![("val", Value::I32(-5))]);
808 let map = map_with(vec![("data", inner)]);
809 let result: i32 = map.get_integer_at_path("data.val").unwrap();
810 assert_eq!(result, -5);
811 }
812
813 #[test]
814 fn get_integer_at_path_missing_errors() {
815 let map: BTreeMap<String, Value> = BTreeMap::new();
816 let result: Result<u64, Error> = map.get_integer_at_path("num");
817 assert!(result.is_err());
818 }
819
820 #[test]
821 fn get_optional_integer_at_path_returns_some() {
822 let map = map_with(vec![("n", Value::U32(7))]);
823 let result: Option<u32> = map.get_optional_integer_at_path("n").unwrap();
824 assert_eq!(result, Some(7));
825 }
826
827 #[test]
828 fn get_optional_integer_at_path_returns_none_for_missing() {
829 let map: BTreeMap<String, Value> = BTreeMap::new();
830 let result: Option<u32> = map.get_optional_integer_at_path("n").unwrap();
831 assert_eq!(result, None);
832 }
833
834 #[test]
835 fn get_optional_integer_at_path_returns_none_for_null() {
836 let map = map_with(vec![("n", Value::Null)]);
837 let result: Option<u32> = map.get_optional_integer_at_path("n").unwrap();
838 assert_eq!(result, None);
839 }
840
841 #[test]
846 fn get_float_at_path_success() {
847 let map = map_with(vec![("f", Value::Float(1.23))]);
848 let result = map.get_float_at_path("f").unwrap();
849 assert!((result - 1.23).abs() < f64::EPSILON);
850 }
851
852 #[test]
853 fn get_float_at_path_missing_errors() {
854 let map: BTreeMap<String, Value> = BTreeMap::new();
855 assert!(map.get_float_at_path("f").is_err());
856 }
857
858 #[test]
859 fn get_optional_float_at_path_returns_some() {
860 let map = map_with(vec![("f", Value::Float(2.72))]);
861 let result = map.get_optional_float_at_path("f").unwrap();
862 assert_eq!(result, Some(2.72));
863 }
864
865 #[test]
866 fn get_optional_float_at_path_returns_none_for_missing() {
867 let map: BTreeMap<String, Value> = BTreeMap::new();
868 let result = map.get_optional_float_at_path("f").unwrap();
869 assert_eq!(result, None);
870 }
871
872 #[test]
873 fn get_optional_float_at_path_returns_none_for_null() {
874 let map = map_with(vec![("f", Value::Null)]);
875 let result = map.get_optional_float_at_path("f").unwrap();
876 assert_eq!(result, None);
877 }
878
879 #[test]
884 fn get_bool_at_path_success() {
885 let map = map_with(vec![("flag", Value::Bool(true))]);
886 let result = map.get_bool_at_path("flag").unwrap();
887 assert!(result);
888 }
889
890 #[test]
891 fn get_bool_at_path_missing_errors() {
892 let map: BTreeMap<String, Value> = BTreeMap::new();
893 assert!(map.get_bool_at_path("flag").is_err());
894 }
895
896 #[test]
897 fn get_optional_bool_at_path_returns_some() {
898 let map = map_with(vec![("b", Value::Bool(false))]);
899 let result = map.get_optional_bool_at_path("b").unwrap();
900 assert_eq!(result, Some(false));
901 }
902
903 #[test]
904 fn get_optional_bool_at_path_returns_none_for_missing() {
905 let map: BTreeMap<String, Value> = BTreeMap::new();
906 let result = map.get_optional_bool_at_path("b").unwrap();
907 assert_eq!(result, None);
908 }
909
910 #[test]
911 fn get_optional_bool_at_path_returns_none_for_null() {
912 let map = map_with(vec![("b", Value::Null)]);
913 let result = map.get_optional_bool_at_path("b").unwrap();
914 assert_eq!(result, None);
915 }
916
917 #[test]
922 fn get_inner_value_array_at_path_success() {
923 let arr = Value::Array(vec![Value::U64(1), Value::U64(2), Value::U64(3)]);
924 let map = map_with(vec![("arr", arr)]);
925 let result: Vec<&Value> = map.get_inner_value_array_at_path("arr").unwrap();
926 assert_eq!(result.len(), 3);
927 assert_eq!(result[0], &Value::U64(1));
928 }
929
930 #[test]
931 fn get_inner_value_array_at_path_missing_errors() {
932 let map: BTreeMap<String, Value> = BTreeMap::new();
933 let result: Result<Vec<&Value>, Error> = map.get_inner_value_array_at_path("arr");
934 assert!(result.is_err());
935 }
936
937 #[test]
938 fn get_optional_inner_value_array_returns_some() {
939 let arr = Value::Array(vec![Value::Bool(true)]);
940 let map = map_with(vec![("arr", arr)]);
941 let result: Option<Vec<&Value>> =
942 map.get_optional_inner_value_array_at_path("arr").unwrap();
943 assert!(result.is_some());
944 assert_eq!(result.unwrap().len(), 1);
945 }
946
947 #[test]
948 fn get_optional_inner_value_array_returns_none_for_missing() {
949 let map: BTreeMap<String, Value> = BTreeMap::new();
950 let result: Option<Vec<&Value>> =
951 map.get_optional_inner_value_array_at_path("arr").unwrap();
952 assert_eq!(result, None);
953 }
954
955 #[test]
960 fn get_inner_string_array_at_path_success() {
961 let arr = Value::Array(vec![
962 Value::Text("a".to_string()),
963 Value::Text("b".to_string()),
964 ]);
965 let map = map_with(vec![("names", arr)]);
966 let result: Vec<String> = map.get_inner_string_array_at_path("names").unwrap();
967 assert_eq!(result, vec!["a".to_string(), "b".to_string()]);
968 }
969
970 #[test]
971 fn get_inner_string_array_at_path_missing_errors() {
972 let map: BTreeMap<String, Value> = BTreeMap::new();
973 let result: Result<Vec<String>, Error> = map.get_inner_string_array_at_path("names");
974 assert!(result.is_err());
975 }
976
977 #[test]
978 fn get_optional_inner_string_array_returns_some() {
979 let arr = Value::Array(vec![Value::Text("x".to_string())]);
980 let map = map_with(vec![("names", arr)]);
981 let result: Option<Vec<String>> = map
982 .get_optional_inner_string_array_at_path("names")
983 .unwrap();
984 assert_eq!(result, Some(vec!["x".to_string()]));
985 }
986
987 #[test]
988 fn get_optional_inner_string_array_returns_none_for_missing() {
989 let map: BTreeMap<String, Value> = BTreeMap::new();
990 let result: Option<Vec<String>> = map
991 .get_optional_inner_string_array_at_path("names")
992 .unwrap();
993 assert_eq!(result, None);
994 }
995
996 #[test]
997 fn get_optional_inner_string_array_errors_on_non_string_elements() {
998 let arr = Value::Array(vec![Value::U64(42)]);
999 let map = map_with(vec![("names", arr)]);
1000 let result: Result<Option<Vec<String>>, Error> =
1001 map.get_optional_inner_string_array_at_path("names");
1002 assert!(result.is_err());
1003 }
1004
1005 #[test]
1010 fn get_optional_inner_borrowed_map_at_path_returns_some() {
1011 let inner = nested_value_map(vec![("k", Value::U64(1))]);
1012 let map = map_with(vec![("m", inner)]);
1013 let result = map.get_optional_inner_borrowed_map_at_path("m").unwrap();
1014 assert!(result.is_some());
1015 }
1016
1017 #[test]
1018 fn get_optional_inner_borrowed_map_at_path_returns_none_for_missing() {
1019 let map: BTreeMap<String, Value> = BTreeMap::new();
1020 let result = map.get_optional_inner_borrowed_map_at_path("m").unwrap();
1021 assert_eq!(result, None);
1022 }
1023
1024 #[test]
1025 fn get_optional_inner_borrowed_map_at_path_errors_on_non_map() {
1026 let map = map_with(vec![("m", Value::U64(42))]);
1027 assert!(map.get_optional_inner_borrowed_map_at_path("m").is_err());
1028 }
1029
1030 #[test]
1036 fn get_inner_borrowed_str_value_map_at_path_success() {
1037 let inner = nested_value_map(vec![("k", Value::Text("v".to_string()))]);
1038 let map = map_with(vec![("m", inner)]);
1039 let result: BTreeMap<String, &Value> =
1040 map.get_inner_borrowed_str_value_map_at_path("m").unwrap();
1041 assert_eq!(result.get("k"), Some(&&Value::Text("v".to_string())));
1042 }
1043
1044 #[test]
1045 fn get_inner_borrowed_str_value_map_at_path_missing_errors() {
1046 let map: BTreeMap<String, Value> = BTreeMap::new();
1047 let result: Result<BTreeMap<String, &Value>, Error> =
1048 map.get_inner_borrowed_str_value_map_at_path("m");
1049 assert!(result.is_err());
1050 }
1051
1052 #[test]
1053 fn get_optional_inner_borrowed_str_value_map_returns_some() {
1054 let inner = nested_value_map(vec![("a", Value::Bool(true))]);
1055 let map = map_with(vec![("m", inner)]);
1056 let result: Option<BTreeMap<String, &Value>> = map
1057 .get_optional_inner_borrowed_str_value_map_at_path("m")
1058 .unwrap();
1059 assert!(result.is_some());
1060 }
1061
1062 #[test]
1063 fn get_optional_inner_borrowed_str_value_map_returns_none_for_missing() {
1064 let map: BTreeMap<String, Value> = BTreeMap::new();
1065 let result: Option<BTreeMap<String, &Value>> = map
1066 .get_optional_inner_borrowed_str_value_map_at_path("m")
1067 .unwrap();
1068 assert_eq!(result, None);
1069 }
1070
1071 #[test]
1076 fn get_hash256_bytes_at_path_success() {
1077 let hash = [5u8; 32];
1078 let map = map_with(vec![("h", Value::Bytes32(hash))]);
1079 let result = map.get_hash256_bytes_at_path("h").unwrap();
1080 assert_eq!(result, hash);
1081 }
1082
1083 #[test]
1084 fn get_hash256_bytes_at_path_missing_errors() {
1085 let map: BTreeMap<String, Value> = BTreeMap::new();
1086 assert!(map.get_hash256_bytes_at_path("h").is_err());
1087 }
1088
1089 #[test]
1090 fn get_optional_hash256_bytes_at_path_returns_some() {
1091 let hash = [6u8; 32];
1092 let map = map_with(vec![("h", Value::Bytes32(hash))]);
1093 let result = map.get_optional_hash256_bytes_at_path("h").unwrap();
1094 assert_eq!(result, Some(hash));
1095 }
1096
1097 #[test]
1098 fn get_optional_hash256_bytes_at_path_returns_none() {
1099 let map: BTreeMap<String, Value> = BTreeMap::new();
1100 let result = map.get_optional_hash256_bytes_at_path("h").unwrap();
1101 assert_eq!(result, None);
1102 }
1103
1104 #[test]
1109 fn get_bytes_at_path_success() {
1110 let bytes = vec![1, 2, 3];
1111 let map = map_with(vec![("b", Value::Bytes(bytes.clone()))]);
1112 let result = map.get_bytes_at_path("b").unwrap();
1113 assert_eq!(result, bytes);
1114 }
1115
1116 #[test]
1117 fn get_bytes_at_path_missing_errors() {
1118 let map: BTreeMap<String, Value> = BTreeMap::new();
1119 assert!(map.get_bytes_at_path("b").is_err());
1120 }
1121
1122 #[test]
1123 fn get_optional_bytes_at_path_returns_some() {
1124 let bytes = vec![4, 5];
1125 let map = map_with(vec![("b", Value::Bytes(bytes.clone()))]);
1126 let result = map.get_optional_bytes_at_path("b").unwrap();
1127 assert_eq!(result, Some(bytes));
1128 }
1129
1130 #[test]
1131 fn get_optional_bytes_at_path_returns_none() {
1132 let map: BTreeMap<String, Value> = BTreeMap::new();
1133 let result = map.get_optional_bytes_at_path("b").unwrap();
1134 assert_eq!(result, None);
1135 }
1136
1137 #[test]
1142 fn get_identifier_bytes_at_path_success() {
1143 let id = [7u8; 32];
1144 let map = map_with(vec![("id", Value::Identifier(id))]);
1145 let result = map.get_identifier_bytes_at_path("id").unwrap();
1146 assert_eq!(result, id.to_vec());
1147 }
1148
1149 #[test]
1150 fn get_identifier_bytes_at_path_missing_errors() {
1151 let map: BTreeMap<String, Value> = BTreeMap::new();
1152 assert!(map.get_identifier_bytes_at_path("id").is_err());
1153 }
1154
1155 #[test]
1156 fn get_optional_identifier_bytes_at_path_returns_some() {
1157 let id = [8u8; 32];
1158 let map = map_with(vec![("id", Value::Identifier(id))]);
1159 let result = map.get_optional_identifier_bytes_at_path("id").unwrap();
1160 assert_eq!(result, Some(id.to_vec()));
1161 }
1162
1163 #[test]
1164 fn get_optional_identifier_bytes_at_path_returns_none() {
1165 let map: BTreeMap<String, Value> = BTreeMap::new();
1166 let result = map.get_optional_identifier_bytes_at_path("id").unwrap();
1167 assert_eq!(result, None);
1168 }
1169
1170 #[test]
1175 fn get_binary_bytes_at_path_success() {
1176 let bytes = vec![10, 20, 30];
1177 let map = map_with(vec![("bin", Value::Bytes(bytes.clone()))]);
1178 let result = map.get_binary_bytes_at_path("bin").unwrap();
1179 assert_eq!(result, bytes);
1180 }
1181
1182 #[test]
1183 fn get_binary_bytes_at_path_missing_errors() {
1184 let map: BTreeMap<String, Value> = BTreeMap::new();
1185 assert!(map.get_binary_bytes_at_path("bin").is_err());
1186 }
1187
1188 #[test]
1189 fn get_optional_binary_bytes_at_path_returns_some() {
1190 let bytes = vec![40, 50];
1191 let map = map_with(vec![("bin", Value::Bytes(bytes.clone()))]);
1192 let result = map.get_optional_binary_bytes_at_path("bin").unwrap();
1193 assert_eq!(result, Some(bytes));
1194 }
1195
1196 #[test]
1197 fn get_optional_binary_bytes_at_path_returns_none() {
1198 let map: BTreeMap<String, Value> = BTreeMap::new();
1199 let result = map.get_optional_binary_bytes_at_path("bin").unwrap();
1200 assert_eq!(result, None);
1201 }
1202
1203 #[test]
1208 fn remove_string_at_path_success() {
1209 let mut map = map_with(vec![("name", Value::Text("test".to_string()))]);
1210 let result = map.remove_string_at_path("name").unwrap();
1211 assert_eq!(result, "test");
1212 assert!(map.is_empty());
1213 }
1214
1215 #[test]
1216 fn remove_string_at_path_missing_errors() {
1217 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1218 assert!(map.remove_string_at_path("name").is_err());
1219 }
1220
1221 #[test]
1222 fn remove_optional_string_at_path_returns_some() {
1223 let mut map = map_with(vec![("s", Value::Text("hi".to_string()))]);
1224 let result = map.remove_optional_string_at_path("s").unwrap();
1225 assert_eq!(result, Some("hi".to_string()));
1226 }
1227
1228 #[test]
1229 fn remove_optional_string_at_path_returns_none() {
1230 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1231 let result = map.remove_optional_string_at_path("s").unwrap();
1232 assert_eq!(result, None);
1233 }
1234
1235 #[test]
1240 fn remove_float_at_path_success() {
1241 let mut map = map_with(vec![("f", Value::Float(1.5))]);
1242 let result = map.remove_float_at_path("f").unwrap();
1243 assert!((result - 1.5).abs() < f64::EPSILON);
1244 }
1245
1246 #[test]
1247 fn remove_float_at_path_missing_errors() {
1248 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1249 assert!(map.remove_float_at_path("f").is_err());
1250 }
1251
1252 #[test]
1253 fn remove_optional_float_at_path_returns_some() {
1254 let mut map = map_with(vec![("f", Value::Float(0.5))]);
1255 let result = map.remove_optional_float_at_path("f").unwrap();
1256 assert_eq!(result, Some(0.5));
1257 }
1258
1259 #[test]
1260 fn remove_optional_float_at_path_returns_none_for_missing() {
1261 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1262 let result = map.remove_optional_float_at_path("f").unwrap();
1263 assert_eq!(result, None);
1264 }
1265
1266 #[test]
1267 fn remove_optional_float_at_path_returns_none_for_null() {
1268 let mut map = map_with(vec![("f", Value::Null)]);
1269 let result = map.remove_optional_float_at_path("f").unwrap();
1270 assert_eq!(result, None);
1271 }
1272
1273 #[test]
1278 fn remove_integer_at_path_success() {
1279 let mut map = map_with(vec![("n", Value::U64(99))]);
1280 let result: u64 = map.remove_integer_at_path("n").unwrap();
1281 assert_eq!(result, 99);
1282 }
1283
1284 #[test]
1285 fn remove_integer_at_path_missing_errors() {
1286 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1287 let result: Result<u64, Error> = map.remove_integer_at_path("n");
1288 assert!(result.is_err());
1289 }
1290
1291 #[test]
1292 fn remove_optional_integer_at_path_returns_some() {
1293 let mut map = map_with(vec![("n", Value::I32(-3))]);
1294 let result: Option<i32> = map.remove_optional_integer_at_path("n").unwrap();
1295 assert_eq!(result, Some(-3));
1296 }
1297
1298 #[test]
1299 fn remove_optional_integer_at_path_returns_none_for_missing() {
1300 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1301 let result: Option<i32> = map.remove_optional_integer_at_path("n").unwrap();
1302 assert_eq!(result, None);
1303 }
1304
1305 #[test]
1306 fn remove_optional_integer_at_path_returns_none_for_null() {
1307 let mut map = map_with(vec![("n", Value::Null)]);
1308 let result: Option<i32> = map.remove_optional_integer_at_path("n").unwrap();
1309 assert_eq!(result, None);
1310 }
1311
1312 #[test]
1317 fn remove_hash256_bytes_at_path_success() {
1318 let hash = [9u8; 32];
1319 let mut map = map_with(vec![("h", Value::Bytes32(hash))]);
1320 let result = map.remove_hash256_bytes_at_path("h").unwrap();
1321 assert_eq!(result, hash);
1322 assert!(map.is_empty());
1323 }
1324
1325 #[test]
1326 fn remove_hash256_bytes_at_path_missing_errors() {
1327 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1328 assert!(map.remove_hash256_bytes_at_path("h").is_err());
1329 }
1330
1331 #[test]
1332 fn remove_optional_hash256_bytes_at_path_returns_some() {
1333 let hash = [10u8; 32];
1334 let mut map = map_with(vec![("h", Value::Bytes32(hash))]);
1335 let result = map.remove_optional_hash256_bytes_at_path("h").unwrap();
1336 assert_eq!(result, Some(hash));
1337 }
1338
1339 #[test]
1340 fn remove_optional_hash256_bytes_at_path_returns_none() {
1341 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1342 let result = map.remove_optional_hash256_bytes_at_path("h").unwrap();
1343 assert_eq!(result, None);
1344 }
1345
1346 #[test]
1351 fn remove_identifier_at_path_success() {
1352 let id = [11u8; 32];
1353 let mut map = map_with(vec![("id", Value::Identifier(id))]);
1354 let result = map.remove_identifier_at_path("id").unwrap();
1355 assert_eq!(result, Identifier::from(id));
1356 assert!(map.is_empty());
1357 }
1358
1359 #[test]
1360 fn remove_identifier_at_path_missing_errors() {
1361 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1362 assert!(map.remove_identifier_at_path("id").is_err());
1363 }
1364
1365 #[test]
1366 fn remove_optional_identifier_at_path_returns_some() {
1367 let id = [12u8; 32];
1368 let mut map = map_with(vec![("id", Value::Identifier(id))]);
1369 let result = map.remove_optional_identifier_at_path("id").unwrap();
1370 assert_eq!(result, Some(Identifier::from(id)));
1371 }
1372
1373 #[test]
1374 fn remove_optional_identifier_at_path_returns_none() {
1375 let mut map: BTreeMap<String, Value> = BTreeMap::new();
1376 let result = map.remove_optional_identifier_at_path("id").unwrap();
1377 assert_eq!(result, None);
1378 }
1379
1380 #[test]
1385 fn get_at_path_works_with_ref_values() {
1386 let source: BTreeMap<String, Value> =
1388 map_with(vec![("key", Value::Text("val".to_string()))]);
1389 let ref_map: BTreeMap<String, &Value> =
1390 source.iter().map(|(k, v)| (k.clone(), v)).collect();
1391 let result = ref_map.get_at_path("key").unwrap();
1392 assert_eq!(result, &Value::Text("val".to_string()));
1393 }
1394
1395 #[test]
1396 fn get_at_path_ref_map_nested() {
1397 let inner = nested_value_map(vec![("deep", Value::Bool(true))]);
1398 let source = map_with(vec![("top", inner)]);
1399 let ref_map: BTreeMap<String, &Value> =
1400 source.iter().map(|(k, v)| (k.clone(), v)).collect();
1401 let result = ref_map.get_at_path("top.deep").unwrap();
1402 assert_eq!(result, &Value::Bool(true));
1403 }
1404
1405 #[test]
1410 fn get_string_at_nested_path() {
1411 let level2 = nested_value_map(vec![("name", Value::Text("deep".to_string()))]);
1412 let level1 = nested_value_map(vec![("child", level2)]);
1413 let map = map_with(vec![("parent", level1)]);
1414 let result = map.get_string_at_path("parent.child.name").unwrap();
1415 assert_eq!(result, "deep");
1416 }
1417
1418 #[test]
1419 fn get_bool_at_nested_path() {
1420 let inner = nested_value_map(vec![("enabled", Value::Bool(false))]);
1421 let map = map_with(vec![("config", inner)]);
1422 let result = map.get_bool_at_path("config.enabled").unwrap();
1423 assert!(!result);
1424 }
1425}