const diagnostic_diagram &diagram);
void end_group ();
+ std::unique_ptr<sarif_log> flush_to_object ();
void flush_to_file (FILE *outf);
std::unique_ptr<json::array>
m_cur_group_result = nullptr;
}
+/* Create a top-level object, and add it to all the results
+ (and other entities) we've seen so far, moving ownership
+ to the object. */
+
+std::unique_ptr<sarif_log>
+sarif_builder::flush_to_object ()
+{
+ m_invocation_obj->prepare_to_flush (m_context);
+ std::unique_ptr<sarif_log> top
+ = make_top_level_object (std::move (m_invocation_obj),
+ std::move (m_results_array));
+ return top;
+}
+
/* Create a top-level object, and add it to all the results
(and other entities) we've seen so far.
void
sarif_builder::flush_to_file (FILE *outf)
{
- m_invocation_obj->prepare_to_flush (m_context);
- std::unique_ptr<sarif_log> top
- = make_top_level_object (std::move (m_invocation_obj),
- std::move (m_results_array));
+ std::unique_ptr<sarif_log> top = flush_to_object ();
top->dump (outf, m_formatted);
- m_invocation_obj = nullptr;
fprintf (outf, "\n");
}
namespace selftest {
+/* A subclass of sarif_output_format for writing selftests.
+ The JSON output is cached internally, rather than written
+ out to a file. */
+
+class test_sarif_diagnostic_context : public test_diagnostic_context
+{
+public:
+ test_sarif_diagnostic_context ()
+ {
+ diagnostic_output_format_init_sarif (*this);
+
+ m_format = new buffered_output_format (*this,
+ "MAIN_INPUT_FILENAME",
+ true);
+ set_output_format (m_format); // give ownership;
+ }
+
+ std::unique_ptr<sarif_log> flush_to_object ()
+ {
+ return m_format->flush_to_object ();
+ }
+
+private:
+ class buffered_output_format : public sarif_output_format
+ {
+ public:
+ buffered_output_format (diagnostic_context &context,
+ const char *main_input_filename_,
+ bool formatted)
+ : sarif_output_format (context, main_input_filename_, formatted)
+ {
+ }
+ bool machine_readable_stderr_p () const final override
+ {
+ return false;
+ }
+ std::unique_ptr<sarif_log> flush_to_object ()
+ {
+ return m_builder.flush_to_object ();
+ }
+ };
+
+ buffered_output_format *m_format; // borrowed
+};
+
+/* Test making a sarif_location for a complex rich_location
+ with labels and escape-on-output. */
+
static void
test_make_location_object (const line_table_case &case_)
{
}
}
+/* Test of reporting a diagnostic to a diagnostic_context and
+ examining the generated sarif_log.
+ Verify various basic properties. */
+
+static void
+test_simple_log ()
+{
+ test_sarif_diagnostic_context dc;
+
+ rich_location richloc (line_table, UNKNOWN_LOCATION);
+ dc.report (DK_ERROR, richloc, nullptr, 0, "this is a test: %i", 42);
+
+ auto log_ptr = dc.flush_to_object ();
+
+ // 3.13 sarifLog:
+ auto log = log_ptr.get ();
+ ASSERT_JSON_STRING_PROPERTY_EQ (log, "$schema", SARIF_SCHEMA); // 3.13.3
+ ASSERT_JSON_STRING_PROPERTY_EQ (log, "version", SARIF_VERSION); // 3.13.2
+
+ auto runs = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (log, "runs"); // 3.13.4
+ ASSERT_EQ (runs->size (), 1);
+
+ // 3.14 "run" object:
+ auto run = (*runs)[0];
+
+ {
+ // 3.14.6:
+ auto tool = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (run, "tool");
+
+ EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (tool, "driver"); // 3.18.2
+ }
+
+ {
+ // 3.14.11
+ auto invocations
+ = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (run, "invocations");
+ ASSERT_EQ (invocations->size (), 1);
+
+ {
+ // 3.20 "invocation" object:
+ auto invocation = (*invocations)[0];
+
+ // 3.20.3 arguments property
+
+ // 3.20.7 startTimeUtc property
+ EXPECT_JSON_OBJECT_WITH_STRING_PROPERTY (invocation, "startTimeUtc");
+
+ // 3.20.8 endTimeUtc property
+ EXPECT_JSON_OBJECT_WITH_STRING_PROPERTY (invocation, "endTimeUtc");
+
+ // 3.20.19 workingDirectory property
+ {
+ auto wd_obj
+ = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (invocation,
+ "workingDirectory");
+ EXPECT_JSON_OBJECT_WITH_STRING_PROPERTY (wd_obj, "uri");
+ }
+
+ // 3.20.21 toolExecutionNotifications property
+ auto notifications
+ = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY
+ (invocation, "toolExecutionNotifications");
+ ASSERT_EQ (notifications->size (), 0);
+ }
+ }
+
+ {
+ // 3.14.15:
+ auto artifacts = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (run, "artifacts");
+ ASSERT_EQ (artifacts->size (), 1);
+
+ {
+ // 3.24 "artifact" object:
+ auto artifact = (*artifacts)[0];
+
+ // 3.24.2:
+ auto location
+ = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (artifact, "location");
+ ASSERT_JSON_STRING_PROPERTY_EQ (location, "uri", "MAIN_INPUT_FILENAME");
+
+ // 3.24.6:
+ auto roles = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (artifact, "roles");
+ ASSERT_EQ (roles->size (), 1);
+ {
+ auto role = (*roles)[0];
+ ASSERT_JSON_STRING_EQ (role, "analysisTarget");
+ }
+ }
+ }
+
+ {
+ // 3.14.23:
+ auto results = EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (run, "results");
+ ASSERT_EQ (results->size (), 1);
+
+ {
+ // 3.27 "result" object:
+ auto result = (*results)[0];
+ ASSERT_JSON_STRING_PROPERTY_EQ (result, "ruleId", "error");
+ ASSERT_JSON_STRING_PROPERTY_EQ (result, "level", "error"); // 3.27.10
+
+ {
+ // 3.27.11:
+ auto message
+ = EXPECT_JSON_OBJECT_WITH_OBJECT_PROPERTY (result, "message");
+ ASSERT_JSON_STRING_PROPERTY_EQ (message, "text",
+ "this is a test: 42");
+ }
+
+ // 3.27.12:
+ EXPECT_JSON_OBJECT_WITH_ARRAY_PROPERTY (result, "locations");
+ }
+ }
+}
+
/* Run all of the selftests within this file. */
void
diagnostic_format_sarif_cc_tests ()
{
for_each_line_table_case (test_make_location_object);
+ test_simple_log ();
}
} // namespace selftest
namespace selftest {
+/* Assert that VALUE is a non-null json::string
+ equalling EXPECTED_VALUE.
+ Use LOC for any failures. */
+
+void
+assert_json_string_eq (const location &loc,
+ const json::value *value,
+ const char *expected_value)
+{
+ ASSERT_EQ_AT (loc, value->get_kind (), json::JSON_STRING);
+ const json::string *str = static_cast<const json::string *> (value);
+ ASSERT_STREQ_AT (loc, expected_value, str->get_string ());
+}
+
/* Assert that VALUE is a non-null json::object,
returning it as such, failing at LOC if this isn't the case. */
return static_cast<const json::array *> (property_value);
}
+/* Assert that VALUE is a non-null json::object that has property
+ PROPERTY_NAME, and that the property value is a non-null JSON string.
+ Return the value of the property as a json::string.
+ Use LOC for any failures. */
+
+const json::string *
+expect_json_object_with_string_property (const location &loc,
+ const json::value *value,
+ const char *property_name)
+{
+ const json::value *property_value
+ = expect_json_object_with_property (loc, value, property_name);
+ ASSERT_EQ_AT (loc, property_value->get_kind (), json::JSON_STRING);
+ return static_cast<const json::string *> (property_value);
+}
+
/* Assert that VALUE is a non-null json::object that has property
PROPERTY_NAME, and that the value of that property is a non-null
JSON string equalling EXPECTED_VALUE.
{
const json::value *property_value
= expect_json_object_with_property (loc, value, property_name);
- ASSERT_EQ_AT (loc, property_value->get_kind (), json::JSON_STRING);
- const json::string *str = static_cast<const json::string *> (property_value);
- ASSERT_STREQ_AT (loc, expected_value, str->get_string ());
+ assert_json_string_eq (loc, property_value, expected_value);
}
} // namespace selftest
namespace selftest {
+/* Assert that VALUE is a non-null json::string
+ equalling EXPECTED_VALUE.
+ Use LOC for any failures. */
+
+void
+assert_json_string_eq (const location &loc,
+ const json::value *value,
+ const char *expected_value);
+#define ASSERT_JSON_STRING_EQ(JSON_VALUE, EXPECTED_VALUE) \
+ assert_json_string_eq ((SELFTEST_LOCATION), \
+ (JSON_VALUE), \
+ (EXPECTED_VALUE))
+
/* Assert that VALUE is a non-null json::object,
returning it as such, failing at LOC if this isn't the case. */
(JSON_VALUE), \
(PROPERTY_NAME))
+/* Assert that VALUE is a non-null json::object that has property
+ PROPERTY_NAME, and that the property value is a non-null JSON string.
+ Return the value of the property as a json::string.
+ Use LOC for any failures. */
+
+const json::string *
+expect_json_object_with_string_property (const location &loc,
+ const json::value *value,
+ const char *property_name);
+#define EXPECT_JSON_OBJECT_WITH_STRING_PROPERTY(JSON_VALUE, PROPERTY_NAME) \
+ expect_json_object_with_string_property ((SELFTEST_LOCATION), \
+ (JSON_VALUE), \
+ (PROPERTY_NAME))
+
/* Assert that VALUE is a non-null json::object that has property
PROPERTY_NAME, and that the value of that property is a non-null
JSON string equalling EXPECTED_VALUE.