[clang] ce0668b - [clang][ssaf] Convert `JSONFormat` tests for `LUSummary` and `LUSummaryEncoding` to lit tests (#192738)

via cfe-commits cfe-commits at lists.llvm.org
Wed Jun 10 07:13:45 PDT 2026


Author: Aviral Goel
Date: 2026-06-10T07:13:39-07:00
New Revision: ce0668b7346c3bbde4e17907d678a739ab1877dd

URL: https://github.com/llvm/llvm-project/commit/ce0668b7346c3bbde4e17907d678a739ab1877dd
DIFF: https://github.com/llvm/llvm-project/commit/ce0668b7346c3bbde4e17907d678a739ab1877dd.diff

LOG: [clang][ssaf] Convert `JSONFormat` tests for `LUSummary` and `LUSummaryEncoding` to lit tests (#192738)

Added: 
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-element-not-object.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-data.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-summary-name.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-not-array.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity-id-in-data-map.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-summary-name.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-element-not-object.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-id.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-summary.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-id-not-uint64.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-namespace.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-suffix.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-usr.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-element-not-object.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-id-not-uint64.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-id.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-name.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-not-array.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/invalid-syntax.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-duplicate-id.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-element-not-object.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-id-not-uint64.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-id.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-linkage.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-extra-id.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-missing-id.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-not-array.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-invalid-kind.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-kind.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-name.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-not-object.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-not-array.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-data.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-id-table.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-linkage-table.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-lu-namespace.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-invalid-kind.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-kind.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-name.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-not-object.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-json-extension.txt
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-object.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-element-not-object.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-first-field.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-pairs-field-type.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-second-field.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-first-field.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-pairs-field.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-second-field.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/read-entity-summary-no-format-info.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-data-entry.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-namespace.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-external.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-internal.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-multiple.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-none.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-multiple-namespace-elements.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-single-namespace-element.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-two-summary-types.json
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/id-table.test
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/io.test
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/linkage.test
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/permissions.test
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/round-trip.test
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/summary-data.test
    clang/test/Analysis/Scalable/ssaf-format/LUSummary/top-level.test

Modified: 
    clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/LUSummaryTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-element-not-object.json
new file mode 100644
index 0000000000000..86d3ef89ffe8f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-element-not-object.json
@@ -0,0 +1,13 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    "invalid"
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-data.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-data.json
new file mode 100644
index 0000000000000..3374f3c31157f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-data.json
@@ -0,0 +1,15 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary"
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-summary-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-summary-name.json
new file mode 100644
index 0000000000000..fe9b2c46d4c8f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-entry-missing-summary-name.json
@@ -0,0 +1,15 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_data": []
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-not-array.json
new file mode 100644
index 0000000000000..9b53c28a16988
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/data-not-array.json
@@ -0,0 +1,11 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": {}
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity-id-in-data-map.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity-id-in-data-map.json
new file mode 100644
index 0000000000000..8a59b795a965b
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity-id-in-data-map.json
@@ -0,0 +1,54 @@
+{
+  "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": "None"
+      }
+    }
+  ],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "pairs": []
+          }
+        },
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "pairs": []
+          }
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity.json
new file mode 100644
index 0000000000000..3330d039515e2
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-entity.json
@@ -0,0 +1,59 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-summary-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-summary-name.json
new file mode 100644
index 0000000000000..9b223799cfcde
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/duplicate-summary-name.json
@@ -0,0 +1,20 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": []
+    },
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": []
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-element-not-object.json
new file mode 100644
index 0000000000000..03dc6925a3679
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-element-not-object.json
@@ -0,0 +1,18 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        "invalid"
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-id.json
new file mode 100644
index 0000000000000..d312667f7b7e0
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-id.json
@@ -0,0 +1,20 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_summary": {}
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-summary.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-summary.json
new file mode 100644
index 0000000000000..a230bf12d35b6
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-data-missing-entity-summary.json
@@ -0,0 +1,20 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-id-not-uint64.json
new file mode 100644
index 0000000000000..efb7db6a7b8d6
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-id-not-uint64.json
@@ -0,0 +1,21 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": "not_a_number",
+          "entity_summary": {}
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-namespace.json
new file mode 100644
index 0000000000000..a04603f75e003
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-namespace.json
@@ -0,0 +1,26 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-suffix.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-suffix.json
new file mode 100644
index 0000000000000..30adfac73018b
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-suffix.json
@@ -0,0 +1,31 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-usr.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-usr.json
new file mode 100644
index 0000000000000..2f36b9095cb45
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/entity-name-missing-usr.json
@@ -0,0 +1,35 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-element-not-object.json
new file mode 100644
index 0000000000000..b7860f1bcc7be
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-element-not-object.json
@@ -0,0 +1,13 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [
+    "invalid"
+  ],
+  "linkage_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-id-not-uint64.json
new file mode 100644
index 0000000000000..dec95270705bc
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-id-not-uint64.json
@@ -0,0 +1,29 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-id.json
new file mode 100644
index 0000000000000..4ec9f8d13a921
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-id.json
@@ -0,0 +1,28 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-name.json
new file mode 100644
index 0000000000000..4a7ff4a3f8b30
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-entry-missing-name.json
@@ -0,0 +1,15 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [
+    {
+      "id": 0
+    }
+  ],
+  "linkage_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-not-array.json
new file mode 100644
index 0000000000000..6d807d558b0ad
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/id-table-not-array.json
@@ -0,0 +1,11 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": {},
+  "linkage_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/invalid-syntax.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/invalid-syntax.json
new file mode 100644
index 0000000000000..572686df131de
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/invalid-syntax.json
@@ -0,0 +1 @@
+{ invalid json }
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-duplicate-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-duplicate-id.json
new file mode 100644
index 0000000000000..a70f7e8ba8207
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-duplicate-id.json
@@ -0,0 +1,42 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-element-not-object.json
new file mode 100644
index 0000000000000..4a5116d64fe7c
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-element-not-object.json
@@ -0,0 +1,13 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [
+    "invalid"
+  ],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-id-not-uint64.json
new file mode 100644
index 0000000000000..1fa2adc4972bd
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-id-not-uint64.json
@@ -0,0 +1,18 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [
+    {
+      "id": "not_a_number",
+      "linkage": {
+        "type": "External"
+      }
+    }
+  ],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
new file mode 100644
index 0000000000000..e76368984868e
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
@@ -0,0 +1,18 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "invalid_type"
+      }
+    }
+  ],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
new file mode 100644
index 0000000000000..7926d1a869537
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
@@ -0,0 +1,16 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {}
+    }
+  ],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-id.json
new file mode 100644
index 0000000000000..e56473d19a15b
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-id.json
@@ -0,0 +1,17 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [
+    {
+      "linkage": {
+        "type": "External"
+      }
+    }
+  ],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-linkage.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-linkage.json
new file mode 100644
index 0000000000000..e0c88f14ce2e0
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-entry-missing-linkage.json
@@ -0,0 +1,15 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [
+    {
+      "id": 0
+    }
+  ],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-extra-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-extra-id.json
new file mode 100644
index 0000000000000..df8800eeaf815
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-extra-id.json
@@ -0,0 +1,18 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "External"
+      }
+    }
+  ],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-missing-id.json
new file mode 100644
index 0000000000000..dafc9ada14147
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-missing-id.json
@@ -0,0 +1,29 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-not-array.json
new file mode 100644
index 0000000000000..c693b839d5750
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/linkage-table-not-array.json
@@ -0,0 +1,11 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": {},
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-invalid-kind.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-invalid-kind.json
new file mode 100644
index 0000000000000..b1dd046962892
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-invalid-kind.json
@@ -0,0 +1,11 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "invalid_kind",
+      "name": "test.cpp"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-kind.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-kind.json
new file mode 100644
index 0000000000000..50631a045c0c9
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-kind.json
@@ -0,0 +1,10 @@
+{
+  "lu_namespace": [
+    {
+      "name": "test.cpp"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-name.json
new file mode 100644
index 0000000000000..855b771ae594d
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-missing-name.json
@@ -0,0 +1,10 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-not-object.json
new file mode 100644
index 0000000000000..b515fb62ac8c4
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-element-not-object.json
@@ -0,0 +1,8 @@
+{
+  "lu_namespace": [
+    "invalid"
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-not-array.json
new file mode 100644
index 0000000000000..66719784515c2
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/lu-namespace-not-array.json
@@ -0,0 +1,9 @@
+{
+  "lu_namespace": {
+    "kind": "CompilationUnit",
+    "name": "test.cpp"
+  },
+  "id_table": [],
+  "linkage_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-data.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-data.json
new file mode 100644
index 0000000000000..5bf3fcc3528fb
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-data.json
@@ -0,0 +1,10 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-id-table.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-id-table.json
new file mode 100644
index 0000000000000..ed3e9267849f1
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-id-table.json
@@ -0,0 +1,9 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-linkage-table.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-linkage-table.json
new file mode 100644
index 0000000000000..774b5df9c6163
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-linkage-table.json
@@ -0,0 +1,10 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-lu-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-lu-namespace.json
new file mode 100644
index 0000000000000..646de61fb1550
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/missing-lu-namespace.json
@@ -0,0 +1,5 @@
+{
+  "id_table": [],
+  "linkage_table": [],
+  "data": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-invalid-kind.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-invalid-kind.json
new file mode 100644
index 0000000000000..5ccec8e79e461
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-invalid-kind.json
@@ -0,0 +1,32 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-kind.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-kind.json
new file mode 100644
index 0000000000000..e5f9c39fc4a10
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-kind.json
@@ -0,0 +1,31 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-name.json
new file mode 100644
index 0000000000000..a80cca7c12626
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-missing-name.json
@@ -0,0 +1,31 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-not-object.json
new file mode 100644
index 0000000000000..9ff091337d04f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/namespace-element-not-object.json
@@ -0,0 +1,29 @@
+{
+  "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": []
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-json-extension.txt b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-json-extension.txt
new file mode 100644
index 0000000000000..9e26dfeeb6e64
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-json-extension.txt
@@ -0,0 +1 @@
+{}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-object.json
new file mode 100644
index 0000000000000..0637a088a01e8
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/not-object.json
@@ -0,0 +1 @@
+[]
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-element-not-object.json
new file mode 100644
index 0000000000000..cccfd58b39470
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-element-not-object.json
@@ -0,0 +1,25 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "pairs": [
+              "not_an_object"
+            ]
+          }
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-first-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-first-field.json
new file mode 100644
index 0000000000000..5b17d9a2bdb63
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-first-field.json
@@ -0,0 +1,30 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "pairs": [
+              {
+                "first": "not_a_number",
+                "second": {
+                  "@": 1
+                }
+              }
+            ]
+          }
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-pairs-field-type.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-pairs-field-type.json
new file mode 100644
index 0000000000000..ea02adf5cec9c
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-pairs-field-type.json
@@ -0,0 +1,23 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "pairs": "not_an_array"
+          }
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-second-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-second-field.json
new file mode 100644
index 0000000000000..fae104bb55c90
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-invalid-second-field.json
@@ -0,0 +1,30 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "pairs": [
+              {
+                "first": {
+                  "@": 0
+                },
+                "second": "not_a_number"
+              }
+            ]
+          }
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-first-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-first-field.json
new file mode 100644
index 0000000000000..ed31f9727cdbf
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-first-field.json
@@ -0,0 +1,29 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "pairs": [
+              {
+                "second": {
+                  "@": 1
+                }
+              }
+            ]
+          }
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-pairs-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-pairs-field.json
new file mode 100644
index 0000000000000..d9c2c1c8246d4
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-pairs-field.json
@@ -0,0 +1,21 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {}
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-second-field.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-second-field.json
new file mode 100644
index 0000000000000..048f2c812ef78
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/pairs-missing-second-field.json
@@ -0,0 +1,29 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "PairsEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "pairs": [
+              {
+                "first": {
+                  "@": 0
+                }
+              }
+            ]
+          }
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/read-entity-summary-no-format-info.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/read-entity-summary-no-format-info.json
new file mode 100644
index 0000000000000..65fbdeb079b77
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/read-entity-summary-no-format-info.json
@@ -0,0 +1,21 @@
+{
+  "lu_namespace": [
+    {
+      "kind": "LinkUnit",
+      "name": "test.exe"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "data": [
+    {
+      "summary_name": "UnregisteredEntitySummary",
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {}
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-data-entry.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-data-entry.json
new file mode 100644
index 0000000000000..015f265924f2a
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-data-entry.json
@@ -0,0 +1,16 @@
+{
+  "data": [
+    {
+      "summary_data": [],
+      "summary_name": "PairsEntitySummary"
+    }
+  ],
+  "id_table": [],
+  "linkage_table": [],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    }
+  ]
+}

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-namespace.json
new file mode 100644
index 0000000000000..a31f370ee0fad
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-empty-namespace.json
@@ -0,0 +1,11 @@
+{
+  "data": [],
+  "id_table": [],
+  "linkage_table": [],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    }
+  ]
+}

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-external.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-external.json
new file mode 100644
index 0000000000000..7dbfd924c701e
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-external.json
@@ -0,0 +1,32 @@
+{
+  "data": [],
+  "id_table": [
+    {
+      "id": 0,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at baz"
+      }
+    }
+  ],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "External"
+      }
+    }
+  ],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    }
+  ]
+}

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-internal.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-internal.json
new file mode 100644
index 0000000000000..638b77e2c1e3f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-internal.json
@@ -0,0 +1,32 @@
+{
+  "data": [],
+  "id_table": [
+    {
+      "id": 0,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at bar"
+      }
+    }
+  ],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "Internal"
+      }
+    }
+  ],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    }
+  ]
+}

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-multiple.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-multiple.json
new file mode 100644
index 0000000000000..51b59f0458923
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-multiple.json
@@ -0,0 +1,70 @@
+{
+  "data": [],
+  "id_table": [
+    {
+      "id": 1,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at bar"
+      }
+    },
+    {
+      "id": 2,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at baz"
+      }
+    },
+    {
+      "id": 0,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at foo"
+      }
+    }
+  ],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "None"
+      }
+    },
+    {
+      "id": 1,
+      "linkage": {
+        "type": "Internal"
+      }
+    },
+    {
+      "id": 2,
+      "linkage": {
+        "type": "External"
+      }
+    }
+  ],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    }
+  ]
+}

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-none.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-none.json
new file mode 100644
index 0000000000000..2d2e9bf20edab
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-linkage-none.json
@@ -0,0 +1,32 @@
+{
+  "data": [],
+  "id_table": [
+    {
+      "id": 0,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at foo"
+      }
+    }
+  ],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "None"
+      }
+    }
+  ],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    }
+  ]
+}

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-multiple-namespace-elements.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-multiple-namespace-elements.json
new file mode 100644
index 0000000000000..86b0ad87e4528
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-multiple-namespace-elements.json
@@ -0,0 +1,19 @@
+{
+  "data": [],
+  "id_table": [],
+  "linkage_table": [],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "a.cpp"
+    },
+    {
+      "kind": "CompilationUnit",
+      "name": "b.cpp"
+    },
+    {
+      "kind": "LinkUnit",
+      "name": "libtest.so"
+    }
+  ]
+}

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-single-namespace-element.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-single-namespace-element.json
new file mode 100644
index 0000000000000..a31f370ee0fad
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-single-namespace-element.json
@@ -0,0 +1,11 @@
+{
+  "data": [],
+  "id_table": [],
+  "linkage_table": [],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    }
+  ]
+}

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-two-summary-types.json b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-two-summary-types.json
new file mode 100644
index 0000000000000..f83708321f0f8
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/Inputs/rt-two-summary-types.json
@@ -0,0 +1,240 @@
+{
+  "data": [
+    {
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "pairs": []
+          }
+        },
+        {
+          "entity_id": 1,
+          "entity_summary": {
+            "pairs": [
+              {
+                "first": {
+                  "@": 1
+                },
+                "second": {
+                  "@": 3
+                }
+              }
+            ]
+          }
+        },
+        {
+          "entity_id": 2,
+          "entity_summary": {
+            "pairs": [
+              {
+                "first": {
+                  "@": 2
+                },
+                "second": {
+                  "@": 4
+                }
+              },
+              {
+                "first": {
+                  "@": 2
+                },
+                "second": {
+                  "@": 3
+                }
+              }
+            ]
+          }
+        },
+        {
+          "entity_id": 3,
+          "entity_summary": {
+            "pairs": [
+              {
+                "first": {
+                  "@": 3
+                },
+                "second": {
+                  "@": 1
+                }
+              }
+            ]
+          }
+        },
+        {
+          "entity_id": 4,
+          "entity_summary": {
+            "pairs": [
+              {
+                "first": {
+                  "@": 4
+                },
+                "second": {
+                  "@": 0
+                }
+              },
+              {
+                "first": {
+                  "@": 4
+                },
+                "second": {
+                  "@": 2
+                }
+              }
+            ]
+          }
+        }
+      ],
+      "summary_name": "PairsEntitySummary"
+    },
+    {
+      "summary_data": [
+        {
+          "entity_id": 0,
+          "entity_summary": {
+            "tags": [
+              "entry-point"
+            ]
+          }
+        },
+        {
+          "entity_id": 1,
+          "entity_summary": {
+            "tags": [
+              "internal-only"
+            ]
+          }
+        },
+        {
+          "entity_id": 2,
+          "entity_summary": {
+            "tags": []
+          }
+        },
+        {
+          "entity_id": 3,
+          "entity_summary": {
+            "tags": [
+              "internal-only"
+            ]
+          }
+        },
+        {
+          "entity_id": 4,
+          "entity_summary": {
+            "tags": [
+              "exported",
+              "hot"
+            ]
+          }
+        }
+      ],
+      "summary_name": "TagsEntitySummary"
+    }
+  ],
+  "id_table": [
+    {
+      "id": 1,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at bar"
+      }
+    },
+    {
+      "id": 2,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at baz"
+      }
+    },
+    {
+      "id": 0,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at foo"
+      }
+    },
+    {
+      "id": 4,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at quux"
+      }
+    },
+    {
+      "id": 3,
+      "name": {
+        "namespace": [
+          {
+            "kind": "CompilationUnit",
+            "name": "test.cpp"
+          }
+        ],
+        "suffix": "",
+        "usr": "c:@F at qux"
+      }
+    }
+  ],
+  "linkage_table": [
+    {
+      "id": 0,
+      "linkage": {
+        "type": "None"
+      }
+    },
+    {
+      "id": 1,
+      "linkage": {
+        "type": "None"
+      }
+    },
+    {
+      "id": 2,
+      "linkage": {
+        "type": "Internal"
+      }
+    },
+    {
+      "id": 3,
+      "linkage": {
+        "type": "Internal"
+      }
+    },
+    {
+      "id": 4,
+      "linkage": {
+        "type": "External"
+      }
+    }
+  ],
+  "lu_namespace": [
+    {
+      "kind": "CompilationUnit",
+      "name": "test.cpp"
+    }
+  ]
+}

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/id-table.test b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/id-table.test
new file mode 100644
index 0000000000000..733cd61d844a2
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/id-table.test
@@ -0,0 +1,148 @@
+// IdTable deserialization error tests: EntityName.namespace, EntityName,
+// EntityIdTable entry, and EntityIdTable structural / consistency errors.
+
+// REQUIRES: plugins
+
+// ============================================================================
+// nestedBuildNamespaceFromJSON() errors (EntityName namespace)
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/namespace-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-ELEMENT-NOT-OBJECT
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/namespace-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-ELEMENT-NOT-OBJECT
+// NAMESPACE-ELEMENT-NOT-OBJECT:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}namespace-element-not-object.json'
+// NAMESPACE-ELEMENT-NOT-OBJECT-NEXT: reading IdTable from field 'id_table'
+// NAMESPACE-ELEMENT-NOT-OBJECT-NEXT: reading EntityIdTable entry from index '0'
+// NAMESPACE-ELEMENT-NOT-OBJECT-NEXT: reading EntityName from field 'name'
+// NAMESPACE-ELEMENT-NOT-OBJECT-NEXT: reading NestedBuildNamespace from field 'namespace'
+// NAMESPACE-ELEMENT-NOT-OBJECT-NEXT: failed to read BuildNamespace from index '0': expected JSON object
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/namespace-element-missing-kind.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-ELEMENT-MISSING-KIND
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/namespace-element-missing-kind.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-ELEMENT-MISSING-KIND
+// NAMESPACE-ELEMENT-MISSING-KIND:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}namespace-element-missing-kind.json'
+// NAMESPACE-ELEMENT-MISSING-KIND-NEXT: reading IdTable from field 'id_table'
+// NAMESPACE-ELEMENT-MISSING-KIND-NEXT: reading EntityIdTable entry from index '0'
+// NAMESPACE-ELEMENT-MISSING-KIND-NEXT: reading EntityName from field 'name'
+// NAMESPACE-ELEMENT-MISSING-KIND-NEXT: reading NestedBuildNamespace from field 'namespace'
+// NAMESPACE-ELEMENT-MISSING-KIND-NEXT: reading BuildNamespace from index '0'
+// NAMESPACE-ELEMENT-MISSING-KIND-NEXT: failed to read BuildNamespaceKind from field 'kind': expected JSON string
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/namespace-element-invalid-kind.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-ELEMENT-INVALID-KIND
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/namespace-element-invalid-kind.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-ELEMENT-INVALID-KIND
+// NAMESPACE-ELEMENT-INVALID-KIND:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}namespace-element-invalid-kind.json'
+// NAMESPACE-ELEMENT-INVALID-KIND-NEXT: reading IdTable from field 'id_table'
+// NAMESPACE-ELEMENT-INVALID-KIND-NEXT: reading EntityIdTable entry from index '0'
+// NAMESPACE-ELEMENT-INVALID-KIND-NEXT: reading EntityName from field 'name'
+// NAMESPACE-ELEMENT-INVALID-KIND-NEXT: reading NestedBuildNamespace from field 'namespace'
+// NAMESPACE-ELEMENT-INVALID-KIND-NEXT: reading BuildNamespace from index '0'
+// NAMESPACE-ELEMENT-INVALID-KIND-NEXT: reading BuildNamespaceKind from field 'kind'
+// NAMESPACE-ELEMENT-INVALID-KIND-NEXT: invalid BuildNamespaceKind value 'invalid_kind' for field 'kind'
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/namespace-element-missing-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-ELEMENT-MISSING-NAME
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/namespace-element-missing-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NAMESPACE-ELEMENT-MISSING-NAME
+// NAMESPACE-ELEMENT-MISSING-NAME:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}namespace-element-missing-name.json'
+// NAMESPACE-ELEMENT-MISSING-NAME-NEXT: reading IdTable from field 'id_table'
+// NAMESPACE-ELEMENT-MISSING-NAME-NEXT: reading EntityIdTable entry from index '0'
+// NAMESPACE-ELEMENT-MISSING-NAME-NEXT: reading EntityName from field 'name'
+// NAMESPACE-ELEMENT-MISSING-NAME-NEXT: reading NestedBuildNamespace from field 'namespace'
+// NAMESPACE-ELEMENT-MISSING-NAME-NEXT: reading BuildNamespace from index '0'
+// NAMESPACE-ELEMENT-MISSING-NAME-NEXT: failed to read BuildNamespaceName from field 'name': expected JSON string
+
+// ============================================================================
+// luEntityNameFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/entity-name-missing-usr.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-NAME-MISSING-USR
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/entity-name-missing-usr.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-NAME-MISSING-USR
+// ENTITY-NAME-MISSING-USR:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}entity-name-missing-usr.json'
+// ENTITY-NAME-MISSING-USR-NEXT: reading IdTable from field 'id_table'
+// ENTITY-NAME-MISSING-USR-NEXT: reading EntityIdTable entry from index '0'
+// ENTITY-NAME-MISSING-USR-NEXT: reading EntityName from field 'name'
+// ENTITY-NAME-MISSING-USR-NEXT: failed to read USR from field 'usr': expected JSON string
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/entity-name-missing-suffix.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-NAME-MISSING-SUFFIX
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/entity-name-missing-suffix.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-NAME-MISSING-SUFFIX
+// ENTITY-NAME-MISSING-SUFFIX:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}entity-name-missing-suffix.json'
+// ENTITY-NAME-MISSING-SUFFIX-NEXT: reading IdTable from field 'id_table'
+// ENTITY-NAME-MISSING-SUFFIX-NEXT: reading EntityIdTable entry from index '0'
+// ENTITY-NAME-MISSING-SUFFIX-NEXT: reading EntityName from field 'name'
+// ENTITY-NAME-MISSING-SUFFIX-NEXT: failed to read Suffix from field 'suffix': expected JSON string
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/entity-name-missing-namespace.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-NAME-MISSING-NAMESPACE
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/entity-name-missing-namespace.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-NAME-MISSING-NAMESPACE
+// ENTITY-NAME-MISSING-NAMESPACE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}entity-name-missing-namespace.json'
+// ENTITY-NAME-MISSING-NAMESPACE-NEXT: reading IdTable from field 'id_table'
+// ENTITY-NAME-MISSING-NAMESPACE-NEXT: reading EntityIdTable entry from index '0'
+// ENTITY-NAME-MISSING-NAMESPACE-NEXT: reading EntityName from field 'name'
+// ENTITY-NAME-MISSING-NAMESPACE-NEXT: failed to read NestedBuildNamespace from field 'namespace': expected JSON array
+
+// ============================================================================
+// luEntityIdTableEntryFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/id-table-entry-missing-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-ENTRY-MISSING-ID
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/id-table-entry-missing-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-ENTRY-MISSING-ID
+// ID-TABLE-ENTRY-MISSING-ID:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}id-table-entry-missing-id.json'
+// ID-TABLE-ENTRY-MISSING-ID-NEXT: reading IdTable from field 'id_table'
+// ID-TABLE-ENTRY-MISSING-ID-NEXT: reading EntityIdTable entry from index '0'
+// ID-TABLE-ENTRY-MISSING-ID-NEXT: failed to read EntityId from field 'id': expected JSON number (unsigned 64-bit integer)
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/id-table-entry-missing-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-ENTRY-MISSING-NAME
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/id-table-entry-missing-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-ENTRY-MISSING-NAME
+// ID-TABLE-ENTRY-MISSING-NAME:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}id-table-entry-missing-name.json'
+// ID-TABLE-ENTRY-MISSING-NAME-NEXT: reading IdTable from field 'id_table'
+// ID-TABLE-ENTRY-MISSING-NAME-NEXT: reading EntityIdTable entry from index '0'
+// ID-TABLE-ENTRY-MISSING-NAME-NEXT: failed to read EntityName from field 'name': expected JSON object
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/id-table-entry-id-not-uint64.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-ENTRY-ID-NOT-UINT64
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/id-table-entry-id-not-uint64.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-ENTRY-ID-NOT-UINT64
+// ID-TABLE-ENTRY-ID-NOT-UINT64:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}id-table-entry-id-not-uint64.json'
+// ID-TABLE-ENTRY-ID-NOT-UINT64-NEXT: reading IdTable from field 'id_table'
+// ID-TABLE-ENTRY-ID-NOT-UINT64-NEXT: reading EntityIdTable entry from index '0'
+// ID-TABLE-ENTRY-ID-NOT-UINT64-NEXT: failed to read EntityId from field 'id': expected JSON number (unsigned 64-bit integer)
+
+// ============================================================================
+// luEntityIdTableFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/id-table-not-array.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-NOT-ARRAY
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/id-table-not-array.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-NOT-ARRAY
+// ID-TABLE-NOT-ARRAY:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}id-table-not-array.json'
+// ID-TABLE-NOT-ARRAY-NEXT: failed to read IdTable from field 'id_table': expected JSON array
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/id-table-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-ELEMENT-NOT-OBJECT
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/id-table-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ID-TABLE-ELEMENT-NOT-OBJECT
+// ID-TABLE-ELEMENT-NOT-OBJECT:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}id-table-element-not-object.json'
+// ID-TABLE-ELEMENT-NOT-OBJECT-NEXT: reading IdTable from field 'id_table'
+// ID-TABLE-ELEMENT-NOT-OBJECT-NEXT: failed to read EntityIdTable entry from index '0': expected JSON object
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/duplicate-entity.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DUPLICATE-ENTITY
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/duplicate-entity.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DUPLICATE-ENTITY
+// DUPLICATE-ENTITY:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}duplicate-entity.json'
+// DUPLICATE-ENTITY-NEXT: reading IdTable from field 'id_table'
+// DUPLICATE-ENTITY-NEXT: failed to insert EntityIdTable entry at index '1': encountered duplicate 'EntityId(0)'

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/io.test b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/io.test
new file mode 100644
index 0000000000000..bfce3a17a446d
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/io.test
@@ -0,0 +1,49 @@
+// File-I/O error tests: readJSON() input validation and writeJSON() output
+// validation for clang-ssaf-format --type lu.
+
+// REQUIRES: plugins
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// ============================================================================
+// readJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/invalid-syntax.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=INVALID-SYNTAX
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/invalid-syntax.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=INVALID-SYNTAX
+// INVALID-SYNTAX:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}invalid-syntax.json'
+// INVALID-SYNTAX-NEXT: {{.*}}Expected object key
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NOT-OBJECT
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NOT-OBJECT
+// NOT-OBJECT:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}not-object.json'
+// NOT-OBJECT-NEXT: failed to read LUSummary: expected JSON object
+
+// ============================================================================
+// writeJSON() errors
+// ============================================================================
+
+// RUN: echo '{}' > %t/existing.json
+// RUN: not clang-ssaf-format --type lu %S/Inputs/rt-empty-namespace.json -o %t/existing.json 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=WRITE-FILE-ALREADY-EXISTS
+// RUN: echo '{}' > %t/existing-enc.json
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/rt-empty-namespace.json -o %t/existing-enc.json 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=WRITE-FILE-ALREADY-EXISTS
+// WRITE-FILE-ALREADY-EXISTS: clang-ssaf-format: error: failed to validate path '{{.*}}existing{{.*}}.json': File already exists
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/rt-empty-namespace.json -o %t/nonexistent-dir/test.json 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=WRITE-PARENT-DIR-NOT-FOUND
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/rt-empty-namespace.json -o %t/nonexistent-dir/test.json 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=WRITE-PARENT-DIR-NOT-FOUND
+// WRITE-PARENT-DIR-NOT-FOUND: clang-ssaf-format: error: failed to validate path '{{.*}}nonexistent-dir{{.*}}test.json': Parent directory does not exist
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/rt-empty-namespace.json -o %t/test.txt 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=WRITE-NOT-JSON-EXTENSION
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/rt-empty-namespace.json -o %t/test.txt 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=WRITE-NOT-JSON-EXTENSION
+// WRITE-NOT-JSON-EXTENSION: clang-ssaf-format: error: failed to validate path '{{.*}}test.txt': No format registered for extension 'txt'

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/linkage.test b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/linkage.test
new file mode 100644
index 0000000000000..192219cadbc12
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/linkage.test
@@ -0,0 +1,104 @@
+// LinkageTable deserialization error tests: EntityLinkage, LinkageTable entry,
+// and LinkageTable structural / consistency errors.
+
+// REQUIRES: plugins
+
+// ============================================================================
+// entityLinkageFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-entry-linkage-missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-MISSING-TYPE
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-entry-linkage-missing-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-MISSING-TYPE
+// LINKAGE-MISSING-TYPE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-entry-linkage-missing-type.json'
+// LINKAGE-MISSING-TYPE-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-MISSING-TYPE-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-MISSING-TYPE-NEXT: reading EntityLinkage from field 'linkage'
+// LINKAGE-MISSING-TYPE-NEXT: failed to read EntityLinkageType from field 'type': expected JSON string
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-entry-linkage-invalid-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-INVALID-TYPE
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-entry-linkage-invalid-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-INVALID-TYPE
+// LINKAGE-INVALID-TYPE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-entry-linkage-invalid-type.json'
+// LINKAGE-INVALID-TYPE-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-INVALID-TYPE-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-INVALID-TYPE-NEXT: reading EntityLinkage from field 'linkage'
+// LINKAGE-INVALID-TYPE-NEXT: reading EntityLinkageType from field 'type'
+// LINKAGE-INVALID-TYPE-NEXT: invalid EntityLinkageType value 'invalid_type' for field 'type'
+
+// ============================================================================
+// linkageTableEntryFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-entry-missing-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-ENTRY-MISSING-ID
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-entry-missing-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-ENTRY-MISSING-ID
+// LINKAGE-ENTRY-MISSING-ID:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-entry-missing-id.json'
+// LINKAGE-ENTRY-MISSING-ID-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-ENTRY-MISSING-ID-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-ENTRY-MISSING-ID-NEXT: failed to read EntityId from field 'id': expected JSON number (unsigned 64-bit integer)
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-entry-id-not-uint64.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-ENTRY-ID-NOT-UINT64
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-entry-id-not-uint64.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-ENTRY-ID-NOT-UINT64
+// LINKAGE-ENTRY-ID-NOT-UINT64:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-entry-id-not-uint64.json'
+// LINKAGE-ENTRY-ID-NOT-UINT64-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-ENTRY-ID-NOT-UINT64-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-ENTRY-ID-NOT-UINT64-NEXT: failed to read EntityId from field 'id': expected JSON number (unsigned 64-bit integer)
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-entry-missing-linkage.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-ENTRY-MISSING-LINKAGE
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-entry-missing-linkage.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-ENTRY-MISSING-LINKAGE
+// LINKAGE-ENTRY-MISSING-LINKAGE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-entry-missing-linkage.json'
+// LINKAGE-ENTRY-MISSING-LINKAGE-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-ENTRY-MISSING-LINKAGE-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-ENTRY-MISSING-LINKAGE-NEXT: failed to read EntityLinkage from field 'linkage': expected JSON object
+
+// ============================================================================
+// linkageTableFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-not-array.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-NOT-ARRAY
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-not-array.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-NOT-ARRAY
+// LINKAGE-TABLE-NOT-ARRAY:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-not-array.json'
+// LINKAGE-TABLE-NOT-ARRAY-NEXT: failed to read LinkageTable from field 'linkage_table': expected JSON array
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ELEMENT-NOT-OBJECT
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ELEMENT-NOT-OBJECT
+// LINKAGE-TABLE-ELEMENT-NOT-OBJECT:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-element-not-object.json'
+// LINKAGE-TABLE-ELEMENT-NOT-OBJECT-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-TABLE-ELEMENT-NOT-OBJECT-NEXT: failed to read LinkageTable entry from index '0': expected JSON object
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-extra-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-EXTRA-ID
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-extra-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-EXTRA-ID
+// LINKAGE-TABLE-EXTRA-ID:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-extra-id.json'
+// LINKAGE-TABLE-EXTRA-ID-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-TABLE-EXTRA-ID-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-TABLE-EXTRA-ID-NEXT: failed to deserialize LinkageTable: extra 'EntityId(0)' not present in IdTable
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-missing-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-MISSING-ID
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-missing-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-MISSING-ID
+// LINKAGE-TABLE-MISSING-ID:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-missing-id.json'
+// LINKAGE-TABLE-MISSING-ID-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-TABLE-MISSING-ID-NEXT: failed to deserialize LinkageTable: missing 'EntityId(0)' present in IdTable
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/linkage-table-duplicate-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-DUPLICATE-ID
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/linkage-table-duplicate-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-DUPLICATE-ID
+// LINKAGE-TABLE-DUPLICATE-ID:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}linkage-table-duplicate-id.json'
+// LINKAGE-TABLE-DUPLICATE-ID-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-TABLE-DUPLICATE-ID-NEXT: failed to insert LinkageTable entry at index '1': encountered duplicate 'EntityId(0)'

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/permissions.test b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/permissions.test
new file mode 100644
index 0000000000000..0d2db01a471db
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/permissions.test
@@ -0,0 +1,40 @@
+// Tests for clang-ssaf-format --type lu that require filesystem permission
+// support (symlinks, chmod).
+
+// UNSUPPORTED: system-windows
+// REQUIRES: non-root-user
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// ============================================================================
+// Broken symlink
+// ============================================================================
+
+// RUN: ln -sf %t/nonexistent-target.json %t/broken-symlink.json
+// RUN: not clang-ssaf-format --type lu %t/broken-symlink.json 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=BROKEN-SYMLINK
+// BROKEN-SYMLINK: clang-ssaf-format: error: failed to validate path '{{.*}}broken-symlink.json': Path does not exist
+
+// ============================================================================
+// No read permission
+// ============================================================================
+
+// RUN: echo '{"lu_namespace": [{"kind": "LinkUnit", "name": "test.exe"}], "id_table": [], "linkage_table": [], "data": []}' > %t/no-read-permission.json
+// RUN: chmod -r %t/no-read-permission.json
+// RUN: not clang-ssaf-format --type lu %t/no-read-permission.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=NO-READ-PERMISSION
+// RUN: chmod +r %t/no-read-permission.json
+// NO-READ-PERMISSION:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}no-read-permission.json'
+// NO-READ-PERMISSION-NEXT: failed to read file '{{.*}}no-read-permission.json': {{.*}}
+
+// ============================================================================
+// Write to directory without write permission
+// ============================================================================
+
+// RUN: mkdir -p %t/write-protected-dir
+// RUN: chmod -w %t/write-protected-dir
+// RUN: not clang-ssaf-format --type lu %S/Inputs/rt-empty-namespace.json -o %t/write-protected-dir/test.json 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=WRITE-STREAM-OPEN-FAILURE
+// RUN: chmod +w %t/write-protected-dir
+// WRITE-STREAM-OPEN-FAILURE: clang-ssaf-format: error: failed to validate path '{{.*}}write-protected-dir{{.}}test.json': Parent directory is not writable

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/round-trip.test b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/round-trip.test
new file mode 100644
index 0000000000000..6761ec436fd7f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/round-trip.test
@@ -0,0 +1,56 @@
+// Round-trip tests: read an LUSummary JSON input, write it back out, and
+// 
diff  the result against the original.
+
+// REQUIRES: plugins
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// ============================================================================
+// Round-Trip Tests
+// ============================================================================
+
+// RUN: clang-ssaf-format --type lu %S/Inputs/rt-empty-namespace.json -o %t/rt-empty-namespace.json
+// RUN: 
diff  %S/Inputs/rt-empty-namespace.json %t/rt-empty-namespace.json
+// RUN: clang-ssaf-format --type lu --encoding %S/Inputs/rt-empty-namespace.json -o %t/rt-empty-namespace-enc.json
+// RUN: 
diff  %S/Inputs/rt-empty-namespace.json %t/rt-empty-namespace-enc.json
+
+// RUN: clang-ssaf-format --type lu %S/Inputs/rt-single-namespace-element.json -o %t/rt-single-namespace-element.json
+// RUN: 
diff  %S/Inputs/rt-single-namespace-element.json %t/rt-single-namespace-element.json
+// RUN: clang-ssaf-format --type lu --encoding %S/Inputs/rt-single-namespace-element.json -o %t/rt-single-namespace-element-enc.json
+// RUN: 
diff  %S/Inputs/rt-single-namespace-element.json %t/rt-single-namespace-element-enc.json
+
+// RUN: clang-ssaf-format --type lu %S/Inputs/rt-multiple-namespace-elements.json -o %t/rt-multiple-namespace-elements.json
+// RUN: 
diff  %S/Inputs/rt-multiple-namespace-elements.json %t/rt-multiple-namespace-elements.json
+// RUN: clang-ssaf-format --type lu --encoding %S/Inputs/rt-multiple-namespace-elements.json -o %t/rt-multiple-namespace-elements-enc.json
+// RUN: 
diff  %S/Inputs/rt-multiple-namespace-elements.json %t/rt-multiple-namespace-elements-enc.json
+
+// RUN: %clang-ssaf-format-with-plugin --type lu %S/Inputs/rt-two-summary-types.json -o %t/rt-two-summary-types.json
+// RUN: 
diff  %S/Inputs/rt-two-summary-types.json %t/rt-two-summary-types.json
+// RUN: %clang-ssaf-format-with-plugin --type lu --encoding %S/Inputs/rt-two-summary-types.json -o %t/rt-two-summary-types-enc.json
+// RUN: 
diff  %S/Inputs/rt-two-summary-types.json %t/rt-two-summary-types-enc.json
+
+// RUN: %clang-ssaf-format-with-plugin --type lu %S/Inputs/rt-empty-data-entry.json -o %t/rt-empty-data-entry.json
+// RUN: 
diff  %S/Inputs/rt-empty-data-entry.json %t/rt-empty-data-entry.json
+// RUN: %clang-ssaf-format-with-plugin --type lu --encoding %S/Inputs/rt-empty-data-entry.json -o %t/rt-empty-data-entry-enc.json
+// RUN: 
diff  %S/Inputs/rt-empty-data-entry.json %t/rt-empty-data-entry-enc.json
+
+// RUN: clang-ssaf-format --type lu %S/Inputs/rt-linkage-none.json -o %t/rt-linkage-none.json
+// RUN: 
diff  %S/Inputs/rt-linkage-none.json %t/rt-linkage-none.json
+// RUN: clang-ssaf-format --type lu --encoding %S/Inputs/rt-linkage-none.json -o %t/rt-linkage-none-enc.json
+// RUN: 
diff  %S/Inputs/rt-linkage-none.json %t/rt-linkage-none-enc.json
+
+// RUN: clang-ssaf-format --type lu %S/Inputs/rt-linkage-internal.json -o %t/rt-linkage-internal.json
+// RUN: 
diff  %S/Inputs/rt-linkage-internal.json %t/rt-linkage-internal.json
+// RUN: clang-ssaf-format --type lu --encoding %S/Inputs/rt-linkage-internal.json -o %t/rt-linkage-internal-enc.json
+// RUN: 
diff  %S/Inputs/rt-linkage-internal.json %t/rt-linkage-internal-enc.json
+
+// RUN: clang-ssaf-format --type lu %S/Inputs/rt-linkage-external.json -o %t/rt-linkage-external.json
+// RUN: 
diff  %S/Inputs/rt-linkage-external.json %t/rt-linkage-external.json
+// RUN: clang-ssaf-format --type lu --encoding %S/Inputs/rt-linkage-external.json -o %t/rt-linkage-external-enc.json
+// RUN: 
diff  %S/Inputs/rt-linkage-external.json %t/rt-linkage-external-enc.json
+
+// RUN: clang-ssaf-format --type lu %S/Inputs/rt-linkage-multiple.json -o %t/rt-linkage-multiple.json
+// RUN: 
diff  %S/Inputs/rt-linkage-multiple.json %t/rt-linkage-multiple.json
+// RUN: clang-ssaf-format --type lu --encoding %S/Inputs/rt-linkage-multiple.json -o %t/rt-linkage-multiple-enc.json
+// RUN: 
diff  %S/Inputs/rt-linkage-multiple.json %t/rt-linkage-multiple-enc.json

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/summary-data.test b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/summary-data.test
new file mode 100644
index 0000000000000..dcf6a31f5c504
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/summary-data.test
@@ -0,0 +1,202 @@
+// SummaryData / EntityDataMap deserialization error tests, including the
+// PairsEntitySummary plugin error tests that exercise the same parsing path.
+
+// REQUIRES: plugins
+
+// ============================================================================
+// readLUSummary() errors
+// ============================================================================
+
+// Note: --encoding variants are not applicable for EntitySummary deserialization
+// tests because the encoding path stores raw JSON without deserializing.
+// RUN: not clang-ssaf-format --type lu %S/Inputs/read-entity-summary-no-format-info.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=READ-ENTITY-SUMMARY-NO-FORMAT-INFO
+// READ-ENTITY-SUMMARY-NO-FORMAT-INFO:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}read-entity-summary-no-format-info.json'
+// READ-ENTITY-SUMMARY-NO-FORMAT-INFO-NEXT: reading SummaryData entries from field 'data'
+// READ-ENTITY-SUMMARY-NO-FORMAT-INFO-NEXT: reading SummaryData entry from index '0'
+// READ-ENTITY-SUMMARY-NO-FORMAT-INFO-NEXT: reading EntitySummary entries from field 'summary_data'
+// READ-ENTITY-SUMMARY-NO-FORMAT-INFO-NEXT: reading EntitySummary entry from index '0'
+// READ-ENTITY-SUMMARY-NO-FORMAT-INFO-NEXT: reading EntitySummary from field 'entity_summary'
+// READ-ENTITY-SUMMARY-NO-FORMAT-INFO-NEXT: failed to deserialize EntitySummary: no FormatInfo registered for 'SummaryName(UnregisteredEntitySummary)'
+
+// ============================================================================
+// PairsEntitySummaryForJSONFormatTest tests
+// ============================================================================
+
+// RUN: not %clang-ssaf-format-with-plugin --type lu %S/Inputs/pairs-missing-pairs-field.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=PAIRS-MISSING-PAIRS-FIELD
+// PAIRS-MISSING-PAIRS-FIELD:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}pairs-missing-pairs-field.json'
+// PAIRS-MISSING-PAIRS-FIELD-NEXT: reading SummaryData entries from field 'data'
+// PAIRS-MISSING-PAIRS-FIELD-NEXT: reading SummaryData entry from index '0'
+// PAIRS-MISSING-PAIRS-FIELD-NEXT: reading EntitySummary entries from field 'summary_data'
+// PAIRS-MISSING-PAIRS-FIELD-NEXT: reading EntitySummary entry from index '0'
+// PAIRS-MISSING-PAIRS-FIELD-NEXT: reading EntitySummary from field 'entity_summary'
+// PAIRS-MISSING-PAIRS-FIELD-NEXT: missing or invalid field 'pairs'
+
+// RUN: not %clang-ssaf-format-with-plugin --type lu %S/Inputs/pairs-invalid-pairs-field-type.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=PAIRS-INVALID-PAIRS-FIELD-TYPE
+// PAIRS-INVALID-PAIRS-FIELD-TYPE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}pairs-invalid-pairs-field-type.json'
+// PAIRS-INVALID-PAIRS-FIELD-TYPE-NEXT: reading SummaryData entries from field 'data'
+// PAIRS-INVALID-PAIRS-FIELD-TYPE-NEXT: reading SummaryData entry from index '0'
+// PAIRS-INVALID-PAIRS-FIELD-TYPE-NEXT: reading EntitySummary entries from field 'summary_data'
+// PAIRS-INVALID-PAIRS-FIELD-TYPE-NEXT: reading EntitySummary entry from index '0'
+// PAIRS-INVALID-PAIRS-FIELD-TYPE-NEXT: reading EntitySummary from field 'entity_summary'
+// PAIRS-INVALID-PAIRS-FIELD-TYPE-NEXT: missing or invalid field 'pairs'
+
+// RUN: not %clang-ssaf-format-with-plugin --type lu %S/Inputs/pairs-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=PAIRS-ELEMENT-NOT-OBJECT
+// PAIRS-ELEMENT-NOT-OBJECT:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}pairs-element-not-object.json'
+// PAIRS-ELEMENT-NOT-OBJECT-NEXT: reading SummaryData entries from field 'data'
+// PAIRS-ELEMENT-NOT-OBJECT-NEXT: reading SummaryData entry from index '0'
+// PAIRS-ELEMENT-NOT-OBJECT-NEXT: reading EntitySummary entries from field 'summary_data'
+// PAIRS-ELEMENT-NOT-OBJECT-NEXT: reading EntitySummary entry from index '0'
+// PAIRS-ELEMENT-NOT-OBJECT-NEXT: reading EntitySummary from field 'entity_summary'
+// PAIRS-ELEMENT-NOT-OBJECT-NEXT: pairs element at index 0 is not a JSON object
+
+// RUN: not %clang-ssaf-format-with-plugin --type lu %S/Inputs/pairs-missing-first-field.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=PAIRS-MISSING-FIRST-FIELD
+// PAIRS-MISSING-FIRST-FIELD:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}pairs-missing-first-field.json'
+// PAIRS-MISSING-FIRST-FIELD-NEXT: reading SummaryData entries from field 'data'
+// PAIRS-MISSING-FIRST-FIELD-NEXT: reading SummaryData entry from index '0'
+// PAIRS-MISSING-FIRST-FIELD-NEXT: reading EntitySummary entries from field 'summary_data'
+// PAIRS-MISSING-FIRST-FIELD-NEXT: reading EntitySummary entry from index '0'
+// PAIRS-MISSING-FIRST-FIELD-NEXT: reading EntitySummary from field 'entity_summary'
+// PAIRS-MISSING-FIRST-FIELD-NEXT: missing or invalid 'first' field at index '0'
+
+// RUN: not %clang-ssaf-format-with-plugin --type lu %S/Inputs/pairs-invalid-first-field.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=PAIRS-INVALID-FIRST-FIELD
+// PAIRS-INVALID-FIRST-FIELD:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}pairs-invalid-first-field.json'
+// PAIRS-INVALID-FIRST-FIELD-NEXT: reading SummaryData entries from field 'data'
+// PAIRS-INVALID-FIRST-FIELD-NEXT: reading SummaryData entry from index '0'
+// PAIRS-INVALID-FIRST-FIELD-NEXT: reading EntitySummary entries from field 'summary_data'
+// PAIRS-INVALID-FIRST-FIELD-NEXT: reading EntitySummary entry from index '0'
+// PAIRS-INVALID-FIRST-FIELD-NEXT: reading EntitySummary from field 'entity_summary'
+// PAIRS-INVALID-FIRST-FIELD-NEXT: missing or invalid 'first' field at index '0'
+
+// RUN: not %clang-ssaf-format-with-plugin --type lu %S/Inputs/pairs-missing-second-field.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=PAIRS-MISSING-SECOND-FIELD
+// PAIRS-MISSING-SECOND-FIELD:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}pairs-missing-second-field.json'
+// PAIRS-MISSING-SECOND-FIELD-NEXT: reading SummaryData entries from field 'data'
+// PAIRS-MISSING-SECOND-FIELD-NEXT: reading SummaryData entry from index '0'
+// PAIRS-MISSING-SECOND-FIELD-NEXT: reading EntitySummary entries from field 'summary_data'
+// PAIRS-MISSING-SECOND-FIELD-NEXT: reading EntitySummary entry from index '0'
+// PAIRS-MISSING-SECOND-FIELD-NEXT: reading EntitySummary from field 'entity_summary'
+// PAIRS-MISSING-SECOND-FIELD-NEXT: missing or invalid 'second' field at index '0'
+
+// RUN: not %clang-ssaf-format-with-plugin --type lu %S/Inputs/pairs-invalid-second-field.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=PAIRS-INVALID-SECOND-FIELD
+// PAIRS-INVALID-SECOND-FIELD:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}pairs-invalid-second-field.json'
+// PAIRS-INVALID-SECOND-FIELD-NEXT: reading SummaryData entries from field 'data'
+// PAIRS-INVALID-SECOND-FIELD-NEXT: reading SummaryData entry from index '0'
+// PAIRS-INVALID-SECOND-FIELD-NEXT: reading EntitySummary entries from field 'summary_data'
+// PAIRS-INVALID-SECOND-FIELD-NEXT: reading EntitySummary entry from index '0'
+// PAIRS-INVALID-SECOND-FIELD-NEXT: reading EntitySummary from field 'entity_summary'
+// PAIRS-INVALID-SECOND-FIELD-NEXT: missing or invalid 'second' field at index '0'
+
+// ============================================================================
+// entityDataMapEntryFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/entity-data-missing-entity-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-DATA-MISSING-ENTITY-ID
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/entity-data-missing-entity-id.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-DATA-MISSING-ENTITY-ID
+// ENTITY-DATA-MISSING-ENTITY-ID:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}entity-data-missing-entity-id.json'
+// ENTITY-DATA-MISSING-ENTITY-ID-NEXT: reading SummaryData entries from field 'data'
+// ENTITY-DATA-MISSING-ENTITY-ID-NEXT: reading SummaryData entry from index '0'
+// ENTITY-DATA-MISSING-ENTITY-ID-NEXT: reading EntitySummary entries from field 'summary_data'
+// ENTITY-DATA-MISSING-ENTITY-ID-NEXT: reading EntitySummary entry from index '0'
+// ENTITY-DATA-MISSING-ENTITY-ID-NEXT: failed to read EntityId from field 'entity_id': expected JSON number (unsigned 64-bit integer)
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/entity-data-missing-entity-summary.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-DATA-MISSING-ENTITY-SUMMARY
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/entity-data-missing-entity-summary.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-DATA-MISSING-ENTITY-SUMMARY
+// ENTITY-DATA-MISSING-ENTITY-SUMMARY:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}entity-data-missing-entity-summary.json'
+// ENTITY-DATA-MISSING-ENTITY-SUMMARY-NEXT: reading SummaryData entries from field 'data'
+// ENTITY-DATA-MISSING-ENTITY-SUMMARY-NEXT: reading SummaryData entry from index '0'
+// ENTITY-DATA-MISSING-ENTITY-SUMMARY-NEXT: reading EntitySummary entries from field 'summary_data'
+// ENTITY-DATA-MISSING-ENTITY-SUMMARY-NEXT: reading EntitySummary entry from index '0'
+// ENTITY-DATA-MISSING-ENTITY-SUMMARY-NEXT: failed to read EntitySummary from field 'entity_summary': expected JSON object
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/entity-id-not-uint64.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-ID-NOT-UINT64
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/entity-id-not-uint64.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-ID-NOT-UINT64
+// ENTITY-ID-NOT-UINT64:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}entity-id-not-uint64.json'
+// ENTITY-ID-NOT-UINT64-NEXT: reading SummaryData entries from field 'data'
+// ENTITY-ID-NOT-UINT64-NEXT: reading SummaryData entry from index '0'
+// ENTITY-ID-NOT-UINT64-NEXT: reading EntitySummary entries from field 'summary_data'
+// ENTITY-ID-NOT-UINT64-NEXT: reading EntitySummary entry from index '0'
+// ENTITY-ID-NOT-UINT64-NEXT: failed to read EntityId from field 'entity_id': expected JSON number (unsigned 64-bit integer)
+
+// ============================================================================
+// entityDataMapFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/entity-data-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-DATA-ELEMENT-NOT-OBJECT
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/entity-data-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=ENTITY-DATA-ELEMENT-NOT-OBJECT
+// ENTITY-DATA-ELEMENT-NOT-OBJECT:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}entity-data-element-not-object.json'
+// ENTITY-DATA-ELEMENT-NOT-OBJECT-NEXT: reading SummaryData entries from field 'data'
+// ENTITY-DATA-ELEMENT-NOT-OBJECT-NEXT: reading SummaryData entry from index '0'
+// ENTITY-DATA-ELEMENT-NOT-OBJECT-NEXT: reading EntitySummary entries from field 'summary_data'
+// ENTITY-DATA-ELEMENT-NOT-OBJECT-NEXT: failed to read EntitySummary entry from index '0': expected JSON object
+
+// RUN: not %clang-ssaf-format-with-plugin --type lu %S/Inputs/duplicate-entity-id-in-data-map.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DUPLICATE-ENTITY-ID-IN-DATA-MAP
+// DUPLICATE-ENTITY-ID-IN-DATA-MAP:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}duplicate-entity-id-in-data-map.json'
+// DUPLICATE-ENTITY-ID-IN-DATA-MAP-NEXT: reading SummaryData entries from field 'data'
+// DUPLICATE-ENTITY-ID-IN-DATA-MAP-NEXT: reading SummaryData entry from index '0'
+// DUPLICATE-ENTITY-ID-IN-DATA-MAP-NEXT: reading EntitySummary entries from field 'summary_data'
+// DUPLICATE-ENTITY-ID-IN-DATA-MAP-NEXT: failed to insert EntitySummary entry at index '1': encountered duplicate 'EntityId(0)'
+
+// ============================================================================
+// summaryDataMapFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/data-entry-missing-summary-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DATA-ENTRY-MISSING-SUMMARY-NAME
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/data-entry-missing-summary-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DATA-ENTRY-MISSING-SUMMARY-NAME
+// DATA-ENTRY-MISSING-SUMMARY-NAME:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}data-entry-missing-summary-name.json'
+// DATA-ENTRY-MISSING-SUMMARY-NAME-NEXT: reading SummaryData entries from field 'data'
+// DATA-ENTRY-MISSING-SUMMARY-NAME-NEXT: reading SummaryData entry from index '0'
+// DATA-ENTRY-MISSING-SUMMARY-NAME-NEXT: failed to read SummaryName from field 'summary_name': expected JSON string
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/data-entry-missing-data.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DATA-ENTRY-MISSING-DATA
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/data-entry-missing-data.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DATA-ENTRY-MISSING-DATA
+// DATA-ENTRY-MISSING-DATA:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}data-entry-missing-data.json'
+// DATA-ENTRY-MISSING-DATA-NEXT: reading SummaryData entries from field 'data'
+// DATA-ENTRY-MISSING-DATA-NEXT: reading SummaryData entry from index '0'
+// DATA-ENTRY-MISSING-DATA-NEXT: failed to read EntitySummary entries from field 'summary_data': expected JSON array
+
+// ============================================================================
+// summaryDataMapFromJSON() / encodingSummaryDataMapFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/data-not-array.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DATA-NOT-ARRAY
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/data-not-array.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DATA-NOT-ARRAY
+// DATA-NOT-ARRAY:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}data-not-array.json'
+// DATA-NOT-ARRAY-NEXT: failed to read SummaryData entries from field 'data': expected JSON array
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/data-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DATA-ELEMENT-NOT-OBJECT
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/data-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DATA-ELEMENT-NOT-OBJECT
+// DATA-ELEMENT-NOT-OBJECT:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}data-element-not-object.json'
+// DATA-ELEMENT-NOT-OBJECT-NEXT: reading SummaryData entries from field 'data'
+// DATA-ELEMENT-NOT-OBJECT-NEXT: failed to read SummaryData entry from index '0': expected JSON object
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/duplicate-summary-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DUPLICATE-SUMMARY-NAME
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/duplicate-summary-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=DUPLICATE-SUMMARY-NAME
+// DUPLICATE-SUMMARY-NAME:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}duplicate-summary-name.json'
+// DUPLICATE-SUMMARY-NAME-NEXT: reading SummaryData entries from field 'data'
+// DUPLICATE-SUMMARY-NAME-NEXT: failed to insert SummaryData entry at index '1': encountered duplicate 'SummaryName(PairsEntitySummary)'

