xref: /aosp_15_r20/external/stg/abigail_reader_test.cc (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
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 <iostream>
23 #include <optional>
24 #include <vector>
25 
26 #include <catch2/catch.hpp>
27 #include <libxml/tree.h>
28 #include "abigail_reader.h"
29 #include "equality.h"
30 #include "graph.h"
31 #include "runtime.h"
32 
33 namespace {
34 
filename_to_path(const char * f)35 std::filesystem::path filename_to_path(const char* f) {
36   return std::filesystem::path("testdata") / f;
37 }
38 
Read(const char * input)39 stg::abixml::Document Read(const char* input) {
40   stg::Runtime runtime(std::cerr, false);
41   return stg::abixml::Read(runtime, filename_to_path(input));
42 }
43 
Read(stg::Graph & graph,const char * input)44 stg::Id Read(stg::Graph& graph, const char* input) {
45   stg::Runtime runtime(std::cerr, false);
46   return stg::abixml::Read(runtime, graph, filename_to_path(input));
47 }
48 
49 struct EqualTreeTestCase {
50   const char* name;
51   const char* left;
52   const char* right;
53   bool equal;
54 };
55 
56 TEST_CASE("EqualTree") {
57   const auto test = GENERATE(
58       EqualTreeTestCase(
59           {"cleaning",
60            "abigail_dirty.xml",
61            "abigail_clean.xml",
62            true}),
63       EqualTreeTestCase(
64           {"self comparison",
65            "abigail_tree_0.xml",
66            "abigail_tree_0.xml",
67            true}),
68       EqualTreeTestCase(
69           {"attribute order is irrelevant",
70            "abigail_tree_0.xml",
71            "abigail_tree_1.xml",
72            true}),
73       EqualTreeTestCase(
74           {"element order is relevant",
75            "abigail_tree_0.xml",
76            "abigail_tree_2.xml",
77            false}),
78       EqualTreeTestCase(
79           {"attribute missing",
80            "abigail_tree_0.xml",
81            "abigail_tree_3.xml",
82            false}),
83       EqualTreeTestCase(
84           {"element missing",
85            "abigail_tree_0.xml",
86            "abigail_tree_4.xml",
87            false}),
88       EqualTreeTestCase(
89           {"attribute changed",
90            "abigail_tree_0.xml",
91            "abigail_tree_5.xml",
92            false}),
93       EqualTreeTestCase(
94           {"element changed",
95            "abigail_tree_0.xml",
96            "abigail_tree_6.xml",
97            false}));
98 
99   SECTION(test.name) {
100     const stg::abixml::Document left_document = Read(test.left);
101     const stg::abixml::Document right_document = Read(test.right);
102     xmlNodePtr left_root = xmlDocGetRootElement(left_document.get());
103     xmlNodePtr right_root = xmlDocGetRootElement(right_document.get());
104     stg::abixml::Clean(left_root);
105     stg::abixml::Clean(right_root);
106     CHECK(stg::abixml::EqualTree(left_root, right_root) == test.equal);
107     CHECK(stg::abixml::EqualTree(right_root, left_root) == test.equal);
108   }
109 }
110 
111 struct SubTreeTestCase {
112   const char* name;
113   const char* left;
114   const char* right;
115   bool left_sub_right;
116   bool right_sub_left;
117 };
118 
119 TEST_CASE("SubTree") {
120   const auto test = GENERATE(
121       SubTreeTestCase(
122           {"self comparison",
123            "abigail_tree_0.xml",
124            "abigail_tree_0.xml",
125            true, true}),
126       SubTreeTestCase(
127           {"attribute missing",
128            "abigail_tree_0.xml",
129            "abigail_tree_3.xml",
130            false, true}),
131       SubTreeTestCase(
132           {"element missing",
133            "abigail_tree_0.xml",
134            "abigail_tree_4.xml",
135            false, true}),
136       SubTreeTestCase(
137           {"member-type access special case",
138            "abigail_tree_0.xml",
139            "abigail_tree_7.xml",
140            true, true}));
141 
142   SECTION(test.name) {
143     const stg::abixml::Document left_document = Read(test.left);
144     const stg::abixml::Document right_document = Read(test.right);
145     xmlNodePtr left_root = xmlDocGetRootElement(left_document.get());
146     xmlNodePtr right_root = xmlDocGetRootElement(right_document.get());
147     stg::abixml::Clean(left_root);
148     stg::abixml::Clean(right_root);
149     CHECK(stg::abixml::SubTree(left_root, right_root) == test.left_sub_right);
150     CHECK(stg::abixml::SubTree(right_root, left_root) == test.right_sub_left);
151   }
152 }
153 
154 struct TidyTestCase {
155   const char* name;
156   const std::vector<const char*> files;
157 };
158 
159 TEST_CASE("Tidy") {
160   const auto test = GENERATE(
161       TidyTestCase(
162           {"bad DWARF ELF link",
163            {"abigail_bad_dwarf_elf_link_0.xml",
164             "abigail_bad_dwarf_elf_link_1.xml",
165             "abigail_bad_dwarf_elf_link_2.xml"}}),
166       TidyTestCase(
167           {"anonymous type normalisation",
168            {"abigail_anonymous_types_0.xml",
169             "abigail_anonymous_types_1.xml",
170             "abigail_anonymous_types_2.xml",
171             "abigail_anonymous_types_3.xml",
172             "abigail_anonymous_types_4.xml"}}),
173       TidyTestCase(
174           {"duplicate data members",
175            {"abigail_duplicate_data_members_0.xml",
176             "abigail_duplicate_data_members_1.xml"}}),
177       TidyTestCase(
178           {"duplicate type resolution - exact duplicate",
179            {"abigail_duplicate_types_0.xml",
180             "abigail_duplicate_types_1.xml"}}),
181       TidyTestCase(
182           {"duplicate type resolution - partial duplicate",
183            {"abigail_duplicate_types_0.xml",
184             "abigail_duplicate_types_2.xml"}}),
185       TidyTestCase(
186           {"duplicate type resolution - multiple partial duplicates",
187            {"abigail_duplicate_types_0.xml",
188             "abigail_duplicate_types_3.xml"}}),
189       TidyTestCase(
190           {"duplicate type resolution - no maximal duplicate",
191            {"abigail_duplicate_types_4.xml",
192             "abigail_duplicate_types_5.xml"}}),
193       TidyTestCase(
194           {"duplicate type resolution - different scopes",
195            {"abigail_duplicate_types_4.xml",
196             "abigail_duplicate_types_6.xml"}}),
197       TidyTestCase(
198           {"duplicate type resolution - stray anonymous member",
199            {"abigail_duplicate_types_7.xml",
200             "abigail_duplicate_types_8.xml"}}),
201       TidyTestCase(
202           {"corpus group handling",
203            {"abigail_duplicate_types_0.xml",
204             "abigail_duplicate_types_9.xml"}}));
205 
206   SECTION(test.name) {
207     // Read inputs.
208     stg::Graph graph;
209     std::vector<stg::Id> ids;
210     ids.reserve(test.files.size());
211     for (const char* file : test.files) {
212       ids.push_back(Read(graph, file));
213     }
214 
215     // Useless equality cache.
216     struct NoCache {
Query__anon5a9898f20111::NoCache217       static std::optional<bool> Query(const stg::Pair&) {
218         return std::nullopt;
219       }
AllSame__anon5a9898f20111::NoCache220       void AllSame(const std::vector<stg::Pair>&) {}
AllDifferent__anon5a9898f20111::NoCache221       void AllDifferent(const std::vector<stg::Pair>&) {}
222     };
223 
224     // Check exact equality.
225     NoCache cache;
226     for (size_t ix = 1; ix < ids.size(); ++ix) {
227       CHECK(stg::Equals<NoCache>(graph, cache)(ids[0], ids[ix]));
228     }
229   }
230 }
231 
232 }  // namespace
233