• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- Mode: C++ -*-
3 //
4 // Copyright (C) 2013-2022 Red Hat, Inc.
5 
6 /// @file read an XML corpus file (in the native Abigail XML format),
7 /// save it back and diff the resulting XML file against the input
8 /// file.  They should be identical.
9 
10 #include <cstdlib>
11 #include <cstring>
12 #include <fstream>
13 #include <iostream>
14 #include <memory>
15 #include <string>
16 #include <vector>
17 #include "abg-ir.h"
18 #include "abg-reader.h"
19 #include "abg-writer.h"
20 #include "abg-workers.h"
21 #include "abg-tools-utils.h"
22 #include "test-utils.h"
23 
24 using std::string;
25 using std::vector;
26 using std::ofstream;
27 using std::cerr;
28 
29 using std::dynamic_pointer_cast;
30 
31 using abigail::tools_utils::file_type;
32 using abigail::tools_utils::check_file;
33 using abigail::tools_utils::guess_file_type;
34 using abigail::tests::get_build_dir;
35 using abigail::ir::environment;
36 using abigail::ir::environment_sptr;
37 using abigail::translation_unit_sptr;
38 using abigail::corpus_sptr;
39 
40 using abigail::workers::queue;
41 using abigail::workers::task;
42 using abigail::workers::task_sptr;
43 using abigail::workers::get_number_of_threads;
44 
45 /// This is an aggregate that specifies where a test shall get its
46 /// input from, and where it shall write its ouput to.
47 struct InOutSpec
48 {
49   const char* in_path;
50   const char* in_suppr_spec_path;
51   const char* ref_out_path;
52   const char* out_path;
53 };// end struct InOutSpec
54 
55 
56 InOutSpec in_out_specs[] =
57 {
58   {
59     "data/test-read-write/test0.xml",
60     "",
61     "data/test-read-write/test0.xml",
62     "output/test-read-write/test0.xml"
63   },
64   {
65     "data/test-read-write/test1.xml",
66     "",
67     "data/test-read-write/test1.xml",
68     "output/test-read-write/test1.xml"
69   },
70   {
71     "data/test-read-write/test2.xml",
72     "",
73     "data/test-read-write/test2.xml",
74     "output/test-read-write/test2.xml"
75   },
76   {
77     "data/test-read-write/test3.xml",
78     "",
79     "data/test-read-write/test3.xml",
80     "output/test-read-write/test3.xml"
81   },
82   {
83     "data/test-read-write/test4.xml",
84     "",
85     "data/test-read-write/test4.xml",
86     "output/test-read-write/test4.xml"
87   },
88   {
89     "data/test-read-write/test5.xml",
90     "",
91     "data/test-read-write/test5.xml",
92     "output/test-read-write/test5.xml"
93   },
94   {
95     "data/test-read-write/test6.xml",
96     "",
97     "data/test-read-write/test6.xml",
98     "output/test-read-write/test6.xml"
99   },
100   {
101     "data/test-read-write/test7.xml",
102     "",
103     "data/test-read-write/test7.xml",
104     "output/test-read-write/test7.xml"
105   },
106   {
107     "data/test-read-write/test8.xml",
108     "",
109     "data/test-read-write/test8.xml",
110     "output/test-read-write/test8.xml"
111   },
112   {
113     "data/test-read-write/test9.xml",
114     "",
115     "data/test-read-write/test9.xml",
116     "output/test-read-write/test9.xml"
117   },
118   {
119     "data/test-read-write/test10.xml",
120     "",
121     "data/test-read-write/test10.xml",
122     "output/test-read-write/test10.xml"
123   },
124   {
125     "data/test-read-write/test11.xml",
126     "",
127     "data/test-read-write/test11.xml",
128     "output/test-read-write/test11.xml"
129   },
130   {
131     "data/test-read-write/test12.xml",
132     "",
133     "data/test-read-write/test12.xml",
134     "output/test-read-write/test12.xml"
135   },
136   {
137     "data/test-read-write/test13.xml",
138     "",
139     "data/test-read-write/test13.xml",
140     "output/test-read-write/test13.xml"
141   },
142   {
143     "data/test-read-write/test14.xml",
144     "",
145     "data/test-read-write/test14.xml",
146     "output/test-read-write/test14.xml"
147   },
148   {
149     "data/test-read-write/test15.xml",
150     "",
151     "data/test-read-write/test15.xml",
152     "output/test-read-write/test15.xml"
153   },
154   {
155     "data/test-read-write/test16.xml",
156     "",
157     "data/test-read-write/test16.xml",
158     "output/test-read-write/test16.xml"
159   },
160   {
161     "data/test-read-write/test17.xml",
162     "",
163     "data/test-read-write/test17.xml",
164     "output/test-read-write/test17.xml"
165   },
166   {
167     "data/test-read-write/test18.xml",
168     "",
169     "data/test-read-write/test18.xml",
170     "output/test-read-write/test18.xml"
171   },
172   {
173     "data/test-read-write/test19.xml",
174     "",
175     "data/test-read-write/test19.xml",
176     "output/test-read-write/test19.xml"
177   },
178   {
179     "data/test-read-write/test20.xml",
180     "",
181     "data/test-read-write/test20.xml",
182     "output/test-read-write/test20.xml"
183   },
184   {
185     "data/test-read-write/test21.xml",
186     "",
187     "data/test-read-write/test21.xml",
188     "output/test-read-write/test21.xml"
189   },
190   {
191     "data/test-read-write/test22.xml",
192     "",
193     "data/test-read-write/test22.xml",
194     "output/test-read-write/test22.xml"
195   },
196   {
197     "data/test-read-write/test23.xml",
198     "",
199     "data/test-read-write/test23.xml",
200     "output/test-read-write/test23.xml"
201   },
202   {
203     "data/test-read-write/test24.xml",
204     "",
205     "data/test-read-write/test24.xml",
206     "output/test-read-write/test24.xml"
207   },
208   {
209     "data/test-read-write/test25.xml",
210     "",
211     "data/test-read-write/test25.xml",
212     "output/test-read-write/test25.xml"
213   },
214   {
215     "data/test-read-write/test26.xml",
216     "",
217     "data/test-read-write/test26.xml",
218     "output/test-read-write/test26.xml"
219   },
220   {
221     "data/test-read-write/test27.xml",
222     "",
223     "data/test-read-write/test27.xml",
224     "output/test-read-write/test27.xml"
225   },
226   {
227     "data/test-read-write/test28.xml",
228     "data/test-read-write/test28-drop-std-fns.abignore",
229     "data/test-read-write/test28-without-std-fns-ref.xml",
230     "output/test-read-write/test28-without-std-fns.xml"
231   },
232   {
233     "data/test-read-write/test28.xml",
234     "data/test-read-write/test28-drop-std-vars.abignore",
235     "data/test-read-write/test28-without-std-vars-ref.xml",
236     "output/test-read-write/test28-without-std-vars.xml"
237   },
238   {
239     "data/test-read-write/test-crc.xml",
240     "",
241     "data/test-read-write/test-crc.xml",
242     "output/test-read-write/test-crc.xml",
243   },
244   // This should be the last entry.
245   {NULL, NULL, NULL, NULL}
246 };
247 
248 /// A task wihch reads an abixml file using abilint and compares its
249 /// output against a reference output.
250 struct test_task : public abigail::workers::task
251 {
252   InOutSpec spec;
253   bool is_ok;
254   string in_path, out_path, in_suppr_spec_path, ref_out_path;
255   string diff_cmd, error_message;
256 
257   /// Constructor of the task.
258   ///
259   /// @param the spec of where to find the abixml file to read and the
260   /// reference output of the test.
test_tasktest_task261   test_task( InOutSpec& s)
262     : spec(s),
263       is_ok(true)
264   {}
265 
266   /// This method defines what the task performs.
267   virtual void
performtest_task268   perform()
269   {
270     string input_suffix(spec.in_path);
271     in_path =
272       string(abigail::tests::get_src_dir()) + "/tests/" + input_suffix;
273 
274     if (!check_file(in_path, cerr))
275       {
276 	is_ok = false;
277 	return;
278       }
279 
280     string ref_out_path_suffix(spec.ref_out_path);
281     ref_out_path =
282       string(abigail::tests::get_src_dir())
283       + "/tests/" + ref_out_path_suffix;
284 
285     if (!check_file(ref_out_path, cerr))
286       {
287 	is_ok = false;
288 	return;
289       }
290 
291     if (spec.in_suppr_spec_path && strcmp(spec.in_suppr_spec_path, ""))
292       {
293 	in_suppr_spec_path = string(spec.in_suppr_spec_path);
294 	in_suppr_spec_path =
295 	  string(abigail::tests::get_src_dir())
296 	  + "/tests/"
297 	  + in_suppr_spec_path;
298       }
299     else
300       in_suppr_spec_path.clear();
301 
302     environment_sptr env(new environment);
303     translation_unit_sptr tu;
304     corpus_sptr corpus;
305 
306     file_type t = guess_file_type(in_path);
307     if (t == abigail::tools_utils::FILE_TYPE_UNKNOWN)
308       {
309 	cerr << in_path << "is an unknown file type\n";
310 	is_ok = false;
311 	return;
312       }
313 
314     string output_suffix(spec.out_path);
315     out_path =
316       string(abigail::tests::get_build_dir()) + "/tests/" + output_suffix;
317     if (!abigail::tools_utils::ensure_parent_dir_created(out_path))
318       {
319 	error_message =
320 	  "Could not create parent director for " + out_path;
321 	is_ok = false;
322 	return;
323       }
324 
325     string abilint = string(get_build_dir()) + "/tools/abilint";
326     if (!in_suppr_spec_path.empty())
327       abilint +=string(" --suppr ") + in_suppr_spec_path;
328     string cmd = abilint + " " + in_path + " > " + out_path;
329 
330     if (system(cmd.c_str()))
331       {
332 	error_message =
333 	  "ABI XML file doesn't pass abilint: " + out_path + "\n";
334 	is_ok = false;
335       }
336 
337     cmd = "diff -u " + ref_out_path + " " + out_path;
338     diff_cmd = cmd;
339     if (system(cmd.c_str()))
340       is_ok = false;
341   }
342 };// end struct test_task
343 
344 /// A convenience typedef for shared
345 typedef shared_ptr<test_task> test_task_sptr;
346 
347 /// Walk the array of InOutSpecs above, read the input files it points
348 /// to, write it into the output it points to and diff them.
349 int
main()350 main()
351 {
352   using abigail::workers::queue;
353   using abigail::workers::task;
354   using abigail::workers::task_sptr;
355   using abigail::workers::get_number_of_threads;
356 
357   const size_t num_tests = sizeof(in_out_specs) / sizeof (InOutSpec) - 1;
358   size_t num_workers = std::min(get_number_of_threads(), num_tests);
359   queue task_queue(num_workers);
360 
361   bool is_ok = true;
362 
363 
364   string in_path, out_path, in_suppr_spec_path, ref_out_path;
365   for (InOutSpec* s = in_out_specs; s->in_path; ++s)
366     {
367       test_task_sptr t(new test_task(*s));
368       ABG_ASSERT(task_queue.schedule_task(t));
369     }
370 
371   /// Wait for all worker threads to finish their job, and wind down.
372   task_queue.wait_for_workers_to_complete();
373 
374   // Now walk the results and print whatever error messages need to be
375   // printed.
376 
377   const vector<task_sptr>& completed_tasks =
378     task_queue.get_completed_tasks();
379 
380   ABG_ASSERT(completed_tasks.size() == num_tests);
381 
382   for (vector<task_sptr>::const_iterator ti = completed_tasks.begin();
383        ti != completed_tasks.end();
384        ++ti)
385     {
386       test_task_sptr t = dynamic_pointer_cast<test_task>(*ti);
387       if (!t->is_ok)
388 	{
389 	  is_ok = false;
390 
391 	  if (!t->error_message.empty())
392 	    cerr << t->error_message << '\n';
393 
394 	  if (!t->diff_cmd.empty())
395 	    if (system(t->diff_cmd.c_str()) == -1)
396 	      cerr << "execution of '" << t->diff_cmd << "' failed\n";
397 	}
398     }
399 
400   return !is_ok;
401 }
402