diff  --git a/clang/test/Analysis/Scalable/ssaf-format/LUSummary/top-level.test b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/top-level.test
new file mode 100644
index 0000000000000..0acd11e682905
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/LUSummary/top-level.test
@@ -0,0 +1,84 @@
+// Top-level LUSummary structure tests: NestedBuildNamespace 'lu_namespace'
+// field parsing and missing top-level fields (lu_namespace, id_table,
+// linkage_table, data).
+
+// REQUIRES: plugins
+
+// ============================================================================
+// nestedBuildNamespaceFromJSON() errors (lu_namespace field) -- LU-SPECIFIC
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/lu-namespace-not-array.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-NOT-ARRAY
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/lu-namespace-not-array.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-NOT-ARRAY
+// LU-NAMESPACE-NOT-ARRAY:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}lu-namespace-not-array.json'
+// LU-NAMESPACE-NOT-ARRAY-NEXT: failed to read NestedBuildNamespace from field 'lu_namespace': expected JSON array
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/lu-namespace-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-ELEMENT-NOT-OBJECT
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/lu-namespace-element-not-object.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-ELEMENT-NOT-OBJECT
+// LU-NAMESPACE-ELEMENT-NOT-OBJECT:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}lu-namespace-element-not-object.json'
+// LU-NAMESPACE-ELEMENT-NOT-OBJECT-NEXT: reading NestedBuildNamespace from field 'lu_namespace'
+// LU-NAMESPACE-ELEMENT-NOT-OBJECT-NEXT: failed to read BuildNamespace from index '0': expected JSON object
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/lu-namespace-element-missing-kind.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-ELEMENT-MISSING-KIND
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/lu-namespace-element-missing-kind.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-ELEMENT-MISSING-KIND
+// LU-NAMESPACE-ELEMENT-MISSING-KIND:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}lu-namespace-element-missing-kind.json'
+// LU-NAMESPACE-ELEMENT-MISSING-KIND-NEXT: reading NestedBuildNamespace from field 'lu_namespace'
+// LU-NAMESPACE-ELEMENT-MISSING-KIND-NEXT: reading BuildNamespace from index '0'
+// LU-NAMESPACE-ELEMENT-MISSING-KIND-NEXT: failed to read BuildNamespaceKind from field 'kind': expected JSON string
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/lu-namespace-element-invalid-kind.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-ELEMENT-INVALID-KIND
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/lu-namespace-element-invalid-kind.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-ELEMENT-INVALID-KIND
+// LU-NAMESPACE-ELEMENT-INVALID-KIND:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}lu-namespace-element-invalid-kind.json'
+// LU-NAMESPACE-ELEMENT-INVALID-KIND-NEXT: reading NestedBuildNamespace from field 'lu_namespace'
+// LU-NAMESPACE-ELEMENT-INVALID-KIND-NEXT: reading BuildNamespace from index '0'
+// LU-NAMESPACE-ELEMENT-INVALID-KIND-NEXT: reading BuildNamespaceKind from field 'kind'
+// LU-NAMESPACE-ELEMENT-INVALID-KIND-NEXT: invalid BuildNamespaceKind value 'invalid_kind' for field 'kind'
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/lu-namespace-element-missing-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-ELEMENT-MISSING-NAME
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/lu-namespace-element-missing-name.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=LU-NAMESPACE-ELEMENT-MISSING-NAME
+// LU-NAMESPACE-ELEMENT-MISSING-NAME:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}lu-namespace-element-missing-name.json'
+// LU-NAMESPACE-ELEMENT-MISSING-NAME-NEXT: reading NestedBuildNamespace from field 'lu_namespace'
+// LU-NAMESPACE-ELEMENT-MISSING-NAME-NEXT: reading BuildNamespace from index '0'
+// LU-NAMESPACE-ELEMENT-MISSING-NAME-NEXT: failed to read BuildNamespaceName from field 'name': expected JSON string
+
+// ============================================================================
+// readLUSummary() / readLUSummaryEncoding() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/missing-lu-namespace.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-LU-NAMESPACE
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/missing-lu-namespace.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-LU-NAMESPACE
+// MISSING-LU-NAMESPACE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}missing-lu-namespace.json'
+// MISSING-LU-NAMESPACE-NEXT: failed to read NestedBuildNamespace from field 'lu_namespace': expected JSON array
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/missing-id-table.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-ID-TABLE
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/missing-id-table.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-ID-TABLE
+// MISSING-ID-TABLE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}missing-id-table.json'
+// MISSING-ID-TABLE-NEXT: failed to read IdTable from field 'id_table': expected JSON array
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/missing-linkage-table.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-LINKAGE-TABLE
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/missing-linkage-table.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-LINKAGE-TABLE
+// MISSING-LINKAGE-TABLE:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}missing-linkage-table.json'
+// MISSING-LINKAGE-TABLE-NEXT: failed to read LinkageTable from field 'linkage_table': expected JSON array
+
+// RUN: not clang-ssaf-format --type lu %S/Inputs/missing-data.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-DATA
+// RUN: not clang-ssaf-format --type lu --encoding %S/Inputs/missing-data.json 2>&1 \
+// RUN:   | FileCheck %s --match-full-lines --check-prefix=MISSING-DATA
+// MISSING-DATA:      clang-ssaf-format: error: reading LUSummary from file '{{.*}}missing-data.json'
+// MISSING-DATA-NEXT: failed to read SummaryData entries from field 'data': expected JSON array

