mirror of
git://sourceware.org/git/libabigail.git
synced 2024-12-11 20:44:48 +00:00
b5b4e23dc7
The error message in test_task::run_abidw in test-read-common.cc is wrong. Fixed thus. Also, emit the error message directly to the standard error as the error is detected. * tests/test-read-common.cc (test_task::run_abidw): Fix error message and emit it to stderr directly. Signed-off-by: Dodji Seketeli <dodji@redhat.com>
267 lines
7.5 KiB
C++
267 lines
7.5 KiB
C++
// -*- Mode: C++ -*-
|
|
//
|
|
|
|
/// @file
|
|
///
|
|
/// This file implements the common functionality for the tests in
|
|
/// CTF and DWARF readers, it does the abstraction in the `act` test
|
|
/// stage.
|
|
|
|
#include <fstream>
|
|
#include <cstring>
|
|
#include "test-read-common.h"
|
|
|
|
using std::ofstream;
|
|
using std::cerr;
|
|
using std::dynamic_pointer_cast;
|
|
|
|
using abigail::tools_utils::emit_prefix;
|
|
using abigail::tests::get_build_dir;
|
|
using abigail::xml_writer::write_context_sptr;
|
|
using abigail::xml_writer::create_write_context;
|
|
using abigail::xml_writer::write_corpus;
|
|
|
|
namespace abigail
|
|
{
|
|
namespace tests
|
|
{
|
|
namespace read_common
|
|
{
|
|
|
|
/// Constructor.
|
|
///
|
|
/// Task to be executed for each test entry in @ref
|
|
/// abigail::tests::read_common::InOutSpec.
|
|
///
|
|
/// @param InOutSpec the set of tests.
|
|
///
|
|
/// @param a_out_abi_base the output base directory for abixml files.
|
|
///
|
|
/// @param a_in_elf_base the input base directory for object files.
|
|
///
|
|
/// @param a_in_elf_base the input base directory for expected
|
|
/// abixml files.
|
|
test_task::test_task(const InOutSpec &s,
|
|
string& a_out_abi_base,
|
|
string& a_in_elf_base,
|
|
string& a_in_abi_base)
|
|
: is_ok(true),
|
|
spec(s),
|
|
out_abi_base(a_out_abi_base),
|
|
in_elf_base(a_in_elf_base),
|
|
in_abi_base(a_in_abi_base)
|
|
{}
|
|
|
|
/// Serialize the abixml @p out_abi_path file.
|
|
///
|
|
/// @param out_abi_path the abixml path file.
|
|
///
|
|
/// @param corp the ABI @ref abigail::ir::corpus.
|
|
///
|
|
/// @return true if abixml file was serialized successfully. Otherwise
|
|
/// `error_message` is set with @p out_abi_path and false is returned.
|
|
bool
|
|
test_task::serialize_corpus(const string& out_abi_path,
|
|
corpus_sptr corp)
|
|
{
|
|
ofstream of(out_abi_path.c_str(), std::ios_base::trunc);
|
|
if (!of.is_open())
|
|
{
|
|
error_message = string("failed to read ") + out_abi_path + "\n";
|
|
return false;
|
|
}
|
|
|
|
write_context_sptr write_ctxt
|
|
= create_write_context(corp->get_environment(), of);
|
|
set_type_id_style(*write_ctxt, spec.type_id_style);
|
|
set_write_undefined_symbols(*write_ctxt, false);
|
|
is_ok = write_corpus(*write_ctxt, corp, /*indent=*/0);
|
|
of.close();
|
|
|
|
return is_ok;
|
|
}
|
|
|
|
/// Spawn `abidw --abidiff` tool appending @p extargs argument.
|
|
///
|
|
/// Thew input file object used by `abidw` will be specified by
|
|
/// `in_elf_path'.
|
|
///
|
|
/// @param extargs the extra argument(s) passed to `abidw` tool.
|
|
///
|
|
/// @return true if `abidw` tool was executed correctly. Otherwise
|
|
/// `error_message` shows the full path of the input file object and
|
|
/// the full output path for the abixml file.
|
|
bool
|
|
test_task::run_abidw(const string& extargs)
|
|
{
|
|
string abidw = string(get_build_dir()) + "/tools/abidw";
|
|
string drop_private_types;
|
|
string spec_options = spec.options ? spec.options : "";
|
|
set_in_abi_path();
|
|
|
|
if (!in_public_headers_path.empty())
|
|
drop_private_types += "--headers-dir " + in_public_headers_path +
|
|
" --drop-private-types";
|
|
string cmd = abidw + " " + spec_options + drop_private_types +
|
|
" --abidiff " + extargs + in_elf_path;
|
|
if (system(cmd.c_str()))
|
|
{
|
|
error_message = string("self comparison with abidw failed:\n")
|
|
+ "command was: '" + cmd + "'\n";
|
|
std::cerr << error_message;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Spawn external `diff` command.
|
|
///
|
|
/// The files to be compared are: abixml generated by the input
|
|
/// object file and the expected abixml file stored in `in_abi_path`.
|
|
///
|
|
/// @return true if `diff` command didn't find defences. Otherwise
|
|
/// `error_message` shows the full path of the input file object and
|
|
/// the full output path for the abixml file.
|
|
bool
|
|
test_task::run_diff()
|
|
{
|
|
set_in_abi_path();
|
|
string cmd = "diff -u " + in_abi_path + " " + out_abi_path;
|
|
if (system(cmd.c_str()))
|
|
{
|
|
error_message = string("ABI files differ:\n")
|
|
+ in_abi_path
|
|
+ "\nand:\n"
|
|
+ out_abi_path
|
|
+ "\n"
|
|
+ "command was: '" + cmd + "'\n";
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// Write the usage message to @p out stream object.
|
|
///
|
|
/// @param prog_name the program name.
|
|
///
|
|
/// @param out the stream object to which want to write.
|
|
void
|
|
display_usage(const string& prog_name, ostream& out)
|
|
{
|
|
emit_prefix(prog_name, out)
|
|
<< "usage: " << prog_name << " [options]\n"
|
|
<< " where options can be: \n"
|
|
<< " --help|-h display this message\n"
|
|
<< " --no-parallel execute testsuite is a sigle thread\n"
|
|
;
|
|
}
|
|
|
|
/// Parse and process test options.
|
|
///
|
|
/// @param argc the arguments number.
|
|
///
|
|
/// @param argv the pointer to the arguments.
|
|
///
|
|
/// @param opts the valid @ref options to be processed/parsed.
|
|
///
|
|
/// @return true if options was processed/parsed successfully. It returns
|
|
/// false when help is requested or an invalid option is supplied.
|
|
bool
|
|
parse_command_line(int argc, char* argv[], options& opts)
|
|
{
|
|
for (int i = 1; i < argc; ++i)
|
|
{
|
|
if (!strcmp(argv[i], "--no-parallel"))
|
|
opts.parallel = false;
|
|
else if (!strcmp(argv[i], "--help")
|
|
|| !strcmp(argv[i], "--h"))
|
|
return false;
|
|
else
|
|
{
|
|
if (strlen(argv[i]) >= 2 && argv[i][0] == '-' && argv[i][1] == '-')
|
|
opts.wrong_option = argv[i];
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// The main entry point to execute the testsuite.
|
|
///
|
|
/// @param num_tests the number of tests to be executed.
|
|
///
|
|
/// @param specs the @ref abigail::tests::read_common::InOutSpec
|
|
/// tests container.
|
|
///
|
|
/// @param opts the test execution @ref abigail::tests::read_common::options.
|
|
///
|
|
/// @param new_test the @ref create_new_test callback function to create
|
|
/// a new test task object.
|
|
///
|
|
/// @return true if `all` tests were performed successfully. Otherwise
|
|
/// false is returned.
|
|
bool
|
|
run_tests(const size_t num_tests, const InOutSpec* specs,
|
|
const options& opts, create_new_test new_test)
|
|
{
|
|
size_t num_workers = (opts.parallel
|
|
? std::min(abigail::workers::get_number_of_threads(),
|
|
num_tests)
|
|
: 1);
|
|
|
|
// Create a task queue. The max number of worker threads of the
|
|
// queue is the number of the concurrent threads supported by the
|
|
// processor of the machine this code runs on. But if
|
|
// --no-parallel was provided then the number of worker threads
|
|
// equals 1.
|
|
abigail::workers::queue task_queue(num_workers);
|
|
bool is_ok = true;
|
|
|
|
string out_abi_base = string(get_build_dir()) + "/tests/";
|
|
string in_elf_base = string(abigail::tests::get_src_dir()) + "/tests/";
|
|
string in_abi_base = in_elf_base;
|
|
|
|
for (const InOutSpec *s = specs; s->in_elf_path; ++s)
|
|
{
|
|
test_task_sptr t(new_test(s, out_abi_base,
|
|
in_elf_base,
|
|
in_abi_base));
|
|
ABG_ASSERT(task_queue.schedule_task(t));
|
|
}
|
|
|
|
// Wait for all worker threads to finish their job, and wind down.
|
|
task_queue.wait_for_workers_to_complete();
|
|
|
|
// Now walk the results and print whatever error messages need to be
|
|
// printed.
|
|
|
|
const vector<abigail::workers::task_sptr>& completed_tasks =
|
|
task_queue.get_completed_tasks();
|
|
|
|
ABG_ASSERT(completed_tasks.size() == num_tests);
|
|
|
|
for (vector<abigail::workers::task_sptr>::const_iterator ti =
|
|
completed_tasks.begin();
|
|
ti != completed_tasks.end();
|
|
++ti)
|
|
{
|
|
test_task_sptr t = dynamic_pointer_cast<test_task>(*ti);
|
|
if (!t->is_ok)
|
|
{
|
|
is_ok = false;
|
|
if (!t->error_message.empty())
|
|
cerr << t->error_message << '\n';
|
|
}
|
|
}
|
|
|
|
return !is_ok;
|
|
}
|
|
|
|
}//end namespace read_common
|
|
}//end namespace tests
|
|
}//end namespace abigail
|