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

kaidokert / picojson-rs / 16187081362

10 Jul 2025 05:39AM UTC coverage: 93.209% (-0.4%) from 93.636%
16187081362

Pull #48

github

kaidokert
Error handling
Pull Request #48: Error handling

5 of 27 new or added lines in 4 files covered. (18.52%)

12 existing lines in 1 file now uncovered.

4296 of 4609 relevant lines covered (93.21%)

546.36 hits per line

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

50.0
/picojson/src/parse_error.rs
1
// SPDX-License-Identifier: Apache-2.0
2

3
use crate::shared::UnexpectedState;
4
use crate::slice_input_buffer;
5
use crate::stream_buffer;
6

7
use crate::ujson;
8

9
/// Errors that can occur during JSON parsing
10
#[derive(Debug, PartialEq)]
11
pub enum ParseError {
12
    /// An error bubbled up from the underlying tokenizer.
13
    TokenizerError(ujson::Error),
14
    /// The provided scratch buffer was not large enough for an operation.
15
    ScratchBufferFull,
16
    /// A string slice was not valid UTF-8.
17
    InvalidUtf8(core::str::Utf8Error),
18
    /// A number string could not be parsed.
19
    InvalidNumber,
20
    /// The parser entered an unexpected internal state.
21
    Unexpected(UnexpectedState),
22
    /// End of input data.
23
    EndOfData,
24
    /// Invalid hex digits in Unicode escape sequence.
25
    InvalidUnicodeHex,
26
    /// Valid hex but invalid Unicode codepoint.
27
    InvalidUnicodeCodepoint,
28
    /// Invalid escape sequence character.
29
    InvalidEscapeSequence,
30
    /// Float encountered but float support is disabled and float-error is configured
31
    FloatNotAllowed,
32
    /// Error from the underlying reader (I/O error, not end-of-stream)
33
    ReaderError,
34
    /// Numeric overflow
35
    NumericOverflow,
36
}
37

38
impl From<slice_input_buffer::Error> for ParseError {
39
    fn from(err: slice_input_buffer::Error) -> Self {
×
40
        match err {
×
41
            slice_input_buffer::Error::ReachedEnd => ParseError::EndOfData,
×
42
            slice_input_buffer::Error::InvalidSliceBounds => {
43
                UnexpectedState::InvalidSliceBounds.into()
×
44
            }
45
        }
46
    }
×
47
}
48

49
impl From<stream_buffer::StreamBufferError> for ParseError {
50
    fn from(err: stream_buffer::StreamBufferError) -> Self {
×
51
        match err {
×
52
            stream_buffer::StreamBufferError::BufferFull => ParseError::ScratchBufferFull,
×
53
            stream_buffer::StreamBufferError::EndOfData => ParseError::EndOfData,
×
54
            stream_buffer::StreamBufferError::Unexpected => {
55
                ParseError::Unexpected(UnexpectedState::BufferCapacityExceeded)
×
56
            }
57
            stream_buffer::StreamBufferError::InvalidSliceBounds => {
58
                ParseError::Unexpected(UnexpectedState::InvalidSliceBounds)
×
59
            }
60
        }
61
    }
×
62
}
63

64
impl From<core::str::Utf8Error> for ParseError {
65
    fn from(err: core::str::Utf8Error) -> Self {
1✔
66
        ParseError::InvalidUtf8(err)
1✔
67
    }
1✔
68
}
69

70
impl From<UnexpectedState> for ParseError {
71
    fn from(info: UnexpectedState) -> Self {
5✔
72
        ParseError::Unexpected(info)
5✔
73
    }
5✔
74
}
75