diff  --git a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/LUSummaryTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/LUSummaryTest.cpp
index 3b733634ccb03..b1f2e0f0870f1 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/LUSummaryTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/LUSummaryTest.cpp
@@ -214,1388 +214,9 @@ TEST_P(LUSummaryTest, NoReadPermission) {
   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::luEntityNameFromJSON() 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::luEntityIdTableEntryFromJSON() 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::luEntityIdTableFromJSON() 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)"))));
-}
+// ============================================================================
+// JSONFormat::entityDataMapFromJSON() Error Tests
+// ============================================================================
 
 TEST_F(JSONFormatLUSummaryTest, ReadEntitySummaryMissingData) {
   auto Result = readLUSummaryFromString(R"({
@@ -1617,311 +238,24 @@ TEST_F(JSONFormatLUSummaryTest, ReadEntitySummaryMissingData) {
           }
         ]
       }
-    ]
-  })");
-
-  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)'"))));
-}
-
-// ============================================================================
-// JSONFormat::entityDataMapEntryToJSON() Fatal Tests
-// ============================================================================
-
-TEST_F(JSONFormatLUSummaryTest, WriteEntitySummaryMissingData) {
-  NestedBuildNamespace NBN(
-      BuildNamespace(BuildNamespaceKind::LinkUnit, "test.exe"));
-  LUSummary Summary(std::move(NBN));
-
-  NestedBuildNamespace Namespace =
-      NestedBuildNamespace::makeCompilationUnit("test.cpp");
-  EntityId EI = getIdTable(Summary).getId(
-      EntityName{"c:@F at foo", "", std::move(Namespace)});
-
-  SummaryName SN("NullEntitySummaryForJSONFormatTest");
-  getData(Summary)[SN][EI] = nullptr;
-
-  EXPECT_DEATH(
-      { (void)writeLUSummary(Summary, "output.json"); },
-      "JSONFormat - null EntitySummary data for "
-      "'SummaryName\\(NullEntitySummaryForJSONFormatTest\\)'");
-}
-
-TEST_F(JSONFormatLUSummaryTest, WriteEntitySummaryMismatchedSummaryName) {
-  NestedBuildNamespace NBN(
-      BuildNamespace(BuildNamespaceKind::LinkUnit, "test.exe"));
-  LUSummary Summary(std::move(NBN));
-
-  NestedBuildNamespace Namespace =
-      NestedBuildNamespace::makeCompilationUnit("test.cpp");
-  EntityId EI = getIdTable(Summary).getId(
-      EntityName{"c:@F at foo", "", std::move(Namespace)});
-
-  SummaryName SN("MismatchedEntitySummaryForJSONFormatTest");
-  getData(Summary)[SN][EI] =
-      std::make_unique<MismatchedEntitySummaryForJSONFormatTest>();
-
-  EXPECT_DEATH(
-      { (void)writeLUSummary(Summary, "output.json"); },
-      "JSONFormat - EntitySummary data for "
-      "'SummaryName\\(MismatchedEntitySummaryForJSONFormatTest\\)' "
-      "reports "
-      "mismatched "
-      "'SummaryName\\(MismatchedEntitySummaryForJSONFormatTest_WrongName\\)'");
-}
-
-// ============================================================================
-// JSONFormat::entityDataMapFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(LUSummaryTest, EntityDataElementNotObject) {
-  auto Result = readFromString(R"({
-    "lu_namespace": [
-      {
-        "kind": "LinkUnit",
-        "name": "test.exe"
-      }
-    ],
-    "id_table": [],
-    "linkage_table": [],
-    "data": [
-      {
-        "summary_name": "PairsEntitySummaryForJSONFormatTest",
-        "summary_data": ["invalid"]
-      }
-    ]
-  })");
-
-  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("failed to read EntitySummary entry from index '0'"),
-          HasSubstr("expected JSON object"))));
-}
-
-TEST_P(LUSummaryTest, DuplicateEntityIdInDataMap) {
-  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": "None"
-        }
-      }
-    ],
-    "data": [
-      {
-        "summary_name": "PairsEntitySummaryForJSONFormatTest",
-        "summary_data": [
-          {
-            "entity_id": 0,
-            "entity_summary": { "pairs": [] }
-          },
-          {
-            "entity_id": 0,
-            "entity_summary": { "pairs": [] }
-          }
-        ]
-      }
-    ]
-  })");
-
-  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("failed to insert EntitySummary entry at index '1'"),
-          HasSubstr("encountered duplicate 'EntityId(0)'"))));
-}
-
-// ============================================================================
-// JSONFormat::summaryDataMapFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(LUSummaryTest, DataEntryMissingSummaryName) {
-  auto Result = readFromString(R"({
-    "lu_namespace": [
-      {
-        "kind": "LinkUnit",
-        "name": "test.exe"
-      }
-    ],
-    "id_table": [],
-    "linkage_table": [],
-    "data": [
-      {
-        "summary_data": []
-      }
-    ]
-  })");
-
-  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("failed to read SummaryName from field 'summary_name'"),
-          HasSubstr("expected JSON string"))));
-}
-
-TEST_P(LUSummaryTest, DataEntryMissingData) {
-  auto Result = readFromString(R"({
-    "lu_namespace": [
-      {
-        "kind": "LinkUnit",
-        "name": "test.exe"
-      }
-    ],
-    "id_table": [],
-    "linkage_table": [],
-    "data": [
-      {
-        "summary_name": "PairsEntitySummaryForJSONFormatTest"
-      }
-    ]
-  })");
-
-  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("failed to read EntitySummary entries from field "
-                          "'summary_data'"),
-                HasSubstr("expected JSON array"))));
-}
-
-// ============================================================================
-// JSONFormat::summaryDataMapFromJSON() / encodingSummaryDataMapFromJSON() Tests
-// ============================================================================
-
-TEST_P(LUSummaryTest, DataNotArray) {
-  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 SummaryData entries from field 'data'"),
-          HasSubstr("expected JSON array"))));
-}
-
-TEST_P(LUSummaryTest, DataElementNotObject) {
-  auto Result = readFromString(R"({
-    "lu_namespace": [
-      {
-        "kind": "LinkUnit",
-        "name": "test.exe"
-      }
-    ],
-    "id_table": [],
-    "linkage_table": [],
-    "data": ["invalid"]
+    ]
   })");
 
