Fix some json schema validation bugs

There were a couple of places where we would add null objects when
they were not allowed.  Fix them.

Change-Id: I7c4c12ea1fa2913014e79603995267a9e560e288
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/tests/fuzz_cper_buf_to_ir.cpp b/tests/fuzz_cper_buf_to_ir.cpp
index 586c2ba..4baef7b 100644
--- a/tests/fuzz_cper_buf_to_ir.cpp
+++ b/tests/fuzz_cper_buf_to_ir.cpp
@@ -1,11 +1,28 @@
 #include "libcper/cper-parse.h"
+#include "test-utils.hpp"
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
 {
 	json_object *ir = cper_buf_to_ir(data, size);
-	if (ir != NULL) {
-		json_object_put(ir);
+	if (ir == NULL) {
+		return 0;
 	}
+	char *str = strdup(json_object_to_json_string(ir));
+
+	nlohmann::json jsonData = nlohmann::json::parse(str, nullptr, false);
+	free(str);
+	assert(jsonData.is_discarded() == false);
+	std::string error_message;
+	static std::unique_ptr<valijson::Schema> schema =
+		load_schema(AddRequiredProps::NO, 0);
+
+	int valid = schema_validate_from_file(*schema, jsonData, error_message);
+	if (!valid) {
+		std::cout << "JSON: " << jsonData.dump(4) << std::endl;
+		std::cout << "Error: " << error_message << std::endl;
+	}
+	assert(valid);
+	json_object_put(ir);
 
 	return 0;
 }
diff --git a/tests/ir-tests.cpp b/tests/ir-tests.cpp
index 97dad1b..d255353 100644
--- a/tests/ir-tests.cpp
+++ b/tests/ir-tests.cpp
@@ -194,13 +194,14 @@
 
 	//Validate against schema.
 	std::string error_message;
-
-	int valid = schema_validate_from_file(LIBCPER_JSON_SPEC, jsonData,
-					      error_message);
+	std::unique_ptr<valijson::Schema> schema =
+		load_schema(AddRequiredProps::YES, single_section);
+	int valid = schema_validate_from_file(*schema, jsonData, error_message);
 	json_object_put(ir);
 	ASSERT_TRUE(valid)
 		<< "IR validation test failed (single section mode = "
-		<< single_section << ") with message: " << error_message;
+		<< single_section << ") with message: " << error_message
+		<< jsonData.dump(4) << "\n";
 }
 
 std::string to_hex(char *input, size_t size)
diff --git a/tests/meson.build b/tests/meson.build
index e86f26b..f65dc41 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -38,13 +38,14 @@
     valijson_dep = valijson_proj.get_variable('valijson_dep')
 endif
 
-sources = ['ir-tests.cpp', 'test-utils.cpp', 'base64_test.cpp']
+test_sources = ['test-utils.cpp', 'base64_test.cpp']
 
 test_include_dirs = ['.', '../include']
 
 cper_tests = executable(
     'cper-tests',
-    sources,
+    'ir-tests.cpp',
+    test_sources,
     implicit_include_directories: false,
     include_directories: include_directories(test_include_dirs),
     cpp_args: '-fpermissive',
@@ -74,7 +75,7 @@
     foreach fuzzer_test : ['fuzz_cper_buf_to_ir']
         fuzz_exe = executable(
             fuzzer_test,
-            [fuzzer_test + '.cpp'] + libcper_parse_sources + edk_sources,
+            [fuzzer_test + '.cpp'] + libcper_parse_sources + edk_sources + test_sources + libcper_generate_sources,
             implicit_include_directories: false,
             include_directories: include_directories(test_include_dirs),
             cpp_args: fuzz_args,
diff --git a/tests/test-utils.cpp b/tests/test-utils.cpp
index 88f9d7d..b38b36c 100644
--- a/tests/test-utils.cpp
+++ b/tests/test-utils.cpp
@@ -28,6 +28,11 @@
 		  { "faultReason", "description" } },
 		{ "./sections/cper-cxl-component.json",
 		  { "cxlComponentEventLog" } },
+		{ "./sections/cper-ia32x64-processor.json",
+		  { "addressSpace", "errorType", "participationType",
+		    "timedOut", "level", "operation", "preciseIP",
+		    "restartableIP", "overflow", "uncorrected",
+		    "transactionType" } },
 	};
 
 nlohmann::json loadJson(const char *filePath)
@@ -121,22 +126,26 @@
 }
 
 // Document loader callback function
