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.8.