-  EXPECT_THAT_ERROR(
-      std::move(Result),
-      FailedWithMessage(
-          AllOf(HasSubstr("reading LUSummary from file"),
-                HasSubstr("reading SummaryData entries from field 'data'"),
-                HasSubstr("failed to read SummaryData entry from index '0'"),
-                HasSubstr("expected JSON 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("failed to deserialize EntitySummary"),
+          HasSubstr("null EntitySummary data for "
+                    "'SummaryName(NullEntitySummaryForJSONFormatTest)'"))));
 }
 
-TEST_P(LUSummaryTest, DuplicateSummaryName) {
-  auto Result = readFromString(R"({
+TEST_F(JSONFormatLUSummaryTest, ReadEntitySummaryMismatchedSummaryName) {
+  auto Result = readLUSummaryFromString(R"({
     "lu_namespace": [
       {
         "kind": "LinkUnit",
@@ -1932,103 +266,77 @@ TEST_P(LUSummaryTest, DuplicateSummaryName) {
     "linkage_table": [],
     "data": [
       {
-        "summary_name": "PairsEntitySummaryForJSONFormatTest",
-        "summary_data": []
-      },
-      {
-        "summary_name": "PairsEntitySummaryForJSONFormatTest",
-        "summary_data": []
+        "summary_name": "MismatchedEntitySummaryForJSONFormatTest",
+        "summary_data": [
+          {
+            "entity_id": 0,
+            "entity_summary": {}
+          }
+        ]
       }
     ]
   })");
 
-  EXPECT_THAT_ERROR(
-      std::move(Result),
+  EXPECT_THAT_EXPECTED(
+      Result,
       FailedWithMessage(AllOf(
           HasSubstr("reading LUSummary from file"),
           HasSubstr("reading SummaryData entries from field 'data'"),
-          HasSubstr("failed to insert SummaryData entry at index '1'"),
-          HasSubstr("encountered duplicate "
-                    "'SummaryName(PairsEntitySummaryForJSONFormatTest)'"))));
+          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)'"))));
 }
 
 // ============================================================================
-// JSONFormat::readLUSummary() / readLUSummaryEncoding() Error Tests
+// JSONFormat::entityDataMapEntryToJSON() Fatal Tests
 // ============================================================================
 
-TEST_P(LUSummaryTest, MissingLUNamespace) {
-  auto Result = readFromString(R"({
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
+TEST_F(JSONFormatLUSummaryTest, WriteEntitySummaryMissingData) {
+  NestedBuildNamespace NBN(
+      BuildNamespace(BuildNamespaceKind::LinkUnit, "test.exe"));
+  LUSummary Summary(std::move(NBN));
 
-  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"))));
-}
+  NestedBuildNamespace Namespace =
+      NestedBuildNamespace::makeCompilationUnit("test.cpp");
+  EntityId EI = getIdTable(Summary).getId(
+      EntityName{"c:@F at foo", "", std::move(Namespace)});
 
-TEST_P(LUSummaryTest, MissingIDTable) {
-  auto Result = readFromString(R"({
-    "lu_namespace": [
-      {
-        "kind": "LinkUnit",
-        "name": "test.exe"
-      }
-    ],
-    "data": []
-  })");
+  SummaryName SN("NullEntitySummaryForJSONFormatTest");
+  getData(Summary)[SN][EI] = nullptr;
 
-  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"))));
+  EXPECT_DEATH(
+      { (void)writeLUSummary(Summary, "output.json"); },
+      "JSONFormat - null EntitySummary data for "
+      "'SummaryName\\(NullEntitySummaryForJSONFormatTest\\)'");
 }
 
-TEST_P(LUSummaryTest, MissingLinkageTable) {
-  auto Result = readFromString(R"({
-    "lu_namespace": [
-      {
-        "kind": "LinkUnit",
-        "name": "test.exe"
-      }
-    ],
-    "id_table": [],
-    "data": []
-  })");
+TEST_F(JSONFormatLUSummaryTest, WriteEntitySummaryMismatchedSummaryName) {
+  NestedBuildNamespace NBN(
+      BuildNamespace(BuildNamespaceKind::LinkUnit, "test.exe"));
+  LUSummary Summary(std::move(NBN));
 
-  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"))));
-}
+  NestedBuildNamespace Namespace =
+      NestedBuildNamespace::makeCompilationUnit("test.cpp");
+  EntityId EI = getIdTable(Summary).getId(
+      EntityName{"c:@F at foo", "", std::move(Namespace)});
 
-TEST_P(LUSummaryTest, MissingData) {
-  auto Result = readFromString(R"({
-    "lu_namespace": [
-      {
-        "kind": "LinkUnit",
-        "name": "test.exe"
-      }
-    ],
-    "id_table": [],
-    "linkage_table": []
-  })");
+  SummaryName SN("MismatchedEntitySummaryForJSONFormatTest");
+  getData(Summary)[SN][EI] =
+      std::make_unique<MismatchedEntitySummaryForJSONFormatTest>();
 
-  EXPECT_THAT_ERROR(
-      std::move(Result),
-      FailedWithMessage(AllOf(
-          HasSubstr("reading LUSummary from file"),
-          HasSubstr("failed to read SummaryData entries from field 'data'"),
-          HasSubstr("expected JSON array"))));
+  EXPECT_DEATH(
+      { (void)writeLUSummary(Summary, "output.json"); },
+      "JSONFormat - EntitySummary data for "
+      "'SummaryName\\(MismatchedEntitySummaryForJSONFormatTest\\)' "
+      "reports "
+      "mismatched "
+      "'SummaryName\\(MismatchedEntitySummaryForJSONFormatTest_WrongName\\)'");
 }
 
 // ============================================================================
@@ -2137,388 +445,4 @@ TEST_F(JSONFormatLUSummaryTest, WriteEntitySummaryNoFormatInfo) {
               "'SummaryName(UnregisteredEntitySummaryForJSONFormatTest)'"))));
 }
 
