103 lines
3.2 KiB
C++
103 lines
3.2 KiB
C++
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
// SPDX-FileCopyrightText: 2025 ai-ad4 and the FreePDFEditor contributors
|
|
//
|
|
// Smoke test for the spike-runner JSON contract. The CI pipeline parses the
|
|
// single-line JSON that emit_json_report produces; if that format drifts the
|
|
// whole gate matrix goes dark. This test pins the format without depending on
|
|
// QPDF, so it runs on every platform even before the spike builds.
|
|
|
|
#include "../spike/common/SpikeRunner.h"
|
|
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
// Capture stdout during emit_json_report by writing to a captured buffer —
|
|
// emit_json_report writes to real stdout, so we redirect via freopen. This is
|
|
// crude but avoids pulling a dependency into the scaffold test.
|
|
std::string capture(freepdfeditor::spike::SpikeResult r)
|
|
{
|
|
std::fflush(stdout);
|
|
FILE* saved = stdout;
|
|
stdout = std::tmpfile();
|
|
if (!stdout) { stdout = saved; return {}; }
|
|
int rc = freepdfeditor::spike::emit_json_report(r);
|
|
std::fflush(stdout);
|
|
std::string buf;
|
|
std::rewind(stdout);
|
|
int c;
|
|
while ((c = std::fgetc(stdout)) != EOF) buf.push_back(static_cast<char>(c));
|
|
std::fclose(stdout);
|
|
stdout = saved;
|
|
(void)rc;
|
|
return buf;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
int main()
|
|
{
|
|
using namespace freepdfeditor::spike;
|
|
|
|
SpikeResult r{};
|
|
r.spike = "A";
|
|
r.name = "test";
|
|
r.total = 10;
|
|
r.passed = 9;
|
|
r.failed = 1;
|
|
r.errored = 0;
|
|
r.metric_name = "byte_identical_rate";
|
|
r.metric_value = 0.9;
|
|
r.target = 0.99;
|
|
r.gate_met = false;
|
|
r.failed_samples = {"bad.pdf"};
|
|
r.notes = "hello \"world\"\nline2";
|
|
|
|
std::string out = capture(r);
|
|
|
|
int failures = 0;
|
|
auto assert_contains = [&](const std::string& needle) {
|
|
if (out.find(needle) == std::string::npos) {
|
|
std::fprintf(stderr, "FAIL: output missing %s\n", needle.c_str());
|
|
std::fprintf(stderr, "output was: %s\n", out.c_str());
|
|
++failures;
|
|
}
|
|
};
|
|
|
|
assert_contains("\"spike\":\"A\"");
|
|
assert_contains("\"name\":\"test\"");
|
|
assert_contains("\"total\":10");
|
|
assert_contains("\"passed\":9");
|
|
assert_contains("\"failed\":1");
|
|
assert_contains("\"metric\":\"byte_identical_rate\"");
|
|
assert_contains("\"value\":0.900000");
|
|
assert_contains("\"target\":0.990000");
|
|
assert_contains("\"gate_met\":false");
|
|
assert_contains("\"samples\":[\"bad.pdf\"]");
|
|
assert_contains("\"notes\":\"hello \\\"world\\\"\\nline2\"");
|
|
// Single line, terminated by newline.
|
|
if (out.empty() || out.back() != '\n') {
|
|
std::fprintf(stderr, "FAIL: output not newline-terminated\n");
|
|
++failures;
|
|
}
|
|
if (out.find('\n') != out.size() - 1) {
|
|
std::fprintf(stderr, "FAIL: output contains embedded newline\n");
|
|
++failures;
|
|
}
|
|
|
|
// Gate-met returns 0; not-met returns 1. Test the contract directly.
|
|
r.gate_met = true;
|
|
if (freepdfeditor::spike::emit_json_report(r) != 0) {
|
|
std::fprintf(stderr, "FAIL: gate_met=true should return 0\n");
|
|
++failures;
|
|
}
|
|
r.gate_met = false;
|
|
if (freepdfeditor::spike::emit_json_report(r) != 1) {
|
|
std::fprintf(stderr, "FAIL: gate_met=false should return 1\n");
|
|
++failures;
|
|
}
|
|
|
|
return failures == 0 ? 0 : 1;
|
|
} |