• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

naomijub / serde_json_shape / 20495575397

24 Dec 2025 11:34PM UTC coverage: 51.955% (+0.1%) from 51.838%
20495575397

push

github

web-flow
chore: Configure Renovate (#13)

* Add renovate.json

* fix

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Julia Naomi <jnboeira@outlook.com>

102 of 190 new or added lines in 5 files covered. (53.68%)

4 existing lines in 1 file now uncovered.

691 of 1330 relevant lines covered (51.95%)

2.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.45
/json_shape/src/value.rs
1
#![allow(clippy::match_same_arms)]
2
use std::{
3
    collections::{BTreeMap, BTreeSet, btree_map::Keys},
4
    fmt::Display,
5
};
6

7
use serde::{Deserialize, Serialize};
8

9
pub mod subset;
10
pub mod subtypes;
11

12
/// Helper trait to identify when two `JsonShapes` are similar but not necessarily equal, meaning they only diverge in being optional.
13
pub trait Similar<Rhs: ?Sized = Self> {
14
    /// Tests for `self` and `other` values to be similar (equal ignoring the optional), returning the optional version
15
    #[must_use]
16
    fn similar(&self, other: &Rhs) -> Option<Value>;
17
}
18

19
/// Represents any valid JSON value shape.
20
///
21
/// See the [`serde_json_shape::value` module documentation](self) for usage examples.
22
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
23
pub enum Value {
24
    /// Represents a JSON null value.
25
    Null,
26

27
    /// Represents a JSON boolean.
28
    Bool {
29
        /// If type is optional
30
        optional: bool,
31
    },
32

33
    /// Represents a JSON number.
34
    Number {
35
        /// If type is optional
36
        optional: bool,
37
    },
38
    /// Represents a JSON string.
39
    String {
40
        /// If type is optional
41
        optional: bool,
42
    },
43
    /// Represents a JSON array.
44
    Array {
45
        /// Type contained in the Array
46
        r#type: Box<Self>,
47
        /// If type is optional
48
        optional: bool,
49
    },
50

51
    /// Represents a JSON object.
52
    Object {
53
        /// Object internal members map, with key as `String` and value as [`JsonShape`]
54
        content: BTreeMap<String, Self>,
55
        /// If type is optional
56
        optional: bool,
57
    },
58

59
    /// Represents a JSON Value that can assume one of the Values described.
60
    /// Similar to an enum containing different internal types in Rust.
61
    OneOf {
62
        /// All possible [`JsonShape`] values
63
        variants: BTreeSet<Self>,
64
        /// If type is optional
65
        optional: bool,
66
    },
67

68
    /// Represents a JSON Array that behaves like a tuple.
69
    /// Similar to a Rust tuple, types are always the same and in same order
70
    Tuple {
71
        /// [`JsonShape`] order
72
        elements: Vec<Self>,
73
        /// If type is optional
74
        optional: bool,
75
    },
76
}
77

78
impl Value {
79
    /// Is this [`JsonShape`] optional? eg, `Option<String>`
80
    #[must_use]
81
    pub const fn is_optional(&self) -> bool {
7✔
82
        match self {
7✔
83
            Self::Null => true,
1✔
84
            Self::Bool { optional } => *optional,
4✔
85
            Self::Number { optional } => *optional,
4✔
86
            Self::String { optional } => *optional,
7✔
87
            Self::Array { optional, .. } => *optional,
1✔
88
            Self::Object { optional, .. } => *optional,
1✔
89
            Self::OneOf { optional, .. } => *optional,
1✔
90
            Self::Tuple { optional, .. } => *optional,
1✔
91
        }
92
    }
93

94
    #[allow(clippy::wrong_self_convention)]
95
    pub(crate) fn as_optional(self) -> Self {
5✔
96
        match self {
5✔
NEW
97
            Self::Null => Self::Null,
×
98
            Self::Bool { .. } => Self::Bool { optional: true },
99
            Self::Number { .. } => Self::Number { optional: true },
100
            Self::String { .. } => Self::String { optional: true },
101
            Self::Array { r#type, .. } => Self::Array {
102
                optional: true,
103
                r#type,
104
            },
105
            Self::Object { content, .. } => Self::Object {
106
                optional: true,
107
                content,
108
            },
109
            Self::OneOf { variants, .. } => Self::OneOf {
110
                optional: true,
111
                variants,
112
            },
113
            Self::Tuple { elements, .. } => Self::Tuple {
114
                optional: true,
115
                elements,
116
            },
117
        }
118
    }
119

120
    #[allow(clippy::wrong_self_convention)]
121
    pub(crate) fn as_non_optional(self) -> Self {
6✔
122
        match self {
6✔
NEW
123
            Self::Null => Self::Null,
×
124
            Self::Bool { .. } => Self::Bool { optional: false },
125
            Self::Number { .. } => Self::Number { optional: false },
126
            Self::String { .. } => Self::String { optional: false },
127
            Self::Array { r#type, .. } => Self::Array {
128
                optional: false,
129
                r#type,
130
            },
131
            Self::Object { content, .. } => Self::Object {
132
                optional: false,
133
                content,
134
            },
135
            Self::OneOf { variants, .. } => Self::OneOf {
136
                optional: false,
137
                variants,
138
            },
139
            Self::Tuple { elements, .. } => Self::Tuple {
140
                optional: false,
141
                elements,
142
            },
143
        }
144
    }
145

146
    pub(crate) const fn to_optional_mut(&mut self) {
5✔
147
        match self {
5✔
148
            Self::Null => (),
149
            Self::Bool { optional } => {
1✔
150
                *optional = true;
1✔
151
            }
152
            Self::Number { optional } => {
5✔
153
                *optional = true;
5✔
154
            }
155
            Self::String { optional } => {
1✔
156
                *optional = true;
1✔
157
            }
NEW
158
            Self::Array { optional, .. } => {
×
159
                *optional = true;
×
160
            }
NEW
161
            Self::Object { optional, .. } => {
×
162
                *optional = true;
×
163
            }
NEW
164
            Self::OneOf { optional, .. } => {
×
165
                *optional = true;
×
166
            }
NEW
167
            Self::Tuple { optional, .. } => {
×
168
                *optional = true;
×
169
            }
170
        }
171
    }
172

173
    /// Return the keys contained in a [`JsonShape::Object`]
174
    #[must_use]
175
    pub fn keys(&self) -> Option<Keys<'_, String, Self>> {
5✔
176
        if let Self::Object { content, .. } = self {
10✔
177
            Some(content.keys())
5✔
178
        } else {
179
            None
1✔
180
        }
181
    }
182

183
    /// Checks if Json Node is null
184
    #[must_use]
185
    pub const fn is_null(&self) -> bool {
3✔
186
        matches!(self, Self::Null)
4✔
187
    }
188

189
    /// Checks if Json Node is boolean
190
    #[must_use]
191
    pub const fn is_boolean(&self) -> bool {
3✔
192
        matches!(self, Self::Bool { .. })
3✔
193
    }
194

195
    /// Checks if Json Node is number
196
    #[must_use]
197
    pub const fn is_number(&self) -> bool {
9✔
198
        matches!(self, Self::Number { .. })
10✔
199
    }
200

201
    /// Checks if Json Node is string
202
    #[must_use]
203
    pub const fn is_string(&self) -> bool {
8✔
204
        matches!(self, Self::String { .. })
8✔
205
    }
206

207
    /// Checks if Json Node is array
208
    #[must_use]
209
    pub const fn is_array(&self) -> bool {
1✔
210
        matches!(self, Self::Array { .. })
1✔
211
    }
212

213
    /// Checks if Json Node is tuple
214
    #[must_use]
215
    pub const fn is_tuple(&self) -> bool {
1✔
216
        matches!(self, Self::Tuple { .. })
1✔
217
    }
218

219
    /// Checks if Json Node is object
220
    #[must_use]
221
    pub const fn is_object(&self) -> bool {
1✔
222
        matches!(self, Self::Object { .. })
1✔
223
    }
224

225
    /// Checks if Json Node is one of
226
    #[must_use]
227
    pub const fn is_oneof(&self) -> bool {
1✔
228
        matches!(self, Self::OneOf { .. })
1✔
229
    }
230
}
231

