1use base64::engine::general_purpose::STANDARD;
6use base64::Engine as _;
7use indexmap::IndexMap;
8use num_traits::FromPrimitive;
9use serde::{Deserialize, Serialize};
10use std::fs::read_to_string;
11use std::path::Path;
12use std::sync::Arc;
13use tee_internal::{Identity, Login, Uuid};
14
15#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
17#[serde(rename_all = "snake_case")]
18pub enum PropType {
19 BinaryBlock,
20 UnsignedInt32,
21 UnsignedInt64,
22 Boolean,
23 Uuid,
24 Identity,
25 String,
26}
27
28#[derive(Clone, Debug, thiserror::Error)]
29pub enum PropertyError {
30 #[error("Bad format: Unable to parse type: {prop_type:?} from value: {value}")]
31 BadFormat { prop_type: PropType, value: String },
32 #[error("Item not found: {name}")]
33 ItemNotFound { name: String },
34 #[error("Generic TeeProperty error: {msg}")]
36 Generic { msg: String },
37}
38
39#[derive(Debug, Deserialize, Serialize)]
40pub struct TeeProperty {
41 name: String,
42 prop_type: PropType,
43 value: String,
44}
45
46pub type TeeProperties = Vec<TeeProperty>;
47
48#[derive(Deserialize, Serialize)]
53#[serde(rename_all = "snake_case")]
54pub enum PropSetType {
55 TeeImplementation,
56 CurrentClient,
57 CurrentTA,
58}
59
60pub type PropertiesMap = IndexMap<String, (PropType, String)>;
61
62#[derive(Clone)]
63pub struct PropSet {
64 properties: PropertiesMap,
65}
66
67impl PropSet {
68 #[cfg(test)]
69 pub(crate) fn new(properties: PropertiesMap) -> Self {
70 Self { properties }
71 }
72
73 pub fn from_config_file(config_path: &Path) -> Result<Self, PropertyError> {
74 match read_to_string(config_path) {
75 Ok(config_string) => Self::from_config_string(&config_string),
76 Err(e) => Err(PropertyError::Generic { msg: e.to_string() }),
77 }
78 }
79
80 pub fn from_config_string(config_string: &str) -> Result<Self, PropertyError> {
81 let props: TeeProperties = match serde_json5::from_str(config_string) {
82 Ok(tee_props) => tee_props,
83 Err(e) => return Err(PropertyError::Generic { msg: e.to_string() }),
84 };
85 let mut property_map = IndexMap::new();
86
87 for property in props {
88 property_map.insert(property.name, (property.prop_type, property.value));
89 }
90
91 Ok(Self { properties: property_map })
92 }
93
94 fn get_value(&self, prop_name: String) -> Result<String, PropertyError> {
95 match self.properties.get(&prop_name) {
96 Some((_, val)) => Ok(val.clone()),
97 None => Err(PropertyError::ItemNotFound { name: prop_name }),
98 }
99 }
100
101 pub fn get_string_property(&self, prop_name: String) -> Result<String, PropertyError> {
102 self.get_value(prop_name)
103 }
104
105 pub fn get_boolean_property(&self, prop_name: String) -> Result<bool, PropertyError> {
106 parse_bool(self.get_value(prop_name)?)
107 }
108
109 pub fn get_uint32_property(&self, prop_name: String) -> Result<u32, PropertyError> {
110 parse_uint32(self.get_value(prop_name)?)
111 }
112
113 pub fn get_uint64_property(&self, prop_name: String) -> Result<u64, PropertyError> {
114 parse_uint64(self.get_value(prop_name)?)
115 }
116
117 pub fn get_binary_block_property(&self, prop_name: String) -> Result<Vec<u8>, PropertyError> {
118 parse_binary_block(self.get_value(prop_name)?)
119 }
120
121 pub fn get_uuid_property(&self, prop_name: String) -> Result<Uuid, PropertyError> {
122 parse_uuid(self.get_value(prop_name)?)
123 }
124
125 pub fn get_identity_property(&self, prop_name: String) -> Result<Identity, PropertyError> {
126 parse_identity(self.get_value(prop_name)?)
127 }
128
129 pub fn get_property_name_at_index(&self, index: usize) -> Result<String, PropertyError> {
130 match self.properties.get_index(index) {
131 Some((prop_name, (_, _))) => Ok(prop_name.to_string()),
132 None => Err(PropertyError::ItemNotFound { name: format!("item at index {}", index) }),
133 }
134 }
135
136 pub fn get_property_type_at_index(&self, index: usize) -> Result<PropType, PropertyError> {
137 match self.properties.get_index(index) {
138 Some((_, (prop_type, _))) => Ok(prop_type.clone()),
139 None => Err(PropertyError::ItemNotFound { name: format!("item at index {}", index) }),
140 }
141 }
142
143 pub fn get_number_of_props(&self) -> usize {
144 self.properties.len()
145 }
146}
147
148pub struct PropEnumerator {
149 properties: Option<Arc<PropSet>>,
150 index: usize,
151}
152
153impl PropEnumerator {
154 pub fn new() -> Self {
155 Self { properties: None, index: 0 }
156 }
157
158 pub fn start(&mut self, propset: Arc<PropSet>) {
161 self.properties = Some(propset);
162 self.index = 0;
163 }
164
165 pub fn reset(&mut self) {
166 self.index = 0;
167 }
168
169 pub fn next(&mut self) -> Result<(), PropertyError> {
171 let num_props = self.get_props()?.get_number_of_props();
173
174 self.index = self.index + 1;
175 if self.index >= num_props {
176 return Err(PropertyError::ItemNotFound {
177 name: "enumerator has reached the end of the property set".to_string(),
178 });
179 }
180 Ok(())
181 }
182
183 pub fn get_property_name(&self) -> Result<String, PropertyError> {
184 self.get_props()?.get_property_name_at_index(self.index)
186 }
187
188 pub fn get_property_type(&self) -> Result<PropType, PropertyError> {
189 self.get_props()?.get_property_type_at_index(self.index)
191 }
192
193 pub fn get_property_as_string(&self) -> Result<String, PropertyError> {
194 let prop_name = self.get_property_name()?;
195 self.get_props()?.get_string_property(prop_name)
196 }
197
198 pub fn get_property_as_bool(&self) -> Result<bool, PropertyError> {
199 let prop_name = self.get_property_name()?;
200 self.get_props()?.get_boolean_property(prop_name)
201 }
202
203 pub fn get_property_as_u32(&self) -> Result<u32, PropertyError> {
204 let prop_name = self.get_property_name()?;
205 self.get_props()?.get_uint32_property(prop_name)
206 }
207
208 pub fn get_property_as_u64(&self) -> Result<u64, PropertyError> {
209 let prop_name = self.get_property_name()?;
210 self.get_props()?.get_uint64_property(prop_name)
211 }
212
213 pub fn get_property_as_binary_block(&self) -> Result<Vec<u8>, PropertyError> {
214 let prop_name = self.get_property_name()?;
215 self.get_props()?.get_binary_block_property(prop_name)
216 }
217
218 pub fn get_property_as_uuid(&self) -> Result<Uuid, PropertyError> {
219 let prop_name = self.get_property_name()?;
220 self.get_props()?.get_uuid_property(prop_name)
221 }
222
223 pub fn get_property_as_identity(&self) -> Result<Identity, PropertyError> {
224 let prop_name = self.get_property_name()?;
225 self.get_props()?.get_identity_property(prop_name)
226 }
227
228 fn get_props(&self) -> Result<&PropSet, PropertyError> {
229 match &self.properties {
230 Some(prop_set) => Ok(prop_set),
231 None => Err(PropertyError::ItemNotFound {
232 name: "enumerator has not been started".to_string(),
233 }),
234 }
235 }
236}
237
238fn parse_bool(value: String) -> Result<bool, PropertyError> {
240 match value.parse::<bool>() {
241 Ok(val) => Ok(val),
242 Err(_) => Err(PropertyError::BadFormat { prop_type: PropType::Boolean, value }),
243 }
244}
245
246fn parse_uint32(value: String) -> Result<u32, PropertyError> {
249 match value.parse::<u32>() {
251 Ok(val) => Ok(val),
252 Err(_) => Err(PropertyError::BadFormat { prop_type: PropType::UnsignedInt32, value }),
253 }
254}
255
256fn parse_uint64(value: String) -> Result<u64, PropertyError> {
259 match value.parse::<u64>() {
261 Ok(val) => Ok(val),
262 Err(_) => Err(PropertyError::BadFormat { prop_type: PropType::UnsignedInt64, value }),
263 }
264}
265
266fn parse_binary_block(value: String) -> Result<Vec<u8>, PropertyError> {
267 match STANDARD.decode(value.clone()) {
269 Ok(bytes) => Ok(Vec::from(bytes)),
270 Err(_) => Err(PropertyError::BadFormat { prop_type: PropType::BinaryBlock, value }),
271 }
272}
273
274fn parse_uuid(value: String) -> Result<Uuid, PropertyError> {
275 match uuid::Uuid::parse_str(&value) {
276 Ok(uuid) => {
277 let (time_low, time_mid, time_hi_and_version, clock_seq_and_node) = uuid.as_fields();
278 Ok(Uuid {
279 time_low: time_low,
280 time_mid: time_mid,
281 time_hi_and_version: time_hi_and_version,
282 clock_seq_and_node: *clock_seq_and_node,
283 })
284 }
285 Err(_) => Err(PropertyError::BadFormat { prop_type: PropType::Uuid, value }),
286 }
287}
288
289fn parse_identity(value: String) -> Result<Identity, PropertyError> {
290 let (login_str, uuid) = match value.split_once(':') {
292 Some((login_str, uuid_str)) => (login_str, parse_uuid(uuid_str.to_string())?),
293 None => (value.as_str(), Uuid::default()),
294 };
295 let login_val = match login_str.parse::<u32>() {
296 Ok(val) => val,
297 Err(_) => return Err(PropertyError::BadFormat { prop_type: PropType::Identity, value }),
298 };
299 let login = Login::from_u32(login_val)
300 .ok_or(PropertyError::BadFormat { prop_type: PropType::Identity, value })?;
301 Ok(Identity { login, uuid })
302}
303
304#[cfg(test)]
306pub mod tests {
307 use super::*;
308
309 const TEST_PROP_NAME_STRING: &str = "gpd.tee.test.string";
310 const TEST_PROP_NAME_BOOL: &str = "gpd.tee.test.bool";
311 const TEST_PROP_NAME_U32: &str = "gpd.tee.test.u32";
312 const TEST_PROP_NAME_U64: &str = "gpd.tee.test.u64";
313 const TEST_PROP_NAME_BINARY_BLOCK: &str = "gpd.tee.test.binaryBlock";
314 const TEST_PROP_NAME_UUID: &str = "gpd.tee.test.uuid";
315 const TEST_PROP_NAME_IDENTITY: &str = "gpd.tee.test.identity";
316
317 const TEST_PROP_VAL_STRING: &str = "asdf";
318 const TEST_PROP_VAL_BOOL: &str = "true";
319 const TEST_PROP_VAL_U32: &str = "57";
320 const TEST_PROP_VAL_U64: &str = "4294967296"; const TEST_PROP_VAL_BINARY_BLOCK: &str = "ZnVjaHNpYQ=="; const TEST_PROP_VAL_UUID: &str = "9cccff19-13b5-4d4c-aa9e-5c8901a52e2f";
325 const TEST_PROP_UUID: Uuid = Uuid {
326 time_low: 0x9cccff19,
327 time_mid: 0x13b5,
328 time_hi_and_version: 0x4d4c,
329 clock_seq_and_node: [0xaa, 0x9e, 0x5c, 0x89, 0x01, 0xa5, 0x2e, 0x2f],
330 };
331
332 const TEST_PROP_VAL_IDENTITY: &str = "4026531840:9cccff19-13b5-4d4c-aa9e-5c8901a52e2f";
334 const TEST_PROP_IDENTITY: Identity =
335 Identity { login: Login::TrustedApp, uuid: TEST_PROP_UUID };
336
337 fn create_test_prop_map() -> PropertiesMap {
338 let mut props: IndexMap<String, (PropType, String)> = IndexMap::new();
339 props.insert(
340 TEST_PROP_NAME_STRING.to_string(),
341 (PropType::String, TEST_PROP_VAL_STRING.to_string()),
342 );
343 props.insert(
344 TEST_PROP_NAME_BOOL.to_string(),
345 (PropType::Boolean, TEST_PROP_VAL_BOOL.to_string()),
346 );
347 props.insert(
348 TEST_PROP_NAME_U32.to_string(),
349 (PropType::UnsignedInt32, TEST_PROP_VAL_U32.to_string()),
350 );
351 props.insert(
352 TEST_PROP_NAME_U64.to_string(),
353 (PropType::UnsignedInt64, TEST_PROP_VAL_U64.to_string()),
354 );
355 props.insert(
356 TEST_PROP_NAME_BINARY_BLOCK.to_string(),
357 (PropType::BinaryBlock, TEST_PROP_VAL_BINARY_BLOCK.to_string()),
358 );
359 props.insert(
360 TEST_PROP_NAME_UUID.to_string(),
361 (PropType::Uuid, TEST_PROP_VAL_UUID.to_string()),
362 );
363 props.insert(
364 TEST_PROP_NAME_IDENTITY.to_string(),
365 (PropType::Identity, TEST_PROP_VAL_IDENTITY.to_string()),
366 );
367 props
368 }
369
370 fn create_test_prop_set() -> PropSet {
371 PropSet::new(create_test_prop_map())
372 }
373
374 #[test]
375 pub fn test_load_config_from_string() {
376 let config_json = r#"[
377 {
378 "name": "gpd.tee.asdf",
379 "prop_type": "boolean",
380 "value": "true"
381 },
382 {
383 "name": "gpd.tee.other",
384 "prop_type": "binary_block",
385 "value": "testingzz"
386 }
387 ]
388 "#;
389
390 let prop_set: PropSet = PropSet::from_config_string(config_json).expect("loading config");
391
392 let bool_prop_value =
393 prop_set.get_boolean_property("gpd.tee.asdf".to_string()).expect("getting bool prop");
394 assert_eq!(true, bool_prop_value)
395 }
396
397 #[test]
398 pub fn test_load_config_from_string_failure() {
399 let config_json = r#"[
401 "name": "gpd.tee.asdf",
402 "prop_type": "boolean",
403 "value": "true"
404 },
405 {
406 "name": "gpd.tee.other",
407 "prop_type": "binary_block",
408 "value": "testingzz"
409 }
410 ]
411 "#;
412
413 let res = PropSet::from_config_string(config_json);
414
415 match res.err() {
416 Some(PropertyError::Generic { .. }) => (),
417 _ => assert!(false, "Unexpected error type"),
418 }
419 }
420
421 #[test]
423 pub fn test_enumerator_query_prop_types_success() {
424 let mut enumerator = PropEnumerator::new();
425
426 enumerator.start(Arc::new(create_test_prop_set()));
428
429 let prop_name = enumerator.get_property_name().expect("getting prop name");
430 assert_eq!(TEST_PROP_NAME_STRING.to_string(), prop_name);
431
432 let prop_type = enumerator.get_property_type().expect("getting prop type");
433 assert_eq!(PropType::String, prop_type);
434
435 let prop_val = enumerator.get_property_as_string().expect("getting prop as string");
436 assert_eq!(TEST_PROP_VAL_STRING.to_string(), prop_val);
437
438 enumerator.next().expect("moving enumerator to next prop");
440
441 let prop_name = enumerator.get_property_name().expect("getting prop name");
442 assert_eq!(TEST_PROP_NAME_BOOL.to_string(), prop_name);
443
444 let prop_type = enumerator.get_property_type().expect("getting prop type");
445 assert_eq!(PropType::Boolean, prop_type);
446
447 let prop_val = enumerator.get_property_as_bool().expect("getting prop as bool");
448 assert_eq!(true, prop_val);
449
450 enumerator.next().expect("moving enumerator to next prop");
452
453 let prop_name = enumerator.get_property_name().expect("getting prop name");
454 assert_eq!(TEST_PROP_NAME_U32.to_string(), prop_name);
455
456 let prop_type = enumerator.get_property_type().expect("getting prop type");
457 assert_eq!(PropType::UnsignedInt32, prop_type);
458
459 let prop_val = enumerator.get_property_as_u32().expect("getting prop as u32");
460 assert_eq!(57, prop_val);
461
462 enumerator.next().expect("moving enumerator to next prop");
464
465 let prop_name = enumerator.get_property_name().expect("getting prop name");
466 assert_eq!(TEST_PROP_NAME_U64.to_string(), prop_name);
467
468 let prop_type = enumerator.get_property_type().expect("getting prop type");
469 assert_eq!(PropType::UnsignedInt64, prop_type);
470
471 let prop_val = enumerator.get_property_as_u64().expect("getting prop as u64");
472 assert_eq!(4294967296, prop_val);
473
474 enumerator.next().expect("moving enumerator to next prop");
476
477 let prop_name = enumerator.get_property_name().expect("getting prop name");
478 assert_eq!(TEST_PROP_NAME_BINARY_BLOCK.to_string(), prop_name);
479
480 let prop_type = enumerator.get_property_type().expect("getting prop type");
481 assert_eq!(PropType::BinaryBlock, prop_type);
482
483 let prop_val =
484 enumerator.get_property_as_binary_block().expect("getting prop as binary block");
485 let bytes_expected = STANDARD.decode("ZnVjaHNpYQ==").expect("decoding binary block string");
486 assert_eq!(bytes_expected, prop_val);
487
488 enumerator.next().expect("moving enumerator to next prop");
490
491 let prop_name = enumerator.get_property_name().expect("getting prop name");
492 assert_eq!(TEST_PROP_NAME_UUID.to_string(), prop_name);
493
494 let prop_type = enumerator.get_property_type().expect("getting prop type");
495 assert_eq!(PropType::Uuid, prop_type);
496
497 let prop_val: Uuid = enumerator.get_property_as_uuid().expect("getting prop as uuid");
498 assert_eq!(TEST_PROP_UUID.time_low, prop_val.time_low);
499 assert_eq!(TEST_PROP_UUID.time_mid, prop_val.time_mid);
500 assert_eq!(TEST_PROP_UUID.time_hi_and_version, prop_val.time_hi_and_version);
501 assert_eq!(TEST_PROP_UUID.clock_seq_and_node, prop_val.clock_seq_and_node);
502
503 enumerator.next().expect("moving enumerator to next prop");
505
506 let prop_name = enumerator.get_property_name().expect("getting prop name");
507 assert_eq!(TEST_PROP_NAME_IDENTITY.to_string(), prop_name);
508
509 let prop_type = enumerator.get_property_type().expect("getting prop type");
510 assert_eq!(PropType::Identity, prop_type);
511
512 let prop_val: Identity =
513 enumerator.get_property_as_identity().expect("getting prop as identity");
514 assert_eq!(TEST_PROP_IDENTITY.login, prop_val.login);
515 assert_eq!(TEST_PROP_IDENTITY.uuid.time_low, prop_val.uuid.time_low);
517 assert_eq!(TEST_PROP_IDENTITY.uuid.time_mid, prop_val.uuid.time_mid);
518 assert_eq!(TEST_PROP_IDENTITY.uuid.time_hi_and_version, prop_val.uuid.time_hi_and_version);
519 assert_eq!(TEST_PROP_IDENTITY.uuid.clock_seq_and_node, prop_val.uuid.clock_seq_and_node);
520
521 let res = enumerator.next();
523 match res.err() {
524 Some(PropertyError::ItemNotFound { .. }) => (),
525 _ => assert!(false, "Unexpected error type"),
526 }
527 }
528
529 #[test]
530 pub fn test_enumerator_reset() {
531 let mut enumerator = PropEnumerator::new();
532 enumerator.start(Arc::new(create_test_prop_set()));
533
534 let prop_name = enumerator.get_property_name().expect("getting prop name");
535 assert_eq!(TEST_PROP_NAME_STRING.to_string(), prop_name);
536
537 enumerator.next().expect("moving enumerator to next prop");
538
539 let prop_name = enumerator.get_property_name().expect("getting prop name");
540 assert_eq!(TEST_PROP_NAME_BOOL.to_string(), prop_name);
541
542 enumerator.reset();
543
544 let prop_name = enumerator.get_property_name().expect("getting prop name");
545 assert_eq!(TEST_PROP_NAME_STRING.to_string(), prop_name);
546 }
547
548 #[test]
549 pub fn test_enumerator_wrong_prop_type_error() {
550 let mut enumerator = PropEnumerator::new();
551 enumerator.start(Arc::new(create_test_prop_set()));
552
553 let res = enumerator.get_property_as_bool();
555 match res.err() {
556 Some(PropertyError::BadFormat { .. }) => (),
557 _ => assert!(false, "Unexpected error type"),
558 }
559
560 enumerator.next().expect("moving enumerator to next prop");
561
562 let res = enumerator.get_property_as_identity();
564 match res.err() {
565 Some(PropertyError::BadFormat { .. }) => (),
566 _ => assert!(false, "Unexpected error type"),
567 }
568
569 let res = enumerator.get_property_as_bool();
571 assert!(res.is_ok());
572 }
573
574 #[test]
575 pub fn test_enumerator_not_started_error() {
576 let enumerator = PropEnumerator::new();
579
580 let res = enumerator.get_property_name();
581
582 match res.err() {
584 Some(PropertyError::ItemNotFound { .. }) => (),
585 _ => assert!(false, "Unexpected error type"),
586 }
587 }
588
589 #[test]
591 pub fn test_propset_get_not_found() {
592 let prop_set = create_test_prop_set();
593
594 let res = prop_set.get_boolean_property("name.that.isnt.there".to_string());
595
596 match res.err() {
597 Some(PropertyError::ItemNotFound { .. }) => (),
598 _ => assert!(false, "Unexpected error type"),
599 }
600 }
601
602 #[test]
603 pub fn test_propset_get_string_success() {
604 let prop_set = create_test_prop_set();
605
606 let test_str_val = prop_set
607 .get_string_property(TEST_PROP_NAME_STRING.to_string())
608 .expect("getting str prop val");
609 assert_eq!(TEST_PROP_VAL_STRING.to_string(), test_str_val);
610
611 let test_bool_val_as_str = prop_set
613 .get_string_property(TEST_PROP_NAME_BOOL.to_string())
614 .expect("getting bool prop val as string");
615 assert_eq!(TEST_PROP_VAL_BOOL.to_string(), test_bool_val_as_str);
616 }
617
618 #[test]
619 pub fn test_propset_get_bool_success() {
620 let prop_set = create_test_prop_set();
621
622 let val = prop_set
623 .get_boolean_property(TEST_PROP_NAME_BOOL.to_string())
624 .expect("getting bool prop val");
625 assert_eq!(true, val);
626 }
627
628 #[test]
629 pub fn test_propset_get_bool_wrong_type() {
630 let prop_set = create_test_prop_set();
631
632 let res = prop_set.get_boolean_property(TEST_PROP_NAME_UUID.to_string());
633 match res.err() {
634 Some(PropertyError::BadFormat { .. }) => (),
635 _ => assert!(false, "Unexpected error type"),
636 }
637 }
638
639 #[test]
640 pub fn test_propset_get_u32_success() {
641 let prop_set = create_test_prop_set();
642
643 let val = prop_set
644 .get_uint32_property(TEST_PROP_NAME_U32.to_string())
645 .expect("getting u32 prop val");
646 assert_eq!(57, val);
647 }
648
649 #[test]
650 pub fn test_propset_get_u32_wrong_type() {
651 let prop_set = create_test_prop_set();
652
653 let res = prop_set.get_uint32_property(TEST_PROP_NAME_BOOL.to_string());
654 match res.err() {
655 Some(PropertyError::BadFormat { .. }) => (),
656 _ => assert!(false, "Unexpected error type"),
657 }
658 }
659
660 #[test]
661 pub fn test_propset_get_u64_success() {
662 let prop_set = create_test_prop_set();
663
664 let val = prop_set
665 .get_uint64_property(TEST_PROP_NAME_U64.to_string())
666 .expect("getting u64 prop val");
667 assert_eq!(4294967296, val);
668 }
669
670 #[test]
671 pub fn test_propset_get_u64_wrong_type() {
672 let prop_set = create_test_prop_set();
673
674 let res = prop_set.get_uint64_property(TEST_PROP_NAME_BOOL.to_string());
675 match res.err() {
676 Some(PropertyError::BadFormat { .. }) => (),
677 _ => assert!(false, "Unexpected error type"),
678 }
679 }
680
681 #[test]
682 pub fn test_propset_get_binary_block_success() {
683 let prop_set = create_test_prop_set();
684
685 let val = prop_set
686 .get_binary_block_property(TEST_PROP_NAME_BINARY_BLOCK.to_string())
687 .expect("getting binary block prop val");
688
689 let expected_bytes = STANDARD
690 .decode(TEST_PROP_VAL_BINARY_BLOCK)
691 .expect("decoding expected binary block bytes");
692 assert_eq!(expected_bytes, val);
693 }
694
695 #[test]
696 pub fn test_propset_get_binary_block_wrong_type() {
697 let prop_set = create_test_prop_set();
698
699 let res = prop_set.get_binary_block_property(TEST_PROP_NAME_IDENTITY.to_string());
702 match res.err() {
703 Some(PropertyError::BadFormat { .. }) => (),
704 _ => assert!(false, "Unexpected error type"),
705 }
706 }
707
708 #[test]
709 pub fn test_propset_get_uuid_success() {
710 let prop_set = create_test_prop_set();
711
712 let val = prop_set
713 .get_uuid_property(TEST_PROP_NAME_UUID.to_string())
714 .expect("getting uuid prop val");
715
716 assert_eq!(TEST_PROP_UUID.time_low, val.time_low);
717 assert_eq!(TEST_PROP_UUID.time_mid, val.time_mid);
718 assert_eq!(TEST_PROP_UUID.time_hi_and_version, val.time_hi_and_version);
719 assert_eq!(TEST_PROP_UUID.clock_seq_and_node, val.clock_seq_and_node);
720 }
721
722 #[test]
723 pub fn test_propset_get_uuid_wrong_type() {
724 let prop_set = create_test_prop_set();
725
726 let res = prop_set.get_uuid_property(TEST_PROP_NAME_BOOL.to_string());
727 match res.err() {
728 Some(PropertyError::BadFormat { .. }) => (),
729 _ => assert!(false, "Unexpected error type"),
730 }
731 }
732
733 #[test]
734 pub fn test_propset_get_identity_success() {
735 let prop_set = create_test_prop_set();
736
737 let val: Identity = prop_set
738 .get_identity_property(TEST_PROP_NAME_IDENTITY.to_string())
739 .expect("getting identity prop val");
740
741 assert_eq!(TEST_PROP_IDENTITY.login, val.login);
742 assert_eq!(TEST_PROP_IDENTITY.uuid.time_low, val.uuid.time_low);
743 assert_eq!(TEST_PROP_IDENTITY.uuid.time_mid, val.uuid.time_mid);
744 assert_eq!(TEST_PROP_IDENTITY.uuid.time_hi_and_version, val.uuid.time_hi_and_version);
745 assert_eq!(TEST_PROP_IDENTITY.uuid.clock_seq_and_node, val.uuid.clock_seq_and_node);
746 }
747
748 #[test]
749 pub fn test_propset_get_identity_wrong_type() {
750 let prop_set = create_test_prop_set();
751
752 let res = prop_set.get_identity_property(TEST_PROP_NAME_BOOL.to_string());
753 match res.err() {
754 Some(PropertyError::BadFormat { .. }) => (),
755 _ => assert!(false, "Unexpected error type"),
756 }
757 }
758
759 #[test]
761 pub fn test_parse_bool_success() {
762 let val_true = "true".to_string();
763 let val_false = "false".to_string();
764
765 let res_true = parse_bool(val_true).expect("parsing true");
766 let res_false = parse_bool(val_false).expect("parsing false");
767
768 assert!(res_true);
769 assert!(!res_false);
770 }
771
772 #[test]
773 pub fn test_parse_bool_empty_string() {
774 let val = "".to_string();
775
776 let res = parse_bool(val);
777
778 match res.err() {
779 Some(PropertyError::BadFormat { .. }) => (),
780 _ => assert!(false, "Unexpected error type"),
781 }
782 }
783
784 #[test]
785 pub fn test_parse_bool_bad_format() {
786 let val = "asdf".to_string();
787
788 let res = parse_bool(val);
789
790 match res.err() {
791 Some(PropertyError::BadFormat { .. }) => (),
792 _ => assert!(false, "Unexpected error type"),
793 }
794 }
795
796 #[test]
797 pub fn test_parse_bool_caps_not_accepted() {
798 let val = "TRUE".to_string();
799
800 let res = parse_bool(val);
801
802 match res.err() {
803 Some(PropertyError::BadFormat { .. }) => (),
804 _ => assert!(false, "Unexpected error type"),
805 }
806 }
807
808 #[test]
809 pub fn test_parse_u32_success() {
810 let val = "15".to_string();
811
812 let res = parse_uint32(val).expect("parsing 15");
813
814 assert_eq!(res, 15);
815 }
816
817 #[test]
818 pub fn test_parse_u32_empty_string() {
819 let val = "".to_string();
820
821 let res = parse_uint32(val);
822
823 match res.err() {
824 Some(PropertyError::BadFormat { .. }) => (),
825 _ => assert!(false, "Unexpected error type"),
826 }
827 }
828
829 #[test]
830 pub fn test_parse_u32_negative_value() {
831 let val = "-15".to_string();
832
833 let res = parse_uint32(val);
834
835 match res.err() {
836 Some(PropertyError::BadFormat { .. }) => (),
837 _ => assert!(false, "Unexpected error type"),
838 }
839 }
840
841 #[test]
842 pub fn test_parse_u32_too_large() {
843 let val = "4294967296".to_string();
845
846 let res = parse_uint32(val);
847
848 match res.err() {
849 Some(PropertyError::BadFormat { .. }) => (),
850 _ => assert!(false, "Unexpected error type"),
851 }
852 }
853
854 #[test]
855 pub fn test_parse_u32_bad_format() {
856 let val = "text".to_string();
857
858 let res = parse_uint32(val);
859
860 match res.err() {
861 Some(PropertyError::BadFormat { .. }) => (),
862 _ => assert!(false, "Unexpected error type"),
863 }
864 }
865
866 #[test]
867 pub fn test_parse_u64_success() {
868 let val = "4294967296".to_string();
869
870 let res = parse_uint64(val).expect("parsing 4294967296");
871
872 assert_eq!(res, 4294967296);
873 }
874
875 #[test]
876 pub fn test_parse_u64_empty_string() {
877 let val = "".to_string();
878
879 let res = parse_uint64(val);
880
881 match res.err() {
882 Some(PropertyError::BadFormat { .. }) => (),
883 _ => assert!(false, "Unexpected error type"),
884 }
885 }
886
887 #[test]
888 pub fn test_parse_u64_negative_value() {
889 let val = "-15".to_string();
890
891 let res = parse_uint64(val);
892
893 match res.err() {
894 Some(PropertyError::BadFormat { .. }) => (),
895 _ => assert!(false, "Unexpected error type"),
896 }
897 }
898
899 #[test]
900 pub fn test_parse_u64_too_large() {
901 let val = "18446744073709551616".to_string();
903
904 let res = parse_uint64(val);
905
906 match res.err() {
907 Some(PropertyError::BadFormat { .. }) => (),
908 _ => assert!(false, "Unexpected error type"),
909 }
910 }
911
912 #[test]
913 pub fn test_parse_u64_bad_format() {
914 let val = "text".to_string();
915
916 let res = parse_uint64(val);
917
918 match res.err() {
919 Some(PropertyError::BadFormat { .. }) => (),
920 _ => assert!(false, "Unexpected error type"),
921 }
922 }
923
924 #[test]
925 pub fn test_parse_binary_block_success() {
926 let bytes: [u8; 6] = [1, 2, 3, 4, 5, 6];
927 let encoded = STANDARD.encode(bytes);
928
929 let res = parse_binary_block(encoded).expect("parsing binary block");
930
931 assert_eq!(bytes.to_vec(), res);
932 }
933
934 #[test]
935 pub fn test_parse_binary_empty_string() {
936 let res = parse_binary_block("".to_string());
937
938 assert!(res.is_ok());
939 }
940
941 #[test]
942 pub fn test_parse_binary_block_invalid_base64() {
943 let bad_val = "asdf&^%@".to_string();
945
946 let res = parse_binary_block(bad_val);
947
948 match res.err() {
949 Some(PropertyError::BadFormat { .. }) => (),
950 _ => assert!(false, "Unexpected error type"),
951 }
952 }
953
954 #[test]
955 pub fn test_parse_binary_block_invalid_padding_chars_only() {
956 let bad_val = "====".to_string();
958
959 let res = parse_binary_block(bad_val);
960
961 match res.err() {
962 Some(PropertyError::BadFormat { .. }) => (),
963 _ => assert!(false, "Unexpected error type"),
964 }
965 }
966
967 #[test]
968 pub fn test_parse_uuid_success() {
969 let valid_uuid = "9cccff19-13b5-4d4c-aa9e-5c8901a52e2f".to_string();
970
971 let res = parse_uuid(valid_uuid);
972
973 assert!(res.is_ok());
974 }
975
976 #[test]
977 pub fn test_parse_uuid_empty_string() {
978 let res = parse_uuid("".to_string());
979
980 match res.err() {
981 Some(PropertyError::BadFormat { .. }) => (),
982 _ => assert!(false, "Unexpected error type"),
983 }
984 }
985
986 #[test]
987 pub fn test_parse_uuid_invalid_uuid() {
988 let invalid_uuid = "asdf".to_string();
989
990 let res = parse_uuid(invalid_uuid);
991
992 match res.err() {
993 Some(PropertyError::BadFormat { .. }) => (),
994 _ => assert!(false, "Unexpected error type"),
995 }
996 }
997
998 #[test]
999 pub fn test_parse_identity_success() {
1000 let res = parse_identity(TEST_PROP_VAL_IDENTITY.to_string());
1001 assert!(res.is_ok());
1002 }
1003
1004 #[test]
1005 pub fn test_parse_identity_empty_uuid() {
1006 let res = parse_identity("4026531840".to_string());
1008 assert!(res.is_ok());
1009 let id = res.unwrap();
1010 assert_eq!(Uuid::default(), id.uuid);
1011 }
1012
1013 #[test]
1014 pub fn test_parse_identity_invalid_login_type() {
1015 let res = parse_identity("4026531839:9cccff19-13b5-4d4c-aa9e-5c8901a52e2f".to_string());
1019 match res.err() {
1020 Some(PropertyError::BadFormat { .. }) => (),
1021 _ => assert!(false, "Unexpected error type"),
1022 }
1023 }
1024}