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.

File Listing

The file content with the documentation metadata removed is:

1// include/contracts/ValidationReport.h
7#pragma once
8
9#include <cstdint>
10#include <sstream>
11#include <string>
12#include <utility>
13#include <vector>
14
15namespace simaai::neat {
16
21 Info = 0,
23 Error,
24};
25
26inline const char* to_string(ValidationSeverity s) {
27 switch (s) {
29 return "INFO";
31 return "WARNING";
33 return "ERROR";
34 }
35 return "UNKNOWN";
36}
37
43
44 // Contract metadata
45 std::string contract_id; // Contract::id()
46 std::string code; // stable machine code (e.g. "SINK_NOT_LAST")
47 std::string message; // human readable
48
49 // Best-effort node location (builder-level)
50 int node_index = -1;
51 std::string node_kind;
52 std::string node_label;
53};
54
60class ValidationReport final {
61public:
62 ValidationReport() = default;
63
64 // -------- Recording --------
66 issues_.push_back(std::move(issue));
67 }
68
69 void add_info(std::string contract_id, std::string code, std::string msg, int node_index = -1,
70 std::string node_kind = {}, std::string node_label = {}) {
71 add_issue({ValidationSeverity::Info, std::move(contract_id), std::move(code), std::move(msg),
72 node_index, std::move(node_kind), std::move(node_label)});
73 }
74
75 void add_warning(std::string contract_id, std::string code, std::string msg, int node_index = -1,
76 std::string node_kind = {}, std::string node_label = {}) {
77 add_issue({ValidationSeverity::Warning, std::move(contract_id), std::move(code), std::move(msg),
78 node_index, std::move(node_kind), std::move(node_label)});
79 }
80
81 void add_error(std::string contract_id, std::string code, std::string msg, int node_index = -1,
82 std::string node_kind = {}, std::string node_label = {}) {
83 add_issue({ValidationSeverity::Error, std::move(contract_id), std::move(code), std::move(msg),
84 node_index, std::move(node_kind), std::move(node_label)});
85 }
86
87 void note_contract_run(std::string id) {
88 contracts_run_.push_back(std::move(id));
89 }
90
91 // Optional: record which mode produced this report (integer to avoid Contract.h include).
92 void set_mode(int mode) {
93 mode_ = mode;
94 }
95 int mode() const {
96 return mode_;
97 }
98
99 // -------- Query --------
100 const std::vector<ValidationIssue>& issues() const noexcept {
101 return issues_;
102 }
103 const std::vector<std::string>& contracts_run() const noexcept {
104 return contracts_run_;
105 }
106
107 bool ok() const noexcept {
108 return !has_errors();
109 }
110
111 bool has_errors() const noexcept {
112 for (const auto& i : issues_) {
113 if (i.severity == ValidationSeverity::Error)
114 return true;
115 }
116 return false;
117 }
118
119 std::size_t error_count() const noexcept {
120 std::size_t n = 0;
121 for (const auto& i : issues_)
122 if (i.severity == ValidationSeverity::Error)
123 ++n;
124 return n;
125 }
126
127 std::size_t warning_count() const noexcept {
128 std::size_t n = 0;
129 for (const auto& i : issues_)
130 if (i.severity == ValidationSeverity::Warning)
131 ++n;
132 return n;
133 }
134
135 std::size_t info_count() const noexcept {
136 std::size_t n = 0;
137 for (const auto& i : issues_)
138 if (i.severity == ValidationSeverity::Info)
139 ++n;
140 return n;
141 }
142
143 // -------- Formatting --------
144 std::string to_string() const {
145 std::ostringstream oss;
146 oss << (ok() ? "OK" : "FAILED") << " (errors=" << error_count()
147 << ", warnings=" << warning_count() << ", info=" << info_count() << ")\n";
148
149 for (const auto& i : issues_) {
150 oss << "- [" << ::simaai::neat::to_string(i.severity) << "] "
151 << (i.contract_id.empty() ? "<contract?>" : i.contract_id);
152
153 if (!i.code.empty())
154 oss << " {" << i.code << "}";
155
156 if (i.node_index >= 0) {
157 oss << " @node[" << i.node_index << "]";
158 if (!i.node_kind.empty())
159 oss << ":" << i.node_kind;
160 if (!i.node_label.empty())
161 oss << " [" << i.node_label << "]";
162 }
163
164 oss << ": " << i.message << "\n";
165 }
166 return oss.str();
167 }
168
169 std::string to_json() const {
170 std::ostringstream oss;
171 oss << "{";
172 oss << "\"ok\":" << (ok() ? "true" : "false") << ",";
173 oss << "\"mode\":" << mode_ << ",";
174 oss << "\"errors\":" << error_count() << ",";
175 oss << "\"warnings\":" << warning_count() << ",";
176 oss << "\"info\":" << info_count() << ",";
177
178 // contracts_run
179 oss << "\"contracts_run\":[";
180 for (std::size_t i = 0; i < contracts_run_.size(); ++i) {
181 if (i)
182 oss << ",";
183 oss << "\"" << json_escape_(contracts_run_[i]) << "\"";
184 }
185 oss << "],";
186
187 // issues
188 oss << "\"issues\":[";
189 for (std::size_t i = 0; i < issues_.size(); ++i) {
190 if (i)
191 oss << ",";
192 const auto& it = issues_[i];
193 oss << "{";
194 oss << "\"severity\":\"" << json_escape_(::simaai::neat::to_string(it.severity)) << "\",";
195 oss << "\"contract_id\":\"" << json_escape_(it.contract_id) << "\",";
196 oss << "\"code\":\"" << json_escape_(it.code) << "\",";
197 oss << "\"message\":\"" << json_escape_(it.message) << "\",";
198 oss << "\"node_index\":" << it.node_index << ",";
199 oss << "\"node_kind\":\"" << json_escape_(it.node_kind) << "\",";
200 oss << "\"node_label\":\"" << json_escape_(it.node_label) << "\"";
201 oss << "}";
202 }
203 oss << "]";
204
205 oss << "}";
206 return oss.str();
207 }
208
209private:
210 static std::string json_escape_(const std::string& s) {
211 std::string out;
212 out.reserve(s.size() + 16);
213 for (char c : s) {
214 switch (c) {
215 case '\\':
216 out += "\\\\";
217 break;
218 case '"':
219 out += "\\\"";
220 break;
221 case '\b':
222 out += "\\b";
223 break;
224 case '\f':
225 out += "\\f";
226 break;
227 case '\n':
228 out += "\\n";
229 break;
230 case '\r':
231 out += "\\r";
232 break;
233 case '\t':
234 out += "\\t";
235 break;
236 default:
237 // Control chars -> escape as \u00XX
238 if (static_cast<unsigned char>(c) < 0x20) {
239 const char* hex = "0123456789abcdef";
240 out += "\\u00";
241 out += hex[(c >> 4) & 0xF];
242 out += hex[c & 0xF];
243 } else {
244 out += c;
245 }
246 break;
247 }
248 }
249 return out;
250 }
251
252 int mode_ = 0;
253 std::vector<std::string> contracts_run_;
254 std::vector<ValidationIssue> issues_;
255};
256
257} // namespace simaai::neat

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.1.