232
impl Display for Value {
233
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
5✔
234
        match self {
5✔
235
            Self::Null => write!(f, "Null"),
4✔
236
            Self::Bool { optional } => write!(
6✔
237
                f,
238
                "{}",
239
                if *optional {
6✔
240
                    "Option<Boolean>"
3✔
241
                } else {
242
                    "Boolean"
3✔
243
                }
244
            ),
245
            Self::Number { optional } => write!(
10✔
246
                f,
247
                "{}",
248
                if *optional {
10✔
249
                    "Option<Number>"
4✔
250
                } else {
251
                    "Number"
5✔
252
                }
253
            ),
254
            Self::String { optional } => write!(
10✔
255
                f,
256
                "{}",
257
                if *optional {
10✔
258
                    "Option<String>"
3✔
259
                } else {
260
                    "String"
5✔
261
                }
262
            ),
263
            Self::Array { r#type, optional } => {
5✔
264
                if *optional {
5✔
265
                    write!(f, "Option<Array<{type}>>")
1✔
266
                } else {
267
                    write!(f, "Array<{type}>")
5✔
268
                }
269
            }
270
            Self::Object { content, optional } => {
5✔
271
                if *optional {
5✔
272
                    write!(f, "Option<Object{{{}}}>", display_object_content(content))
1✔
273
                } else {
274
                    write!(f, "Object{{{}}}", display_object_content(content))
5✔
275
                }
276
            }
277
            Self::OneOf { variants, optional } => {
3✔
278
                let variants = variants
3✔
279
                    .iter()
280
                    .map(ToString::to_string)
3✔
281
                    .collect::<Vec<_>>()
282
                    .join(" | ");
283
                if *optional {
4✔
284
                    write!(f, "Option<OneOf[{variants}]>",)
2✔
285
                } else {
286
                    write!(f, "OneOf[{variants}]",)
6✔
287
                }
288
            }
289
            Self::Tuple { elements, optional } => {
5✔
290
                let elements = elements
9✔
291
                    .iter()
292
                    .map(ToString::to_string)
5✔
293
                    .collect::<Vec<_>>()
294
                    .join(", ");
295
                if *optional {
5✔
296
                    write!(f, "Option<Tuple({elements})>",)
2✔
297
                } else {
298
                    write!(f, "Tuple({elements})",)
11✔
299
                }
300
            }
301
        }
302
    }
