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