[clang] [clang][ssaf] Add `JSONFormat` serialization support for `LUSummary` and `LUSummaryEncoding` (PR #184037)
Balázs Benics via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 2 04:02:11 PST 2026
================
@@ -0,0 +1,2525 @@
+//===- LUSummaryTest.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Unit tests for SSAF JSON serialization format reading and writing of
+// LUSummary and LUSummaryEncoding.
+//
+//===----------------------------------------------------------------------===//
+
+#include "JSONFormatTest.h"
+
+#include "clang/Analysis/Scalable/EntityLinker/LUSummary.h"
+#include "clang/Analysis/Scalable/EntityLinker/LUSummaryEncoding.h"
+#include "clang/Analysis/Scalable/Serialization/JSONFormat.h"
+#include "llvm/Testing/Support/Error.h"
+#include "gmock/gmock.h"
+
+#include <memory>
+#include <vector>
+
+using namespace clang::ssaf;
+using namespace llvm;
+using ::testing::AllOf;
+using ::testing::HasSubstr;
+
+namespace {
+
+// ============================================================================
+// LUSummaryOps - Parameterization for LUSummary/LUSummaryEncoding tests
+// ============================================================================
+
+SummaryOps LUSummaryOps{
+ "Resolved", "LUSummary",
+ [](llvm::StringRef FilePath) -> llvm::Error {
+ auto Result = JSONFormat().readLUSummary(FilePath);
+ return Result ? llvm::Error::success() : Result.takeError();
+ },
+ [](llvm::StringRef FilePath) -> llvm::Error {
+ BuildNamespace BN(BuildNamespaceKind::CompilationUnit, "test.cpp");
+ NestedBuildNamespace NBN(std::move(BN));
+ LUSummary S(std::move(NBN));
+ return JSONFormat().writeLUSummary(S, FilePath);
+ },
+ [](llvm::StringRef InputFilePath,
+ llvm::StringRef OutputFilePath) -> llvm::Error {
+ auto ExpectedS = JSONFormat().readLUSummary(InputFilePath);
+ if (!ExpectedS) {
+ return ExpectedS.takeError();
+ }
+ return JSONFormat().writeLUSummary(*ExpectedS, OutputFilePath);
+ }};
+
+SummaryOps LUSummaryEncodingOps{
+ "Encoding", "LUSummary",
+ [](llvm::StringRef FilePath) -> llvm::Error {
+ auto Result = JSONFormat().readLUSummaryEncoding(FilePath);
+ return Result ? llvm::Error::success() : Result.takeError();
+ },
+ [](llvm::StringRef FilePath) -> llvm::Error {
+ BuildNamespace BN(BuildNamespaceKind::CompilationUnit, "test.cpp");
+ NestedBuildNamespace NBN(std::move(BN));
+ LUSummaryEncoding E(std::move(NBN));
+ return JSONFormat().writeLUSummaryEncoding(E, FilePath);
+ },
+ [](llvm::StringRef InputFilePath,
+ llvm::StringRef OutputFilePath) -> llvm::Error {
+ auto ExpectedE = JSONFormat().readLUSummaryEncoding(InputFilePath);
+ if (!ExpectedE) {
+ return ExpectedE.takeError();
+ }
+ return JSONFormat().writeLUSummaryEncoding(*ExpectedE, OutputFilePath);
+ }};
+
+// ============================================================================
+// LUSummaryTest Test Fixture
+// ============================================================================
+
+class LUSummaryTest : public SummaryTest {};
+
+INSTANTIATE_TEST_SUITE_P(JSONFormat, LUSummaryTest,
+ ::testing::Values(LUSummaryOps, LUSummaryEncodingOps),
+ [](const ::testing::TestParamInfo<SummaryOps> &Info) {
+ return Info.param.Name;
+ });
+
+// ============================================================================
+// JSONFormatLUSummaryTest Test Fixture
+// ============================================================================
+
+class JSONFormatLUSummaryTest : public JSONFormatTest {
+protected:
+ llvm::Expected<LUSummary> readLUSummaryFromFile(StringRef FileName) const {
+ PathString FilePath = makePath(FileName);
+ return JSONFormat().readLUSummary(FilePath);
+ }
+
+ llvm::Expected<LUSummary>
+ readLUSummaryFromString(StringRef JSON,
+ StringRef FileName = "test.json") const {
+ auto ExpectedFilePath = writeJSON(JSON, FileName);
+ if (!ExpectedFilePath) {
+ return ExpectedFilePath.takeError();
+ }
+
+ return readLUSummaryFromFile(FileName);
+ }
+
+ llvm::Error writeLUSummary(const LUSummary &Summary,
+ StringRef FileName) const {
+ PathString FilePath = makePath(FileName);
+ return JSONFormat().writeLUSummary(Summary, FilePath);
+ }
+};
+
+// ============================================================================
+// readJSON() Error Tests
+// ============================================================================
+
+TEST_P(LUSummaryTest, NonexistentFile) {
+ auto Result = readFromFile("nonexistent.json");
+
+ EXPECT_THAT_ERROR(std::move(Result),
+ FailedWithMessage(AllOf(HasSubstr("reading LUSummary from"),
+ HasSubstr("file does not exist"))));
+}
+
+TEST_P(LUSummaryTest, PathIsDirectory) {
+ PathString DirName("test_directory.json");
+
+ auto ExpectedDirPath = makeDirectory(DirName);
+ ASSERT_THAT_EXPECTED(ExpectedDirPath, Succeeded());
+
+ auto Result = readFromFile(DirName);
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(HasSubstr("reading LUSummary from"),
+ HasSubstr("path is a directory, not a file"))));
+}
+
+TEST_P(LUSummaryTest, NotJsonExtension) {
+ PathString FileName("test.txt");
+
+ auto ExpectedFilePath = writeJSON("{}", FileName);
+ ASSERT_THAT_EXPECTED(ExpectedFilePath, Succeeded());
+
+ auto Result = readFromFile(FileName);
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("failed to read file"),
+ HasSubstr("file does not end with '.json' extension"))));
+}
+
+TEST_P(LUSummaryTest, BrokenSymlink) {
+#ifdef _WIN32
+ GTEST_SKIP() << "Symlink model differs on Windows";
+#endif
+
+ const PathString SymlinkFileName("broken_symlink.json");
+
+ // Create a symlink pointing to a non-existent file
+ auto ExpectedSymlinkPath =
+ makeSymlink("nonexistent_target.json", "broken_symlink.json");
+ ASSERT_THAT_EXPECTED(ExpectedSymlinkPath, Succeeded());
+
+ auto Result = readFromFile(SymlinkFileName);
+
+ EXPECT_THAT_ERROR(std::move(Result),
+ FailedWithMessage(AllOf(HasSubstr("reading LUSummary from"),
+ HasSubstr("failed to read file"))));
+}
+
+TEST_P(LUSummaryTest, NoReadPermission) {
+ if (!permissionsAreEnforced()) {
+ GTEST_SKIP() << "File permission checks are not enforced in this "
+ "environment";
+ }
+
+ PathString FileName("no-read-permission.json");
+
+ auto ExpectedFilePath = writeJSON(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ })",
+ FileName);
+ ASSERT_THAT_EXPECTED(ExpectedFilePath, Succeeded());
+
+ auto PermError = setPermission(FileName, sys::fs::perms::owner_write |
+ sys::fs::perms::owner_exe);
+ ASSERT_THAT_ERROR(std::move(PermError), Succeeded());
+
+ auto Result = readFromFile(FileName);
+
+ EXPECT_THAT_ERROR(std::move(Result),
+ FailedWithMessage(AllOf(HasSubstr("reading LUSummary from"),
+ HasSubstr("failed to read file"))));
+
+ // Restore permissions for cleanup
+ auto RestoreError = setPermission(FileName, sys::fs::perms::all_all);
+ EXPECT_THAT_ERROR(std::move(RestoreError), Succeeded());
+}
+
+TEST_P(LUSummaryTest, InvalidSyntax) {
+ auto Result = readFromString("{ invalid json }");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("Expected object key"))));
+}
+
+TEST_P(LUSummaryTest, NotObject) {
+ auto Result = readFromString("[]");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("failed to read LUSummary"),
+ HasSubstr("expected JSON object"))));
+}
+
+// ============================================================================
+// JSONFormat::entityLinkageFromJSON() Error Tests
+// ============================================================================
+
+TEST_P(LUSummaryTest, LinkageTableEntryLinkageMissingType) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": {}
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading LinkageTable from field 'linkage_table'"),
+ HasSubstr("reading LinkageTable entry from index '0'"),
+ HasSubstr("reading EntityLinkage from field 'linkage'"),
+ HasSubstr("failed to read EntityLinkageType from field 'type'"),
+ HasSubstr("expected JSON string"))));
+}
+
+TEST_P(LUSummaryTest, LinkageTableEntryLinkageInvalidType) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "invalid_type" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading LinkageTable from field 'linkage_table'"),
+ HasSubstr("reading LinkageTable entry from index '0'"),
+ HasSubstr("reading EntityLinkage from field 'linkage'"),
+ HasSubstr("invalid EntityLinkageType value 'invalid_type' for "
+ "field 'type'"))));
+}
+
+// ============================================================================
+// JSONFormat::linkageTableEntryFromJSON() Error Tests
+// ============================================================================
+
+TEST_P(LUSummaryTest, LinkageTableEntryMissingId) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [
+ {
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading LinkageTable from field 'linkage_table'"),
+ HasSubstr("reading LinkageTable entry from index '0'"),
+ HasSubstr("failed to read EntityId from field 'id'"),
+ HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
+}
+
+TEST_P(LUSummaryTest, LinkageTableEntryIdNotUInt64) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": "not_a_number",
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading LinkageTable from field 'linkage_table'"),
+ HasSubstr("reading LinkageTable entry from index '0'"),
+ HasSubstr("failed to read EntityId from field 'id'"),
+ HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
+}
+
+TEST_P(LUSummaryTest, LinkageTableEntryMissingLinkage) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": 0
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading LinkageTable from field 'linkage_table'"),
+ HasSubstr("reading LinkageTable entry from index '0'"),
+ HasSubstr("failed to read EntityLinkage from field 'linkage'"),
+ HasSubstr("expected JSON object"))));
+}
+
+// ============================================================================
+// JSONFormat::linkageTableFromJSON() Error Tests
+// ============================================================================
+
+TEST_P(LUSummaryTest, LinkageTableNotArray) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": {},
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("failed to read LinkageTable from field 'linkage_table'"),
+ HasSubstr("expected JSON array"))));
+}
+
+TEST_P(LUSummaryTest, LinkageTableElementNotObject) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": ["invalid"],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading LinkageTable from field 'linkage_table'"),
+ HasSubstr("failed to read LinkageTable entry from index '0'"),
+ HasSubstr("expected JSON object"))));
+}
+
+TEST_P(LUSummaryTest, LinkageTableExtraId) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading LinkageTable from field 'linkage_table'"),
+ HasSubstr("reading LinkageTable entry from index '0'"),
+ HasSubstr("failed to deserialize LinkageTable"),
+ HasSubstr("extra 'EntityId(0)' not present in IdTable"))));
+}
+
+TEST_P(LUSummaryTest, LinkageTableMissingId) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading LinkageTable from field 'linkage_table'"),
+ HasSubstr("failed to deserialize LinkageTable"),
+ HasSubstr("missing 'EntityId(0)' present in IdTable"))));
+}
+
+TEST_P(LUSummaryTest, LinkageTableDuplicateId) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "External" }
+ },
+ {
+ "id": 0,
+ "linkage": { "type": "Internal" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading LinkageTable from field 'linkage_table'"),
+ HasSubstr("failed to insert LinkageTable entry at index '1'"),
+ HasSubstr("encountered duplicate 'EntityId(0)'"))));
+}
+
+// ============================================================================
+// JSONFormat::nestedBuildNamespaceFromJSON() Error Tests (lu_namespace field)
+// ============================================================================
+
+TEST_P(LUSummaryTest, LUNamespaceNotArray) {
+ auto Result = readFromString(R"({
+ "lu_namespace": { "kind": "CompilationUnit", "name": "test.cpp" },
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr(
+ "failed to read NestedBuildNamespace from field 'lu_namespace'"),
+ HasSubstr("expected JSON array"))));
+}
+
+TEST_P(LUSummaryTest, LUNamespaceElementNotObject) {
+ auto Result = readFromString(R"({
+ "lu_namespace": ["invalid"],
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading NestedBuildNamespace from field 'lu_namespace'"),
+ HasSubstr("failed to read BuildNamespace from index '0'"),
+ HasSubstr("expected JSON object"))));
+}
+
+TEST_P(LUSummaryTest, LUNamespaceElementMissingKind) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [{ "name": "test.cpp" }],
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading NestedBuildNamespace from field 'lu_namespace'"),
+ HasSubstr("reading BuildNamespace from index '0'"),
+ HasSubstr("failed to read BuildNamespaceKind from field 'kind'"),
+ HasSubstr("expected JSON string"))));
+}
+
+TEST_P(LUSummaryTest, LUNamespaceElementInvalidKind) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [{ "kind": "invalid_kind", "name": "test.cpp" }],
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading NestedBuildNamespace from field 'lu_namespace'"),
+ HasSubstr("reading BuildNamespace from index '0'"),
+ HasSubstr("reading BuildNamespaceKind from field 'kind'"),
+ HasSubstr("invalid BuildNamespaceKind value 'invalid_kind' for "
+ "field 'kind'"))));
+}
+
+TEST_P(LUSummaryTest, LUNamespaceElementMissingName) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [{ "kind": "CompilationUnit" }],
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading NestedBuildNamespace from field 'lu_namespace'"),
+ HasSubstr("reading BuildNamespace from index '0'"),
+ HasSubstr("failed to read BuildNamespaceName from field 'name'"),
+ HasSubstr("expected JSON string"))));
+}
+
+// ============================================================================
+// JSONFormat::nestedBuildNamespaceFromJSON() Error Tests (EntityName namespace)
+// ============================================================================
+
+TEST_P(LUSummaryTest, NamespaceElementNotObject) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": ["invalid"]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "None" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("reading EntityName from field 'name'"),
+ HasSubstr("reading NestedBuildNamespace from field 'namespace'"),
+ HasSubstr("failed to read BuildNamespace from index '0'"),
+ HasSubstr("expected JSON object"))));
+}
+
+TEST_P(LUSummaryTest, NamespaceElementMissingKind) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "name": "test.cpp"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "Internal" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("reading EntityName from field 'name'"),
+ HasSubstr("reading NestedBuildNamespace from field 'namespace'"),
+ HasSubstr("reading BuildNamespace from index '0'"),
+ HasSubstr("failed to read BuildNamespaceKind from field 'kind'"),
+ HasSubstr("expected JSON string"))));
+}
+
+TEST_P(LUSummaryTest, NamespaceElementInvalidKind) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "invalid_kind",
+ "name": "test.cpp"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("reading EntityName from field 'name'"),
+ HasSubstr("reading NestedBuildNamespace from field 'namespace'"),
+ HasSubstr("reading BuildNamespace from index '0'"),
+ HasSubstr("reading BuildNamespaceKind from field 'kind'"),
+ HasSubstr("invalid BuildNamespaceKind value 'invalid_kind' for "
+ "field 'kind'"))));
+}
+
+TEST_P(LUSummaryTest, NamespaceElementMissingName) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "None" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("reading EntityName from field 'name'"),
+ HasSubstr("reading NestedBuildNamespace from field 'namespace'"),
+ HasSubstr("reading BuildNamespace from index '0'"),
+ HasSubstr("failed to read BuildNamespaceName from field 'name'"),
+ HasSubstr("expected JSON string"))));
+}
+
+// ============================================================================
+// JSONFormat::entityNameFromJSON() Error Tests
+// ============================================================================
+
+TEST_P(LUSummaryTest, EntityNameMissingUSR) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "None" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("reading EntityName from field 'name'"),
+ HasSubstr("failed to read USR from field 'usr'"),
+ HasSubstr("expected JSON string"))));
+}
+
+TEST_P(LUSummaryTest, EntityNameMissingSuffix) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("reading EntityName from field 'name'"),
+ HasSubstr("failed to read Suffix from field 'suffix'"),
+ HasSubstr("expected JSON string"))));
+}
+
+TEST_P(LUSummaryTest, EntityNameMissingNamespace) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": ""
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "None" }
+ }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("reading EntityName from field 'name'"),
+ HasSubstr("failed to read NestedBuildNamespace from field "
+ "'namespace'"),
+ HasSubstr("expected JSON array"))));
+}
+
+// ============================================================================
+// JSONFormat::entityIdTableEntryFromJSON() Error Tests
+// ============================================================================
+
+TEST_P(LUSummaryTest, IDTableEntryMissingID) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("failed to read EntityId from field 'id'"),
+ HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
+}
+
+TEST_P(LUSummaryTest, IDTableEntryMissingName) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0
+ }
+ ],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("failed to read EntityName from field 'name'"),
+ HasSubstr("expected JSON object"))));
+}
+
+TEST_P(LUSummaryTest, IDTableEntryIDNotUInt64) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": "not_a_number",
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("reading EntityIdTable entry from index '0'"),
+ HasSubstr("failed to read EntityId from field 'id'"),
+ HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
+}
+
+// ============================================================================
+// JSONFormat::entityIdTableFromJSON() Error Tests
+// ============================================================================
+
+TEST_P(LUSummaryTest, IDTableNotArray) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": {},
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("failed to read IdTable from field 'id_table'"),
+ HasSubstr("expected JSON array"))));
+}
+
+TEST_P(LUSummaryTest, IDTableElementNotObject) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": ["invalid"],
+ "linkage_table": [],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("failed to read EntityIdTable entry from index '0'"),
+ HasSubstr("expected JSON object"))));
+}
+
+TEST_P(LUSummaryTest, DuplicateEntity) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ]
+ }
+ },
+ {
+ "id": 1,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ { "id": 0, "linkage": { "type": "None" } },
+ { "id": 1, "linkage": { "type": "None" } }
+ ],
+ "data": []
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(
+ AllOf(HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading IdTable from field 'id_table'"),
+ HasSubstr("failed to insert EntityIdTable entry at index '1'"),
+ HasSubstr("encountered duplicate 'EntityId(0)'"))));
+}
+
+// ============================================================================
+// JSONFormat::readLUSummary() Error Tests (LUSummary-only)
+// ============================================================================
+
+TEST_F(JSONFormatLUSummaryTest, ReadEntitySummaryNoFormatInfo) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "UnregisteredEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("reading EntitySummary from field 'entity_summary'"),
+ HasSubstr("failed to deserialize EntitySummary"),
+ HasSubstr(
+ "no FormatInfo registered for "
+ "'SummaryName(UnregisteredEntitySummaryForJSONFormatTest)'"))));
+}
+
+// ============================================================================
+// PairsEntitySummaryForJSONFormatTest Deserialization Error Tests
+// ============================================================================
+
+TEST_F(JSONFormatLUSummaryTest,
+ PairsEntitySummaryForJSONFormatTestMissingPairsField) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("reading EntitySummary from field 'entity_summary'"),
+ HasSubstr("missing or invalid field 'pairs'"))));
+}
+
+TEST_F(JSONFormatLUSummaryTest,
+ PairsEntitySummaryForJSONFormatTestInvalidPairsFieldType) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": "not_an_array"
+ }
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("reading EntitySummary from field 'entity_summary'"),
+ HasSubstr("missing or invalid field 'pairs'"))));
+}
+
+TEST_F(JSONFormatLUSummaryTest,
+ PairsEntitySummaryForJSONFormatTestPairsElementNotObject) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": ["not_an_object"]
+ }
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("reading EntitySummary from field 'entity_summary'"),
+ HasSubstr("pairs element at index 0 is not a JSON object"))));
+}
+
+TEST_F(JSONFormatLUSummaryTest,
+ PairsEntitySummaryForJSONFormatTestMissingFirstField) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": [
+ {
+ "second": 1
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("reading EntitySummary from field 'entity_summary'"),
+ HasSubstr("missing or invalid 'first' field at index '0'"))));
+}
+
+TEST_F(JSONFormatLUSummaryTest,
+ PairsEntitySummaryForJSONFormatTestInvalidFirstField) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": [
+ {
+ "first": "not_a_number",
+ "second": 1
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("reading EntitySummary from field 'entity_summary'"),
+ HasSubstr("missing or invalid 'first' field at index '0'"))));
+}
+
+TEST_F(JSONFormatLUSummaryTest,
+ PairsEntitySummaryForJSONFormatTestMissingSecondField) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": [
+ {
+ "first": 0
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("reading EntitySummary from field 'entity_summary'"),
+ HasSubstr("missing or invalid 'second' field at index '0'"))));
+}
+
+TEST_F(JSONFormatLUSummaryTest,
+ PairsEntitySummaryForJSONFormatTestInvalidSecondField) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": [
+ {
+ "first": 0,
+ "second": "not_a_number"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("reading EntitySummary from field 'entity_summary'"),
+ HasSubstr("missing or invalid 'second' field at index '0'"))));
+}
+
+// ============================================================================
+// JSONFormat::entityDataMapFromJSON() Error Tests
+// ============================================================================
+
+TEST_P(LUSummaryTest, EntityDataMissingEntityID) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("failed to read EntityId from field 'entity_id'"),
+ HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
+}
+
+TEST_P(LUSummaryTest, EntityDataMissingEntitySummary) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("failed to read EntitySummary from field 'entity_summary'"),
+ HasSubstr("expected JSON object"))));
+}
+
+TEST_P(LUSummaryTest, EntityIDNotUInt64) {
+ auto Result = readFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": "not_a_number",
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_ERROR(
+ std::move(Result),
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("failed to read EntityId from field 'entity_id'"),
+ HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
+}
+
+TEST_F(JSONFormatLUSummaryTest, ReadEntitySummaryMissingData) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "NullEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("failed to deserialize EntitySummary"),
+ HasSubstr("null EntitySummary data for "
+ "'SummaryName(NullEntitySummaryForJSONFormatTest)'"))));
+}
+
+TEST_F(JSONFormatLUSummaryTest, ReadEntitySummaryMismatchedSummaryName) {
+ auto Result = readLUSummaryFromString(R"({
+ "lu_namespace": [
+ {
+ "kind": "LinkUnit",
+ "name": "test.exe"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "MismatchedEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+ })");
+
+ EXPECT_THAT_EXPECTED(
+ Result,
+ FailedWithMessage(AllOf(
+ HasSubstr("reading LUSummary from file"),
+ HasSubstr("reading SummaryData entries from field 'data'"),
+ HasSubstr("reading SummaryData entry from index '0'"),
+ HasSubstr("reading EntitySummary entries from field 'summary_data'"),
+ HasSubstr("reading EntitySummary entry from index '0'"),
+ HasSubstr("failed to deserialize EntitySummary"),
+ HasSubstr(
+ "EntitySummary data for "
+ "'SummaryName(MismatchedEntitySummaryForJSONFormatTest)' reports "
+ "mismatched "
+ "'SummaryName(MismatchedEntitySummaryForJSONFormatTest_WrongName)"
+ "'"))));
----------------
steakhal wrote:
Could you re-chunk these strings?
https://github.com/llvm/llvm-project/pull/184037
More information about the cfe-commits
mailing list