303
}
304

305
impl Similar for Value {
306
    fn similar(&self, other: &Self) -> Option<Value> {
1✔
307
        match (self, other) {
3✔
308
            (Self::Null, Self::Null) => Some(Self::Null),
1✔
309
            (Self::Bool { optional }, Self::Bool { optional: opt }) => Some(Self::Bool {
2✔
310
                optional: *optional || *opt,
1✔
311
            }),
312
            (Self::Number { optional }, Self::Number { optional: opt }) => Some(Self::Number {
2✔
313
                optional: *optional || *opt,
1✔
314
            }),
315
            (Self::String { optional }, Self::String { optional: opt }) => Some(Self::String {
2✔
316
                optional: *optional || *opt,
1✔
317
            }),
318
            (
1✔
319
                Self::Array { r#type, optional },
320
                Self::Array {
321
                    r#type: ty,
322
                    optional: opt,
323
                },
324
            ) if ty == r#type => Some(Self::Array {
325
                r#type: ty.clone(),
1✔
326
                optional: *optional || *opt,
1✔
327
            }),
328
            (
1✔
329
                Self::Object { content, optional },
330
                Self::Object {
331
                    content: cont,
332
                    optional: opt,
333
                },
334
            ) if cont == content => Some(Self::Object {
335
                content: content.clone(),
1✔
336
                optional: *optional || *opt,
1✔
337
            }),
338
            (
1✔
339
                Self::OneOf { variants, optional },
340
                Self::OneOf {
341
                    variants: var,
342
                    optional: opt,
343
                },
344
            ) if var == variants => Some(Self::OneOf {
345
                variants: variants.clone(),
1✔
346
                optional: *optional || *opt,
1✔
347
            }),
348
            (
1✔
349
                Self::Tuple { elements, optional },
350
                Self::Tuple {
351
                    elements: ty,
352
                    optional: opt,
353
                },
354
            ) if ty == elements => Some(Self::Tuple {
355
                elements: ty.clone(),
1✔
356
                optional: *optional || *opt,
1✔
357
            }),
358
            _ => None,
1✔
359
        }
360
    }
361
}
362

363
fn display_object_content(content: &BTreeMap<String, Value>) -> String {
5✔
364
    content
5✔
365
        .iter()
366
        .map(|(key, value)| {
17✔
367
            if key
12✔
368
                .chars()
6✔
369
                .all(|char| char.is_alphanumeric() || char == '_' || char == '-')
18✔
370
            {
371
                format!("{key}: {value}")
5✔
372
            } else {
373
                format!("\"{key}\": {value}")
5✔
374
            }
375
        })
376
        .collect::<Vec<_>>()
377
        .join(", ")
378
}
379