-const nlohmann::json *documentLoader(const std::string &uri)
+const nlohmann::json *documentLoader(const std::string &uri,
+				     AddRequiredProps add_required_props)
 {
 	// Load the schema from a file
-	nlohmann::json *ref_schema = new nlohmann::json;
+	std::unique_ptr<nlohmann::json> ref_schema =
+		std::make_unique<nlohmann::json>();
 	*ref_schema = loadJson(uri.c_str());
 	if (ref_schema->is_discarded()) {
 		std::cerr << "Could not open schema file: " << uri << std::endl;
 	}
-	std::vector<std::string> opt = {};
-	const auto it_optional_file = optional_properties_map.find(uri);
-	if (it_optional_file != optional_properties_map.end()) {
-		opt = it_optional_file->second;
+	if (add_required_props == AddRequiredProps::YES) {
+		std::vector<std::string> opt = {};
+		const auto it_optional_file = optional_properties_map.find(uri);
+		if (it_optional_file != optional_properties_map.end()) {
+			opt = it_optional_file->second;
+		}
+		iterate_make_required_props(*ref_schema, opt);
 	}
-	iterate_make_required_props(*ref_schema, opt);
 
-	return ref_schema;
+	return ref_schema.release();
 }
 
 // Document release callback function
@@ -145,20 +154,19 @@
 	delete adapter; // Free the adapter memory
 }
 
-int schema_validate_from_file(const char *schema_file_path,
-			      nlohmann::json &jsonData,
-			      std::string &error_message)
+std::unique_ptr<valijson::Schema>
+load_schema(AddRequiredProps add_required_props, int single_section)
 {
 	// Load the schema
-	nlohmann::json schema_root = loadJson(schema_file_path);
-	if (schema_root.is_discarded()) {
-		std::cerr << "Could not open schema file: " << schema_file_path
-			  << std::endl;
-		return 0;
-	}
+	fs::path pathObj(LIBCPER_JSON_SPEC);
 
-	fs::path pathObj(schema_file_path);
-	fs::path base_path = pathObj.parent_path();
+	if (single_section) {
+		pathObj /= "cper-json-section-log.json";
+	} else {
+		pathObj /= "cper-json-full-log.json";
+	}
+	nlohmann::json schema_root = loadJson(pathObj.c_str());
+	fs::path base_path(LIBCPER_JSON_SPEC);
 	try {
 		fs::current_path(base_path);
 		// std::cout << "Changed directory to: " << fs::current_path()
@@ -168,21 +176,31 @@
 	}
 
 	// Parse the json schema into an internal schema format
-	valijson::Schema schema;
+	std::unique_ptr<valijson::Schema> schema =
+		std::make_unique<valijson::Schema>();
 	valijson::SchemaParser parser;
 	valijson::adapters::NlohmannJsonAdapter schemaDocumentAdapter(
 		schema_root);
 
 	// Set up callbacks for resolving external references
 	try {
-		parser.populateSchema(schemaDocumentAdapter, schema,
-				      documentLoader, documentRelease);
+		parser.populateSchema(
+			schemaDocumentAdapter, *schema,
+			[add_required_props](const std::string &uri) {
+				return documentLoader(uri, add_required_props);
+			},
+			documentRelease);
 	} catch (std::exception &e) {
 		std::cerr << "Failed to parse schema: " << e.what()
 			  << std::endl;
-		return 0;
 	}
+	return schema;
+}
 
+int schema_validate_from_file(const valijson::Schema &schema,
+			      nlohmann::json &jsonData,
+			      std::string &error_message)
+{
 	// Perform validation
 	valijson::Validator validator(valijson::Validator::kStrongTypes);
 	valijson::ValidationResults results;
diff --git a/tests/test-utils.hpp b/tests/test-utils.hpp
index 42e41bc..ec5f064 100644
--- a/tests/test-utils.hpp
+++ b/tests/test-utils.hpp
@@ -13,12 +13,23 @@
 #include <libcper/generator/sections/gen-section.h>
 }
 
+// Controls whether required properties are added to the majority of property
+// definitions.  This is useful for unit tests that are validating JSON where
+// all fields are valid
+enum class AddRequiredProps { YES, NO };
+
 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);
-int schema_validate_from_file(const char *file_path, nlohmann::json &jsonData,
+
+std::unique_ptr<valijson::Schema>
+load_schema(AddRequiredProps add_required_props, int single_section);
+
+int schema_validate_from_file(const valijson::Schema &schema,
+			      nlohmann::json &jsonData,
 			      std::string &error_message);
+
 nlohmann::json loadJson(const char *filePath);
 
 #endif