1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright 2023 Google LLC
5 //
6 // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7 // "License"); you may not use this file except in compliance with the
8 // License. You may obtain a copy of the License at
9 //
10 // https://llvm.org/LICENSE.txt
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 // Author: Giuliano Procida
19
20 #include <cstddef>
21 #include <filesystem>
22 #include <fstream>
23 #include <iostream>
24 #include <optional>
25 #include <ostream>
26 #include <sstream>
27 #include <vector>
28
29 #include <catch2/catch.hpp>
30 #include "abigail_reader.h"
31 #include "equality.h"
32 #include "graph.h"
33 #include "runtime.h"
34
35 namespace {
36
filename_to_path(const char * f)37 std::filesystem::path filename_to_path(const char* f) {
38 return std::filesystem::path("testdata") / f;
39 }
40
Read(const char * input)41 stg::abixml::Document Read(const char* input) {
42 stg::Runtime runtime(std::cerr, false);
43 return stg::abixml::Read(runtime, filename_to_path(input));
44 }
45
Read(stg::Graph & graph,const char * input)46 stg::Id Read(stg::Graph& graph, const char* input) {
47 stg::Runtime runtime(std::cerr, false);
48 return stg::abixml::Read(runtime, graph, filename_to_path(input));
49 }
50
51 struct EqualTreeTestCase {
52 const char* name;
53 const char* left;
54 const char* right;
55 bool equal;
56 };
57
58 TEST_CASE("EqualTree") {
59 const auto test = GENERATE(
60 EqualTreeTestCase(
61 {"cleaning",
62 "abigail_dirty.xml",
63 "abigail_clean.xml",
64 true}),
65 EqualTreeTestCase(
66 {"self comparison",
67 "abigail_tree_0.xml",
68 "abigail_tree_0.xml",
69 true}),
70 EqualTreeTestCase(
71 {"attribute order is irrelevant",
72 "abigail_tree_0.xml",
73 "abigail_tree_1.xml",
74 true}),
75 EqualTreeTestCase(
76 {"element order is relevant",
77 "abigail_tree_0.xml",
78 "abigail_tree_2.xml",
79 false}),
80 EqualTreeTestCase(
81 {"attribute missing",
82 "abigail_tree_0.xml",
83 "abigail_tree_3.xml",
84 false}),
85 EqualTreeTestCase(
86 {"element missing",
87 "abigail_tree_0.xml",
88 "abigail_tree_4.xml",
89 false}),
90 EqualTreeTestCase(
91 {"attribute changed",
92 "abigail_tree_0.xml",
93 "abigail_tree_5.xml",
94 false}),
95 EqualTreeTestCase(
96 {"element changed",
97 "abigail_tree_0.xml",
98 "abigail_tree_6.xml",
99 false}));
100
101 SECTION(test.name) {
102 const stg::abixml::Document left_document = Read(test.left);
103 const stg::abixml::Document right_document = Read(test.right);
104 xmlNodePtr left_root = xmlDocGetRootElement(left_document.get());
105 xmlNodePtr right_root = xmlDocGetRootElement(right_document.get());
106 stg::abixml::Clean(left_root);
107 stg::abixml::Clean(right_root);
108 CHECK(stg::abixml::EqualTree(left_root, right_root) == test.equal);
109 CHECK(stg::abixml::EqualTree(right_root, left_root) == test.equal);
110 }
111 }
112
113 struct SubTreeTestCase {
114 const char* name;
115 const char* left;
116 const char* right;
117 bool left_sub_right;
118 bool right_sub_left;
119 };
120
121 TEST_CASE("SubTree") {
122 const auto test = GENERATE(
123 SubTreeTestCase(
124 {"self comparison",
125 "abigail_tree_0.xml",
126 "abigail_tree_0.xml",
127 true, true}),
128 SubTreeTestCase(
129 {"attribute missing",
130 "abigail_tree_0.xml",
131 "abigail_tree_3.xml",
132 false, true}),
133 SubTreeTestCase(
134 {"element missing",
135 "abigail_tree_0.xml",
136 "abigail_tree_4.xml",
137 false, true}),
138 SubTreeTestCase(
139 {"member-type access special case",
140 "abigail_tree_0.xml",
141 "abigail_tree_7.xml",
142 true, true}));
143
144 SECTION(test.name) {
145 const stg::abixml::Document left_document = Read(test.left);
146 const stg::abixml::Document right_document = Read(test.right);
147 xmlNodePtr left_root = xmlDocGetRootElement(left_document.get());
148 xmlNodePtr right_root = xmlDocGetRootElement(right_document.get());
149 stg::abixml::Clean(left_root);
150 stg::abixml::Clean(right_root);
151 CHECK(stg::abixml::SubTree(left_root, right_root) == test.left_sub_right);
152 CHECK(stg::abixml::SubTree(right_root, left_root) == test.right_sub_left);
153 }
154 }
155
156 struct TidyTestCase {
157 const char* name;
158 const std::vector<const char*> files;
159 };
160
161 TEST_CASE("Tidy") {
162 const auto test = GENERATE(
163 TidyTestCase(
164 {"bad DWARF ELF link",
165 {"abigail_bad_dwarf_elf_link_0.xml",
166 "abigail_bad_dwarf_elf_link_1.xml",
167 "abigail_bad_dwarf_elf_link_2.xml"}}),
168 TidyTestCase(
169 {"anonymous type normalisation",
170 {"abigail_anonymous_types_0.xml",
171 "abigail_anonymous_types_1.xml",
172 "abigail_anonymous_types_2.xml",
173 "abigail_anonymous_types_3.xml",
174 "abigail_anonymous_types_4.xml"}}),
175 TidyTestCase(
176 {"duplicate data members",
177 {"abigail_duplicate_data_members_0.xml",
178 "abigail_duplicate_data_members_1.xml"}}),
179 TidyTestCase(
180 {"duplicate type resolution - exact duplicate",
181 {"abigail_duplicate_types_0.xml",
182 "abigail_duplicate_types_1.xml"}}),
183 TidyTestCase(
184 {"duplicate type resolution - partial duplicate",
185 {"abigail_duplicate_types_0.xml",
186 "abigail_duplicate_types_2.xml"}}),
187 TidyTestCase(
188 {"duplicate type resolution - multiple partial duplicates",
189 {"abigail_duplicate_types_0.xml",
190 "abigail_duplicate_types_3.xml"}}),
191 TidyTestCase(
192 {"duplicate type resolution - no maximal duplicate",
193 {"abigail_duplicate_types_4.xml",
194 "abigail_duplicate_types_5.xml"}}),
195 TidyTestCase(
196 {"duplicate type resolution - different scopes",
197 {"abigail_duplicate_types_4.xml",
198 "abigail_duplicate_types_6.xml"}}),
199 TidyTestCase(
200 {"duplicate type resolution - stray anonymous member",
201 {"abigail_duplicate_types_7.xml",
202 "abigail_duplicate_types_8.xml"}}),
203 TidyTestCase(
204 {"corpus group handling",
205 {"abigail_duplicate_types_0.xml",
206 "abigail_duplicate_types_9.xml"}}));
207
208 SECTION(test.name) {
209 // Read inputs.
210 stg::Graph graph;
211 std::vector<stg::Id> ids;
212 ids.reserve(test.files.size());
213 for (const char* file : test.files) {
214 ids.push_back(Read(graph, file));
215 }
216
217 // Useless equality cache.
218 struct NoCache {
Query__anonb78125900111::NoCache219 static std::optional<bool> Query(const stg::Pair&) {
220 return std::nullopt;
221 }
AllSame__anonb78125900111::NoCache222 void AllSame(const std::vector<stg::Pair>&) {}
AllDifferent__anonb78125900111::NoCache223 void AllDifferent(const std::vector<stg::Pair>&) {}
224 };
225
226 // Check exact equality.
227 NoCache cache;
228 for (size_t ix = 1; ix < ids.size(); ++ix) {
229 CHECK(stg::Equals<NoCache>(graph, cache)(ids[0], ids[ix]));
230 }
231 }
232 }
233
234 } // namespace
235