380
#[cfg(test)]
381
mod tests {
382
    use super::*;
383

384
    #[test]
385
    fn is_optional_returns_true_when_values_are_optional() {
386
        assert!(Value::Null.is_optional());
387
        assert!(Value::Bool { optional: true }.is_optional());
388
        assert!(Value::Number { optional: true }.is_optional());
389
        assert!(Value::String { optional: true }.is_optional());
390
        assert!(
391
            Value::Array {
392
                optional: true,
393
                r#type: Box::new(Value::Null)
394
            }
395
            .is_optional()
396
        );
397
        assert!(
398
            Value::Tuple {
399
                optional: true,
400
                elements: vec![Value::Null]
401
            }
402
            .is_optional()
403
        );
404
        assert!(
405
            Value::Object {
406
                optional: true,
407
                content: BTreeMap::default()
408
            }
409
            .is_optional()
410
        );
411
        assert!(
412
            Value::OneOf {
413
                optional: true,
414
                variants: BTreeSet::default()
415
            }
416
            .is_optional()
417
        );
418
    }
419

420
    #[test]
421
    fn is_optional_returns_false_when_values_are_not_optional() {
422
        assert!(!Value::Bool { optional: false }.is_optional());
423
        assert!(!Value::Number { optional: false }.is_optional());
424
        assert!(!Value::String { optional: false }.is_optional());
425
        assert!(
426
            !Value::Array {
427
                optional: false,
428
                r#type: Box::new(Value::Null)
429
            }
430
            .is_optional()
431
        );
432
        assert!(
433
            !Value::Tuple {
434
                optional: false,
435
                elements: vec![Value::Null]
436
            }
437
            .is_optional()
438
        );
439
        assert!(
440
            !Value::Object {
441
                optional: false,
442
                content: BTreeMap::default()
443
            }
444
            .is_optional()
445
        );
446
        assert!(
447
            !Value::OneOf {
448
                optional: false,
449
                variants: BTreeSet::default()
450
            }
451
            .is_optional()
452
        );
453
    }
454

455
    #[test]
456
    fn as_optional_returns_optional_version_of_values() {
457
        assert!(Value::Bool { optional: false }.as_optional().is_optional());
458
        assert!(
459
            Value::Number { optional: false }
460
                .as_optional()
461
                .is_optional()
462
        );
463
        assert!(
464
            Value::String { optional: false }
465
                .as_optional()
466
                .is_optional()
467
        );
468
        assert!(
469
            Value::Array {
470
                optional: false,
471
                r#type: Box::new(Value::Null)
472
            }
473
            .as_optional()
474
            .is_optional()
475
        );
476
        assert!(
477
            Value::Object {
478
                optional: false,
479
                content: BTreeMap::default()
480
            }
481
            .as_optional()
482
            .is_optional()
483
        );
484
        assert!(
485
            Value::OneOf {
486
                optional: false,
487
                variants: BTreeSet::default()
488
            }
489
            .as_optional()
490
            .is_optional()
491
        );
492
        assert!(
493
            Value::Tuple {
494
                optional: false,
495
                elements: vec![Value::Null]
496
            }
497
            .as_optional()
498
            .is_optional()
499
        );
500
    }
501

502
    #[test]
503
    fn keys_returns_keys_only_for_object() {
504
        assert!(Value::Null.keys().is_none());
505
        assert!(Value::Bool { optional: true }.keys().is_none());
506
        assert!(Value::Number { optional: true }.keys().is_none());
507
        assert!(Value::String { optional: true }.keys().is_none());
508
        assert!(
509
            Value::Array {
510
                optional: true,
511
                r#type: Box::new(Value::Null)
512
            }
513
            .keys()
514
            .is_none()
515
        );
516
        assert!(
517
            Value::OneOf {
518
                optional: true,
519
                variants: BTreeSet::default()
520
            }
521
            .keys()
522
            .is_none()
523
        );
524
        assert!(
525
            Value::Tuple {
526
                optional: true,
527
                elements: Vec::default()
528
            }
529
            .keys()
530
            .is_none()
531
        );
532
        assert_eq!(
533
            Value::Object {
534
                optional: true,
535
                content: [
536
                    ("key_1".to_string(), Value::Null),
537
                    ("key_2".to_string(), Value::Null),
538
                ]
539
                .into()
540
            }
541
            .keys()
542
            .unwrap()
543
            .collect::<Vec<_>>(),
544
            vec!["key_1", "key_2"]
545
        );
546
    }
547

548
    #[test]
549
    fn to_string_for_optional_values() {
550
        assert_eq!(Value::Null.to_string(), "Null");
551
        assert_eq!(
552
            Value::Bool { optional: true }.to_string(),
553
            "Option<Boolean>"
554
        );
555
        assert_eq!(
556
            Value::Number { optional: true }.to_string(),
557
            "Option<Number>"
558
        );
559
        assert_eq!(
560
            Value::String { optional: true }.to_string(),
561
            "Option<String>"
562
        );
563
        assert_eq!(
564
            Value::Array {
565
                optional: true,
566
                r#type: Box::new(Value::Null)
567
            }
568
            .to_string(),
569
            "Option<Array<Null>>"
570
        );
571
        assert_eq!(
572
            Value::Object {
573
                optional: true,
574
                content: BTreeMap::default()
575
            }
576
            .to_string(),
577
            "Option<Object{}>"
578
        );
579
        assert_eq!(
580
            Value::Object {
581
                optional: true,
582
                content: [
583
                    ("key_1".to_string(), Value::Null),
584
                    ("key_2".to_string(), Value::Number { optional: true }),
585
                    ("key_3".to_string(), Value::Number { optional: false })
586
                ]
587
                .into()
588
            }
589
            .to_string(),
590
            "Option<Object{key_1: Null, key_2: Option<Number>, key_3: Number}>"
591
        );
592
        assert_eq!(
593
            Value::OneOf {
594
                optional: true,
595
                variants: [
596
                    Value::Null,
597
                    Value::Number { optional: true },
598
                    Value::Number { optional: false }
599
                ]
600
                .into()
601
            }
602
            .to_string(),
603
            "Option<OneOf[Null | Number | Option<Number>]>"
604
        );
605
        assert_eq!(
606
            Value::Tuple {
607
                optional: true,
608
                elements: [
609
                    Value::Null,
610
                    Value::Number { optional: true },
611
                    Value::Number { optional: false }
612
                ]
613
                .into()
614
            }
615
            .to_string(),
616
            "Option<Tuple(Null, Option<Number>, Number)>"
617
        );
618
    }
619

620
    #[test]
621
    fn to_string_for_non_optional_values() {
622
        assert_eq!(Value::Bool { optional: false }.to_string(), "Boolean");
623
        assert_eq!(Value::Number { optional: false }.to_string(), "Number");
624
        assert_eq!(Value::String { optional: false }.to_string(), "String");
625
        assert_eq!(
626
            Value::Array {
627
                optional: false,
628
                r#type: Box::new(Value::Null)
629
            }
630
            .to_string(),
631
            "Array<Null>"
632
        );
633
        assert_eq!(
634
            Value::Object {
635
                optional: false,
636
                content: BTreeMap::default()
637
            }
638
            .to_string(),
639
            "Object{}"
640
        );
641
        assert_eq!(
642
            Value::Object {
643
                optional: false,
644
                content: [
645
                    ("key_1".to_string(), Value::Null),
646
                    ("key_2".to_string(), Value::Number { optional: true }),
647
                    ("key_3".to_string(), Value::Number { optional: false })
648
                ]
649
                .into()
650
            }
651
            .to_string(),
652
            "Object{key_1: Null, key_2: Option<Number>, key_3: Number}"
653
        );
654
        assert_eq!(
655
            Value::OneOf {
656
                optional: false,
657
                variants: [
658
                    Value::Null,
659
                    Value::Number { optional: false },
660
                    Value::Number { optional: true }
661
                ]
662
                .into()
663
            }
664
            .to_string(),
665
            "OneOf[Null | Number | Option<Number>]"
666
        );
667
        assert_eq!(
668
            Value::Tuple {
669
                optional: false,
670
                elements: [
671
                    Value::Null,
672
                    Value::Number { optional: true },
673
                    Value::Number { optional: false }
674
                ]
675
                .into()
676
            }
677
            .to_string(),
678
            "Tuple(Null, Option<Number>, Number)"
679
        );
680
    }
681

682
    #[test]
683
    fn to_optional_mut_transforms_value_inline_as_ref_mut() {
684
        let mut v = Value::Bool { optional: false };
685
        assert!(!v.is_optional());
686
        v.to_optional_mut();
687
        assert!(v.is_optional());
688
        let mut v = Value::Number { optional: false };
689
        assert!(!v.is_optional());
690
        v.to_optional_mut();
691
        assert!(v.is_optional());
692
        let mut v = Value::String { optional: false };
693
        assert!(!v.is_optional());
694
        v.to_optional_mut();
695
        assert!(v.is_optional());
696
    }
697

698
    #[test]
699
    fn parse_multiple_keys() {
700
        let map = [
701
            ("key_value_1".to_string(), Value::Null),
702
            ("key-value-1".to_string(), Value::Null),
703
            ("KeyValue1".to_string(), Value::Null),
704
            ("key value 1".to_string(), Value::Null),
705
            ("key_value?".to_string(), Value::Null),
706
            ("key_value!".to_string(), Value::Null),
707
        ]
708
        .into();
709

710
        let s = display_object_content(&map);
711

712
        assert_eq!(
713
            s,
714
            "KeyValue1: Null, \"key value 1\": Null, key-value-1: Null, \"key_value!\": Null, \"key_value?\": Null, key_value_1: Null"
715
        );
716
    }
717
}
718