-// ============================================================================
-// Round-Trip Tests - Serialization Verification
-// ============================================================================
-
-TEST_P(LUSummaryTest, RoundTripEmptyNamespace) {
-  readWriteCompare(R"({
-    "lu_namespace": [
-      {
-        "kind": "CompilationUnit",
-        "name": "test.cpp"
-      }
-    ],
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
-}
-
-TEST_P(LUSummaryTest, RoundTripSingleNamespaceElement) {
-  readWriteCompare(R"({
-    "lu_namespace": [
-      { "kind": "CompilationUnit", "name": "test.cpp" }
-    ],
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
-}
-
-TEST_P(LUSummaryTest, RoundTripMultipleNamespaceElements) {
-  readWriteCompare(R"({
-    "lu_namespace": [
-      { "kind": "CompilationUnit", "name": "a.cpp" },
-      { "kind": "CompilationUnit", "name": "b.cpp" },
-      { "kind": "LinkUnit", "name": "libtest.so" }
-    ],
-    "id_table": [],
-    "linkage_table": [],
-    "data": []
-  })");
-}
-
-TEST_P(LUSummaryTest, RoundTripWithTwoSummaryTypes) {
-  readWriteCompare(R"({
-    "lu_namespace": [
-      {
-        "kind": "CompilationUnit",
-        "name": "test.cpp"
-      }
-    ],
-    "id_table": [
-      {
-        "id": 3,
-        "name": {
-          "usr": "c:@F at qux",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      },
-      {
-        "id": 1,
-        "name": {
-          "usr": "c:@F at bar",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      },
-      {
-        "id": 4,
-        "name": {
-          "usr": "c:@F at quux",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      },
-      {
-        "id": 0,
-        "name": {
-          "usr": "c:@F at foo",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      },
-      {
-        "id": 2,
-        "name": {
-          "usr": "c:@F at baz",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      }
-    ],
-    "linkage_table": [
-      {
-        "id": 3,
-        "linkage": { "type": "Internal" }
-      },
-      {
-        "id": 1,
-        "linkage": { "type": "None" }
-      },
-      {
-        "id": 4,
-        "linkage": { "type": "External" }
-      },
-      {
-        "id": 0,
-        "linkage": { "type": "None" }
-      },
-      {
-        "id": 2,
-        "linkage": { "type": "Internal" }
-      }
-    ],
-    "data": [
-      {
-        "summary_name": "TagsEntitySummaryForJSONFormatTest",
-        "summary_data": [
-          {
-            "entity_id": 4,
-            "entity_summary": { "tags": ["exported", "hot"] }
-          },
-          {
-            "entity_id": 1,
-            "entity_summary": { "tags": ["internal-only"] }
-          },
-          {
-            "entity_id": 3,
-            "entity_summary": { "tags": ["internal-only"] }
-          },
-          {
-            "entity_id": 0,
-            "entity_summary": { "tags": ["entry-point"] }
-          },
-          {
-            "entity_id": 2,
-            "entity_summary": { "tags": [] }
-          }
-        ]
-      },
-      {
-        "summary_name": "PairsEntitySummaryForJSONFormatTest",
-        "summary_data": [
-          {
-            "entity_id": 1,
-            "entity_summary": {
-              "pairs": [
-                { "first": {"@": 1}, "second": {"@": 3} }
-              ]
-            }
-          },
-          {
-            "entity_id": 4,
-            "entity_summary": {
-              "pairs": [
-                { "first": {"@": 4}, "second": {"@": 0} },
-                { "first": {"@": 4}, "second": {"@": 2} }
-              ]
-            }
-          },
-          {
-            "entity_id": 0,
-            "entity_summary": {
-              "pairs": []
-            }
-          },
-          {
-            "entity_id": 3,
-            "entity_summary": {
-              "pairs": [
-                { "first": {"@": 3}, "second": {"@": 1} }
-              ]
-            }
-          },
-          {
-            "entity_id": 2,
-            "entity_summary": {
-              "pairs": [
-                { "first": {"@": 2}, "second": {"@": 4} },
-                { "first": {"@": 2}, "second": {"@": 3} }
-              ]
-            }
-          }
-        ]
-      }
-    ]
-  })");
-}
-
-TEST_P(LUSummaryTest, RoundTripWithEmptyDataEntry) {
-  readWriteCompare(R"({
-    "lu_namespace": [
-      { "kind": "CompilationUnit", "name": "test.cpp" }
-    ],
-    "id_table": [],
-    "linkage_table": [],
-    "data": [
-      {
-        "summary_name": "PairsEntitySummaryForJSONFormatTest",
-        "summary_data": []
-      }
-    ]
-  })");
-}
-
-TEST_P(LUSummaryTest, RoundTripLinkageTableWithNoneLinkage) {
-  readWriteCompare(R"({
-    "lu_namespace": [
-      { "kind": "CompilationUnit", "name": "test.cpp" }
-    ],
-    "id_table": [
-      {
-        "id": 0,
-        "name": {
-          "usr": "c:@F at foo",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      }
-    ],
-    "linkage_table": [
-      {
-        "id": 0,
-        "linkage": { "type": "None" }
-      }
-    ],
-    "data": []
-  })");
-}
-
-TEST_P(LUSummaryTest, RoundTripLinkageTableWithInternalLinkage) {
-  readWriteCompare(R"({
-    "lu_namespace": [
-      { "kind": "CompilationUnit", "name": "test.cpp" }
-    ],
-    "id_table": [
-      {
-        "id": 0,
-        "name": {
-          "usr": "c:@F at bar",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      }
-    ],
-    "linkage_table": [
-      {
-        "id": 0,
-        "linkage": { "type": "Internal" }
-      }
-    ],
-    "data": []
-  })");
-}
-
-TEST_P(LUSummaryTest, RoundTripLinkageTableWithExternalLinkage) {
-  readWriteCompare(R"({
-    "lu_namespace": [
-      { "kind": "CompilationUnit", "name": "test.cpp" }
-    ],
-    "id_table": [
-      {
-        "id": 0,
-        "name": {
-          "usr": "c:@F at baz",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      }
-    ],
-    "linkage_table": [
-      {
-        "id": 0,
-        "linkage": { "type": "External" }
-      }
-    ],
-    "data": []
-  })");
-}
-
-TEST_P(LUSummaryTest, RoundTripLinkageTableWithMultipleEntries) {
-  readWriteCompare(R"({
-    "lu_namespace": [
-      { "kind": "CompilationUnit", "name": "test.cpp" }
-    ],
-    "id_table": [
-      {
-        "id": 0,
-        "name": {
-          "usr": "c:@F at foo",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      },
-      {
-        "id": 1,
-        "name": {
-          "usr": "c:@F at bar",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      },
-      {
-        "id": 2,
-        "name": {
-          "usr": "c:@F at baz",
-          "suffix": "",
-          "namespace": [
-            {
-              "kind": "CompilationUnit",
-              "name": "test.cpp"
-            }
-          ]
-        }
-      }
-    ],
-    "linkage_table": [
-      {
-        "id": 0,
-        "linkage": { "type": "None" }
-      },
-      {
-        "id": 1,
-        "linkage": { "type": "Internal" }
-      },
-      {
-        "id": 2,
-        "linkage": { "type": "External" }
-      }
-    ],
-    "data": []
-  })");
-}
-
 } // anonymous namespace


        


More information about the cfe-commits mailing list