[clang] [clang][ssaf] Convert `JSONFormat` tests for `TUSummary` and `TUSummaryEncoding` to lit tests (PR #192187)
Aviral Goel via cfe-commits
cfe-commits at lists.llvm.org
Wed Apr 15 15:54:45 PDT 2026
https://github.com/aviralg updated https://github.com/llvm/llvm-project/pull/192187
>From b4630bef3259f58f8e8881d89121570dfe99bdad Mon Sep 17 00:00:00 2001
From: Aviral Goel <agoel26 at apple.com>
Date: Tue, 14 Apr 2026 22:39:17 -0700
Subject: [PATCH] [clang][ssaf] Add `JSONFormat` lit tests for `TUSummary`
---
.../Inputs/data-element-not-object.json | 9 +
.../Inputs/data-entry-missing-data.json | 13 +
.../data-entry-missing-summary-name.json | 13 +
.../TUSummary/Inputs/data-not-array.json | 9 +
.../duplicate-entity-id-in-data-map.json | 43 +
.../TUSummary/Inputs/duplicate-entity.json | 45 +
.../Inputs/duplicate-summary-name.json | 18 +
.../entity-data-element-not-object.json | 14 +
.../Inputs/entity-data-missing-entity-id.json | 18 +
.../entity-data-missing-entity-summary.json | 18 +
.../Inputs/entity-id-not-uint64.json | 19 +
.../Inputs/entity-name-missing-namespace.json | 22 +
.../Inputs/entity-name-missing-suffix.json | 22 +
.../Inputs/entity-name-missing-usr.json | 22 +
.../Inputs/id-table-element-not-object.json | 9 +
.../Inputs/id-table-entry-id-not-uint64.json | 18 +
.../Inputs/id-table-entry-missing-id.json | 17 +
.../Inputs/id-table-entry-missing-name.json | 18 +
.../TUSummary/Inputs/id-table-not-array.json | 9 +
.../TUSummary/Inputs/invalid-kind.json | 9 +
.../TUSummary/Inputs/invalid-syntax.json | 1 +
.../Inputs/linkage-table-duplicate-id.json | 32 +
.../linkage-table-element-not-object.json | 9 +
.../linkage-table-entry-id-not-uint64.json | 14 +
...kage-table-entry-linkage-invalid-type.json | 14 +
...kage-table-entry-linkage-missing-type.json | 14 +
.../linkage-table-entry-missing-id.json | 13 +
.../linkage-table-entry-missing-linkage.json | 13 +
.../Inputs/linkage-table-extra-id.json | 14 +
.../Inputs/linkage-table-missing-id.json | 23 +
.../Inputs/linkage-table-not-array.json | 9 +
.../TUSummary/Inputs/missing-data.json | 8 +
.../TUSummary/Inputs/missing-id-table.json | 7 +
.../TUSummary/Inputs/missing-kind.json | 8 +
.../Inputs/missing-linkage-table.json | 8 +
.../TUSummary/Inputs/missing-name.json | 8 +
.../Inputs/missing-tu-namespace.json | 5 +
.../namespace-element-invalid-kind.json | 28 +
.../namespace-element-missing-kind.json | 27 +
.../namespace-element-missing-name.json | 27 +
.../Inputs/namespace-element-not-object.json | 23 +
.../TUSummary/Inputs/not-json-extension.txt | 1 +
.../TUSummary/Inputs/not-object.json | 1 +
.../Inputs/pairs-element-not-object.json | 21 +
.../Inputs/pairs-invalid-first-field.json | 26 +
.../pairs-invalid-pairs-field-type.json | 21 +
.../Inputs/pairs-invalid-second-field.json | 26 +
.../Inputs/pairs-missing-first-field.json | 25 +
.../Inputs/pairs-missing-pairs-field.json | 19 +
.../Inputs/pairs-missing-second-field.json | 25 +
.../read-entity-summary-no-format-info.json | 19 +
.../TUSummary/Inputs/rt-empty-data-entry.json | 14 +
.../TUSummary/Inputs/rt-empty.json | 9 +
.../TUSummary/Inputs/rt-link-unit.json | 9 +
.../TUSummary/Inputs/rt-linkage-external.json | 30 +
.../TUSummary/Inputs/rt-linkage-internal.json | 30 +
.../TUSummary/Inputs/rt-linkage-multiple.json | 68 +
.../TUSummary/Inputs/rt-linkage-none.json | 30 +
.../Inputs/rt-two-summary-types.json | 238 ++
.../ssaf-format/TUSummary/permissions.test | 40 +
.../ssaf-format/TUSummary/serialization.test | 612 +++++
.../JSONFormatTest/TUSummaryTest.cpp | 2058 +----------------
62 files changed, 2010 insertions(+), 1982 deletions(-)
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-element-not-object.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-data.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-summary-name.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-not-array.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity-id-in-data-map.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-summary-name.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-element-not-object.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-id.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-summary.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-id-not-uint64.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-namespace.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-suffix.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-usr.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-element-not-object.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-id-not-uint64.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-id.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-name.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-not-array.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-kind.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-syntax.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-duplicate-id.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-element-not-object.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-id-not-uint64.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-id.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-linkage.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-extra-id.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-missing-id.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-not-array.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-data.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-id-table.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-kind.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-linkage-table.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-name.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-tu-namespace.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-invalid-kind.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-missing-kind.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-missing-name.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-not-object.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-json-extension.txt
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-object.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-element-not-object.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-first-field.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-pairs-field-type.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-second-field.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-first-field.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-pairs-field.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-second-field.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/read-entity-summary-no-format-info.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty-data-entry.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-link-unit.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-external.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-internal.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-multiple.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-none.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-two-summary-types.json
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/permissions.test
create mode 100644 clang/test/Analysis/Scalable/ssaf-format/TUSummary/serialization.test
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-element-not-object.json
new file mode 100644
index 0000000000000..c96c7156c5494
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-element-not-object.json
@@ -0,0 +1,9 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": ["invalid"]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-data.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-data.json
new file mode 100644
index 0000000000000..3214233104187
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-data.json
@@ -0,0 +1,13 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary"
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-summary-name.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-summary-name.json
new file mode 100644
index 0000000000000..2304f3f90d5ca
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-entry-missing-summary-name.json
@@ -0,0 +1,13 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_data": []
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-not-array.json
new file mode 100644
index 0000000000000..4a8e3ac953ce6
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/data-not-array.json
@@ -0,0 +1,9 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": {}
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity-id-in-data-map.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity-id-in-data-map.json
new file mode 100644
index 0000000000000..8c42f0d344d38
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity-id-in-data-map.json
@@ -0,0 +1,43 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": []
+ }
+ }
+ ],
+ "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": []
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity.json
new file mode 100644
index 0000000000000..de755207997a0
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-entity.json
@@ -0,0 +1,45 @@
+{
+ "tu_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 foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "Internal" }
+ },
+ {
+ "id": 1,
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-summary-name.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-summary-name.json
new file mode 100644
index 0000000000000..ec190677f1650
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/duplicate-summary-name.json
@@ -0,0 +1,18 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": []
+ },
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": []
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-element-not-object.json
new file mode 100644
index 0000000000000..7d203771a4baa
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-element-not-object.json
@@ -0,0 +1,14 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": ["invalid"]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-id.json
new file mode 100644
index 0000000000000..db708c4ee2fd6
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-id.json
@@ -0,0 +1,18 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-summary.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-summary.json
new file mode 100644
index 0000000000000..3108bce074bed
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-data-missing-entity-summary.json
@@ -0,0 +1,18 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": 0
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-id-not-uint64.json
new file mode 100644
index 0000000000000..2cac6f854e2a4
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-id-not-uint64.json
@@ -0,0 +1,19 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": "not_a_number",
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-namespace.json
new file mode 100644
index 0000000000000..ab429bf06d74a
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-namespace.json
@@ -0,0 +1,22 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": ""
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "None" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-suffix.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-suffix.json
new file mode 100644
index 0000000000000..51b08a56653e0
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-suffix.json
@@ -0,0 +1,22 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "namespace": []
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-usr.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-usr.json
new file mode 100644
index 0000000000000..798f6c1db0afd
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/entity-name-missing-usr.json
@@ -0,0 +1,22 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "suffix": "",
+ "namespace": []
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "Internal" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-element-not-object.json
new file mode 100644
index 0000000000000..56046b99cea11
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-element-not-object.json
@@ -0,0 +1,9 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [123],
+ "linkage_table": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-id-not-uint64.json
new file mode 100644
index 0000000000000..d623ce420d716
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-id-not-uint64.json
@@ -0,0 +1,18 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "id": "not_a_number",
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": []
+ }
+ }
+ ],
+ "linkage_table": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-id.json
new file mode 100644
index 0000000000000..82d522b4b04e7
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-id.json
@@ -0,0 +1,17 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": []
+ }
+ }
+ ],
+ "linkage_table": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-name.json
new file mode 100644
index 0000000000000..6aa76b6c81c34
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-entry-missing-name.json
@@ -0,0 +1,18 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "id": 0
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "None" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-not-array.json
new file mode 100644
index 0000000000000..7bfef9104a8b1
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/id-table-not-array.json
@@ -0,0 +1,9 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": {},
+ "linkage_table": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-kind.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-kind.json
new file mode 100644
index 0000000000000..3dd960cc76ca9
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-kind.json
@@ -0,0 +1,9 @@
+{
+ "tu_namespace": {
+ "kind": "invalid_kind",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-syntax.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-syntax.json
new file mode 100644
index 0000000000000..b0e13f61aa06e
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/invalid-syntax.json
@@ -0,0 +1 @@
+{ invalid json }
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-duplicate-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-duplicate-id.json
new file mode 100644
index 0000000000000..54136fa99a0bb
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-duplicate-id.json
@@ -0,0 +1,32 @@
+{
+ "tu_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": "External" }
+ },
+ {
+ "id": 0,
+ "linkage": { "type": "Internal" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-element-not-object.json
new file mode 100644
index 0000000000000..660a98049add5
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-element-not-object.json
@@ -0,0 +1,9 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": ["invalid"],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-id-not-uint64.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-id-not-uint64.json
new file mode 100644
index 0000000000000..b3668bd39ee29
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-id-not-uint64.json
@@ -0,0 +1,14 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": "not_a_number",
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
new file mode 100644
index 0000000000000..e1cb23b8f5d21
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-invalid-type.json
@@ -0,0 +1,14 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "invalid_type" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-missing-type.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
new file mode 100644
index 0000000000000..1a7f39e93af81
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-linkage-missing-type.json
@@ -0,0 +1,14 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": {}
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-id.json
new file mode 100644
index 0000000000000..7c3e96cb75cb3
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-id.json
@@ -0,0 +1,13 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [
+ {
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-linkage.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-linkage.json
new file mode 100644
index 0000000000000..b837fb327d8f4
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-entry-missing-linkage.json
@@ -0,0 +1,13 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": 0
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-extra-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-extra-id.json
new file mode 100644
index 0000000000000..ea22b8a23cfdb
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-extra-id.json
@@ -0,0 +1,14 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "External" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-missing-id.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-missing-id.json
new file mode 100644
index 0000000000000..0a44babcb9e2b
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-missing-id.json
@@ -0,0 +1,23 @@
+{
+ "tu_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": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-not-array.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-not-array.json
new file mode 100644
index 0000000000000..11f8239d72d8a
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/linkage-table-not-array.json
@@ -0,0 +1,9 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": {},
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-data.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-data.json
new file mode 100644
index 0000000000000..a872795383a61
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-data.json
@@ -0,0 +1,8 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-id-table.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-id-table.json
new file mode 100644
index 0000000000000..61ce449823c20
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-id-table.json
@@ -0,0 +1,7 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-kind.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-kind.json
new file mode 100644
index 0000000000000..c78bc51c55863
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-kind.json
@@ -0,0 +1,8 @@
+{
+ "tu_namespace": {
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-linkage-table.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-linkage-table.json
new file mode 100644
index 0000000000000..400a330603a37
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-linkage-table.json
@@ -0,0 +1,8 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-name.json
new file mode 100644
index 0000000000000..3e521780ffceb
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-name.json
@@ -0,0 +1,8 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-tu-namespace.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-tu-namespace.json
new file mode 100644
index 0000000000000..5f9b7dd71944c
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/missing-tu-namespace.json
@@ -0,0 +1,5 @@
+{
+ "id_table": [],
+ "linkage_table": [],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-invalid-kind.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-invalid-kind.json
new file mode 100644
index 0000000000000..bebdfdff67efc
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-invalid-kind.json
@@ -0,0 +1,28 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "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": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-missing-kind.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-missing-kind.json
new file mode 100644
index 0000000000000..cb354c7772df6
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-missing-kind.json
@@ -0,0 +1,27 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "name": "test.cpp"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "Internal" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-missing-name.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-missing-name.json
new file mode 100644
index 0000000000000..16a78edf99279
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-missing-name.json
@@ -0,0 +1,27 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": [
+ {
+ "kind": "CompilationUnit"
+ }
+ ]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "None" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-not-object.json
new file mode 100644
index 0000000000000..c898d6ec14a7f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/namespace-element-not-object.json
@@ -0,0 +1,23 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [
+ {
+ "id": 0,
+ "name": {
+ "usr": "c:@F at foo",
+ "suffix": "",
+ "namespace": ["invalid"]
+ }
+ }
+ ],
+ "linkage_table": [
+ {
+ "id": 0,
+ "linkage": { "type": "None" }
+ }
+ ],
+ "data": []
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-json-extension.txt b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-json-extension.txt
new file mode 100644
index 0000000000000..0967ef424bce6
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-json-extension.txt
@@ -0,0 +1 @@
+{}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-object.json
new file mode 100644
index 0000000000000..fe51488c7066f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/not-object.json
@@ -0,0 +1 @@
+[]
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-element-not-object.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-element-not-object.json
new file mode 100644
index 0000000000000..e5af7ec227db5
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-element-not-object.json
@@ -0,0 +1,21 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": ["not_an_object"]
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-first-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-first-field.json
new file mode 100644
index 0000000000000..dfe0ded6832b7
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-first-field.json
@@ -0,0 +1,26 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": [
+ {
+ "first": "not_a_number",
+ "second": {"@": 1}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-pairs-field-type.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-pairs-field-type.json
new file mode 100644
index 0000000000000..457a9ebe0a4a8
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-pairs-field-type.json
@@ -0,0 +1,21 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": "not_an_array"
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-second-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-second-field.json
new file mode 100644
index 0000000000000..546ec248e349d
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-invalid-second-field.json
@@ -0,0 +1,26 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": [
+ {
+ "first": {"@": 0},
+ "second": "not_a_number"
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-first-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-first-field.json
new file mode 100644
index 0000000000000..096385b144088
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-first-field.json
@@ -0,0 +1,25 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": [
+ {
+ "second": {"@": 1}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-pairs-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-pairs-field.json
new file mode 100644
index 0000000000000..3ff28b1458135
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-pairs-field.json
@@ -0,0 +1,19 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-second-field.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-second-field.json
new file mode 100644
index 0000000000000..ffc544ab0e05d
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/pairs-missing-second-field.json
@@ -0,0 +1,25 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "PairsEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {
+ "pairs": [
+ {
+ "first": {"@": 0}
+ }
+ ]
+ }
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/read-entity-summary-no-format-info.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/read-entity-summary-no-format-info.json
new file mode 100644
index 0000000000000..ec4f06978088f
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/read-entity-summary-no-format-info.json
@@ -0,0 +1,19 @@
+{
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ },
+ "id_table": [],
+ "linkage_table": [],
+ "data": [
+ {
+ "summary_name": "UnregisteredEntitySummary",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty-data-entry.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty-data-entry.json
new file mode 100644
index 0000000000000..ecc9c224c4e41
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty-data-entry.json
@@ -0,0 +1,14 @@
+{
+ "data": [
+ {
+ "summary_data": [],
+ "summary_name": "PairsEntitySummary"
+ }
+ ],
+ "id_table": [],
+ "linkage_table": [],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty.json
new file mode 100644
index 0000000000000..9c9fd1e54cd34
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-empty.json
@@ -0,0 +1,9 @@
+{
+ "data": [],
+ "id_table": [],
+ "linkage_table": [],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-link-unit.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-link-unit.json
new file mode 100644
index 0000000000000..9c2ebf5e18b9c
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-link-unit.json
@@ -0,0 +1,9 @@
+{
+ "data": [],
+ "id_table": [],
+ "linkage_table": [],
+ "tu_namespace": {
+ "kind": "LinkUnit",
+ "name": "libtest.so"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-external.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-external.json
new file mode 100644
index 0000000000000..253ec97903e36
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-external.json
@@ -0,0 +1,30 @@
+{
+ "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"
+ }
+ }
+ ],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-internal.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-internal.json
new file mode 100644
index 0000000000000..bea95a580b215
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-internal.json
@@ -0,0 +1,30 @@
+{
+ "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"
+ }
+ }
+ ],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-multiple.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-multiple.json
new file mode 100644
index 0000000000000..e97a8991207c9
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-multiple.json
@@ -0,0 +1,68 @@
+{
+ "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"
+ }
+ }
+ ],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-none.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-none.json
new file mode 100644
index 0000000000000..3f6c14327ee74
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-linkage-none.json
@@ -0,0 +1,30 @@
+{
+ "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"
+ }
+ }
+ ],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-two-summary-types.json b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-two-summary-types.json
new file mode 100644
index 0000000000000..fb2e633a2e7e3
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/Inputs/rt-two-summary-types.json
@@ -0,0 +1,238 @@
+{
+ "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"
+ }
+ }
+ ],
+ "tu_namespace": {
+ "kind": "CompilationUnit",
+ "name": "test.cpp"
+ }
+}
diff --git a/clang/test/Analysis/Scalable/ssaf-format/TUSummary/permissions.test b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/permissions.test
new file mode 100644
index 0000000000000..86e6ccb82e7b3
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/permissions.test
@@ -0,0 +1,40 @@
+// Tests for clang-ssaf-format --type tu 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 tu %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: cp %S/Inputs/rt-empty.json %t/no-read-permission.json
+// RUN: chmod -r %t/no-read-permission.json
+// RUN: not clang-ssaf-format --type tu %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 TUSummary 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 tu %S/Inputs/rt-empty.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/TUSummary/serialization.test b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/serialization.test
new file mode 100644
index 0000000000000..88443b86b17df
--- /dev/null
+++ b/clang/test/Analysis/Scalable/ssaf-format/TUSummary/serialization.test
@@ -0,0 +1,612 @@
+// Tests for TUSummary and TUSummaryEncoding JSON serialization.
+
+// REQUIRES: plugins
+
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+
+// ============================================================================
+// readJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/nonexistent.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=NONEXISTENT-FILE
+// NONEXISTENT-FILE: clang-ssaf-format: error: failed to validate path '{{.*}}nonexistent.json': Path does not exist
+
+// RUN: mkdir -p %t/test-directory.json
+// RUN: not clang-ssaf-format --type tu %t/test-directory.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=PATH-IS-DIRECTORY
+// PATH-IS-DIRECTORY: clang-ssaf-format: error: failed to validate path '{{.*}}test-directory.json': Path is not a file
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/not-json-extension.txt 2>&1 \
+// RUN: | FileCheck %s --check-prefix=NOT-JSON-EXTENSION
+// NOT-JSON-EXTENSION: clang-ssaf-format: error: failed to validate path '{{.*}}not-json-extension.txt': No format registered for extension 'txt'
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/invalid-syntax.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=INVALID-SYNTAX
+// RUN: not clang-ssaf-format --type tu --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 TUSummary from file '{{.*}}invalid-syntax.json'
+// INVALID-SYNTAX-NEXT: {{.*}}Expected object key
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/not-object.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=NOT-OBJECT
+// RUN: not clang-ssaf-format --type tu --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 TUSummary from file '{{.*}}not-object.json'
+// NOT-OBJECT-NEXT: failed to read TUSummary: expected JSON object
+
+// ============================================================================
+// entityLinkageFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/linkage-table-entry-linkage-missing-type.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-LINKAGE-MISSING-TYPE
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/linkage-table-entry-linkage-missing-type.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-LINKAGE-MISSING-TYPE
+// LINKAGE-TABLE-ENTRY-LINKAGE-MISSING-TYPE: clang-ssaf-format: error: reading TUSummary from file '{{.*}}linkage-table-entry-linkage-missing-type.json'
+// LINKAGE-TABLE-ENTRY-LINKAGE-MISSING-TYPE-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-TABLE-ENTRY-LINKAGE-MISSING-TYPE-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-TABLE-ENTRY-LINKAGE-MISSING-TYPE-NEXT: reading EntityLinkage from field 'linkage'
+// LINKAGE-TABLE-ENTRY-LINKAGE-MISSING-TYPE-NEXT: failed to read EntityLinkageType from field 'type': expected JSON string
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/linkage-table-entry-linkage-invalid-type.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-LINKAGE-INVALID-TYPE
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/linkage-table-entry-linkage-invalid-type.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-LINKAGE-INVALID-TYPE
+// LINKAGE-TABLE-ENTRY-LINKAGE-INVALID-TYPE: clang-ssaf-format: error: reading TUSummary from file '{{.*}}linkage-table-entry-linkage-invalid-type.json'
+// LINKAGE-TABLE-ENTRY-LINKAGE-INVALID-TYPE-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-TABLE-ENTRY-LINKAGE-INVALID-TYPE-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-TABLE-ENTRY-LINKAGE-INVALID-TYPE-NEXT: reading EntityLinkage from field 'linkage'
+// LINKAGE-TABLE-ENTRY-LINKAGE-INVALID-TYPE-NEXT: reading EntityLinkageType from field 'type'
+// LINKAGE-TABLE-ENTRY-LINKAGE-INVALID-TYPE-NEXT: invalid EntityLinkageType value 'invalid_type' for field 'type'
+
+// ============================================================================
+// linkageTableEntryFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/linkage-table-entry-missing-id.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-MISSING-ID
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/linkage-table-entry-missing-id.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-MISSING-ID
+// LINKAGE-TABLE-ENTRY-MISSING-ID: clang-ssaf-format: error: reading TUSummary from file '{{.*}}linkage-table-entry-missing-id.json'
+// LINKAGE-TABLE-ENTRY-MISSING-ID-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-TABLE-ENTRY-MISSING-ID-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-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 tu %S/Inputs/linkage-table-entry-id-not-uint64.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-ID-NOT-UINT64
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/linkage-table-entry-id-not-uint64.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-ID-NOT-UINT64
+// LINKAGE-TABLE-ENTRY-ID-NOT-UINT64: clang-ssaf-format: error: reading TUSummary from file '{{.*}}linkage-table-entry-id-not-uint64.json'
+// LINKAGE-TABLE-ENTRY-ID-NOT-UINT64-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-TABLE-ENTRY-ID-NOT-UINT64-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-TABLE-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 tu %S/Inputs/linkage-table-entry-missing-linkage.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-MISSING-LINKAGE
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/linkage-table-entry-missing-linkage.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=LINKAGE-TABLE-ENTRY-MISSING-LINKAGE
+// LINKAGE-TABLE-ENTRY-MISSING-LINKAGE: clang-ssaf-format: error: reading TUSummary from file '{{.*}}linkage-table-entry-missing-linkage.json'
+// LINKAGE-TABLE-ENTRY-MISSING-LINKAGE-NEXT: reading LinkageTable from field 'linkage_table'
+// LINKAGE-TABLE-ENTRY-MISSING-LINKAGE-NEXT: reading LinkageTable entry from index '0'
+// LINKAGE-TABLE-ENTRY-MISSING-LINKAGE-NEXT: failed to read EntityLinkage from field 'linkage': expected JSON object
+
+// ============================================================================
+// linkageTableFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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)'
+
+// ============================================================================
+// buildNamespaceKindFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/invalid-kind.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=INVALID-KIND
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/invalid-kind.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=INVALID-KIND
+// INVALID-KIND: clang-ssaf-format: error: reading TUSummary from file '{{.*}}invalid-kind.json'
+// INVALID-KIND-NEXT: reading BuildNamespace from field 'tu_namespace'
+// INVALID-KIND-NEXT: reading BuildNamespaceKind from field 'kind'
+// INVALID-KIND-NEXT: invalid BuildNamespaceKind value 'invalid_kind' for field 'kind'
+
+// ============================================================================
+// buildNamespaceFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/missing-kind.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-KIND
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/missing-kind.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-KIND
+// MISSING-KIND: clang-ssaf-format: error: reading TUSummary from file '{{.*}}missing-kind.json'
+// MISSING-KIND-NEXT: reading BuildNamespace from field 'tu_namespace'
+// MISSING-KIND-NEXT: failed to read BuildNamespaceKind from field 'kind': expected JSON string
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/missing-name.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-NAME
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/missing-name.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-NAME
+// MISSING-NAME: clang-ssaf-format: error: reading TUSummary from file '{{.*}}missing-name.json'
+// MISSING-NAME-NEXT: reading BuildNamespace from field 'tu_namespace'
+// MISSING-NAME-NEXT: failed to read BuildNamespaceName from field 'name': expected JSON string
+
+// ============================================================================
+// nestedBuildNamespaceFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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
+
+// ============================================================================
+// entityNameFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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
+
+// ============================================================================
+// entityIdTableEntryFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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)
+
+// ============================================================================
+// entityIdTableFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %S/Inputs/duplicate-entity.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=DUPLICATE-ENTITY
+// RUN: not clang-ssaf-format --type tu --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 TUSummary 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)'
+
+// ============================================================================
+// entitySummaryFromJSON() / encodingDataMapEntryFromJSON() 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 tu %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 TUSummary 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 Deserialization Error Tests
+// ============================================================================
+
+// RUN: not %clang-ssaf-format-with-plugin --type tu %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 TUSummary 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 tu %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 TUSummary 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 tu %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 TUSummary 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 tu %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 TUSummary 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 tu %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 TUSummary 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 tu %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 TUSummary 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 tu %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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 TUSummary 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)'
+
+// ============================================================================
+// summaryDataMapEntryFromJSON() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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)'
+
+// ============================================================================
+// readTUSummary() / readTUSummaryEncoding() errors
+// ============================================================================
+
+// RUN: not clang-ssaf-format --type tu %S/Inputs/missing-tu-namespace.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-TU-NAMESPACE
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/missing-tu-namespace.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-TU-NAMESPACE
+// MISSING-TU-NAMESPACE: clang-ssaf-format: error: reading TUSummary from file '{{.*}}missing-tu-namespace.json'
+// MISSING-TU-NAMESPACE-NEXT: failed to read BuildNamespace from field 'tu_namespace': expected JSON object
+
+// RUN: not clang-ssaf-format --type tu %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 tu --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 TUSummary 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 tu %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 tu --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 TUSummary 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 tu %S/Inputs/missing-data.json 2>&1 \
+// RUN: | FileCheck %s --match-full-lines --check-prefix=MISSING-DATA
+// RUN: not clang-ssaf-format --type tu --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 TUSummary from file '{{.*}}missing-data.json'
+// MISSING-DATA-NEXT: failed to read SummaryData entries from field 'data': expected JSON array
+
+// ============================================================================
+// writeJSON() errors
+// ============================================================================
+
+// RUN: echo '{}' > %t/existing.json
+// RUN: not clang-ssaf-format --type tu %S/Inputs/rt-empty.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 tu --encoding %S/Inputs/rt-empty.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 tu %S/Inputs/rt-empty.json -o %t/nonexistent-dir/test.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=WRITE-PARENT-DIRECTORY-NOT-FOUND
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/rt-empty.json -o %t/nonexistent-dir/test.json 2>&1 \
+// RUN: | FileCheck %s --check-prefix=WRITE-PARENT-DIRECTORY-NOT-FOUND
+// WRITE-PARENT-DIRECTORY-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 tu %S/Inputs/rt-empty.json -o %t/test.txt 2>&1 \
+// RUN: | FileCheck %s --check-prefix=WRITE-NOT-JSON-EXTENSION
+// RUN: not clang-ssaf-format --type tu --encoding %S/Inputs/rt-empty.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'
+
+// ============================================================================
+// Round-Trip Tests
+// ============================================================================
+
+// RUN: clang-ssaf-format --type tu %S/Inputs/rt-empty.json -o %t/rt-empty.json
+// RUN: diff %S/Inputs/rt-empty.json %t/rt-empty.json
+// RUN: clang-ssaf-format --type tu --encoding %S/Inputs/rt-empty.json -o %t/rt-empty-enc.json
+// RUN: diff %S/Inputs/rt-empty.json %t/rt-empty-enc.json
+
+// RUN: %clang-ssaf-format-with-plugin --type tu %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 tu --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 --type tu %S/Inputs/rt-link-unit.json -o %t/rt-link-unit.json
+// RUN: diff %S/Inputs/rt-link-unit.json %t/rt-link-unit.json
+// RUN: clang-ssaf-format --type tu --encoding %S/Inputs/rt-link-unit.json -o %t/rt-link-unit-enc.json
+// RUN: diff %S/Inputs/rt-link-unit.json %t/rt-link-unit-enc.json
+
+// RUN: %clang-ssaf-format-with-plugin --type tu %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 tu --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 tu %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 tu --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 tu %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 tu --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 tu %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 tu --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 tu %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 tu --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/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/TUSummaryTest.cpp b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/TUSummaryTest.cpp
index 7d0e34dd7c569..cd78c04cf15e1 100644
--- a/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/TUSummaryTest.cpp
+++ b/clang/unittests/ScalableStaticAnalysisFramework/Serialization/JSONFormatTest/TUSummaryTest.cpp
@@ -209,1560 +209,46 @@ TEST_P(TUSummaryTest, NoReadPermission) {
EXPECT_THAT_ERROR(std::move(RestoreError), Succeeded());
}
-TEST_P(TUSummaryTest, InvalidSyntax) {
- auto Result = readFromString("{ invalid json }");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("Expected object key"))));
-}
-
-TEST_P(TUSummaryTest, NotObject) {
- auto Result = readFromString("[]");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("failed to read TUSummary"),
- HasSubstr("expected JSON object"))));
-}
-
-// ============================================================================
-// JSONFormat::entityLinkageFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, LinkageTableEntryLinkageMissingType) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [
- {
- "id": 0,
- "linkage": {}
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary 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(TUSummaryTest, LinkageTableEntryLinkageInvalidType) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [
- {
- "id": 0,
- "linkage": { "type": "invalid_type" }
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary 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(TUSummaryTest, LinkageTableEntryMissingId) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [
- {
- "linkage": { "type": "External" }
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary 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(TUSummaryTest, LinkageTableEntryIdNotUInt64) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [
- {
- "id": "not_a_number",
- "linkage": { "type": "External" }
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary 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(TUSummaryTest, LinkageTableEntryMissingLinkage) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [
- {
- "id": 0
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary 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(TUSummaryTest, LinkageTableNotArray) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": {},
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary from file"),
- HasSubstr("failed to read LinkageTable from field 'linkage_table'"),
- HasSubstr("expected JSON array"))));
-}
-
-TEST_P(TUSummaryTest, LinkageTableElementNotObject) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": ["invalid"],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("reading LinkageTable from field 'linkage_table'"),
- HasSubstr("failed to read LinkageTable entry from index '0'"),
- HasSubstr("expected JSON object"))));
-}
-
-TEST_P(TUSummaryTest, LinkageTableExtraId) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [
- {
- "id": 0,
- "linkage": { "type": "External" }
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary 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(TUSummaryTest, LinkageTableMissingId) {
- auto Result = readFromString(R"({
- "tu_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": [],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("reading LinkageTable from field 'linkage_table'"),
- HasSubstr("failed to deserialize LinkageTable"),
- HasSubstr("missing 'EntityId(0)' present in IdTable"))));
-}
-
-TEST_P(TUSummaryTest, LinkageTableDuplicateId) {
- auto Result = readFromString(R"({
- "tu_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": "External" }
- },
- {
- "id": 0,
- "linkage": { "type": "Internal" }
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("reading LinkageTable from field 'linkage_table'"),
- HasSubstr("failed to insert LinkageTable entry at index '1'"),
- HasSubstr("encountered duplicate 'EntityId(0)'"))));
-}
-
-// ============================================================================
-// JSONFormat::buildNamespaceKindFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, InvalidKind) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "invalid_kind",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("reading BuildNamespace from field 'tu_namespace'"),
- HasSubstr("reading BuildNamespaceKind from field 'kind'"),
- HasSubstr("invalid BuildNamespaceKind value 'invalid_kind' for "
- "field 'kind'"))));
-}
-
-// ============================================================================
-// JSONFormat::buildNamespaceFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, MissingKind) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary from file"),
- HasSubstr("reading BuildNamespace from field 'tu_namespace'"),
- HasSubstr("failed to read BuildNamespaceKind from field 'kind'"),
- HasSubstr("expected JSON string"))));
-}
-
-TEST_P(TUSummaryTest, MissingName) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit"
- },
- "id_table": [],
- "linkage_table": [],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary from file"),
- HasSubstr("reading BuildNamespace from field 'tu_namespace'"),
- HasSubstr("failed to read BuildNamespaceName from field 'name'"),
- HasSubstr("expected JSON string"))));
-}
-
-// ============================================================================
-// JSONFormat::nestedBuildNamespaceFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, NamespaceElementNotObject) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary 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(TUSummaryTest, NamespaceElementMissingKind) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary 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(TUSummaryTest, NamespaceElementInvalidKind) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary 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(TUSummaryTest, NamespaceElementMissingName) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary from file"),
- HasSubstr("reading IdTable from field 'id_table'"),
- HasSubstr("reading EntityIdTable entry from index '0'"),
- HasSubstr("reading EntityName from field 'name'"),
- HasSubstr("reading NestedBuildNamespace from field 'namespace'"),
- HasSubstr("reading BuildNamespace from index '0'"),
- HasSubstr("failed to read BuildNamespaceName from field 'name'"),
- HasSubstr("expected JSON string"))));
-}
-
-// ============================================================================
-// JSONFormat::entityNameFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, EntityNameMissingUSR) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [
- {
- "id": 0,
- "name": {
- "suffix": "",
- "namespace": []
- }
- }
- ],
- "linkage_table": [
- {
- "id": 0,
- "linkage": { "type": "Internal" }
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(TUSummaryTest, EntityNameMissingSuffix) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [
- {
- "id": 0,
- "name": {
- "usr": "c:@F at foo",
- "namespace": []
- }
- }
- ],
- "linkage_table": [
- {
- "id": 0,
- "linkage": { "type": "External" }
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(TUSummaryTest, EntityNameMissingNamespace) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary from file"),
- HasSubstr("reading IdTable from field 'id_table'"),
- HasSubstr("reading EntityIdTable entry from index '0'"),
- HasSubstr("reading EntityName from field 'name'"),
- HasSubstr(
- "failed to read NestedBuildNamespace from field 'namespace'"),
- HasSubstr("expected JSON array"))));
-}
-
-// ============================================================================
-// JSONFormat::entityIdTableEntryFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, IDTableEntryMissingID) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [
- {
- "name": {
- "usr": "c:@F at foo",
- "suffix": "",
- "namespace": []
- }
- }
- ],
- "linkage_table": [],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary 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(TUSummaryTest, IDTableEntryMissingName) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [
- {
- "id": 0
- }
- ],
- "linkage_table": [
- {
- "id": 0,
- "linkage": { "type": "None" }
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary 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(TUSummaryTest, IDTableEntryIDNotUInt64) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [
- {
- "id": "not_a_number",
- "name": {
- "usr": "c:@F at foo",
- "suffix": "",
- "namespace": []
- }
- }
- ],
- "linkage_table": [],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("reading IdTable from field 'id_table'"),
- HasSubstr("reading EntityIdTable entry from index '0'"),
- HasSubstr("failed to read EntityId from field 'id'"),
- HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
-}
-
-// ============================================================================
-// JSONFormat::entityIdTableFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, IDTableNotArray) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": {},
- "linkage_table": [],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("failed to read IdTable from field 'id_table'"),
- HasSubstr("expected JSON array"))));
-}
-
-TEST_P(TUSummaryTest, IDTableElementNotObject) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [123],
- "linkage_table": [],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("reading IdTable from field 'id_table'"),
- HasSubstr("failed to read EntityIdTable entry from index '0'"),
- HasSubstr("expected JSON object"))));
-}
-
-TEST_P(TUSummaryTest, DuplicateEntity) {
- auto Result = readFromString(R"({
- "tu_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 foo",
- "suffix": "",
- "namespace": [
- {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- }
- ]
- }
- }
- ],
- "linkage_table": [
- {
- "id": 0,
- "linkage": { "type": "Internal" }
- },
- {
- "id": 1,
- "linkage": { "type": "External" }
- }
- ],
- "data": []
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("reading IdTable from field 'id_table'"),
- HasSubstr("failed to insert EntityIdTable entry at index '1'"),
- HasSubstr("encountered duplicate 'EntityId(0)'"))));
-}
-
-// ============================================================================
-// JSONFormat::entitySummaryFromJSON() / encodingDataMapEntryFromJSON() Tests
-// ============================================================================
-
-TEST_F(JSONFormatTUSummaryTest, ReadEntitySummaryNoFormatInfo) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_name": "UnregisteredEntitySummaryForJSONFormatTest",
- "summary_data": [
- {
- "entity_id": 0,
- "entity_summary": {}
- }
- ]
- }
- ]
- })");
-
- EXPECT_THAT_EXPECTED(
- Result,
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(JSONFormatTUSummaryTest,
- PairsEntitySummaryForJSONFormatTestMissingPairsField) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_name": "PairsEntitySummaryForJSONFormatTest",
- "summary_data": [
- {
- "entity_id": 0,
- "entity_summary": {}
- }
- ]
- }
- ]
- })");
-
- EXPECT_THAT_EXPECTED(
- Result,
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(JSONFormatTUSummaryTest,
- PairsEntitySummaryForJSONFormatTestInvalidPairsFieldType) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary 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(JSONFormatTUSummaryTest,
- PairsEntitySummaryForJSONFormatTestPairsElementNotObject) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary 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(JSONFormatTUSummaryTest,
- PairsEntitySummaryForJSONFormatTestMissingFirstField) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary 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(JSONFormatTUSummaryTest,
- PairsEntitySummaryForJSONFormatTestInvalidFirstField) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary 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(JSONFormatTUSummaryTest,
- PairsEntitySummaryForJSONFormatTestMissingSecondField) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary 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(JSONFormatTUSummaryTest,
- PairsEntitySummaryForJSONFormatTestInvalidSecondField) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary 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::entityDataMapEntryFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, EntityDataMissingEntityID) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_name": "PairsEntitySummaryForJSONFormatTest",
- "summary_data": [
- {
- "entity_summary": {}
- }
- ]
- }
- ]
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(TUSummaryTest, EntityDataMissingEntitySummary) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_name": "PairsEntitySummaryForJSONFormatTest",
- "summary_data": [
- {
- "entity_id": 0
- }
- ]
- }
- ]
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(TUSummaryTest, EntityIDNotUInt64) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary from file"),
- HasSubstr("reading SummaryData entries from field 'data'"),
- HasSubstr("reading SummaryData entry from index '0'"),
- HasSubstr("reading EntitySummary entries from field 'summary_data'"),
- HasSubstr("reading EntitySummary entry from index '0'"),
- HasSubstr("failed to read EntityId from field 'entity_id'"),
- HasSubstr("expected JSON number (unsigned 64-bit integer)"))));
-}
-
-TEST_F(JSONFormatTUSummaryTest, ReadEntitySummaryMissingData) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_name": "NullEntitySummaryForJSONFormatTest",
- "summary_data": [
- {
- "entity_id": 0,
- "entity_summary": {}
- }
- ]
- }
- ]
- })");
-
- EXPECT_THAT_EXPECTED(
- Result,
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(JSONFormatTUSummaryTest, ReadEntitySummaryMismatchedSummaryName) {
- auto Result = readTUSummaryFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_name": "MismatchedEntitySummaryForJSONFormatTest",
- "summary_data": [
- {
- "entity_id": 0,
- "entity_summary": {}
- }
- ]
- }
- ]
- })");
-
- EXPECT_THAT_EXPECTED(
- Result,
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(JSONFormatTUSummaryTest, WriteEntitySummaryMissingData) {
- TUSummary Summary(
- BuildNamespace(BuildNamespaceKind::CompilationUnit, "test.cpp"));
-
- 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)writeTUSummary(Summary, "output.json"); },
- "JSONFormat - null EntitySummary data for "
- "'SummaryName\\(NullEntitySummaryForJSONFormatTest\\)'");
-}
-
-TEST_F(JSONFormatTUSummaryTest, WriteEntitySummaryMismatchedSummaryName) {
- TUSummary Summary(
- BuildNamespace(BuildNamespaceKind::CompilationUnit, "test.cpp"));
-
- 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)writeTUSummary(Summary, "output.json"); },
- "JSONFormat - EntitySummary data for "
- "'SummaryName\\(MismatchedEntitySummaryForJSONFormatTest\\)' reports "
- "mismatched "
- "'SummaryName\\(MismatchedEntitySummaryForJSONFormatTest_WrongName\\)'");
-}
-
-// ============================================================================
-// JSONFormat::entityDataMapFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, EntityDataElementNotObject) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_name": "PairsEntitySummaryForJSONFormatTest",
- "summary_data": ["invalid"]
- }
- ]
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(TUSummaryTest, DuplicateEntityIdInDataMap) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [
- {
- "id": 0,
- "name": {
- "usr": "c:@F at foo",
- "suffix": "",
- "namespace": []
- }
- }
- ],
- "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 TUSummary 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::summaryDataMapEntryFromJSON() Error Tests
-// ============================================================================
-
-TEST_P(TUSummaryTest, DataEntryMissingSummaryName) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_data": []
- }
- ]
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(TUSummaryTest, DataEntryMissingData) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_name": "PairsEntitySummaryForJSONFormatTest"
- }
- ]
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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
+// JSONFormat::entityDataMapEntryFromJSON() Error Tests
// ============================================================================
-TEST_P(TUSummaryTest, DataNotArray) {
- auto Result = readFromString(R"({
+TEST_F(JSONFormatTUSummaryTest, ReadEntitySummaryMissingData) {
+ auto Result = readTUSummaryFromString(R"({
"tu_namespace": {
"kind": "CompilationUnit",
"name": "test.cpp"
},
"id_table": [],
"linkage_table": [],
- "data": {}
+ "data": [
+ {
+ "summary_name": "NullEntitySummaryForJSONFormatTest",
+ "summary_data": [
+ {
+ "entity_id": 0,
+ "entity_summary": {}
+ }
+ ]
+ }
+ ]
})");
- EXPECT_THAT_ERROR(
- std::move(Result),
+ EXPECT_THAT_EXPECTED(
+ Result,
FailedWithMessage(AllOf(
HasSubstr("reading TUSummary from file"),
- HasSubstr("failed to read SummaryData entries from field 'data'"),
- HasSubstr("expected JSON array"))));
-}
-
-TEST_P(TUSummaryTest, DataElementNotObject) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": ["invalid"]
- })");
-
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("reading SummaryData entries from field 'data'"),
- HasSubstr("failed to read SummaryData entry from index '0'"),
- HasSubstr("expected JSON object"))));
+ 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(TUSummaryTest, DuplicateSummaryName) {
- auto Result = readFromString(R"({
+TEST_F(JSONFormatTUSummaryTest, ReadEntitySummaryMismatchedSummaryName) {
+ auto Result = readTUSummaryFromString(R"({
"tu_namespace": {
"kind": "CompilationUnit",
"name": "test.cpp"
@@ -1771,96 +257,77 @@ TEST_P(TUSummaryTest, 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 TUSummary 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::readTUSummary() / readTUSummaryEncoding() Error Tests
+// JSONFormat::entityDataMapEntryToJSON() Fatal Tests
// ============================================================================
-TEST_P(TUSummaryTest, MissingTUNamespace) {
- auto Result = readFromString(R"({
- "id_table": [],
- "linkage_table": [],
- "data": []
- })");
+TEST_F(JSONFormatTUSummaryTest, WriteEntitySummaryMissingData) {
+ TUSummary Summary(
+ BuildNamespace(BuildNamespaceKind::CompilationUnit, "test.cpp"));
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary from file"),
- HasSubstr("failed to read BuildNamespace from field 'tu_namespace'"),
- HasSubstr("expected JSON object"))));
-}
+ NestedBuildNamespace Namespace =
+ NestedBuildNamespace::makeCompilationUnit("test.cpp");
+ EntityId EI = getIdTable(Summary).getId(
+ EntityName{"c:@F at foo", "", std::move(Namespace)});
-TEST_P(TUSummaryTest, MissingIDTable) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "data": []
- })");
+ SummaryName SN("NullEntitySummaryForJSONFormatTest");
+ getData(Summary)[SN][EI] = nullptr;
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(
- AllOf(HasSubstr("reading TUSummary from file"),
- HasSubstr("failed to read IdTable from field 'id_table'"),
- HasSubstr("expected JSON array"))));
+ EXPECT_DEATH(
+ { (void)writeTUSummary(Summary, "output.json"); },
+ "JSONFormat - null EntitySummary data for "
+ "'SummaryName\\(NullEntitySummaryForJSONFormatTest\\)'");
}
-TEST_P(TUSummaryTest, MissingLinkageTable) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "data": []
- })");
+TEST_F(JSONFormatTUSummaryTest, WriteEntitySummaryMismatchedSummaryName) {
+ TUSummary Summary(
+ BuildNamespace(BuildNamespaceKind::CompilationUnit, "test.cpp"));
- EXPECT_THAT_ERROR(
- std::move(Result),
- FailedWithMessage(AllOf(
- HasSubstr("reading TUSummary 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(TUSummaryTest, MissingData) {
- auto Result = readFromString(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "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 TUSummary from file"),
- HasSubstr("failed to read SummaryData entries from field 'data'"),
- HasSubstr("expected JSON array"))));
+ EXPECT_DEATH(
+ { (void)writeTUSummary(Summary, "output.json"); },
+ "JSONFormat - EntitySummary data for "
+ "'SummaryName\\(MismatchedEntitySummaryForJSONFormatTest\\)' reports "
+ "mismatched "
+ "'SummaryName\\(MismatchedEntitySummaryForJSONFormatTest_WrongName\\)"
+ "'");
}
// ============================================================================
@@ -1968,377 +435,4 @@ TEST_F(JSONFormatTUSummaryTest, WriteEntitySummaryNoFormatInfo) {
"'SummaryName(UnregisteredEntitySummaryForJSONFormatTest)'"))));
}
-// ============================================================================
-// Round-Trip Tests - Serialization Verification
-// ============================================================================
-
-TEST_P(TUSummaryTest, RoundTripEmpty) {
- readWriteCompare(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": []
- })");
-}
-
-TEST_P(TUSummaryTest, RoundTripWithTwoSummaryTypes) {
- readWriteCompare(R"({
- "tu_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(TUSummaryTest, RoundTripLinkUnit) {
- readWriteCompare(R"({
- "tu_namespace": {
- "kind": "LinkUnit",
- "name": "libtest.so"
- },
- "id_table": [],
- "linkage_table": [],
- "data": []
- })");
-}
-
-TEST_P(TUSummaryTest, RoundTripWithEmptyDataEntry) {
- readWriteCompare(R"({
- "tu_namespace": {
- "kind": "CompilationUnit",
- "name": "test.cpp"
- },
- "id_table": [],
- "linkage_table": [],
- "data": [
- {
- "summary_name": "PairsEntitySummaryForJSONFormatTest",
- "summary_data": []
- }
- ]
- })");
-}
-
-TEST_P(TUSummaryTest, RoundTripLinkageTableWithNoneLinkage) {
- readWriteCompare(R"({
- "tu_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(TUSummaryTest, RoundTripLinkageTableWithInternalLinkage) {
- readWriteCompare(R"({
- "tu_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(TUSummaryTest, RoundTripLinkageTableWithExternalLinkage) {
- readWriteCompare(R"({
- "tu_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(TUSummaryTest, RoundTripLinkageTableWithMultipleEntries) {
- readWriteCompare(R"({
- "tu_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