Coverage Report

Created: 2026-08-13 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/valijson/include/valijson/validation_results.hpp
Line
Count
Source
1
#pragma once
2
3
#include <deque>
4
#include <string>
5
#include <utility>
6
#include <vector>
7
8
namespace valijson {
9
10
/**
11
 * @brief  Class that encapsulates the storage of validation errors.
12
 *
13
 * This class maintains an internal FIFO queue of errors that are reported
14
 * during validation. Errors are pushed on to the back of an internal
15
 * queue, and can retrieved by popping them from the front of the queue.
16
 */
17
class ValidationResults
18
{
19
public:
20
21
    enum Kind
22
    {
23
        kArray,
24
        kObject
25
    };
26
27
    struct Segment
28
    {
29
        /// What kind of traversal is this?
30
        Kind kind;
31
32
        /// Index or name of property to traverse into
33
        std::string name;
34
    };
35
36
    typedef std::vector<Segment> Path;
37
38
    /**
39
     * @brief  Describes a validation error.
40
     *
41
     * This struct is used to pass around the path and description of a
42
     * validation error. The path is stored in two formats. First is 'context',
43
     * a legacy format, used only by Valijson. Second is JSON Pointer format,
44
     * which is defined in RFC 6901.
45
     */
46
    struct Error
47
    {
48
        /**
49
         * Path to the node that failed validation (LEGACY).
50
         *
51
         * @deprecated use \c jsonPointer instead
52
         */
53
        std::vector<std::string> context;
54
55
        /// A detailed description of the validation error.
56
        std::string description;
57
58
        /// JSON Pointer identifying the node that failed validation.
59
        std::string jsonPointer;
60
    };
61
62
    /**
63
     * @brief  Return begin iterator for results in the queue.
64
     */
65
    std::deque<Error>::const_iterator begin() const
66
0
    {
67
0
        return m_errors.begin();
68
0
    }
69
70
    /**
71
     * @brief  Return end iterator for results in the queue.
72
     */
73
    std::deque<Error>::const_iterator end() const
74
0
    {
75
0
        return m_errors.end();
76
0
    }
77
78
    /**
79
     * @brief  Return the number of errors in the queue.
80
     */
81
    size_t numErrors() const
82
0
    {
83
0
        return m_errors.size();
84
0
    }
85
86
    /**
87
     * @brief  Copy an Error and push it on to the back of the queue.
88
     *
89
     * @param  error  Reference to an Error object to be copied.
90
     */
91
    void pushError(const Error &error)
92
94.9k
    {
93
94.9k
        m_errors.push_back(error);
94
94.9k
    }
95
96
    /**
97
     * @brief  Push an error onto the back of the queue.
98
     *
99
     * @param  path         Path of the validation error.
100
     * @param  description  Description of the validation error.
101
     */
102
    void
103
    pushError(const Path &path, const std::string &description)
104
1.88M
    {
105
        // construct legacy context
106
        //  e.g. <root>["my_object"][1]["some_property"]
107
1.88M
        const std::vector<std::string> context = toContext(path);
108
109
        // construct JSON pointer
110
        //  e.g. /my_object/1/some_property
111
1.88M
        const std::string jsonPointer = toJsonPointer(path);
112
113
1.88M
        m_errors.push_back({context, description, jsonPointer});
114
1.88M
    }
115
116
    /**
117
     * @brief  Pop an error from the front of the queue.
118
     *
119
     * @param  error  Reference to an Error object to populate.
120
     *
121
     * @returns  true if an Error was popped, false otherwise.
122
     */
123
    bool
124
    popError(Error &error)
125
104k
    {
126
104k
        if (m_errors.empty()) {
127
9.20k
            return false;
128
9.20k
        }
129
130
94.9k
        error = m_errors.front();
131
94.9k
        m_errors.pop_front();
132
94.9k
        return true;
133
104k
    }
134
135
private:
136
137
    /// FIFO queue of validation errors that have been reported
138
    std::deque<Error> m_errors;
139
140
    static std::string escapeJsonPointerToken(const std::string &token)
141
217k
    {
142
217k
        std::string escaped;
143
217k
        escaped.reserve(token.size());
144
145
6.07M
        for (const char ch : token) {
146
6.07M
            switch (ch) {
147
17.6k
            case '~':
148
17.6k
                escaped.append("~0");
149
17.6k
                break;
150
18.4k
            case '/':
151
18.4k
                escaped.append("~1");
152
18.4k
                break;
153
6.03M
            default:
154
6.03M
                escaped.push_back(ch);
155
6.03M
                break;
156
6.07M
            }
157
6.07M
        }
158
159
217k
        return escaped;
160
217k
    }
161
162
    /**
163
     * @brief  Convert a path to a legacy v1.0 context string
164
     *
165
     * e.g. <root>["my_object"][1]["some_property"]
166
     */
167
    static std::vector<std::string> toContext(const Path &path)
168
1.88M
    {
169
1.88M
        auto context = std::vector<std::string>();
170
1.88M
        context.push_back("<root>");
171
1.88M
        for (const auto &segment : path) {
172
217k
            if (segment.kind == kObject) {
173
203k
                std::string s("[\"");
174
203k
                s += segment.name;
175
203k
                s += "\"]";
176
203k
                context.push_back(s);
177
203k
            } else {
178
14.3k
                std::string s("[");
179
14.3k
                s += segment.name;
180
14.3k
                s += "]";
181
14.3k
                context.push_back(s);
182
14.3k
            }
183
217k
        }
184
185
1.88M
        return context;
186
1.88M
    }
187
188
    /**
189
     * Convert a path to a JSON Pointer
190
     *
191
     * e.g. /my_object/1/some_property
192
     */
193
    static std::string toJsonPointer(const Path &path)
194
1.88M
    {
195
1.88M
        std::string pointer;
196
1.88M
        for (const auto &segment : path) {
197
217k
            pointer.push_back('/');
198
217k
            pointer.append(escapeJsonPointerToken(segment.name));
199
217k
        }
200
201
1.88M
        return pointer;
202
1.88M
    }
203
};
204
205
} // namespace valijson