1use std::borrow::Cow;
2use std::fmt::Display;
3use std::str::FromStr;
4
5use super::{AutosarVersion, CharacterData, CharacterDataSpec, EnumItem};
6
7impl CharacterData {
8 pub(crate) fn check_value(value: &CharacterData, spec: &CharacterDataSpec, file_version: AutosarVersion) -> bool {
9 match spec {
10 CharacterDataSpec::Enum { items } => {
12 if let CharacterData::Enum(enumitem) = &value {
14 if let Some((_, version_mask)) = items.iter().find(|(name, _)| *name == *enumitem) {
16 if *version_mask & (file_version as u32) != 0 {
18 return true;
19 }
20 }
21 }
22 }
23 CharacterDataSpec::Pattern {
24 check_fn, max_length, ..
25 } => {
26 if let CharacterData::String(stringval) = &value {
27 if stringval.len() <= max_length.unwrap_or(usize::MAX) && check_fn(stringval.as_bytes()) {
28 return true;
29 }
30 }
31 }
32 CharacterDataSpec::String { max_length, .. } => {
33 if let CharacterData::String(stringval) = &value {
34 if stringval.len() <= max_length.unwrap_or(usize::MAX) {
35 return true;
36 }
37 }
38 }
39 CharacterDataSpec::UnsignedInteger => {
40 if let CharacterData::UnsignedInteger(_) = &value {
41 return true;
42 }
43 }
44 CharacterDataSpec::Float => {
45 if let CharacterData::Float(_) = &value {
46 return true;
47 }
48 }
49 }
50 false
51 }
52
53 pub(crate) fn check_version_compatibility(
54 &self,
55 data_spec: &CharacterDataSpec,
56 target_version: AutosarVersion,
57 ) -> (bool, u32) {
58 if let CharacterDataSpec::Enum { items } = data_spec {
59 if let CharacterData::Enum(attrval) = self {
60 if let Some((_, enumitem_version_mask)) = items.iter().find(|(item, _)| *item == *attrval) {
61 if target_version.compatible(*enumitem_version_mask) {
62 (true, *enumitem_version_mask)
63 } else {
64 (false, *enumitem_version_mask)
65 }
66 } else {
67 (false, 0)
69 }
70 } else {
71 (false, u32::MAX)
73 }
74 } else {
75 (true, u32::MAX)
76 }
77 }
78
79 pub(crate) fn parse(input: &str, character_data_spec: &CharacterDataSpec, version: AutosarVersion) -> Option<Self> {
80 match character_data_spec {
81 CharacterDataSpec::Enum { items } => {
82 if let Ok(enumitem) = EnumItem::from_str(input) {
83 if let Some((_, version_mask)) = items.iter().find(|(item, _)| *item == enumitem) {
84 if version as u32 & version_mask != 0 {
85 return Some(CharacterData::Enum(enumitem));
86 }
87 }
88 }
89 }
90 CharacterDataSpec::Pattern {
91 check_fn, max_length, ..
92 } => {
93 if input.len() <= max_length.unwrap_or(usize::MAX) && check_fn(input.as_bytes()) {
94 return Some(CharacterData::String(input.to_owned()));
95 }
96 }
97 CharacterDataSpec::String { max_length, .. } => {
98 if input.len() <= max_length.unwrap_or(usize::MAX) {
99 return Some(CharacterData::String(input.to_owned()));
100 }
101 }
102 CharacterDataSpec::UnsignedInteger => {
103 if let Ok(value) = input.parse() {
104 return Some(CharacterData::UnsignedInteger(value));
105 }
106 }
107 CharacterDataSpec::Float => {
108 if let Ok(value) = input.parse() {
109 return Some(CharacterData::Float(value));
110 }
111 }
112 }
113 None
114 }
115
116 pub(crate) fn serialize_internal(&self, outstring: &mut String) {
117 match self {
118 CharacterData::Enum(enumval) => outstring.push_str(enumval.to_str()),
119 CharacterData::String(strval) => outstring.push_str(&escape_text(strval)),
120 CharacterData::UnsignedInteger(intval) => outstring.push_str(&intval.to_string()),
121 CharacterData::Float(floatval) => outstring.push_str(&floatval.to_string()),
122 }
123 }
124
125 #[must_use]
129 pub fn enum_value(&self) -> Option<EnumItem> {
130 if let CharacterData::Enum(item) = self {
131 Some(*item)
132 } else {
133 None
134 }
135 }
136
137 #[must_use]
141 pub fn string_value(&self) -> Option<String> {
142 if let CharacterData::String(value) = self {
143 Some(value.to_owned())
144 } else {
145 None
146 }
147 }
148
149 #[must_use]
153 pub fn unsigned_integer_value(&self) -> Option<u64> {
154 if let CharacterData::UnsignedInteger(uintval) = self {
155 Some(*uintval)
156 } else {
157 None
158 }
159 }
160
161 #[must_use]
165 pub fn float_value(&self) -> Option<f64> {
166 if let CharacterData::Float(value) = self {
167 Some(*value)
168 } else {
169 None
170 }
171 }
172
173 #[must_use]
190 pub fn parse_integer<T: num_traits::Num + TryFrom<u64>>(&self) -> Option<T> {
191 if let CharacterData::String(text) = self {
192 if text == "0" {
193 T::try_from(0u64).ok()
195 } else if let Some(hexstr) = text.strip_prefix("0x") {
196 T::from_str_radix(hexstr, 16).ok()
197 } else if let Some(hexstr) = text.strip_prefix("0X") {
198 T::from_str_radix(hexstr, 16).ok()
199 } else if let Some(binstr) = text.strip_prefix("0b") {
200 T::from_str_radix(binstr, 2).ok()
201 } else if let Some(binstr) = text.strip_prefix("0B") {
202 T::from_str_radix(binstr, 2).ok()
203 } else if let Some(octstr) = text.strip_prefix('0') {
204 T::from_str_radix(octstr, 8).ok()
205 } else {
206 T::from_str_radix(text, 10).ok()
207 }
208 } else if let CharacterData::UnsignedInteger(value) = self {
209 T::try_from(*value).ok()
210 } else {
211 None
212 }
213 }
214
215 #[must_use]
237 pub fn parse_float(&self) -> Option<f64> {
238 if let CharacterData::String(text) = self {
239 if text == "0" {
240 Some(0f64)
242 } else if let Some(hexval) = text
243 .strip_prefix("0x")
244 .and_then(|hextxt| u64::from_str_radix(hextxt, 16).ok())
245 {
246 Some(hexval as f64)
247 } else if let Some(hexval) = text
248 .strip_prefix("0X")
249 .and_then(|hextxt| u64::from_str_radix(hextxt, 16).ok())
250 {
251 Some(hexval as f64)
252 } else if let Some(binval) = text
253 .strip_prefix("0b")
254 .and_then(|bintxt| u64::from_str_radix(bintxt, 2).ok())
255 {
256 Some(binval as f64)
257 } else if let Some(binval) = text
258 .strip_prefix("0B")
259 .and_then(|bintxt| u64::from_str_radix(bintxt, 2).ok())
260 {
261 Some(binval as f64)
262 } else if let Some(octval) = text
263 .strip_prefix('0')
264 .and_then(|octtxt| u64::from_str_radix(octtxt, 8).ok())
265 {
266 Some(octval as f64)
267 } else {
268 text.parse().ok()
270 }
271 } else if let CharacterData::Float(value) = self {
272 Some(*value)
273 } else if let CharacterData::UnsignedInteger(value) = self {
274 Some(*value as f64)
275 } else {
276 None
277 }
278 }
279
280 #[must_use]
296 pub fn parse_bool(&self) -> Option<bool> {
297 if let CharacterData::String(text) = self {
298 match text.as_str() {
299 "true" | "1" => Some(true),
300 "false" | "0" => Some(false),
301 _ => None,
302 }
303 } else {
304 None
305 }
306 }
307}
308
309impl From<String> for CharacterData {
310 fn from(value: String) -> Self {
311 Self::String(value)
312 }
313}
314
315impl From<&str> for CharacterData {
316 fn from(value: &str) -> Self {
317 Self::String(value.to_string())
318 }
319}
320
321impl From<EnumItem> for CharacterData {
322 fn from(value: EnumItem) -> Self {
323 Self::Enum(value)
324 }
325}
326
327impl From<u64> for CharacterData {
328 fn from(value: u64) -> Self {
329 Self::UnsignedInteger(value)
330 }
331}
332
333impl From<f64> for CharacterData {
334 fn from(value: f64) -> Self {
335 Self::Float(value)
336 }
337}
338
339impl From<bool> for CharacterData {
340 fn from(value: bool) -> Self {
341 Self::String(value.to_string())
342 }
343}
344
345impl Display for CharacterData {
346 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
347 match self {
348 CharacterData::Enum(enumitem) => f.write_str(enumitem.to_str()),
349 CharacterData::String(stringval) => f.write_str(stringval),
350 CharacterData::UnsignedInteger(uintval) => f.write_str(&uintval.to_string()),
351 CharacterData::Float(f64val) => f.write_str(&f64val.to_string()),
352 }
353 }
354}
355
356impl Ord for CharacterData {
357 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
358 match (self, other) {
362 (CharacterData::Enum(a), CharacterData::Enum(b)) => a.to_str().cmp(b.to_str()),
363 (CharacterData::String(a), CharacterData::String(b)) => a.cmp(b),
364 (CharacterData::UnsignedInteger(a), CharacterData::UnsignedInteger(b)) => a.cmp(b),
365 (CharacterData::Float(a), CharacterData::Float(b)) => a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal),
366 (CharacterData::Enum(_), _) => std::cmp::Ordering::Less,
367 (CharacterData::String(_), CharacterData::Enum(_)) => std::cmp::Ordering::Greater,
368 (CharacterData::String(_), _) => std::cmp::Ordering::Less,
369 (CharacterData::UnsignedInteger(_), CharacterData::Enum(_)) => std::cmp::Ordering::Greater,
370 (CharacterData::UnsignedInteger(_), CharacterData::String(_)) => std::cmp::Ordering::Greater,
371 (CharacterData::UnsignedInteger(_), _) => std::cmp::Ordering::Less,
372 (CharacterData::Float(_), _) => std::cmp::Ordering::Greater,
373 }
374 }
375}
376
377impl PartialOrd for CharacterData {
378 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
379 Some(self.cmp(other))
380 }
381}
382
383impl Eq for CharacterData {}
384
385fn escape_text(input: &str) -> Cow<str> {
386 if input.contains(['&', '>', '<', '\'', '"']) {
387 let mut escaped = String::with_capacity(input.len() + 6);
388
389 for c in input.chars() {
390 match c {
391 '<' => escaped.push_str("<"),
392 '>' => escaped.push_str(">"),
393 '&' => escaped.push_str("&"),
394 '"' => escaped.push_str("""),
395 '\'' => escaped.push_str("'"),
396 other => escaped.push(other),
397 }
398 }
399
400 Cow::Owned(escaped)
401 } else {
402 Cow::Borrowed(input)
403 }
404}
405
406#[cfg(test)]
407mod test {
408 use super::*;
409
410 fn dummy_validate(s: &[u8]) -> bool {
411 s.len() == 1 && (s[0] == b'0' || s[0] == b'1')
412 }
413
414 #[test]
415 fn check_value() {
416 let spec_enum = CharacterDataSpec::Enum {
417 items: &[(EnumItem::default, 0x3ffff), (EnumItem::preserve, 0x0ffff)],
418 };
419 let data = CharacterData::Enum(EnumItem::default);
420 assert!(CharacterData::check_value(
421 &data,
422 &spec_enum,
423 AutosarVersion::Autosar_00050
424 ));
425 let data = CharacterData::Enum(EnumItem::preserve);
426 assert!(!CharacterData::check_value(
427 &data,
428 &spec_enum,
429 AutosarVersion::Autosar_00050
430 ));
431 let data = CharacterData::Enum(EnumItem::Abstract);
432 assert!(!CharacterData::check_value(
433 &data,
434 &spec_enum,
435 AutosarVersion::Autosar_00050
436 ));
437 let data = CharacterData::Float(1.23);
438 assert!(!CharacterData::check_value(
439 &data,
440 &spec_enum,
441 AutosarVersion::Autosar_00050
442 ));
443
444 let spec_double = CharacterDataSpec::Float;
445 let data = CharacterData::Float(1.23);
446 assert!(CharacterData::check_value(
447 &data,
448 &spec_double,
449 AutosarVersion::Autosar_00050
450 ));
451 let data = CharacterData::String("1.23".to_string());
452 assert!(!CharacterData::check_value(
453 &data,
454 &spec_double,
455 AutosarVersion::Autosar_00050
456 ));
457
458 let spec_uint = CharacterDataSpec::UnsignedInteger;
459 let data = CharacterData::UnsignedInteger(123);
460 assert!(CharacterData::check_value(
461 &data,
462 &spec_uint,
463 AutosarVersion::Autosar_00050
464 ));
465 let data = CharacterData::String("123".to_string());
466 assert!(!CharacterData::check_value(
467 &data,
468 &spec_uint,
469 AutosarVersion::Autosar_00050
470 ));
471
472 let spec_string = CharacterDataSpec::String {
473 preserve_whitespace: false,
474 max_length: Some(10),
475 };
476 let data = CharacterData::String("123".to_string());
477 assert!(CharacterData::check_value(
478 &data,
479 &spec_string,
480 AutosarVersion::Autosar_00050
481 ));
482 let data = CharacterData::String("12345678901".to_string());
483 assert!(!CharacterData::check_value(
484 &data,
485 &spec_string,
486 AutosarVersion::Autosar_00050
487 ));
488 let data = CharacterData::UnsignedInteger(1);
489 assert!(!CharacterData::check_value(
490 &data,
491 &spec_string,
492 AutosarVersion::Autosar_00050
493 ));
494
495 let spec_pattern = CharacterDataSpec::Pattern {
496 check_fn: dummy_validate,
497 regex: r"0|1",
498 max_length: Some(1),
499 };
500 let data = CharacterData::String("0".to_string());
501 assert!(CharacterData::check_value(
502 &data,
503 &spec_pattern,
504 AutosarVersion::Autosar_00050
505 ));
506 let data = CharacterData::String("2".to_string());
507 assert!(!CharacterData::check_value(
508 &data,
509 &spec_pattern,
510 AutosarVersion::Autosar_00050
511 ));
512 }
513
514 #[test]
515 fn check_version_compatibility() {
516 let spec_enum = CharacterDataSpec::Enum {
517 items: &[(EnumItem::default, 0x0001), (EnumItem::preserve, 0x0002)],
518 };
519 let data = CharacterData::Enum(EnumItem::default);
520 let (result, _) = data.check_version_compatibility(&spec_enum, AutosarVersion::Autosar_4_0_1);
521 assert!(result);
522 let (result, _) = data.check_version_compatibility(&spec_enum, AutosarVersion::Autosar_00050);
523 assert!(!result);
524 let data = CharacterData::Enum(EnumItem::Abstract);
525 let (result, _) = data.check_version_compatibility(&spec_enum, AutosarVersion::Autosar_00050);
526 assert!(!result);
527 let data = CharacterData::UnsignedInteger(0);
528 let (result, _) = data.check_version_compatibility(&spec_enum, AutosarVersion::Autosar_00050);
529 assert!(!result);
530 }
531
532 #[test]
533 fn parse() {
534 let spec_enum = CharacterDataSpec::Enum {
535 items: &[(EnumItem::default, 0x3ffff), (EnumItem::preserve, 0x0ffff)],
536 };
537 let data = CharacterData::parse("default", &spec_enum, AutosarVersion::Autosar_00050).unwrap();
538 assert_eq!(data.enum_value().unwrap(), EnumItem::default);
539 let data = CharacterData::parse("preserve", &spec_enum, AutosarVersion::Autosar_00050);
540 assert!(data.is_none());
541 let data = CharacterData::parse("ABSTRACT", &spec_enum, AutosarVersion::Autosar_00050);
542 assert!(data.is_none());
543 let data = CharacterData::parse("", &spec_enum, AutosarVersion::Autosar_00050);
544 assert!(data.is_none());
545
546 let spec_double = CharacterDataSpec::Float;
547 let data = CharacterData::parse("2.0", &spec_double, AutosarVersion::Autosar_00050).unwrap();
548 assert_eq!(data.float_value().unwrap(), 2.0);
549 let data = CharacterData::parse("text", &spec_double, AutosarVersion::Autosar_00050);
550 assert!(data.is_none());
551
552 let spec_uint = CharacterDataSpec::UnsignedInteger;
553 let data = CharacterData::parse("2", &spec_uint, AutosarVersion::Autosar_00050).unwrap();
554 assert_eq!(data.unsigned_integer_value().unwrap(), 2);
555 let data = CharacterData::parse("text", &spec_uint, AutosarVersion::Autosar_00050);
556 assert!(data.is_none());
557
558 let spec_string = CharacterDataSpec::String {
559 preserve_whitespace: false,
560 max_length: Some(10),
561 };
562 let data = CharacterData::parse("text", &spec_string, AutosarVersion::Autosar_00050).unwrap();
563 assert_eq!(data.string_value().unwrap(), "text");
564 let data = CharacterData::parse("text text text", &spec_string, AutosarVersion::Autosar_00050);
565 assert!(data.is_none());
566
567 let spec_pattern = CharacterDataSpec::Pattern {
568 check_fn: dummy_validate,
569 regex: r"0|1",
570 max_length: Some(1),
571 };
572 let data = CharacterData::parse("0", &spec_pattern, AutosarVersion::Autosar_00050).unwrap();
573 assert_eq!(data.string_value().unwrap(), "0");
574 let data = CharacterData::parse("2", &spec_pattern, AutosarVersion::Autosar_00050);
575 assert!(data.is_none());
576 }
577
578 #[test]
579 fn serialize() {
580 let mut out = "".to_string();
581 let data = CharacterData::Enum(EnumItem::Abstract);
582 data.serialize_internal(&mut out);
583 assert_eq!(out, "ABSTRACT");
584 assert_eq!(format!("{data}"), "ABSTRACT");
585
586 let mut out = "".to_string();
587 let data = CharacterData::Float(1.23);
588 data.serialize_internal(&mut out);
589 assert_eq!(out, "1.23");
590 assert_eq!(format!("{data}"), "1.23");
591
592 let mut out = "".to_string();
593 let data = CharacterData::UnsignedInteger(0);
594 data.serialize_internal(&mut out);
595 assert_eq!(out, "0");
596 assert_eq!(format!("{data}"), "0");
597
598 let mut out = "".to_string();
599 let data = CharacterData::String("text".to_string());
600 data.serialize_internal(&mut out);
601 assert_eq!(out, "text");
602 assert_eq!(format!("{data}"), "text");
603
604 let mut out = "".to_string();
605 let data = CharacterData::String("special chars: <, >, &, \', \"".to_string());
606 data.serialize_internal(&mut out);
607 assert_eq!(out, "special chars: <, >, &, ', "");
608 assert_eq!(format!("{data}"), "special chars: <, >, &, \', \"");
609 }
610
611 #[test]
612 fn get_value() {
613 assert!(CharacterData::Enum(EnumItem::Abstract).enum_value().is_some());
614 assert!(CharacterData::Enum(EnumItem::Abstract).string_value().is_none());
615
616 assert!(CharacterData::Float(1.23).float_value().is_some());
617 assert!(CharacterData::Float(1.23).unsigned_integer_value().is_none());
618
619 assert!(CharacterData::String("x".to_string()).string_value().is_some());
620 assert!(CharacterData::String("x".to_string()).float_value().is_none());
621
622 assert!(CharacterData::UnsignedInteger(1).unsigned_integer_value().is_some());
623 assert!(CharacterData::UnsignedInteger(1).enum_value().is_none());
624 }
625
626 #[test]
627 fn parse_integer() {
628 let data = CharacterData::String("text".to_string());
629 let result = data.parse_integer::<u32>();
630 assert!(result.is_none());
631
632 let data = CharacterData::String("0x123412341234".to_string());
633 let result = data.parse_integer::<u32>();
634 assert!(result.is_none());
635
636 let data = CharacterData::String("0x1234".to_string());
637 let result = data.parse_integer::<u32>().unwrap();
638 assert_eq!(result, 0x1234);
639
640 let data = CharacterData::String("0X123456".to_string());
641 let result = data.parse_integer::<u32>().unwrap();
642 assert_eq!(result, 0x123456);
643
644 let data = CharacterData::String("0b1010".to_string());
645 let result = data.parse_integer::<u32>().unwrap();
646 assert_eq!(result, 10);
647
648 let data = CharacterData::String("0B101010".to_string());
649 let result = data.parse_integer::<u32>().unwrap();
650 assert_eq!(result, 42);
651
652 let data = CharacterData::String("0733".to_string());
653 let result = data.parse_integer::<u32>().unwrap();
654 assert_eq!(result, 475);
655
656 let data = CharacterData::String("0".to_string());
657 let result = data.parse_integer::<u32>().unwrap();
658 assert_eq!(result, 0);
659
660 let data = CharacterData::String("-55".to_string());
661 let result = data.parse_integer::<i32>().unwrap();
662 assert_eq!(result, -55);
663
664 let data = CharacterData::UnsignedInteger(0);
665 let result = data.parse_integer::<u32>().unwrap();
666 assert_eq!(result, 0);
667
668 let data = CharacterData::Float(0.0);
669 let result = data.parse_integer::<u32>();
670 assert!(result.is_none());
671 }
672
673 #[test]
674 fn parse_float() {
675 let data = CharacterData::String("text".to_string());
677 let result = data.parse_float();
678 assert!(result.is_none());
679
680 let data = CharacterData::String("0".to_string());
682 let result = data.parse_float().unwrap();
683 assert_eq!(result, 0.0);
684
685 let data = CharacterData::String("0xFFFFFFFFF".to_string());
687 let result = data.parse_float().unwrap();
688 assert_eq!(result, 68719476735.0);
689
690 let data = CharacterData::String("0x1.234".to_string());
692 let result = data.parse_float();
693 assert!(result.is_none());
694
695 let data = CharacterData::String("0.0001".to_string());
697 let result = data.parse_float().unwrap();
698 assert_eq!(result, 0.0001);
699
700 let data = CharacterData::String("1.234e5".to_string());
702 let result = data.parse_float().unwrap();
703 assert_eq!(result, 1.234e5);
704
705 let data = CharacterData::String("00.12".to_string());
707 let result = data.parse_float().unwrap();
708 assert_eq!(result, 0.12);
709
710 let data = CharacterData::String("NaN".to_string());
712 let result = data.parse_float().unwrap();
713 assert!(result.is_nan());
714
715 let data = CharacterData::String("INF".to_string());
717 let result = data.parse_float().unwrap();
718 assert!(result.is_infinite());
719
720 let data = CharacterData::String("0x1234".to_string());
722 let result = data.parse_float().unwrap();
723 assert_eq!(result, 4660.0);
724
725 let data = CharacterData::String("0X1234".to_string());
727 let result = data.parse_float().unwrap();
728 assert_eq!(result, 4660.0);
729
730 let data = CharacterData::String("0b1101".to_string());
732 let result = data.parse_float().unwrap();
733 assert_eq!(result, 13.0);
734
735 let data = CharacterData::String("0B1101".to_string());
737 let result = data.parse_float().unwrap();
738 assert_eq!(result, 13.0);
739
740 let data = CharacterData::String("0777".to_string());
742 let result = data.parse_float().unwrap();
743 assert_eq!(result, 511.0);
744
745 let data = CharacterData::UnsignedInteger(0);
747 let result = data.parse_float().unwrap();
748 assert_eq!(result, 0.0);
749
750 let data = CharacterData::Float(5.0);
752 let result = data.parse_float().unwrap();
753 assert_eq!(result, 5.0);
754
755 let data = CharacterData::Enum(EnumItem::Abstract);
757 let result = data.parse_float();
758 assert!(result.is_none());
759 }
760
761 #[test]
762 fn parse_bool() {
763 let data = CharacterData::String("true".to_string());
764 let result = data.parse_bool().unwrap();
765 assert!(result);
766
767 let data = CharacterData::String("1".to_string());
768 let result = data.parse_bool().unwrap();
769 assert!(result);
770
771 let data = CharacterData::String("false".to_string());
772 let result = data.parse_bool().unwrap();
773 assert!(!result);
774
775 let data = CharacterData::String("0".to_string());
776 let result = data.parse_bool().unwrap();
777 assert!(!result);
778
779 let data = CharacterData::String("text".to_string());
780 let result = data.parse_bool();
781 assert!(result.is_none());
782
783 let data = CharacterData::UnsignedInteger(0);
784 let result = data.parse_bool();
785 assert!(result.is_none());
786 }
787
788 #[test]
789 fn ordering() {
790 let enum1 = CharacterData::Enum(EnumItem::Abstract);
791 let enum2 = CharacterData::Enum(EnumItem::default);
792 assert!(enum1 < enum2);
793
794 let string1 = CharacterData::String("abcdef".to_string());
795 let string2 = CharacterData::String("text".to_string());
796 assert!(string1 < string2);
797
798 let integer1 = CharacterData::UnsignedInteger(123);
799 let integer2 = CharacterData::UnsignedInteger(456);
800 assert!(integer1 < integer2);
801
802 let float1 = CharacterData::Float(1.23);
803 let float2 = CharacterData::Float(4.56);
804 assert!(float1 < float2);
805
806 assert!(enum1 < string1);
808 assert!(enum1 < integer1);
809 assert!(enum1 < float1);
810 assert!(string1 > enum1);
811 assert!(string1 < integer1);
812 assert!(string1 < float1);
813 assert!(integer1 > enum1);
814 assert!(integer1 > string1);
815 assert!(integer1 < float1);
816 assert!(float1 > enum1);
817 assert!(float1 > string1);
818 assert!(float1 > integer1);
819
820 assert!(enum1.partial_cmp(&enum2).unwrap() == std::cmp::Ordering::Less);
822 }
823
824 #[test]
825 fn cdata_conversion() {
826 let cdata: CharacterData = 0.into();
827 assert_eq!(cdata, CharacterData::UnsignedInteger(0));
828
829 let cdata: CharacterData = (1.0).into();
830 assert_eq!(cdata, CharacterData::Float(1.0));
831
832 let cdata: CharacterData = "text".into();
833 assert_eq!(cdata, CharacterData::String("text".to_string()));
834
835 let cdata: CharacterData = String::from("text").into();
836 assert_eq!(cdata, CharacterData::String("text".to_string()));
837
838 let cdata: CharacterData = EnumItem::Abstract.into();
839 assert_eq!(cdata, CharacterData::Enum(EnumItem::Abstract));
840
841 let cdata: CharacterData = true.into();
842 assert_eq!(cdata, CharacterData::String("true".to_string()));
843 }
844}