// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2025 ai-ad4 and the FreePDFEditor contributors #include "SpikeRunner.h" #include #include #include namespace freepdfeditor::spike { namespace { // Minimal hand-rolled JSON string escaper — avoids pulling a JSON lib into the // spike harness, which must stay dependency-light so it builds first. std::string esc(std::string s) { std::string out; out.reserve(s.size() + 8); for (char c : s) { switch (c) { case '"': out += "\\\""; break; case '\\': out += "\\\\"; break; case '\n': out += "\\n"; break; case '\r': out += "\\r"; break; case '\t': out += "\\t"; break; default: if (static_cast(c) < 0x20) { char buf[8]; std::snprintf(buf, sizeof(buf), "\\u%04x", c); out += buf; } else { out += c; } } } return out; } } // namespace int emit_json_report(const SpikeResult& r) { std::string samples; for (std::size_t i = 0; i < r.failed_samples.size(); ++i) { if (i) samples += ","; samples += "\"" + esc(r.failed_samples[i]) + "\""; } std::printf( "{\"spike\":\"%s\",\"name\":\"%s\",\"total\":%zu,\"passed\":%zu," "\"failed\":%zu,\"errored\":%zu,\"metric\":\"%s\",\"value\":%.6f," "\"target\":%.6f,\"gate_met\":%s,\"samples\":[%s],\"notes\":\"%s\"}\n", r.spike.c_str(), r.name.c_str(), r.total, r.passed, r.failed, r.errored, r.metric_name.c_str(), r.metric_value, r.target, r.gate_met ? "true" : "false", samples.c_str(), esc(r.notes).c_str()); std::fflush(stdout); return r.gate_met ? 0 : 1; } } // namespace freepdfeditor::spike