76
impl core::fmt::Display for ParseError {
NEW
77
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
×
NEW
78
        match self {
×
NEW
79
            ParseError::TokenizerError(e) => write!(f, "{}", e),
×
NEW
80
            ParseError::ScratchBufferFull => write!(f, "Scratch buffer is full"),
×
NEW
81
            ParseError::InvalidUtf8(e) => write!(f, "Invalid UTF-8 sequence: {}", e),
×
NEW
82
            ParseError::InvalidNumber => write!(f, "Invalid number format"),
×
NEW
83
            ParseError::Unexpected(e) => write!(f, "Unexpected parser state: {:?}", e),
×
NEW
84
            ParseError::EndOfData => write!(f, "Unexpected end of data"),
×
85
            ParseError::InvalidUnicodeHex => {
NEW
UNCOV
86
                write!(f, "Invalid hexadecimal digit in Unicode escape")
×
87
            }
NEW
UNCOV
88
            ParseError::InvalidUnicodeCodepoint => write!(f, "Invalid Unicode codepoint"),
×
NEW
UNCOV
89
            ParseError::InvalidEscapeSequence => write!(f, "Invalid escape sequence"),
×
NEW
UNCOV
90
            ParseError::FloatNotAllowed => write!(f, "Floating point numbers are not allowed"),
×
NEW
UNCOV
91
            ParseError::ReaderError => write!(f, "Underlying reader error"),
×
NEW
UNCOV
92
            ParseError::NumericOverflow => write!(f, "Numeric overflow detected"),
×
93
        }
NEW
UNCOV
94
    }
×
95
}
96

97
#[cfg(test)]
98
mod tests {
99
    use super::*;
100

101
    #[test]
102
    fn test_error_constructors() {
1✔
103
        // Test state_mismatch error constructor
104
        let error: ParseError = UnexpectedState::StateMismatch.into();
1✔
105
        match error {
1✔
106
            ParseError::Unexpected(info) => {
1✔
107
                assert_eq!(info, UnexpectedState::StateMismatch);
1✔
108
            }
UNCOV
109
            _ => panic!("Expected UnexpectedState error"),
×
110
        }
111

112
        // Test invalid_unicode_length error constructor
113
        let error: ParseError = UnexpectedState::InvalidUnicodeEscape.into();
1✔
114
        match error {
1✔
115
            ParseError::Unexpected(info) => {
1✔
116
                assert_eq!(info, UnexpectedState::InvalidUnicodeEscape);
1✔
117
            }
UNCOV
118
            _ => panic!("Expected UnexpectedState error"),
×
119
        }
120

121
        // Test incomplete_unicode_escape error constructor
122
        let error: ParseError = UnexpectedState::InvalidUnicodeEscape.into();
1✔
123
        match error {
1✔
124
            ParseError::Unexpected(info) => {
1✔
125
                assert_eq!(info, UnexpectedState::InvalidUnicodeEscape);
1✔
126
            }
UNCOV
127
            _ => panic!("Expected UnexpectedState error"),
×
128
        }
129
    }
1✔
130

131
    #[test]
132
    fn test_utf8_error_conversion() {
1✔
133
        // Test From<Utf8Error> trait implementation
134
        use core::str;
135
        // Create a proper invalid UTF-8 sequence (lone continuation byte) dynamically
136
        // to avoid compile-time warning about static invalid UTF-8 literals
137
        let mut invalid_utf8_array = [0u8; 1];
1✔
138
        invalid_utf8_array[0] = 0b10000000u8; // Invalid UTF-8 - continuation byte without start
1✔
139
        let invalid_utf8 = &invalid_utf8_array;
1✔
140

141
        match str::from_utf8(invalid_utf8) {
1✔
142
            Err(utf8_error) => {
1✔
143
                let parse_error: ParseError = utf8_error.into();
1✔
144
                match parse_error {
1✔
145
                    ParseError::InvalidUtf8(_) => {
1✔
146
                        // Expected - conversion works correctly
1✔
147
                    }
1✔
UNCOV
148
                    _ => panic!("Expected InvalidUtf8 error"),
×
149
                }
150
            }
UNCOV
151
            Ok(_) => panic!("Expected UTF-8 validation to fail"),
×
152
        }
153
    }
1✔
154
}
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