libabigail/tests/test-abidiff-exit.cc
Dodji Seketeli ee2b54ddd9 Make abidiff and abidw support several --headers-dir{1,2} options
When handling a binary with abidiff or abidw it can be useful to
provide several different header files directories, for the cases
where the header files of the binary are scathered in several
different directories.

It thus becomes possible to invoke abidiff like this:

    abidiff --headers-dir1 first-header-dir1   \
	    --headers-dir1 second-header-dir1  \
	    --headers-dir2 first-header-dir2   \
	    --headers-dir2 second-header-dir2  \
	    binary1 binary2

This patch adds support for that.  It also modifies the
tests/test-abidiff-exit.cc test harness to make it take header
directories.  With that modification done, a new test is added in that
harness to exercise this new feature.

This should close the feature request over at
https://sourceware.org/bugzilla/show_bug.cgi?id=26565.

	* doc/manuals/abidiff.rst: Update documentation for the
	--headers-dir{1,2} options.
	* doc/manuals/abidw.rst: Likewise for the --header-dir option.
	* include/abg-tools-utils.h (gen_suppr_spec_from_headers): Add new
	overload that takes a vector of headers root dirs.
	* src/abg-tools-utils.cc (gen_suppr_spec_from_headers_root_dir):
	Define new function.
	(gen_suppr_spec_from_headers): Define a new overload that takes a
	vector of head_root_dir strings; it uses the new
	gen_suppr_spec_from_headers function.  Use the new overload in the
	previous one that takes just one head_root_dir string.
	* tools/abidiff.cc (options::headers_dirs{1,2}): Rename
	option::headers_dir{1,2} into this one and make it be a vector of
	strings rather than just a string.
	(parse_command_line): Support several --headers-dir{1,2} on the
	command line.
	(set_diff_context_from_opts, set_suppressions): Adjust.
	* tools/abidw.cc (options::headers_dirs): Renamed
	options::headers_dir into this and make it be a vector of strings
	rather than just a string.
	(parse_command_line): Support several --headers-dir on the command
	line.
	(set_suppressions): Adjust.
	* tests/data/test-abidiff-exit/test-headers-dirs/headers-a/header-a-v{0,1}.h:
	Header files of new binary test input.
	* tests/data/test-abidiff-exit/test-headers-dirs/headers-b/header-b-v{0,1}.h:
	Likewise.
	* tests/data/test-abidiff-exit/test-headers-dirs/test-headers-dir-v{0,1}.c:
	Source code of new binary test input.
	* tests/data/test-abidiff-exit/test-headers-dirs/test-headers-dir-report-{1,2}.txt:
	Reference output of new binary test input.
	* tests/data/test-abidiff-exit/test-headers-dirs/test-headers-dir-v{0,1}.o:
	New binary test input.
	* tests/data/Makefile.am: Add the new files above to source
	distribution.
	* tests/test-abidiff-exit.cc (InOutSpec::in_elfv{0,1}_path): Add
	new data members.
	(in_out_specs): Adjust the content of this array as its type
	changed.  Also, add two new entries to run the test over the new
	binary test inputs above.
	(do_prefix_strings): Define new static function.
	(main): Use it the new do_prefix_strings here.  Make abidiff
	use the --header-dir{1,2} option whenever header directories are
	specified in an entry of the in_out_specs array.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
2020-09-18 10:27:18 +02:00

470 lines
15 KiB
C++