719
#[cfg(test)]
720
mod tests_is_a {
721
    use super::*;
722

723
    #[test]
724
    fn only_string_is_a_string() {
725
        assert!(Value::String { optional: false }.is_string());
726
        assert!(Value::String { optional: true }.is_string());
727
        assert!(!Value::Null.is_string());
728
        assert!(!Value::Bool { optional: false }.is_string());
729
        assert!(!Value::Number { optional: false }.is_string());
730
        assert!(
731
            !Value::Array {
732
                optional: false,
733
                r#type: Box::new(Value::Null)
734
            }
735
            .is_string()
736
        );
737
        assert!(
738
            !Value::Object {
739
                optional: false,
740
                content: BTreeMap::default()
741
            }
742
            .is_string()
743
        );
744
        assert!(
745
            !Value::OneOf {
746
                optional: false,
747
                variants: BTreeSet::default()
748
            }
749
            .is_string()
750
        );
751
        assert!(
752
            !Value::Tuple {
753
                optional: false,
754
                elements: Vec::default()
755
            }
756
            .is_string()
757
        );
758
    }
759

760
    #[test]
761
    fn only_number_is_a_number() {
762
        assert!(!Value::String { optional: false }.is_number());
763
        assert!(!Value::Null.is_number());
764
        assert!(!Value::Bool { optional: false }.is_number());
765
        assert!(Value::Number { optional: false }.is_number());
766
        assert!(Value::Number { optional: true }.is_number());
767
        assert!(
768
            !Value::Array {
769
                optional: false,
770
                r#type: Box::new(Value::Null)
771
            }
772
            .is_number()
773
        );
774
        assert!(
775
            !Value::Object {
776
                optional: false,
777
                content: BTreeMap::default()
778
            }
779
            .is_number()
780
        );
781
        assert!(
782
            !Value::OneOf {
783
                optional: false,
784
                variants: BTreeSet::default()
785
            }
786
            .is_number()
787
        );
788
        assert!(
789
            !Value::Tuple {
790
                optional: false,
791
                elements: Vec::default()
792
            }
793
            .is_number()
794
        );
795
    }
796

797
    #[test]
798
    fn only_null_is_null() {
799
        assert!(!Value::String { optional: false }.is_null());
800
        assert!(Value::Null.is_null());
801
        assert!(!Value::Bool { optional: false }.is_null());
802
        assert!(!Value::Number { optional: true }.is_null());
803
        assert!(
804
            !Value::Array {
805
                optional: false,
806
                r#type: Box::new(Value::Null)
807
            }
808
            .is_null()
809
        );
810
        assert!(
811
            !Value::Object {
812
                optional: false,
813
                content: BTreeMap::default()
814
            }
815
            .is_null()
816
        );
817
        assert!(
818
            !Value::OneOf {
819
                optional: false,
820
                variants: BTreeSet::default()
821
            }
822
            .is_null()
823
        );
824
        assert!(
825
            !Value::Tuple {
826
                optional: false,
827
                elements: Vec::default()
828
            }
829
            .is_null()
830
        );
831
    }
832

833
    #[test]
834
    fn only_bool_is_bool() {
835
        assert!(!Value::String { optional: false }.is_boolean());
836
        assert!(!Value::Null.is_boolean());
837
        assert!(Value::Bool { optional: false }.is_boolean());
838
        assert!(!Value::Number { optional: true }.is_boolean());
839
        assert!(
840
            !Value::Array {
841
                optional: false,
842
                r#type: Box::new(Value::Null)
843
            }
844
            .is_boolean()
845
        );
846
        assert!(
847
            !Value::Object {
848
                optional: false,
849
                content: BTreeMap::default()
850
            }
851
            .is_boolean()
852
        );
853
        assert!(
854
            !Value::OneOf {
855
                optional: false,
856
                variants: BTreeSet::default()
857
            }
858
            .is_boolean()
859
        );
860
        assert!(
861
            !Value::Tuple {
862
                optional: false,
863
                elements: Vec::default()
864
            }
865
            .is_boolean()
866
        );
867
    }
868

869
    #[test]
870
    fn only_array_is_array() {
871
        assert!(!Value::String { optional: false }.is_array());
872
        assert!(!Value::Null.is_array());
873
        assert!(!Value::Bool { optional: false }.is_array());
874
        assert!(!Value::Number { optional: true }.is_array());
875
        assert!(
876
            Value::Array {
877
                optional: false,
878
                r#type: Box::new(Value::Null)
879
            }
880
            .is_array()
881
        );
882
        assert!(
883
            !Value::Object {
884
                optional: false,
885
                content: BTreeMap::default()
886
            }
887
            .is_array()
888
        );
889
        assert!(
890
            !Value::OneOf {
891
                optional: false,
892
                variants: BTreeSet::default()
893
            }
894
            .is_array()
895
        );
896
        assert!(
897
            !Value::Tuple {
898
                optional: false,
899
                elements: Vec::default()
900
            }
901
            .is_array()
902
        );
903
    }
904

905
    #[test]
906
    fn only_object_is_object() {
907
        assert!(!Value::String { optional: false }.is_object());
908
        assert!(!Value::Null.is_object());
909
        assert!(!Value::Bool { optional: false }.is_object());
910
        assert!(!Value::Number { optional: true }.is_object());
911
        assert!(
912
            !Value::Array {
913
                optional: false,
914
                r#type: Box::new(Value::Null)
915
            }
916
            .is_object()
917
        );
918
        assert!(
919
            Value::Object {
920
                optional: false,
921
                content: BTreeMap::default()
922
            }
923
            .is_object()
924
        );
925
        assert!(
926
            !Value::OneOf {
927
                optional: false,
928
                variants: BTreeSet::default()
929
            }
930
            .is_object()
931
        );
932
        assert!(
933
            !Value::Tuple {
934
                optional: false,
935
                elements: Vec::default()
936
            }
937
            .is_object()
938
        );
939
    }
940

941
    #[test]
942
    fn only_one_of_is_one_of() {
943
        assert!(!Value::String { optional: false }.is_oneof());
944
        assert!(!Value::Null.is_oneof());
945
        assert!(!Value::Bool { optional: false }.is_oneof());
946
        assert!(!Value::Number { optional: true }.is_oneof());
947
        assert!(
948
            !Value::Array {
949
                optional: false,
950
                r#type: Box::new(Value::Null)
951
            }
952
            .is_oneof()
953
        );
954
        assert!(
955
            !Value::Object {
956
                optional: false,
957
                content: BTreeMap::default()
958
            }
959
            .is_oneof()
960
        );
961
        assert!(
962
            Value::OneOf {
963
                optional: false,
964
                variants: BTreeSet::default()
965
            }
966
            .is_oneof()
967
        );
968
        assert!(
969
            !Value::Tuple {
970
                optional: false,
971
                elements: Vec::default()
972
            }
973
            .is_oneof()
974
        );
975
    }
976

977
    #[test]
978
    fn only_tuple_is_tuple() {
979
        assert!(!Value::String { optional: false }.is_tuple());
980
        assert!(!Value::Null.is_tuple());
981
        assert!(!Value::Bool { optional: false }.is_tuple());
982
        assert!(!Value::Number { optional: true }.is_tuple());
983
        assert!(
984
            !Value::Array {
985
                optional: false,
986
                r#type: Box::new(Value::Null)
987
            }
988
            .is_tuple()
989
        );
990
        assert!(
991
            !Value::Object {
992
                optional: false,
993
                content: BTreeMap::default()
994
            }
995
            .is_tuple()
996
        );
997
        assert!(
998
            !Value::OneOf {
999
                optional: false,
1000
                variants: BTreeSet::default()
1001
            }
1002
            .is_tuple()
1003
        );
1004
        assert!(
1005
            Value::Tuple {
1006
                optional: false,
1007
                elements: Vec::default()
1008
            }
1009
            .is_tuple()
1010
        );
1011
    }
1012
}
1013

