• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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