1141cc406Sopenharmony_ci/* sane - Scanner Access Now Easy. 2141cc406Sopenharmony_ci 3141cc406Sopenharmony_ci Copyright (C) 2019 Povilas Kanapickas <povilas@radix.lt> 4141cc406Sopenharmony_ci 5141cc406Sopenharmony_ci This file is part of the SANE package. 6141cc406Sopenharmony_ci 7141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 8141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 9141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 10141cc406Sopenharmony_ci License, or (at your option) any later version. 11141cc406Sopenharmony_ci 12141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 13141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 14141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15141cc406Sopenharmony_ci General Public License for more details. 16141cc406Sopenharmony_ci 17141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 18141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 19141cc406Sopenharmony_ci*/ 20141cc406Sopenharmony_ci 21141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY 22141cc406Sopenharmony_ci 23141cc406Sopenharmony_ci#include "../../../backend/genesys/device.h" 24141cc406Sopenharmony_ci#include "../../../backend/genesys/enums.h" 25141cc406Sopenharmony_ci#include "../../../backend/genesys/error.h" 26141cc406Sopenharmony_ci#include "../../../backend/genesys/low.h" 27141cc406Sopenharmony_ci#include "../../../backend/genesys/genesys.h" 28141cc406Sopenharmony_ci#include "../../../backend/genesys/test_settings.h" 29141cc406Sopenharmony_ci#include "../../../backend/genesys/test_scanner_interface.h" 30141cc406Sopenharmony_ci#include "../../../backend/genesys/utilities.h" 31141cc406Sopenharmony_ci#include "../../../include/sane/saneopts.h" 32141cc406Sopenharmony_ci#include "sys/stat.h" 33141cc406Sopenharmony_ci#include <cstdio> 34141cc406Sopenharmony_ci#include <cstring> 35141cc406Sopenharmony_ci#include <fstream> 36141cc406Sopenharmony_ci#include <sstream> 37141cc406Sopenharmony_ci#include <string> 38141cc406Sopenharmony_ci#include <unordered_set> 39141cc406Sopenharmony_ci 40141cc406Sopenharmony_ci#define XSTR(s) STR(s) 41141cc406Sopenharmony_ci#define STR(s) #s 42141cc406Sopenharmony_ci#define CURR_SRCDIR XSTR(TESTSUITE_BACKEND_GENESYS_SRCDIR) 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_cistruct TestConfig 45141cc406Sopenharmony_ci{ 46141cc406Sopenharmony_ci std::uint16_t vendor_id = 0; 47141cc406Sopenharmony_ci std::uint16_t product_id = 0; 48141cc406Sopenharmony_ci std::uint16_t bcd_device = 0; 49141cc406Sopenharmony_ci std::string model_name; 50141cc406Sopenharmony_ci genesys::ScanMethod method = genesys::ScanMethod::FLATBED; 51141cc406Sopenharmony_ci genesys::ScanColorMode color_mode = genesys::ScanColorMode::COLOR_SINGLE_PASS; 52141cc406Sopenharmony_ci unsigned depth = 0; 53141cc406Sopenharmony_ci unsigned resolution = 0; 54141cc406Sopenharmony_ci 55141cc406Sopenharmony_ci std::string name() const 56141cc406Sopenharmony_ci { 57141cc406Sopenharmony_ci std::stringstream out; 58141cc406Sopenharmony_ci out << "capture_" << model_name 59141cc406Sopenharmony_ci << '_' << method 60141cc406Sopenharmony_ci << '_' << color_mode 61141cc406Sopenharmony_ci << "_depth" << depth 62141cc406Sopenharmony_ci << "_dpi" << resolution; 63141cc406Sopenharmony_ci return out.str(); 64141cc406Sopenharmony_ci } 65141cc406Sopenharmony_ci 66141cc406Sopenharmony_ci}; 67141cc406Sopenharmony_ci 68141cc406Sopenharmony_ciclass SaneOptions 69141cc406Sopenharmony_ci{ 70141cc406Sopenharmony_cipublic: 71141cc406Sopenharmony_ci void fetch(SANE_Handle handle) 72141cc406Sopenharmony_ci { 73141cc406Sopenharmony_ci handle_ = handle; 74141cc406Sopenharmony_ci options_.resize(1); 75141cc406Sopenharmony_ci options_[0] = fetch_option(0); 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ci if (std::strcmp(options_[0].name, SANE_NAME_NUM_OPTIONS) != 0 || 78141cc406Sopenharmony_ci options_[0].type != SANE_TYPE_INT) 79141cc406Sopenharmony_ci { 80141cc406Sopenharmony_ci throw std::runtime_error("Expected option number option"); 81141cc406Sopenharmony_ci } 82141cc406Sopenharmony_ci int option_count = 0; 83141cc406Sopenharmony_ci TIE(sane_control_option(handle, 0, SANE_ACTION_GET_VALUE, &option_count, nullptr)); 84141cc406Sopenharmony_ci 85141cc406Sopenharmony_ci options_.resize(option_count); 86141cc406Sopenharmony_ci for (int i = 0; i < option_count; ++i) { 87141cc406Sopenharmony_ci options_[i] = fetch_option(i); 88141cc406Sopenharmony_ci } 89141cc406Sopenharmony_ci } 90141cc406Sopenharmony_ci 91141cc406Sopenharmony_ci void close() 92141cc406Sopenharmony_ci { 93141cc406Sopenharmony_ci handle_ = nullptr; 94141cc406Sopenharmony_ci } 95141cc406Sopenharmony_ci 96141cc406Sopenharmony_ci bool get_value_bool(const std::string& name) const 97141cc406Sopenharmony_ci { 98141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_BOOL); 99141cc406Sopenharmony_ci int value = 0; 100141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_GET_VALUE, &value, nullptr)); 101141cc406Sopenharmony_ci return value; 102141cc406Sopenharmony_ci } 103141cc406Sopenharmony_ci 104141cc406Sopenharmony_ci void set_value_bool(const std::string& name, bool value) 105141cc406Sopenharmony_ci { 106141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_BOOL); 107141cc406Sopenharmony_ci int value_int = value; 108141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_SET_VALUE, &value_int, nullptr)); 109141cc406Sopenharmony_ci } 110141cc406Sopenharmony_ci 111141cc406Sopenharmony_ci bool get_value_button(const std::string& name) const 112141cc406Sopenharmony_ci { 113141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_BUTTON); 114141cc406Sopenharmony_ci int value = 0; 115141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_GET_VALUE, &value, nullptr)); 116141cc406Sopenharmony_ci return value; 117141cc406Sopenharmony_ci } 118141cc406Sopenharmony_ci 119141cc406Sopenharmony_ci void set_value_button(const std::string& name, bool value) 120141cc406Sopenharmony_ci { 121141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_BUTTON); 122141cc406Sopenharmony_ci int value_int = value; 123141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_SET_VALUE, &value_int, nullptr)); 124141cc406Sopenharmony_ci } 125141cc406Sopenharmony_ci 126141cc406Sopenharmony_ci int get_value_int(const std::string& name) const 127141cc406Sopenharmony_ci { 128141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_INT); 129141cc406Sopenharmony_ci int value = 0; 130141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_GET_VALUE, &value, nullptr)); 131141cc406Sopenharmony_ci return value; 132141cc406Sopenharmony_ci } 133141cc406Sopenharmony_ci 134141cc406Sopenharmony_ci void set_value_int(const std::string& name, int value) 135141cc406Sopenharmony_ci { 136141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_INT); 137141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_SET_VALUE, &value, nullptr)); 138141cc406Sopenharmony_ci } 139141cc406Sopenharmony_ci 140141cc406Sopenharmony_ci float get_value_float(const std::string& name) const 141141cc406Sopenharmony_ci { 142141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_FIXED); 143141cc406Sopenharmony_ci int value = 0; 144141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_GET_VALUE, &value, nullptr)); 145141cc406Sopenharmony_ci return genesys::fixed_to_float(value); 146141cc406Sopenharmony_ci } 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_ci void set_value_float(const std::string& name, float value) 149141cc406Sopenharmony_ci { 150141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_FIXED); 151141cc406Sopenharmony_ci int value_int = SANE_FIX(value); 152141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_SET_VALUE, &value_int, nullptr)); 153141cc406Sopenharmony_ci } 154141cc406Sopenharmony_ci 155141cc406Sopenharmony_ci std::string get_value_string(const std::string& name) const 156141cc406Sopenharmony_ci { 157141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_STRING); 158141cc406Sopenharmony_ci std::string value; 159141cc406Sopenharmony_ci value.resize(options_[i].size + 1); 160141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_GET_VALUE, &value.front(), nullptr)); 161141cc406Sopenharmony_ci value.resize(std::strlen(&value.front())); 162141cc406Sopenharmony_ci return value; 163141cc406Sopenharmony_ci } 164141cc406Sopenharmony_ci 165141cc406Sopenharmony_ci void set_value_string(const std::string& name, const std::string& value) 166141cc406Sopenharmony_ci { 167141cc406Sopenharmony_ci auto i = find_option(name, SANE_TYPE_STRING); 168141cc406Sopenharmony_ci TIE(sane_control_option(handle_, i, SANE_ACTION_SET_VALUE, 169141cc406Sopenharmony_ci const_cast<char*>(&value.front()), nullptr)); 170141cc406Sopenharmony_ci } 171141cc406Sopenharmony_ci 172141cc406Sopenharmony_ciprivate: 173141cc406Sopenharmony_ci SANE_Option_Descriptor fetch_option(int index) 174141cc406Sopenharmony_ci { 175141cc406Sopenharmony_ci const auto* option = sane_get_option_descriptor(handle_, index); 176141cc406Sopenharmony_ci if (option == nullptr) { 177141cc406Sopenharmony_ci throw std::runtime_error("Got nullptr option"); 178141cc406Sopenharmony_ci } 179141cc406Sopenharmony_ci return *option; 180141cc406Sopenharmony_ci } 181141cc406Sopenharmony_ci 182141cc406Sopenharmony_ci std::size_t find_option(const std::string& name, SANE_Value_Type type) const 183141cc406Sopenharmony_ci { 184141cc406Sopenharmony_ci for (std::size_t i = 0; i < options_.size(); ++i) { 185141cc406Sopenharmony_ci if (options_[i].name == name) { 186141cc406Sopenharmony_ci if (options_[i].type != type) { 187141cc406Sopenharmony_ci throw std::runtime_error("Option has incorrect type"); 188141cc406Sopenharmony_ci } 189141cc406Sopenharmony_ci return i; 190141cc406Sopenharmony_ci } 191141cc406Sopenharmony_ci } 192141cc406Sopenharmony_ci throw std::runtime_error("Could not find option"); 193141cc406Sopenharmony_ci } 194141cc406Sopenharmony_ci 195141cc406Sopenharmony_ci SANE_Handle handle_; 196141cc406Sopenharmony_ci std::vector<SANE_Option_Descriptor> options_; 197141cc406Sopenharmony_ci}; 198141cc406Sopenharmony_ci 199141cc406Sopenharmony_ci 200141cc406Sopenharmony_civoid print_params(const SANE_Parameters& params, std::stringstream& out) 201141cc406Sopenharmony_ci{ 202141cc406Sopenharmony_ci out << "\n\n================\n" 203141cc406Sopenharmony_ci << "Scan params:\n" 204141cc406Sopenharmony_ci << "format: " << params.format << "\n" 205141cc406Sopenharmony_ci << "last_frame: " << params.last_frame << "\n" 206141cc406Sopenharmony_ci << "bytes_per_line: " << params.bytes_per_line << "\n" 207141cc406Sopenharmony_ci << "pixels_per_line: " << params.pixels_per_line << "\n" 208141cc406Sopenharmony_ci << "lines: " << params.lines << "\n" 209141cc406Sopenharmony_ci << "depth: " << params.depth << "\n"; 210141cc406Sopenharmony_ci} 211141cc406Sopenharmony_ci 212141cc406Sopenharmony_civoid print_checkpoint(const genesys::Genesys_Device& dev, 213141cc406Sopenharmony_ci genesys::TestScannerInterface& iface, 214141cc406Sopenharmony_ci const std::string& checkpoint_name, 215141cc406Sopenharmony_ci std::stringstream& out) 216141cc406Sopenharmony_ci{ 217141cc406Sopenharmony_ci out << "\n\n================\n" 218141cc406Sopenharmony_ci << "Checkpoint: " << checkpoint_name << "\n" 219141cc406Sopenharmony_ci << "================\n\n" 220141cc406Sopenharmony_ci << "dev: " << genesys::format_indent_braced_list(4, dev) << "\n\n" 221141cc406Sopenharmony_ci << "iface.cached_regs: " 222141cc406Sopenharmony_ci << genesys::format_indent_braced_list(4, iface.cached_regs()) << "\n\n" 223141cc406Sopenharmony_ci << "iface.cached_fe_regs: " 224141cc406Sopenharmony_ci << genesys::format_indent_braced_list(4, iface.cached_fe_regs()) << "\n\n" 225141cc406Sopenharmony_ci << "iface.last_progress_message: " << iface.last_progress_message() << "\n\n"; 226141cc406Sopenharmony_ci out << "iface.slope_tables: {\n"; 227141cc406Sopenharmony_ci for (const auto& kv : iface.recorded_slope_tables()) { 228141cc406Sopenharmony_ci out << " " << kv.first << ": {"; 229141cc406Sopenharmony_ci for (unsigned i = 0; i < kv.second.size(); ++i) { 230141cc406Sopenharmony_ci if (i % 10 == 0) { 231141cc406Sopenharmony_ci out << "\n "; 232141cc406Sopenharmony_ci } 233141cc406Sopenharmony_ci out << ' ' << kv.second[i]; 234141cc406Sopenharmony_ci } 235141cc406Sopenharmony_ci out << "\n }\n"; 236141cc406Sopenharmony_ci } 237141cc406Sopenharmony_ci out << "}\n"; 238141cc406Sopenharmony_ci if (iface.recorded_key_values().empty()) { 239141cc406Sopenharmony_ci out << "iface.recorded_key_values: []\n"; 240141cc406Sopenharmony_ci } else { 241141cc406Sopenharmony_ci out << "iface.recorded_key_values: {\n"; 242141cc406Sopenharmony_ci for (const auto& kv : iface.recorded_key_values()) { 243141cc406Sopenharmony_ci out << " " << kv.first << " : " << kv.second << '\n'; 244141cc406Sopenharmony_ci } 245141cc406Sopenharmony_ci out << "}\n"; 246141cc406Sopenharmony_ci } 247141cc406Sopenharmony_ci iface.recorded_key_values().clear(); 248141cc406Sopenharmony_ci out << "\n"; 249141cc406Sopenharmony_ci} 250141cc406Sopenharmony_ci 251141cc406Sopenharmony_civoid run_single_test_scan(const TestConfig& config, std::stringstream& out) 252141cc406Sopenharmony_ci{ 253141cc406Sopenharmony_ci auto print_checkpoint_wrapper = [&](const genesys::Genesys_Device& dev, 254141cc406Sopenharmony_ci genesys::TestScannerInterface& iface, 255141cc406Sopenharmony_ci const std::string& checkpoint_name) 256141cc406Sopenharmony_ci { 257141cc406Sopenharmony_ci print_checkpoint(dev, iface, checkpoint_name, out); 258141cc406Sopenharmony_ci }; 259141cc406Sopenharmony_ci 260141cc406Sopenharmony_ci genesys::enable_testing_mode(config.vendor_id, config.product_id, config.bcd_device, 261141cc406Sopenharmony_ci print_checkpoint_wrapper); 262141cc406Sopenharmony_ci 263141cc406Sopenharmony_ci SANE_Handle handle; 264141cc406Sopenharmony_ci 265141cc406Sopenharmony_ci TIE(sane_init(nullptr, nullptr)); 266141cc406Sopenharmony_ci TIE(sane_open(genesys::get_testing_device_name().c_str(), &handle)); 267141cc406Sopenharmony_ci 268141cc406Sopenharmony_ci SaneOptions options; 269141cc406Sopenharmony_ci options.fetch(handle); 270141cc406Sopenharmony_ci 271141cc406Sopenharmony_ci options.set_value_button("force-calibration", true); 272141cc406Sopenharmony_ci options.set_value_string(SANE_NAME_SCAN_SOURCE, 273141cc406Sopenharmony_ci genesys::scan_method_to_option_string(config.method)); 274141cc406Sopenharmony_ci options.set_value_string(SANE_NAME_SCAN_MODE, 275141cc406Sopenharmony_ci genesys::scan_color_mode_to_option_string(config.color_mode)); 276141cc406Sopenharmony_ci if (config.color_mode != genesys::ScanColorMode::LINEART) { 277141cc406Sopenharmony_ci options.set_value_int(SANE_NAME_BIT_DEPTH, config.depth); 278141cc406Sopenharmony_ci } 279141cc406Sopenharmony_ci options.set_value_int(SANE_NAME_SCAN_RESOLUTION, config.resolution); 280141cc406Sopenharmony_ci options.close(); 281141cc406Sopenharmony_ci 282141cc406Sopenharmony_ci TIE(sane_start(handle)); 283141cc406Sopenharmony_ci 284141cc406Sopenharmony_ci SANE_Parameters params; 285141cc406Sopenharmony_ci TIE(sane_get_parameters(handle, ¶ms)); 286141cc406Sopenharmony_ci 287141cc406Sopenharmony_ci print_params(params, out); 288141cc406Sopenharmony_ci 289141cc406Sopenharmony_ci int buffer_size = 1024 * 1024; 290141cc406Sopenharmony_ci std::vector<std::uint8_t> buffer; 291141cc406Sopenharmony_ci buffer.resize(buffer_size); 292141cc406Sopenharmony_ci 293141cc406Sopenharmony_ci std::uint64_t total_data_size = std::uint64_t(params.bytes_per_line) * params.lines; 294141cc406Sopenharmony_ci std::uint64_t total_got_data = 0; 295141cc406Sopenharmony_ci 296141cc406Sopenharmony_ci while (total_got_data < total_data_size) { 297141cc406Sopenharmony_ci int ask_len = std::min<std::size_t>(buffer_size, total_data_size - total_got_data); 298141cc406Sopenharmony_ci 299141cc406Sopenharmony_ci int got_data = 0; 300141cc406Sopenharmony_ci auto status = sane_read(handle, buffer.data(), ask_len, &got_data); 301141cc406Sopenharmony_ci total_got_data += got_data; 302141cc406Sopenharmony_ci if (status == SANE_STATUS_EOF) { 303141cc406Sopenharmony_ci break; 304141cc406Sopenharmony_ci } 305141cc406Sopenharmony_ci TIE(status); 306141cc406Sopenharmony_ci } 307141cc406Sopenharmony_ci 308141cc406Sopenharmony_ci sane_cancel(handle); 309141cc406Sopenharmony_ci sane_close(handle); 310141cc406Sopenharmony_ci sane_exit(); 311141cc406Sopenharmony_ci 312141cc406Sopenharmony_ci genesys::disable_testing_mode(); 313141cc406Sopenharmony_ci} 314141cc406Sopenharmony_ci 315141cc406Sopenharmony_cistd::string read_file_to_string(const std::string& path) 316141cc406Sopenharmony_ci{ 317141cc406Sopenharmony_ci std::ifstream in; 318141cc406Sopenharmony_ci in.open(path); 319141cc406Sopenharmony_ci if (!in.is_open()) { 320141cc406Sopenharmony_ci return ""; 321141cc406Sopenharmony_ci } 322141cc406Sopenharmony_ci std::stringstream in_str; 323141cc406Sopenharmony_ci in_str << in.rdbuf(); 324141cc406Sopenharmony_ci return in_str.str(); 325141cc406Sopenharmony_ci} 326141cc406Sopenharmony_ci 327141cc406Sopenharmony_civoid write_string_to_file(const std::string& path, const std::string& contents) 328141cc406Sopenharmony_ci{ 329141cc406Sopenharmony_ci std::ofstream out; 330141cc406Sopenharmony_ci out.open(path); 331141cc406Sopenharmony_ci if (!out.is_open()) { 332141cc406Sopenharmony_ci throw std::runtime_error("Could not open output file: " + path); 333141cc406Sopenharmony_ci } 334141cc406Sopenharmony_ci out << contents; 335141cc406Sopenharmony_ci out.close(); 336141cc406Sopenharmony_ci} 337141cc406Sopenharmony_ci 338141cc406Sopenharmony_cistruct TestResult 339141cc406Sopenharmony_ci{ 340141cc406Sopenharmony_ci bool success = true; 341141cc406Sopenharmony_ci TestConfig config; 342141cc406Sopenharmony_ci std::string failure_message; 343141cc406Sopenharmony_ci}; 344141cc406Sopenharmony_ci 345141cc406Sopenharmony_ciTestResult perform_single_test(const TestConfig& config, const std::string& check_directory, 346141cc406Sopenharmony_ci const std::string& output_directory) 347141cc406Sopenharmony_ci{ 348141cc406Sopenharmony_ci TestResult test_result; 349141cc406Sopenharmony_ci test_result.config = config; 350141cc406Sopenharmony_ci 351141cc406Sopenharmony_ci std::stringstream result_output_stream; 352141cc406Sopenharmony_ci std::string exception_output; 353141cc406Sopenharmony_ci try { 354141cc406Sopenharmony_ci run_single_test_scan(config, result_output_stream); 355141cc406Sopenharmony_ci } catch (const std::exception& exc) { 356141cc406Sopenharmony_ci exception_output = std::string("got exception: ") + typeid(exc).name() + 357141cc406Sopenharmony_ci " with message\n" + exc.what() + "\n"; 358141cc406Sopenharmony_ci test_result.success = false; 359141cc406Sopenharmony_ci test_result.failure_message += exception_output; 360141cc406Sopenharmony_ci } catch (...) { 361141cc406Sopenharmony_ci exception_output = "got unknown exception\n"; 362141cc406Sopenharmony_ci test_result.success = false; 363141cc406Sopenharmony_ci test_result.failure_message += exception_output; 364141cc406Sopenharmony_ci } 365141cc406Sopenharmony_ci auto result_output = result_output_stream.str(); 366141cc406Sopenharmony_ci if (!exception_output.empty()) { 367141cc406Sopenharmony_ci result_output += "\n\n" + exception_output; 368141cc406Sopenharmony_ci } 369141cc406Sopenharmony_ci 370141cc406Sopenharmony_ci auto test_filename = config.name() + ".txt"; 371141cc406Sopenharmony_ci auto expected_session_path = check_directory + "/" + test_filename; 372141cc406Sopenharmony_ci auto current_session_path = output_directory + "/" + test_filename; 373141cc406Sopenharmony_ci 374141cc406Sopenharmony_ci auto expected_output = read_file_to_string(expected_session_path); 375141cc406Sopenharmony_ci 376141cc406Sopenharmony_ci bool has_output = !output_directory.empty(); 377141cc406Sopenharmony_ci 378141cc406Sopenharmony_ci if (has_output) { 379141cc406Sopenharmony_ci mkdir(output_directory.c_str(), 0777); 380141cc406Sopenharmony_ci // note that check_directory and output_directory may be the same, so make sure removal 381141cc406Sopenharmony_ci // happens after the expected output has already been read. 382141cc406Sopenharmony_ci std::remove(current_session_path.c_str()); 383141cc406Sopenharmony_ci } 384141cc406Sopenharmony_ci 385141cc406Sopenharmony_ci if (expected_output.empty()) { 386141cc406Sopenharmony_ci test_result.failure_message += "the expected data file does not exist\n"; 387141cc406Sopenharmony_ci test_result.success = false; 388141cc406Sopenharmony_ci } else if (expected_output != result_output) { 389141cc406Sopenharmony_ci test_result.failure_message += "expected and current output are not equal\n"; 390141cc406Sopenharmony_ci if (has_output) { 391141cc406Sopenharmony_ci test_result.failure_message += "To examine, run:\ndiff -u \"" + current_session_path + 392141cc406Sopenharmony_ci "\" \"" + expected_session_path + "\"\n"; 393141cc406Sopenharmony_ci } 394141cc406Sopenharmony_ci test_result.success = false; 395141cc406Sopenharmony_ci } 396141cc406Sopenharmony_ci 397141cc406Sopenharmony_ci if (has_output) { 398141cc406Sopenharmony_ci write_string_to_file(current_session_path, result_output); 399141cc406Sopenharmony_ci } 400141cc406Sopenharmony_ci return test_result; 401141cc406Sopenharmony_ci} 402141cc406Sopenharmony_ci 403141cc406Sopenharmony_cistd::vector<TestConfig> get_all_test_configs() 404141cc406Sopenharmony_ci{ 405141cc406Sopenharmony_ci genesys::genesys_init_usb_device_tables(); 406141cc406Sopenharmony_ci genesys::genesys_init_sensor_tables(); 407141cc406Sopenharmony_ci genesys::verify_usb_device_tables(); 408141cc406Sopenharmony_ci genesys::verify_sensor_tables(); 409141cc406Sopenharmony_ci 410141cc406Sopenharmony_ci std::vector<TestConfig> configs; 411141cc406Sopenharmony_ci std::unordered_set<std::string> model_names; 412141cc406Sopenharmony_ci 413141cc406Sopenharmony_ci for (const auto& usb_dev : *genesys::s_usb_devices) { 414141cc406Sopenharmony_ci 415141cc406Sopenharmony_ci const auto& model = usb_dev.model(); 416141cc406Sopenharmony_ci 417141cc406Sopenharmony_ci if (genesys::has_flag(model.flags, genesys::ModelFlag::UNTESTED)) { 418141cc406Sopenharmony_ci continue; 419141cc406Sopenharmony_ci } 420141cc406Sopenharmony_ci if (model_names.find(model.name) != model_names.end()) { 421141cc406Sopenharmony_ci continue; 422141cc406Sopenharmony_ci } 423141cc406Sopenharmony_ci model_names.insert(model.name); 424141cc406Sopenharmony_ci 425141cc406Sopenharmony_ci for (auto scan_mode : { genesys::ScanColorMode::GRAY, 426141cc406Sopenharmony_ci genesys::ScanColorMode::COLOR_SINGLE_PASS }) { 427141cc406Sopenharmony_ci 428141cc406Sopenharmony_ci auto depth_values = model.bpp_gray_values; 429141cc406Sopenharmony_ci if (scan_mode == genesys::ScanColorMode::COLOR_SINGLE_PASS) { 430141cc406Sopenharmony_ci depth_values = model.bpp_color_values; 431141cc406Sopenharmony_ci } 432141cc406Sopenharmony_ci for (unsigned depth : depth_values) { 433141cc406Sopenharmony_ci for (auto method_resolutions : model.resolutions) { 434141cc406Sopenharmony_ci for (auto method : method_resolutions.methods) { 435141cc406Sopenharmony_ci for (unsigned resolution : method_resolutions.get_resolutions()) { 436141cc406Sopenharmony_ci TestConfig config; 437141cc406Sopenharmony_ci config.vendor_id = usb_dev.vendor_id(); 438141cc406Sopenharmony_ci config.product_id = usb_dev.product_id(); 439141cc406Sopenharmony_ci config.bcd_device = usb_dev.bcd_device(); 440141cc406Sopenharmony_ci config.model_name = model.name; 441141cc406Sopenharmony_ci config.method = method; 442141cc406Sopenharmony_ci config.depth = depth; 443141cc406Sopenharmony_ci config.resolution = resolution; 444141cc406Sopenharmony_ci config.color_mode = scan_mode; 445141cc406Sopenharmony_ci configs.push_back(config); 446141cc406Sopenharmony_ci } 447141cc406Sopenharmony_ci } 448141cc406Sopenharmony_ci } 449141cc406Sopenharmony_ci } 450141cc406Sopenharmony_ci } 451141cc406Sopenharmony_ci } 452141cc406Sopenharmony_ci return configs; 453141cc406Sopenharmony_ci} 454141cc406Sopenharmony_ci 455141cc406Sopenharmony_civoid print_help() 456141cc406Sopenharmony_ci{ 457141cc406Sopenharmony_ci std::cerr << "Usage:\n" 458141cc406Sopenharmony_ci << "session_config_test [--test={test_name}] {check_directory} [{output_directory}]\n" 459141cc406Sopenharmony_ci << "session_config_test --help\n" 460141cc406Sopenharmony_ci << "session_config_test --print_test_names\n"; 461141cc406Sopenharmony_ci} 462141cc406Sopenharmony_ci 463141cc406Sopenharmony_ciint main(int argc, const char* argv[]) 464141cc406Sopenharmony_ci{ 465141cc406Sopenharmony_ci std::string check_directory; 466141cc406Sopenharmony_ci std::string output_directory; 467141cc406Sopenharmony_ci std::string test_name_filter; 468141cc406Sopenharmony_ci bool print_test_names = false; 469141cc406Sopenharmony_ci 470141cc406Sopenharmony_ci for (int argi = 1; argi < argc; ++argi) { 471141cc406Sopenharmony_ci std::string arg = argv[argi]; 472141cc406Sopenharmony_ci if (arg.rfind("--test=", 0) == 0) { 473141cc406Sopenharmony_ci test_name_filter = arg.substr(7); 474141cc406Sopenharmony_ci } else if (arg == "-h" || arg == "--help") { 475141cc406Sopenharmony_ci print_help(); 476141cc406Sopenharmony_ci return 0; 477141cc406Sopenharmony_ci } else if (arg == "--print_test_names") { 478141cc406Sopenharmony_ci print_test_names = true; 479141cc406Sopenharmony_ci } else if (check_directory.empty()) { 480141cc406Sopenharmony_ci check_directory = arg; 481141cc406Sopenharmony_ci } else if (output_directory.empty()) { 482141cc406Sopenharmony_ci output_directory = arg; 483141cc406Sopenharmony_ci } 484141cc406Sopenharmony_ci } 485141cc406Sopenharmony_ci 486141cc406Sopenharmony_ci auto configs = get_all_test_configs(); 487141cc406Sopenharmony_ci 488141cc406Sopenharmony_ci if (print_test_names) { 489141cc406Sopenharmony_ci for (const auto& config : configs) { 490141cc406Sopenharmony_ci std::cout << config.name() << "\n"; 491141cc406Sopenharmony_ci } 492141cc406Sopenharmony_ci return 0; 493141cc406Sopenharmony_ci } 494141cc406Sopenharmony_ci 495141cc406Sopenharmony_ci if (check_directory.empty()) { 496141cc406Sopenharmony_ci print_help(); 497141cc406Sopenharmony_ci return 1; 498141cc406Sopenharmony_ci } 499141cc406Sopenharmony_ci 500141cc406Sopenharmony_ci bool test_success = true; 501141cc406Sopenharmony_ci for (unsigned i = 0; i < configs.size(); ++i) { 502141cc406Sopenharmony_ci const auto& config = configs[i]; 503141cc406Sopenharmony_ci 504141cc406Sopenharmony_ci if (!test_name_filter.empty() && config.name() != test_name_filter) { 505141cc406Sopenharmony_ci continue; 506141cc406Sopenharmony_ci } 507141cc406Sopenharmony_ci 508141cc406Sopenharmony_ci auto result = perform_single_test(config, check_directory, output_directory); 509141cc406Sopenharmony_ci std::cerr << "(" << i << "/" << configs.size() << "): " 510141cc406Sopenharmony_ci << (result.success ? "SUCCESS: " : "FAIL: ") 511141cc406Sopenharmony_ci << result.config.name() << "\n"; 512141cc406Sopenharmony_ci if (!result.success) { 513141cc406Sopenharmony_ci std::cerr << result.failure_message; 514141cc406Sopenharmony_ci } 515141cc406Sopenharmony_ci 516141cc406Sopenharmony_ci test_success &= result.success; 517141cc406Sopenharmony_ci } 518141cc406Sopenharmony_ci 519141cc406Sopenharmony_ci if (!test_success) { 520141cc406Sopenharmony_ci return 1; 521141cc406Sopenharmony_ci } 522141cc406Sopenharmony_ci return 0; 523141cc406Sopenharmony_ci} 524