// -*- Mode: C++ -*-
//
// Copyright (C) 2016-2020 Red Hat, Inc.
//
// This file is part of the GNU Application Binary Interface Generic
// Analysis and Instrumentation Library (libabigail). This library is
// free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License as published by the
// Free Software Foundation; either version 3, or (at your option) any
// later version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Lesser Public License for more details.
// You should have received a copy of the GNU Lesser General Public
// License along with this program; see the file COPYING-LGPLV3. If
// not, see <http://www.gnu.org/licenses/>.
// Author: Dodji Seketeli
/// @file
///
/// This program runs abidiff between input files and checks that
/// the exit code of the abidiff is the one we expect.
///
/// The set of input files and reference reports to consider should be
/// present in the source distribution.
/// This is an aggregate that specifies where a test shall get its
/// input from and where it shall write its ouput to.
#include <sys/wait.h>
#include <cstring>
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <cstdlib>
#include "abg-tools-utils.h"
#include "test-utils.h"
using abigail::tools_utils::abidiff_status;
struct InOutSpec
{
const char* in_elfv0_path;
const char* in_elfv1_path;
const char* in_suppr_path;
const char* in_elfv0_headers_dirs;
const char* in_elfv1_headers_dirs;
const char* abidiff_options;
abidiff_status status;
const char* in_report_path;
const char* out_report_path;
};// end struct InOutSpec;
InOutSpec in_out_specs[] =
{
{
"data/test-abidiff-exit/test1-voffset-change-v0.o",
"data/test-abidiff-exit/test1-voffset-change-v1.o",
"",
"",
"",
"--no-default-suppression --no-show-locs",
abigail::tools_utils::ABIDIFF_ABI_CHANGE
| abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE,
"data/test-abidiff-exit/test1-voffset-change-report0.txt",
"output/test-abidiff-exit/test1-voffset-change-report0.txt"
},
{
"data/test-abidiff-exit/test1-voffset-change-v0.o",
"data/test-abidiff-exit/test1-voffset-change-v1.o",
"data/test-abidiff-exit/test1-voffset-change.abignore",
"",
"",
"--no-default-suppression --no-show-locs",
abigail::tools_utils::ABIDIFF_OK,
"data/test-abidiff-exit/test1-voffset-change-report1.txt",
"output/test-abidiff-exit/test1-voffset-change-report1.txt"
},
{
"data/test-abidiff-exit/test2-filtered-removed-fns-v0.o",
"data/test-abidiff-exit/test2-filtered-removed-fns-v1.o",
"",
"",
"",
"--no-default-suppression --no-show-locs",
abigail::tools_utils::ABIDIFF_ABI_CHANGE
| abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE,
"data/test-abidiff-exit/test2-filtered-removed-fns-report0.txt",
"output/test-abidiff-exit/test2-filtered-removed-fns-report0.txt"
},
{
"data/test-abidiff-exit/test2-filtered-removed-fns-v0.o",
"data/test-abidiff-exit/test2-filtered-removed-fns-v1.o",
"data/test-abidiff-exit/test2-filtered-removed-fns.abignore",
"",
"",
"--no-default-suppression --no-show-locs",
abigail::tools_utils::ABIDIFF_OK,
"data/test-abidiff-exit/test2-filtered-removed-fns-report1.txt",
"output/test-abidiff-exit/test2-filtered-removed-fns-report1.txt"
},
{
"data/test-abidiff-exit/test-loc-v0.bi",
"data/test-abidiff-exit/test-loc-v1.bi",
"",
"",
"",
"",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-loc-with-locs-report.txt",
"output/test-abidiff-exit/test-loc-with-locs-report.txt"
},
{
"data/test-abidiff-exit/test-loc-v0.bi",
"data/test-abidiff-exit/test-loc-v1.bi",
"",
"",
"",
"--no-show-locs",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-loc-without-locs-report.txt",
"output/test-abidiff-exit/test-loc-without-locs-report.txt"
},
{
"data/test-abidiff-exit/test-no-stray-comma-v0.o",
"data/test-abidiff-exit/test-no-stray-comma-v1.o",
"",
"",
"",
"--leaf-changes-only",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-no-stray-comma-report.txt",
"output/test-abidiff-exit/test-no-stray-comma-report.txt"
},
{
"data/test-abidiff-exit/test-leaf-stats-v0.o",
"data/test-abidiff-exit/test-leaf-stats-v1.o",
"",
"",
"",
"--no-show-locs --leaf-changes-only",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-leaf-stats-report.txt",
"output/test-abidiff-exit/test-leaf-stats-report.txt"
},
{
"data/test-abidiff-exit/test-leaf-more-v0.o",
"data/test-abidiff-exit/test-leaf-more-v1.o",
"",
"",
"",
"--no-show-locs --leaf-changes-only",
abigail::tools_utils::ABIDIFF_ABI_CHANGE
| abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE,
"data/test-abidiff-exit/test-leaf-more-report.txt",
"output/test-abidiff-exit/test-leaf-more-report.txt"
},
{
"data/test-abidiff-exit/test-leaf-fun-type-v0.o",
"data/test-abidiff-exit/test-leaf-fun-type-v1.o",
"",
"",
"",
"--no-show-locs --leaf-changes-only",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-leaf-fun-type-report.txt",
"output/test-abidiff-exit/test-leaf-fun-type-report.txt"
},
{
"data/test-abidiff-exit/test-leaf-redundant-v0.o",
"data/test-abidiff-exit/test-leaf-redundant-v1.o",
"",
"",
"",
"--leaf-changes-only",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-leaf-redundant-report.txt",
"output/test-abidiff-exit/test-leaf-redundant-report.txt"
},
{
"data/test-abidiff-exit/test-leaf-peeling-v0.o",
"data/test-abidiff-exit/test-leaf-peeling-v1.o",
"",
"",
"",
"--leaf-changes-only",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-leaf-peeling-report.txt",
"output/test-abidiff-exit/test-leaf-peeling-report.txt"
},
{
"data/test-abidiff-exit/test-leaf-cxx-members-v0.o",
"data/test-abidiff-exit/test-leaf-cxx-members-v1.o",
"",
"",
"",
"--leaf-changes-only",
abigail::tools_utils::ABIDIFF_ABI_CHANGE
| abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE,
"data/test-abidiff-exit/test-leaf-cxx-members-report.txt",
"output/test-abidiff-exit/test-leaf-cxx-members-report.txt"
},
{
"data/test-abidiff-exit/test-member-size-v0.o",
"data/test-abidiff-exit/test-member-size-v1.o",
"",
"",
"",
"",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-member-size-report0.txt",
"output/test-abidiff-exit/test-member-size-report0.txt"
},
{
"data/test-abidiff-exit/test-member-size-v0.o",
"data/test-abidiff-exit/test-member-size-v1.o",
"",
"",
"",
"--leaf-changes-only",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-member-size-report1.txt",
"output/test-abidiff-exit/test-member-size-report1.txt"
},
{
"data/test-abidiff-exit/test-decl-struct-v0.o",
"data/test-abidiff-exit/test-decl-struct-v1.o",
"",
"",
"",
"--harmless",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-decl-struct-report.txt",
"output/test-abidiff-exit/test-decl-struct-report.txt"
},
{
"data/test-abidiff-exit/test-fun-param-v0.abi",
"data/test-abidiff-exit/test-fun-param-v1.abi",
"",
"",
"",
"",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-fun-param-report.txt",
"output/test-abidiff-exit/test-fun-param-report.txt"
},
{
"data/test-abidiff-exit/test-decl-enum-v0.o",
"data/test-abidiff-exit/test-decl-enum-v1.o",
"",
"",
"",
"--harmless",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-decl-enum-report.txt",
"output/test-abidiff-exit/test-decl-enum-report.txt"
},
{
"data/test-abidiff-exit/test-decl-enum-v0.o",
"data/test-abidiff-exit/test-decl-enum-v1.o",
"",
"",
"",
"",
abigail::tools_utils::ABIDIFF_OK,
"data/test-abidiff-exit/test-decl-enum-report-2.txt",
"output/test-abidiff-exit/test-decl-enum-report-2.txt"
},
{
"data/test-abidiff-exit/test-decl-enum-v0.o",
"data/test-abidiff-exit/test-decl-enum-v1.o",
"",
"",
"",
"--leaf-changes-only",
abigail::tools_utils::ABIDIFF_OK,
"data/test-abidiff-exit/test-decl-enum-report-3.txt",
"output/test-abidiff-exit/test-decl-enum-report-3.txt"
},
{
"data/test-abidiff-exit/test-net-change-v0.o",
"data/test-abidiff-exit/test-net-change-v1.o",
"",
"",
"",
"--no-default-suppression --no-show-locs",
abigail::tools_utils::ABIDIFF_ABI_CHANGE
| abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE,
"data/test-abidiff-exit/test-net-change-report0.txt",
"output/test-abidiff-exit/test-net-change-report0.txt"
},
{
"data/test-abidiff-exit/test-net-change-v0.o",
"data/test-abidiff-exit/test-net-change-v1.o",
"data/test-abidiff-exit/test-net-change.abignore",
"",
"",
"--no-default-suppression --no-show-locs",
abigail::tools_utils::ABIDIFF_OK,
"data/test-abidiff-exit/test-net-change-report1.txt",
"output/test-abidiff-exit/test-net-change-report1.txt"
},
{
"data/test-abidiff-exit/test-net-change-v0.o",
"data/test-abidiff-exit/test-net-change-v1.o",
"",
"",
"",
"--no-default-suppression --no-show-locs --leaf-changes-only",
abigail::tools_utils::ABIDIFF_ABI_CHANGE
| abigail::tools_utils::ABIDIFF_ABI_INCOMPATIBLE_CHANGE,
"data/test-abidiff-exit/test-net-change-report2.txt",
"output/test-abidiff-exit/test-net-change-report2.txt"
},
{
"data/test-abidiff-exit/test-net-change-v0.o",
"data/test-abidiff-exit/test-net-change-v1.o",
"data/test-abidiff-exit/test-net-change.abignore",
"",
"",
"--no-default-suppression --no-show-locs --leaf-changes-only",
abigail::tools_utils::ABIDIFF_OK,
"data/test-abidiff-exit/test-net-change-report3.txt",
"output/test-abidiff-exit/test-net-change-report3.txt"
},
{
"data/test-abidiff-exit/test-headers-dirs/test-headers-dir-v0.o",
"data/test-abidiff-exit/test-headers-dirs/test-headers-dir-v1.o",
"",
"data/test-abidiff-exit/test-headers-dirs/headers-a",
"data/test-abidiff-exit/test-headers-dirs/headers-a",
"--no-default-suppression",
abigail::tools_utils::ABIDIFF_OK,
"data/test-abidiff-exit/test-headers-dirs/test-headers-dir-report-1.txt",
"output/test-abidiff-exit/test-headers-dirs/test-headers-dir-report-1.txt"
},
{
"data/test-abidiff-exit/test-headers-dirs/test-headers-dir-v0.o",
"data/test-abidiff-exit/test-headers-dirs/test-headers-dir-v1.o",
"",
"data/test-abidiff-exit/test-headers-dirs/headers-a, "
"data/test-abidiff-exit/test-headers-dirs/headers-b",
"data/test-abidiff-exit/test-headers-dirs/headers-a, "
"data/test-abidiff-exit/test-headers-dirs/headers-b",
"--no-default-suppression",
abigail::tools_utils::ABIDIFF_ABI_CHANGE,
"data/test-abidiff-exit/test-headers-dirs/test-headers-dir-report-2.txt",
"output/test-abidiff-exit/test-headers-dirs/test-headers-dir-report-2.txt"
},
{0, 0, 0 ,0, 0, 0, abigail::tools_utils::ABIDIFF_OK, 0, 0}
};
/// Prefix the strings in a vector of string.
///
/// @param strings the strings to prefix.
///
/// @param prefix the prefix to use.
static void
do_prefix_strings(std::vector<std::string> &strings,
const std::string& prefix)
{
for (std::vector<std::string>::size_type i = 0; i < strings.size(); ++i)
strings[i] = prefix + strings[i];
}
int
main()
{
using std::string;
using std::vector;
using std::cerr;
using abigail::tests::get_src_dir;
using abigail::tests::get_build_dir;
using abigail::tools_utils::ensure_parent_dir_created;
using abigail::tools_utils::split_string;
using abigail::tools_utils::abidiff_status;
bool is_ok = true;
string in_elfv0_path, in_elfv1_path,
in_suppression_path, abidiff_options, abidiff, cmd,
ref_diff_report_path, out_diff_report_path;
vector<string> in_elfv0_headers_dirs, in_elfv1_headers_dirs;
string source_dir_prefix = string(get_src_dir()) + "/tests/";
string build_dir_prefix = string(get_build_dir()) + "/tests/";
for (InOutSpec* s = in_out_specs; s->in_elfv0_path; ++s)
{
in_elfv0_path = source_dir_prefix + s->in_elfv0_path;
in_elfv1_path = source_dir_prefix + s->in_elfv1_path;
split_string(s->in_elfv0_headers_dirs, ",", in_elfv0_headers_dirs);
split_string(s->in_elfv1_headers_dirs, ",", in_elfv1_headers_dirs);
do_prefix_strings(in_elfv0_headers_dirs, source_dir_prefix);
do_prefix_strings(in_elfv1_headers_dirs, source_dir_prefix);
if (s->in_suppr_path && strcmp(s->in_suppr_path, ""))
in_suppression_path = source_dir_prefix + s->in_suppr_path;
else
in_suppression_path.clear();
abidiff_options = s->abidiff_options;
ref_diff_report_path = source_dir_prefix + s->in_report_path;
out_diff_report_path = build_dir_prefix + s->out_report_path;
if (!ensure_parent_dir_created(out_diff_report_path))
{
cerr << "could not create parent directory for "
<< out_diff_report_path;
is_ok = false;
continue;
}
abidiff = string(get_build_dir()) + "/tools/abidiff";
if (!abidiff_options.empty())
abidiff += " " + abidiff_options;
if (!in_elfv0_headers_dirs.empty())
for (vector<string>::const_iterator s = in_elfv0_headers_dirs.begin();
s != in_elfv0_headers_dirs.end();
++s)
abidiff += " --headers-dir1 " + *s;
if (!in_elfv1_headers_dirs.empty())
for (vector<string>::const_iterator s = in_elfv1_headers_dirs.begin();
s != in_elfv1_headers_dirs.end();
++s)
abidiff += " --headers-dir2 " + *s;
if (!in_suppression_path.empty())
abidiff += " --suppressions " + in_suppression_path;
cmd = abidiff + " " + in_elfv0_path + " " + in_elfv1_path;
cmd += " > " + out_diff_report_path;
bool abidiff_ok = true;
int code = system(cmd.c_str());
if (!WIFEXITED(code))
abidiff_ok = false;
else
{
abigail::tools_utils::abidiff_status status =
static_cast<abidiff_status>(WEXITSTATUS(code));
if (status != s->status)
{
cerr << "for command '"
<< cmd
<< "', expected abidiff status to be " << s->status
<< " but instead, got " << status << "\n";
abidiff_ok = false;
}
}
if (abidiff_ok)
{
cmd = "diff -u " + ref_diff_report_path
+ " " + out_diff_report_path;
if (system(cmd.c_str()))
is_ok = false;
}
else
is_ok = false;
}
return !is_ok;
}