1014
#[cfg(test)]
1015
mod tests_similar {
1016
    use super::*;
1017

1018
    #[test]
1019
    fn null_is_similar_to_null() {
1020
        assert!(Value::Null.similar(&Value::Null).is_some());
1021
        assert!(
1022
            Value::Null
1023
                .similar(&Value::String { optional: false })
1024
                .is_none()
1025
        );
1026
    }
1027

1028
    #[test]
1029
    fn str_is_similar_to_str() {
1030
        assert_eq!(
1031
            Value::String { optional: false }.similar(&Value::String { optional: false }),
1032
            Some(Value::String { optional: false })
1033
        );
1034
        assert_eq!(
1035
            Value::String { optional: false }.similar(&Value::String { optional: true }),
1036
            Some(Value::String { optional: true })
1037
        );
1038
        assert_eq!(
1039
            Value::String { optional: false }.similar(&Value::Number { optional: true }),
1040
            None
1041
        );
1042
    }
1043

1044
    #[test]
1045
    fn bool_is_similar_to_bool() {
1046
        assert_eq!(
1047
            Value::Bool { optional: false }.similar(&Value::Bool { optional: false }),
1048
            Some(Value::Bool { optional: false })
1049
        );
1050
        assert_eq!(
1051
            Value::Bool { optional: false }.similar(&Value::Bool { optional: true }),
1052
            Some(Value::Bool { optional: true })
1053
        );
1054
        assert_eq!(
1055
            Value::Bool { optional: false }.similar(&Value::Number { optional: true }),
1056
            None
1057
        );
1058
    }
1059

1060
    #[test]
1061
    fn number_is_similar_to_number() {
1062
        assert_eq!(
1063
            Value::Number { optional: false }.similar(&Value::Number { optional: false }),
1064
            Some(Value::Number { optional: false })
1065
        );
1066
        assert_eq!(
1067
            Value::Number { optional: false }.similar(&Value::Number { optional: true }),
1068
            Some(Value::Number { optional: true })
1069
        );
1070
        assert_eq!(
1071
            Value::Number { optional: false }.similar(&Value::Bool { optional: true }),
1072
            None
1073
        );
1074
    }
1075

1076
    #[test]
1077
    fn object_is_similar_to_object() {
1078
        assert_eq!(
1079
            Value::Object {
1080
                optional: false,
1081
                content: BTreeMap::default()
1082
            }
1083
            .similar(&Value::Object {
1084
                optional: false,
1085
                content: BTreeMap::default()
1086
            }),
1087
            Some(Value::Object {
1088
                optional: false,
1089
                content: BTreeMap::default()
1090
            })
1091
        );
1092
        assert_eq!(
1093
            Value::Object {
1094
                optional: false,
1095
                content: BTreeMap::default()
1096
            }
1097
            .similar(&Value::Object {
1098
                optional: true,
1099
                content: BTreeMap::default()
1100
            }),
1101
            Some(Value::Object {
1102
                optional: true,
1103
                content: BTreeMap::default()
1104
            })
1105
        );
1106
        assert_eq!(
1107
            Value::Object {
1108
                optional: false,
1109
                content: BTreeMap::default()
1110
            }
1111
            .similar(&Value::Bool { optional: true }),
1112
            None
1113
        );
1114
    }
1115

1116
    #[test]
1117
    fn array_is_similar_to_array() {
1118
        assert_eq!(
1119
            Value::Array {
1120
                r#type: Box::new(Value::Null),
1121
                optional: false
1122
            }
1123
            .similar(&Value::Array {
1124
                r#type: Box::new(Value::Null),
1125
                optional: false
1126
            }),
1127
            Some(Value::Array {
1128
                r#type: Box::new(Value::Null),
1129
                optional: false
1130
            })
1131
        );
1132
        assert_eq!(
1133
            Value::Array {
1134
                r#type: Box::new(Value::Null),
1135
                optional: false
1136
            }
1137
            .similar(&Value::Array {
1138
                r#type: Box::new(Value::Null),
1139
                optional: true
1140
            }),
1141
            Some(Value::Array {
1142
                r#type: Box::new(Value::Null),
1143
                optional: true
1144
            })
1145
        );
1146
        assert_eq!(
1147
            Value::Array {
1148
                r#type: Box::new(Value::Null),
1149
                optional: false
1150
            }
1151
            .similar(&Value::Bool { optional: true }),
1152
            None
1153
        );
1154
    }
1155

1156
    #[test]
1157
    fn oneof_is_similar_to_oneof() {
1158
        assert_eq!(
1159
            Value::OneOf {
1160
                variants: BTreeSet::new(),
1161
                optional: false
1162
            }
1163
            .similar(&Value::OneOf {
1164
                variants: BTreeSet::new(),
1165
                optional: false
1166
            }),
1167
            Some(Value::OneOf {
1168
                variants: BTreeSet::new(),
1169
                optional: false
1170
            })
1171
        );
1172
        assert_eq!(
1173
            Value::OneOf {
1174
                variants: BTreeSet::new(),
1175
                optional: false
1176
            }
1177
            .similar(&Value::OneOf {
1178
                variants: BTreeSet::new(),
1179
                optional: true
1180
            }),
1181
            Some(Value::OneOf {
1182
                variants: BTreeSet::new(),
1183
                optional: true
1184
            })
1185
        );
1186
        assert_eq!(
1187
            Value::OneOf {
1188
                variants: BTreeSet::new(),
1189
                optional: false
1190
            }
1191
            .similar(&Value::Bool { optional: true }),
1192
            None
1193
        );
1194
    }
1195

1196
    #[test]
1197
    fn tuple_is_similar_to_tuple() {
1198
        assert_eq!(
1199
            Value::Tuple {
1200
                elements: Vec::new(),
1201
                optional: false
1202
            }
1203
            .similar(&Value::Tuple {
1204
                elements: Vec::new(),
1205
                optional: false
1206
            }),
1207
            Some(Value::Tuple {
1208
                elements: Vec::new(),
1209
                optional: false
1210
            })
1211
        );
1212
        assert_eq!(
1213
            Value::Tuple {
1214
                elements: Vec::new(),
1215
                optional: false
1216
            }
1217
            .similar(&Value::Tuple {
1218
                elements: Vec::new(),
1219
                optional: true
1220
            }),
1221
            Some(Value::Tuple {
1222
                elements: Vec::new(),
1223
                optional: true
1224
            })
1225
        );
1226
        assert_eq!(
1227
            Value::Tuple {
1228
                elements: Vec::new(),
1229
                optional: false
1230
            }
1231
            .similar(&Value::Bool { optional: true }),
1232
            None
1233
        );
1234
    }
1235
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc