Use less c++
As a design, it would be better if we didn't need to have a dependency
on c++ in a c library. Moving things to C will reduce both
dependencies and compile times.
Reduced dependencies makes the library itself easier to use in
more environments.
libmctp Is a library that doesn't take a dependency on gtest for its
tests
libpldm Is an example that does take a dependency on gtest.
Change-Id: If1dc638f87b75b28181a0baf67f5a18d389cff81
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/tests/test-utils.c b/tests/test-utils.c
new file mode 100644
index 0000000..1b2adac
--- /dev/null
+++ b/tests/test-utils.c
@@ -0,0 +1,248 @@
+/**
+ * Defines utility functions for testing CPER-JSON IR output from the cper-parse library.
+ *
+ * Author: Lawrence.Tang@arm.com
+ **/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "test-utils.h"
+
+#include <libcper/BaseTypes.h>
+#include <libcper/generator/cper-generate.h>
+
+#include <jsoncdaccord.h>
+#include <json.h>
+#include <libcper/log.h>
+
+// Objects that have mutually exclusive fields (and thereforce can't have both
+// required at the same time) can be added to this list.
+// Truly optional properties that shouldn't be added to "required" field for
+// validating the entire schema with validationbits=1
+// In most cases making sure examples set all valid bits is preferable to adding to this list
+static const char *optional_props[] = {
+ // Some sections don't parse header correctly?
+ "header",
+
+ // Each section is optional
+ "GenericProcessor", "Ia32x64Processor", "ArmProcessor", "Memory",
+ "Memory2", "Pcie", "PciBus", "PciComponent", "Firmware", "GenericDmar",
+ "VtdDmar", "IommuDmar", "CcixPer", "CxlProtocol", "CxlComponent",
+ "Nvidia", "Ampere", "Unknown",
+
+ // CXL? might have a bug?
+ "partitionID",
+
+ // CXL protocol
+ "capabilityStructure", "deviceSerial",
+
+ // CXL component
+ "cxlComponentEventLog", "addressSpace", "errorType",
+ "participationType", "timedOut", "level", "operation", "preciseIP",
+ "restartableIP", "overflow", "uncorrected", "transactionType",
+
+ // PCIe AER
+ "addressSpace", "errorType", "participationType", "timedOut", "level",
+ "operation", "preciseIP", "restartableIP", "overflow", "uncorrected",
+ "transactionType"
+};
+
+//Returns a ready-for-use memory stream containing a CPER record with the given sections inside.
+FILE *generate_record_memstream(const char **types, UINT16 num_types,
+ char **buf, size_t *buf_size,
+ int single_section,
+ GEN_VALID_BITS_TEST_TYPE validBitsType)
+{
+ //Open a memory stream.
+ FILE *stream = open_memstream(buf, buf_size);
+
+ //Generate a section to the stream, close & return.
+ if (!single_section) {
+ generate_cper_record((char **)(types), num_types, stream,
+ validBitsType);
+ } else {
+ generate_single_section_record((char *)(types[0]), stream,
+ validBitsType);
+ }
+ fclose(stream);
+
+ //Return fmemopen() buffer for reading.
+ return fmemopen(*buf, *buf_size, "r");
+}
+
+int iterate_make_required_props(json_object *jsonSchema, int all_valid_bits)
+{
+ //properties
+ json_object *properties =
+ json_object_object_get(jsonSchema, "properties");
+
+ if (properties != NULL) {
+ json_object *requrired_arr = json_object_new_array();
+
+ json_object_object_foreach(properties, property_name,
+ property_value)
+ {
+ (void)property_value;
+ int add_to_required = 1;
+ size_t num = sizeof(optional_props) /
+ sizeof(optional_props[0]);
+ for (size_t i = 0; i < num; i++) {
+ if (strcmp(optional_props[i], property_name) ==
+ 0) {
+ add_to_required = 0;
+ break;
+ }
+ }
+
+ if (add_to_required) {
+ //Add to list if property is not optional
+ json_object_array_add(
+ requrired_arr,
+ json_object_new_string(property_name));
+ }
+ }
+
+ json_object_object_foreach(properties, property_name2,
+ property_value2)
+ {
+ (void)property_name2;
+ if (iterate_make_required_props(property_value2,
+ all_valid_bits) < 0) {
+ json_object_put(requrired_arr);
+ return -1;
+ }
+ }
+
+ if (all_valid_bits) {
+ json_object_object_add(jsonSchema, "required",
+ requrired_arr);
+ } else {
+ json_object_put(requrired_arr);
+ }
+ }
+
+ // ref
+ json_object *ref = json_object_object_get(jsonSchema, "$ref");
+ if (ref != NULL) {
+ const char *ref_str = json_object_get_string(ref);
+ if (ref_str != NULL) {
+ if (strlen(ref_str) < 1) {
+ cper_print_log("Failed seek filepath: %s\n",
+ ref_str);
+ return -1;
+ }
+ size_t size =
+ strlen(LIBCPER_JSON_SPEC) + strlen(ref_str);
+ char *path = (char *)malloc(size);
+ int n = snprintf(path, size, "%s%s", LIBCPER_JSON_SPEC,
+ ref_str + 1);
+ if (n != (int)size - 1) {
+ cper_print_log("Failed concat filepath: %s\n",
+ ref_str);
+ free(path);
+ return -1;
+ }
+ json_object *ref_obj = json_object_from_file(path);
+ free(path);
+ if (ref_obj == NULL) {
+ cper_print_log("Failed to parse file: %s\n",
+ ref_str);
+ return -1;
+ }
+
+ if (iterate_make_required_props(ref_obj,
+ all_valid_bits) < 0) {
+ json_object_put(ref_obj);
+ return -1;
+ }
+
+ json_object_object_foreach(ref_obj, key, val)
+ {
+ json_object_object_add(jsonSchema, key,
+ json_object_get(val));
+ }
+ json_object_object_del(jsonSchema, "$ref");
+
+ json_object_put(ref_obj);
+ }
+ }
+
+ //oneOf
+ const json_object *oneOf = json_object_object_get(jsonSchema, "oneOf");
+ if (oneOf != NULL) {
+ size_t num_elements = json_object_array_length(oneOf);
+
+ for (size_t i = 0; i < num_elements; i++) {
+ json_object *obj = json_object_array_get_idx(oneOf, i);
+ if (iterate_make_required_props(obj, all_valid_bits) <
+ 0) {
+ return -1;
+ }
+ }
+ }
+
+ //items
+ const json_object *items = json_object_object_get(jsonSchema, "items");
+ if (items != NULL) {
+ json_object_object_foreach(items, key, val)
+ {
+ (void)key;
+ if (iterate_make_required_props(val, all_valid_bits) <
+ 0) {
+ return -1;
+ }
+ }
+ }
+
+ return 1;
+}
+
+int schema_validate_from_file(json_object *to_test, int single_section,
+ int all_valid_bits)
+{
+ const char *schema_file;
+ if (single_section) {
+ schema_file = "cper-json-section-log.json";
+ } else {
+ schema_file = "cper-json-full-log.json";
+ }
+ int size = strlen(schema_file) + 1 + strlen(LIBCPER_JSON_SPEC) + 1;
+ char *schema_path = malloc(size);
+ snprintf(schema_path, size, "%s/%s", LIBCPER_JSON_SPEC, schema_file);
+
+ json_object *schema = json_object_from_file(schema_path);
+
+ if (schema == NULL) {
+ cper_print_log("Could not parse schema file: %s", schema_path);
+ free(schema_path);
+ return 0;
+ }
+
+ if (iterate_make_required_props(schema, all_valid_bits) < 0) {
+ cper_print_log("Failed to make required props\n");
+ json_object_put(schema);
+ free(schema_path);
+ return -1;
+ }
+
+ int err = jdac_validate(to_test, schema);
+ if (err == JDAC_ERR_VALID) {
+ cper_print_log("validation ok\n");
+ json_object_put(schema);
+ free(schema_path);
+ return 1;
+ }
+
+ cper_print_log("validate failed %d: %s\n", err, jdac_errorstr(err));
+
+ cper_print_log("schema: \n%s\n",
+ json_object_to_json_string_ext(schema,
+ JSON_C_TO_STRING_PRETTY));
+ cper_print_log("to_test: \n%s\n",
+ json_object_to_json_string_ext(to_test,
+ JSON_C_TO_STRING_PRETTY));
+ json_object_put(schema);
+ free(schema_path);
+ return 0;
+}