From 3114b2520554af2b1064a1e2e014deec2f0de048 Mon Sep 17 00:00:00 2001 From: Hugo Date: Fri, 23 Oct 2026 04:49:48 +0200 Subject: [PATCH] test(sarif): check the log root and runs[0] are objects before using them The Run helper dereferenced the parsed log and its first run without checking they were objects, so a log of the wrong shape crashed sarif_unit instead of failing a check. RunOf now returns an empty run for such a log, and a test feeds it an array and a non-object run. Closes #33 --- unittests/sarif_test.cpp | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/unittests/sarif_test.cpp b/unittests/sarif_test.cpp index 543c590..a320c93 100644 --- a/unittests/sarif_test.cpp +++ b/unittests/sarif_test.cpp @@ -173,17 +173,35 @@ namespace "one warning: no locations, no column when the runtime gave none"); } - // The one run of the log Sarif() writes for `findings`. - [[nodiscard]] llvm::json::Object Run(const std::vector& findings) + // The one run of the SARIF log `text`, or an empty object when the log has none. + [[nodiscard]] llvm::json::Object RunOf(std::string_view text) { - llvm::Expected log = llvm::json::parse(Sarif(findings)); + llvm::Expected log = llvm::json::parse(text); if (!log) { llvm::consumeError(log.takeError()); return {}; } - const llvm::json::Array* runs = log->getAsObject()->getArray("runs"); - return runs != nullptr && !runs->empty() ? *(*runs)[0].getAsObject() : llvm::json::Object{}; + const llvm::json::Object* root = log->getAsObject(); + const llvm::json::Array* runs = root != nullptr ? root->getArray("runs") : nullptr; + const llvm::json::Object* run = + runs != nullptr && !runs->empty() ? (*runs)[0].getAsObject() : nullptr; + return run != nullptr ? *run : llvm::json::Object{}; + } + + // The one run of the log Sarif() writes for `findings`. + [[nodiscard]] llvm::json::Object Run(const std::vector& findings) + { + return RunOf(Sarif(findings)); + } + + // A log of the wrong shape has no run, so the checks on it fail instead of crashing. + void MalformedLogHasNoRun() + { + for (const std::string_view text : {R"([])", R"({"runs": [1]})"}) + { + Expect(RunOf(text).empty(), std::string(text) + ": no run"); + } } [[nodiscard]] Finding OfRule(std::string rule) @@ -254,6 +272,7 @@ int main() EmptyLog(); FindingWithLocations(); WarningWithoutLocation(); + MalformedLogHasNoRun(); EveryRuleIsDescribed(); EveryFindingHasAConfidence(); return unittests::Finish("sarif_test");