Skip to main content

ValidationReport.h File

Structured validation results for builder-level checks. More...

Included Headers​

#include <cstdint> #include <sstream> #include <string> #include <utility> #include <vector>

Namespaces Index​

namespacesimaai
namespaceneat

Classes Index​

structValidationIssue

A single reported issue from a Contract. More...

classValidationReport

Report produced by running a ContractRegistry. More...

Description​

Structured validation results for builder-level checks.

Defines ValidationSeverity, ValidationIssue, and ValidationReport — the data types that ContractRegistry::validate() produces. The report is STL-only and JSON-serializable so CI tools and dashboards can consume it without pulling in any framework dependencies.

See Also

Contract

See Also

ContractRegistry

File Listing​

The file content with the documentation metadata removed is:

1// include/contracts/ValidationReport.h
15#pragma once
16
17#include <cstdint>
18#include <sstream>
19#include <string>
20#include <utility>
21#include <vector>
22
23namespace simaai::neat {
24
30 Info = 0,
31 Warning,
32 Error,
33};
34
36inline const char* to_string(ValidationSeverity s) {
37 switch (s) {
39 return "INFO";
41 return "WARNING";
43 return "ERROR";
44 }
45 return "UNKNOWN";
46}
47
59
60 // Contract metadata
61 std::string contract_id;
62 std::string code;
63 std::string message;
64
65 // Best-effort node location (builder-level)
66 int node_index = -1;
67 std::string node_kind;
68 std::string node_label;
69};
70
82class ValidationReport final {
83public:
85 ValidationReport() = default;
86
87 // -------- Recording --------
88
91 issues_.push_back(std::move(issue));
92 }
93
95 void add_info(std::string contract_id, std::string code, std::string msg, int node_index = -1,
96 std::string node_kind = {}, std::string node_label = {}) {
97 add_issue({ValidationSeverity::Info, std::move(contract_id), std::move(code), std::move(msg),
98 node_index, std::move(node_kind), std::move(node_label)});
99 }
100
102 void add_warning(std::string contract_id, std::string code, std::string msg, int node_index = -1,
103 std::string node_kind = {}, std::string node_label = {}) {
104 add_issue({ValidationSeverity::Warning, std::move(contract_id), std::move(code), std::move(msg),
105 node_index, std::move(node_kind), std::move(node_label)});
106 }
107
109 void add_error(std::string contract_id, std::string code, std::string msg, int node_index = -1,
110 std::string node_kind = {}, std::string node_label = {}) {
111 add_issue({ValidationSeverity::Error, std::move(contract_id), std::move(code), std::move(msg),
112 node_index, std::move(node_kind), std::move(node_label)});
113 }
114
116 void note_contract_run(std::string id) {
117 contracts_run_.push_back(std::move(id));
118 }
119
121 void set_mode(int mode) {
122 mode_ = mode;
123 }
125 int mode() const {
126 return mode_;
127 }
128
129 // -------- Query --------
130
132 const std::vector<ValidationIssue>& issues() const noexcept {
133 return issues_;
134 }
136 const std::vector<std::string>& contracts_run() const noexcept {
137 return contracts_run_;
138 }
139
141 bool ok() const noexcept {
142 return !has_errors();
143 }
144
146 bool has_errors() const noexcept {
147 for (const auto& i : issues_) {
148 if (i.severity == ValidationSeverity::Error)
149 return true;
150 }
151 return false;
152 }
153
155 std::size_t error_count() const noexcept {
156 std::size_t n = 0;
157 for (const auto& i : issues_)
158 if (i.severity == ValidationSeverity::Error)
159 ++n;
160 return n;
161 }
162
164 std::size_t warning_count() const noexcept {
165 std::size_t n = 0;
166 for (const auto& i : issues_)
167 if (i.severity == ValidationSeverity::Warning)
168 ++n;
169 return n;
170 }
171
173 std::size_t info_count() const noexcept {
174 std::size_t n = 0;
175 for (const auto& i : issues_)
176 if (i.severity == ValidationSeverity::Info)
177 ++n;
178 return n;
179 }
180
181 // -------- Formatting --------
182
184 std::string to_string() const {
185 std::ostringstream oss;
186 oss << (ok() ? "OK" : "FAILED") << " (errors=" << error_count()
187 << ", warnings=" << warning_count() << ", info=" << info_count() << ")\n";
188
189 for (const auto& i : issues_) {
190 oss << "- [" << ::simaai::neat::to_string(i.severity) << "] "
191 << (i.contract_id.empty() ? "<contract?>" : i.contract_id);
192
193 if (!i.code.empty())
194 oss << " {" << i.code << "}";
195
196 if (i.node_index >= 0) {
197 oss << " @node[" << i.node_index << "]";
198 if (!i.node_kind.empty())
199 oss << ":" << i.node_kind;
200 if (!i.node_label.empty())
201 oss << " [" << i.node_label << "]";
202 }
203
204 oss << ": " << i.message << "\n";
205 }
206 return oss.str();
207 }
208
210 std::string to_json() const {
211 std::ostringstream oss;
212 oss << "{";
213 oss << "\"ok\":" << (ok() ? "true" : "false") << ",";
214 oss << "\"mode\":" << mode_ << ",";
215 oss << "\"errors\":" << error_count() << ",";
216 oss << "\"warnings\":" << warning_count() << ",";
217 oss << "\"info\":" << info_count() << ",";
218
219 // contracts_run
220 oss << "\"contracts_run\":[";
221 for (std::size_t i = 0; i < contracts_run_.size(); ++i) {
222 if (i)
223 oss << ",";
224 oss << "\"" << json_escape_(contracts_run_[i]) << "\"";
225 }
226 oss << "],";
227
228 // issues
229 oss << "\"issues\":[";
230 for (std::size_t i = 0; i < issues_.size(); ++i) {
231 if (i)
232 oss << ",";
233 const auto& it = issues_[i];
234 oss << "{";
235 oss << "\"severity\":\"" << json_escape_(::simaai::neat::to_string(it.severity)) << "\",";
236 oss << "\"contract_id\":\"" << json_escape_(it.contract_id) << "\",";
237 oss << "\"code\":\"" << json_escape_(it.code) << "\",";
238 oss << "\"message\":\"" << json_escape_(it.message) << "\",";
239 oss << "\"node_index\":" << it.node_index << ",";
240 oss << "\"node_kind\":\"" << json_escape_(it.node_kind) << "\",";
241 oss << "\"node_label\":\"" << json_escape_(it.node_label) << "\"";
242 oss << "}";
243 }
244 oss << "]";
245
246 oss << "}";
247 return oss.str();
248 }
249
250private:
251 static std::string json_escape_(const std::string& s) {
252 std::string out;
253 out.reserve(s.size() + 16);
254 for (char c : s) {
255 switch (c) {
256 case '\\':
257 out += "\\\\";
258 break;
259 case '"':
260 out += "\\\"";
261 break;
262 case '\b':
263 out += "\\b";
264 break;
265 case '\f':
266 out += "\\f";
267 break;
268 case '\n':
269 out += "\\n";
270 break;
271 case '\r':
272 out += "\\r";
273 break;
274 case '\t':
275 out += "\\t";
276 break;
277 default:
278 // Control chars -> escape as \u00XX
279 if (static_cast<unsigned char>(c) < 0x20) {
280 const char* hex = "0123456789abcdef";
281 out += "\\u00";
282 out += hex[(c >> 4) & 0xF];
283 out += hex[c & 0xF];
284 } else {
285 out += c;
286 }
287 break;
288 }
289 }
290 return out;
291 }
292
293 int mode_ = 0;
294 std::vector<std::string> contracts_run_;
295 std::vector<ValidationIssue> issues_;
296};
297
298} // namespace simaai::neat

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.1.