1141cc406Sopenharmony_ci/* 2141cc406Sopenharmony_ci tstbackend -- backend test utility 3141cc406Sopenharmony_ci 4141cc406Sopenharmony_ci Uses the SANE library. 5141cc406Sopenharmony_ci Copyright (C) 2002 Frank Zago (sane at zago dot net) 6141cc406Sopenharmony_ci Copyright (C) 2013 Stéphane Voltz <stef.dev@free.fr> : sane_get_devices test 7141cc406Sopenharmony_ci 8141cc406Sopenharmony_ci This file is part of the SANE package. 9141cc406Sopenharmony_ci 10141cc406Sopenharmony_ci This program is free software; you can redistribute it and/or 11141cc406Sopenharmony_ci modify it under the terms of the GNU General Public License as 12141cc406Sopenharmony_ci published by the Free Software Foundation; either version 2 of the 13141cc406Sopenharmony_ci License, or (at your option) any later version. 14141cc406Sopenharmony_ci 15141cc406Sopenharmony_ci This program is distributed in the hope that it will be useful, but 16141cc406Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 17141cc406Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18141cc406Sopenharmony_ci General Public License for more details. 19141cc406Sopenharmony_ci 20141cc406Sopenharmony_ci You should have received a copy of the GNU General Public License 21141cc406Sopenharmony_ci along with this program. If not, see <https://www.gnu.org/licenses/>. 22141cc406Sopenharmony_ci*/ 23141cc406Sopenharmony_ci 24141cc406Sopenharmony_ci#define BUILD 19 /* 2013-03-29 */ 25141cc406Sopenharmony_ci 26141cc406Sopenharmony_ci#include "../include/sane/config.h" 27141cc406Sopenharmony_ci 28141cc406Sopenharmony_ci#include <assert.h> 29141cc406Sopenharmony_ci#include <getopt.h> 30141cc406Sopenharmony_ci#include <stdio.h> 31141cc406Sopenharmony_ci#include <stdlib.h> 32141cc406Sopenharmony_ci#include <string.h> 33141cc406Sopenharmony_ci#include <unistd.h> 34141cc406Sopenharmony_ci#include <stdarg.h> 35141cc406Sopenharmony_ci#include <time.h> 36141cc406Sopenharmony_ci 37141cc406Sopenharmony_ci#include <sys/types.h> 38141cc406Sopenharmony_ci#include <sys/stat.h> 39141cc406Sopenharmony_ci 40141cc406Sopenharmony_ci#include "../include/sane/sane.h" 41141cc406Sopenharmony_ci#include "../include/sane/sanei.h" 42141cc406Sopenharmony_ci#include "../include/sane/saneopts.h" 43141cc406Sopenharmony_ci 44141cc406Sopenharmony_cistatic struct option basic_options[] = { 45141cc406Sopenharmony_ci {"device-name", required_argument, NULL, 'd'}, 46141cc406Sopenharmony_ci {"level", required_argument, NULL, 'l'}, 47141cc406Sopenharmony_ci {"scan", no_argument, NULL, 's'}, 48141cc406Sopenharmony_ci {"recursion", required_argument, NULL, 'r'}, 49141cc406Sopenharmony_ci {"get-devices", required_argument, NULL, 'g'}, 50141cc406Sopenharmony_ci {"help", no_argument, NULL, 'h'} 51141cc406Sopenharmony_ci}; 52141cc406Sopenharmony_ci 53141cc406Sopenharmony_cistatic void 54141cc406Sopenharmony_citest_options (SANE_Device * device, int can_do_recursive); 55141cc406Sopenharmony_ci 56141cc406Sopenharmony_cienum message_level { 57141cc406Sopenharmony_ci MSG, /* info message */ 58141cc406Sopenharmony_ci INF, /* non-urgent warning */ 59141cc406Sopenharmony_ci WRN, /* warning */ 60141cc406Sopenharmony_ci ERR, /* error, test can continue */ 61141cc406Sopenharmony_ci FATAL, /* error, test can't/mustn't continue */ 62141cc406Sopenharmony_ci BUG /* bug in tstbackend */ 63141cc406Sopenharmony_ci}; 64141cc406Sopenharmony_ci 65141cc406Sopenharmony_ciint message_number_wrn = 0; 66141cc406Sopenharmony_ciint message_number_err = 0; 67141cc406Sopenharmony_ci#ifdef HAVE_LONG_LONG 68141cc406Sopenharmony_cilong long checks_done = 0; 69141cc406Sopenharmony_ci#else 70141cc406Sopenharmony_ci/* It may overflow, but it's no big deal. */ 71141cc406Sopenharmony_cilong int checks_done = 0; 72141cc406Sopenharmony_ci#endif 73141cc406Sopenharmony_ci 74141cc406Sopenharmony_ciint test_level; 75141cc406Sopenharmony_ciint verbose_level; 76141cc406Sopenharmony_ci 77141cc406Sopenharmony_ci/* Maybe add that to sane.h */ 78141cc406Sopenharmony_ci#define SANE_OPTION_IS_GETTABLE(cap) (((cap) & (SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE)) == SANE_CAP_SOFT_DETECT) 79141cc406Sopenharmony_ci 80141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/ 81141cc406Sopenharmony_ci 82141cc406Sopenharmony_ci/* Display the message error statistics. */ 83141cc406Sopenharmony_cistatic void display_stats(void) 84141cc406Sopenharmony_ci{ 85141cc406Sopenharmony_ci#ifdef HAVE_LONG_LONG 86141cc406Sopenharmony_ci printf("warnings: %d error: %d checks: %lld\n", 87141cc406Sopenharmony_ci message_number_wrn, message_number_err, checks_done); 88141cc406Sopenharmony_ci#else 89141cc406Sopenharmony_ci printf("warnings: %d error: %d checks: %ld\n", 90141cc406Sopenharmony_ci message_number_wrn, message_number_err, checks_done); 91141cc406Sopenharmony_ci#endif 92141cc406Sopenharmony_ci} 93141cc406Sopenharmony_ci 94141cc406Sopenharmony_ci/* 95141cc406Sopenharmony_ci * If the condition is false, display a message with some headers 96141cc406Sopenharmony_ci * depending on the level. 97141cc406Sopenharmony_ci * 98141cc406Sopenharmony_ci * Returns the condition. 99141cc406Sopenharmony_ci * 100141cc406Sopenharmony_ci */ 101141cc406Sopenharmony_ci#ifdef __GNUC__ 102141cc406Sopenharmony_cistatic int check(enum message_level, int condition, const char *format, ...) __attribute__ ((format (printf, 3, 4))); 103141cc406Sopenharmony_ci#endif 104141cc406Sopenharmony_cistatic int check(enum message_level level, int condition, const char *format, ...) 105141cc406Sopenharmony_ci{ 106141cc406Sopenharmony_ci char str[1000]; 107141cc406Sopenharmony_ci va_list args; 108141cc406Sopenharmony_ci 109141cc406Sopenharmony_ci if (level != MSG && level != INF) checks_done ++; 110141cc406Sopenharmony_ci 111141cc406Sopenharmony_ci if (condition != 0) 112141cc406Sopenharmony_ci return condition; 113141cc406Sopenharmony_ci 114141cc406Sopenharmony_ci va_start(args, format); 115141cc406Sopenharmony_ci vsprintf(str, format, args); 116141cc406Sopenharmony_ci va_end(args); 117141cc406Sopenharmony_ci 118141cc406Sopenharmony_ci switch(level) { 119141cc406Sopenharmony_ci case MSG: 120141cc406Sopenharmony_ci printf(" %s\n", str); 121141cc406Sopenharmony_ci break; 122141cc406Sopenharmony_ci case INF: /* info */ 123141cc406Sopenharmony_ci printf("info : %s\n", str); 124141cc406Sopenharmony_ci break; 125141cc406Sopenharmony_ci case WRN: /* warning */ 126141cc406Sopenharmony_ci printf("warning : %s\n", str); 127141cc406Sopenharmony_ci message_number_wrn ++; 128141cc406Sopenharmony_ci break; 129141cc406Sopenharmony_ci case ERR: /* error */ 130141cc406Sopenharmony_ci printf("ERROR : %s\n", str); 131141cc406Sopenharmony_ci message_number_err ++; 132141cc406Sopenharmony_ci break; 133141cc406Sopenharmony_ci case FATAL: /* fatal error */ 134141cc406Sopenharmony_ci printf("FATAL ERROR : %s\n", str); 135141cc406Sopenharmony_ci message_number_err ++; 136141cc406Sopenharmony_ci break; 137141cc406Sopenharmony_ci case BUG: /* bug in tstbackend */ 138141cc406Sopenharmony_ci printf("tstbackend BUG : %s\n", str); 139141cc406Sopenharmony_ci break; 140141cc406Sopenharmony_ci } 141141cc406Sopenharmony_ci 142141cc406Sopenharmony_ci if (level == FATAL || level == BUG) { 143141cc406Sopenharmony_ci /* Fatal error. Generate a core dump. */ 144141cc406Sopenharmony_ci display_stats(); 145141cc406Sopenharmony_ci abort(); 146141cc406Sopenharmony_ci } 147141cc406Sopenharmony_ci 148141cc406Sopenharmony_ci fflush(stdout); 149141cc406Sopenharmony_ci 150141cc406Sopenharmony_ci return(0); 151141cc406Sopenharmony_ci} 152141cc406Sopenharmony_ci 153141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/ 154141cc406Sopenharmony_ci 155141cc406Sopenharmony_ci#define GUARDS_SIZE 4 /* 4 bytes */ 156141cc406Sopenharmony_ci#define GUARD1 ((SANE_Word)0x5abf8ea5) 157141cc406Sopenharmony_ci#define GUARD2 ((SANE_Word)0xa58ebf5a) 158141cc406Sopenharmony_ci 159141cc406Sopenharmony_ci/* Allocate the requested memory plus enough room to store some guard bytes. */ 160141cc406Sopenharmony_cistatic void *guards_malloc(size_t size) 161141cc406Sopenharmony_ci{ 162141cc406Sopenharmony_ci unsigned char *ptr; 163141cc406Sopenharmony_ci 164141cc406Sopenharmony_ci size += 2*GUARDS_SIZE; 165141cc406Sopenharmony_ci ptr = malloc(size); 166141cc406Sopenharmony_ci 167141cc406Sopenharmony_ci assert(ptr); 168141cc406Sopenharmony_ci 169141cc406Sopenharmony_ci ptr += GUARDS_SIZE; 170141cc406Sopenharmony_ci 171141cc406Sopenharmony_ci return(ptr); 172141cc406Sopenharmony_ci} 173141cc406Sopenharmony_ci 174141cc406Sopenharmony_ci/* Free some memory allocated by guards_malloc. */ 175141cc406Sopenharmony_cistatic void guards_free(void *ptr) 176141cc406Sopenharmony_ci{ 177141cc406Sopenharmony_ci unsigned char *p = ptr; 178141cc406Sopenharmony_ci 179141cc406Sopenharmony_ci p -= GUARDS_SIZE; 180141cc406Sopenharmony_ci free(p); 181141cc406Sopenharmony_ci} 182141cc406Sopenharmony_ci 183141cc406Sopenharmony_ci/* Set the guards */ 184141cc406Sopenharmony_cistatic void guards_set(void *ptr, size_t size) 185141cc406Sopenharmony_ci{ 186141cc406Sopenharmony_ci SANE_Word *p; 187141cc406Sopenharmony_ci 188141cc406Sopenharmony_ci p = (SANE_Word *)(((unsigned char *)ptr) - GUARDS_SIZE); 189141cc406Sopenharmony_ci *p = GUARD1; 190141cc406Sopenharmony_ci 191141cc406Sopenharmony_ci p = (SANE_Word *)(((unsigned char *)ptr) + size); 192141cc406Sopenharmony_ci *p = GUARD2; 193141cc406Sopenharmony_ci} 194141cc406Sopenharmony_ci 195141cc406Sopenharmony_ci/* Check that the guards have not been tampered with. */ 196141cc406Sopenharmony_cistatic void guards_check(void *ptr, size_t size) 197141cc406Sopenharmony_ci{ 198141cc406Sopenharmony_ci SANE_Word *p; 199141cc406Sopenharmony_ci 200141cc406Sopenharmony_ci p = (SANE_Word *)(((unsigned char *)ptr) - GUARDS_SIZE); 201141cc406Sopenharmony_ci check(FATAL, (*p == GUARD1), 202141cc406Sopenharmony_ci "guard before the block has been tampered"); 203141cc406Sopenharmony_ci 204141cc406Sopenharmony_ci p = (SANE_Word *)(((unsigned char *)ptr) + size); 205141cc406Sopenharmony_ci check(FATAL, (*p == GUARD2), 206141cc406Sopenharmony_ci "guard after the block has been tampered"); 207141cc406Sopenharmony_ci} 208141cc406Sopenharmony_ci 209141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/ 210141cc406Sopenharmony_ci 211141cc406Sopenharmony_cistatic void 212141cc406Sopenharmony_citest_parameters (SANE_Device * device, SANE_Parameters *params) 213141cc406Sopenharmony_ci{ 214141cc406Sopenharmony_ci SANE_Status status; 215141cc406Sopenharmony_ci SANE_Parameters p; 216141cc406Sopenharmony_ci 217141cc406Sopenharmony_ci status = sane_get_parameters (device, &p); 218141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 219141cc406Sopenharmony_ci "cannot get the parameters (error %s)", sane_strstatus(status)); 220141cc406Sopenharmony_ci 221141cc406Sopenharmony_ci check(FATAL, ((p.format == SANE_FRAME_GRAY) || 222141cc406Sopenharmony_ci (p.format == SANE_FRAME_RGB) || 223141cc406Sopenharmony_ci (p.format == SANE_FRAME_RED) || 224141cc406Sopenharmony_ci (p.format == SANE_FRAME_GREEN) || 225141cc406Sopenharmony_ci (p.format == SANE_FRAME_BLUE)), 226141cc406Sopenharmony_ci "parameter format is not a known SANE_FRAME_* (%d)", p.format); 227141cc406Sopenharmony_ci 228141cc406Sopenharmony_ci check(FATAL, ((p.last_frame == SANE_FALSE) || 229141cc406Sopenharmony_ci (p.last_frame == SANE_TRUE)), 230141cc406Sopenharmony_ci "parameter last_frame is neither SANE_FALSE or SANE_TRUE (%d)", p.last_frame); 231141cc406Sopenharmony_ci 232141cc406Sopenharmony_ci check(FATAL, ((p.depth == 1) || 233141cc406Sopenharmony_ci (p.depth == 8) || 234141cc406Sopenharmony_ci (p.depth == 16)), 235141cc406Sopenharmony_ci "parameter depth is neither 1, 8 or 16 (%d)", p.depth); 236141cc406Sopenharmony_ci 237141cc406Sopenharmony_ci if (params) { 238141cc406Sopenharmony_ci *params = p; 239141cc406Sopenharmony_ci } 240141cc406Sopenharmony_ci} 241141cc406Sopenharmony_ci 242141cc406Sopenharmony_ci/* Try to set every option in a word list. */ 243141cc406Sopenharmony_cistatic void 244141cc406Sopenharmony_citest_options_word_list (SANE_Device * device, int option_num, 245141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt, 246141cc406Sopenharmony_ci int can_do_recursive) 247141cc406Sopenharmony_ci{ 248141cc406Sopenharmony_ci SANE_Status status; 249141cc406Sopenharmony_ci int i; 250141cc406Sopenharmony_ci SANE_Int val_int; 251141cc406Sopenharmony_ci SANE_Int info; 252141cc406Sopenharmony_ci 253141cc406Sopenharmony_ci check(FATAL, (opt->type == SANE_TYPE_INT || 254141cc406Sopenharmony_ci opt->type == SANE_TYPE_FIXED), 255141cc406Sopenharmony_ci "type must be SANE_TYPE_INT or SANE_TYPE_FIXED (%d)", opt->type); 256141cc406Sopenharmony_ci 257141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE(opt->cap)) return; 258141cc406Sopenharmony_ci 259141cc406Sopenharmony_ci for (i=1; i<opt->constraint.word_list[0]; i++) { 260141cc406Sopenharmony_ci 261141cc406Sopenharmony_ci info = 0x1010; /* garbage */ 262141cc406Sopenharmony_ci 263141cc406Sopenharmony_ci val_int = opt->constraint.word_list[i]; 264141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 265141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &val_int, &info); 266141cc406Sopenharmony_ci 267141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 268141cc406Sopenharmony_ci "cannot set a settable option (status=%s)", sane_strstatus(status)); 269141cc406Sopenharmony_ci 270141cc406Sopenharmony_ci check(WRN, ((info & ~(SANE_INFO_RELOAD_OPTIONS | 271141cc406Sopenharmony_ci SANE_INFO_RELOAD_PARAMS)) == 0), 272141cc406Sopenharmony_ci "sane_control_option set an invalid info (%d)", info); 273141cc406Sopenharmony_ci 274141cc406Sopenharmony_ci if ((info & SANE_INFO_RELOAD_OPTIONS) && can_do_recursive) { 275141cc406Sopenharmony_ci test_options(device, can_do_recursive-1); 276141cc406Sopenharmony_ci } 277141cc406Sopenharmony_ci if (info & SANE_INFO_RELOAD_PARAMS) { 278141cc406Sopenharmony_ci test_parameters(device, NULL); 279141cc406Sopenharmony_ci } 280141cc406Sopenharmony_ci 281141cc406Sopenharmony_ci /* The option might have become inactive or unsettable. Skip it. */ 282141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE(opt->cap) || 283141cc406Sopenharmony_ci !SANE_OPTION_IS_SETTABLE(opt->cap)) 284141cc406Sopenharmony_ci return; 285141cc406Sopenharmony_ci 286141cc406Sopenharmony_ci } 287141cc406Sopenharmony_ci} 288141cc406Sopenharmony_ci 289141cc406Sopenharmony_ci/* Try to set every option in a string list. */ 290141cc406Sopenharmony_cistatic void 291141cc406Sopenharmony_citest_options_string_list (SANE_Device * device, int option_num, 292141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt, 293141cc406Sopenharmony_ci int can_do_recursive) 294141cc406Sopenharmony_ci{ 295141cc406Sopenharmony_ci SANE_Int info; 296141cc406Sopenharmony_ci SANE_Status status; 297141cc406Sopenharmony_ci SANE_String val_string; 298141cc406Sopenharmony_ci int i; 299141cc406Sopenharmony_ci 300141cc406Sopenharmony_ci check(FATAL, (opt->type == SANE_TYPE_STRING), 301141cc406Sopenharmony_ci "type must be SANE_TYPE_STRING (%d)", opt->type); 302141cc406Sopenharmony_ci 303141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE(opt->cap)) return; 304141cc406Sopenharmony_ci 305141cc406Sopenharmony_ci for (i=0; opt->constraint.string_list[i] != NULL; i++) { 306141cc406Sopenharmony_ci 307141cc406Sopenharmony_ci val_string = strdup(opt->constraint.string_list[i]); 308141cc406Sopenharmony_ci assert(val_string); 309141cc406Sopenharmony_ci 310141cc406Sopenharmony_ci check(WRN, (strlen(val_string) < (size_t)opt->size), 311141cc406Sopenharmony_ci "string [%s] is longer than the max size (%d)", 312141cc406Sopenharmony_ci val_string, opt->size); 313141cc406Sopenharmony_ci 314141cc406Sopenharmony_ci info = 0xE1000; /* garbage */ 315141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 316141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, val_string, &info); 317141cc406Sopenharmony_ci 318141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 319141cc406Sopenharmony_ci "cannot set a settable option (status=%s)", sane_strstatus(status)); 320141cc406Sopenharmony_ci 321141cc406Sopenharmony_ci check(WRN, ((info & ~(SANE_INFO_RELOAD_OPTIONS | 322141cc406Sopenharmony_ci SANE_INFO_RELOAD_PARAMS)) == 0), 323141cc406Sopenharmony_ci "sane_control_option set an invalid info (%d)", info); 324141cc406Sopenharmony_ci 325141cc406Sopenharmony_ci free(val_string); 326141cc406Sopenharmony_ci 327141cc406Sopenharmony_ci if ((info & SANE_INFO_RELOAD_OPTIONS) && can_do_recursive) { 328141cc406Sopenharmony_ci test_options(device, can_do_recursive-1); 329141cc406Sopenharmony_ci } 330141cc406Sopenharmony_ci if (info & SANE_INFO_RELOAD_PARAMS) { 331141cc406Sopenharmony_ci test_parameters(device, NULL); 332141cc406Sopenharmony_ci } 333141cc406Sopenharmony_ci 334141cc406Sopenharmony_ci /* The option might have become inactive or unsettable. Skip it. */ 335141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE(opt->cap) || 336141cc406Sopenharmony_ci !SANE_OPTION_IS_SETTABLE(opt->cap)) 337141cc406Sopenharmony_ci return; 338141cc406Sopenharmony_ci } 339141cc406Sopenharmony_ci} 340141cc406Sopenharmony_ci 341141cc406Sopenharmony_ci/* Test the consistency of the options. */ 342141cc406Sopenharmony_cistatic void 343141cc406Sopenharmony_citest_options (SANE_Device * device, int can_do_recursive) 344141cc406Sopenharmony_ci{ 345141cc406Sopenharmony_ci SANE_Word info; 346141cc406Sopenharmony_ci SANE_Int num_dev_options; 347141cc406Sopenharmony_ci SANE_Status status; 348141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt; 349141cc406Sopenharmony_ci int option_num; 350141cc406Sopenharmony_ci void *optval; /* value for the option */ 351141cc406Sopenharmony_ci size_t optsize; /* size of the optval buffer */ 352141cc406Sopenharmony_ci 353141cc406Sopenharmony_ci /* 354141cc406Sopenharmony_ci * Test option 0 355141cc406Sopenharmony_ci */ 356141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, 0); 357141cc406Sopenharmony_ci check(FATAL, (opt != NULL), 358141cc406Sopenharmony_ci "cannot get option descriptor for option 0 (it must exist)"); 359141cc406Sopenharmony_ci check(INF, (opt->cap == SANE_CAP_SOFT_DETECT), 360141cc406Sopenharmony_ci "invalid capabilities for option 0 (%d)", opt->cap); 361141cc406Sopenharmony_ci check(ERR, (opt->type == SANE_TYPE_INT), 362141cc406Sopenharmony_ci "option 0 type must be SANE_TYPE_INT"); 363141cc406Sopenharmony_ci 364141cc406Sopenharmony_ci /* Get the number of options. */ 365141cc406Sopenharmony_ci status = sane_control_option (device, 0, SANE_ACTION_GET_VALUE, &num_dev_options, 0); 366141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 367141cc406Sopenharmony_ci "cannot get option 0 value"); 368141cc406Sopenharmony_ci 369141cc406Sopenharmony_ci /* Try to change the number of options. */ 370141cc406Sopenharmony_ci status = sane_control_option (device, 0, SANE_ACTION_SET_VALUE, 371141cc406Sopenharmony_ci &num_dev_options, &info); 372141cc406Sopenharmony_ci check(WRN, (status != SANE_STATUS_GOOD), 373141cc406Sopenharmony_ci "the option 0 value can be set"); 374141cc406Sopenharmony_ci 375141cc406Sopenharmony_ci /* 376141cc406Sopenharmony_ci * Test all options 377141cc406Sopenharmony_ci */ 378141cc406Sopenharmony_ci option_num = 0; 379141cc406Sopenharmony_ci for (option_num = 0; option_num < num_dev_options; option_num++) { 380141cc406Sopenharmony_ci 381141cc406Sopenharmony_ci /* Get the option descriptor */ 382141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, option_num); 383141cc406Sopenharmony_ci check(FATAL, (opt != NULL), 384141cc406Sopenharmony_ci "cannot get option descriptor for option %d", option_num); 385141cc406Sopenharmony_ci check(WRN, ((opt->cap & ~(SANE_CAP_SOFT_SELECT | 386141cc406Sopenharmony_ci SANE_CAP_HARD_SELECT | 387141cc406Sopenharmony_ci SANE_CAP_SOFT_DETECT | 388141cc406Sopenharmony_ci SANE_CAP_EMULATED | 389141cc406Sopenharmony_ci SANE_CAP_AUTOMATIC | 390141cc406Sopenharmony_ci SANE_CAP_INACTIVE | 391141cc406Sopenharmony_ci SANE_CAP_ADVANCED)) == 0), 392141cc406Sopenharmony_ci "invalid capabilities for option [%d, %s] (%x)", option_num, opt->name, opt->cap); 393141cc406Sopenharmony_ci check(WRN, (opt->title != NULL), 394141cc406Sopenharmony_ci "option [%d, %s] must have a title", option_num, opt->name); 395141cc406Sopenharmony_ci check(WRN, (opt->desc != NULL), 396141cc406Sopenharmony_ci "option [%d, %s] must have a description", option_num, opt->name); 397141cc406Sopenharmony_ci 398141cc406Sopenharmony_ci if (!SANE_OPTION_IS_ACTIVE (opt->cap)) { 399141cc406Sopenharmony_ci /* Option not active. Skip the remaining tests. */ 400141cc406Sopenharmony_ci continue; 401141cc406Sopenharmony_ci } 402141cc406Sopenharmony_ci 403141cc406Sopenharmony_ci if(verbose_level) { 404141cc406Sopenharmony_ci printf("checking option ""%s""\n",opt->title); 405141cc406Sopenharmony_ci } 406141cc406Sopenharmony_ci 407141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_GROUP) { 408141cc406Sopenharmony_ci check(INF, (opt->name == NULL || *opt->name == 0), 409141cc406Sopenharmony_ci "option [%d, %s] has a name", option_num, opt->name); 410141cc406Sopenharmony_ci check(ERR, (!SANE_OPTION_IS_SETTABLE (opt->cap)), 411141cc406Sopenharmony_ci "option [%d, %s], group option is settable", option_num, opt->name); 412141cc406Sopenharmony_ci } else { 413141cc406Sopenharmony_ci if (option_num == 0) { 414141cc406Sopenharmony_ci check(ERR, (opt->name != NULL && *opt->name ==0), 415141cc406Sopenharmony_ci "option 0 must have an empty name (ie. \"\")"); 416141cc406Sopenharmony_ci } else { 417141cc406Sopenharmony_ci check(ERR, (opt->name != NULL && *opt->name !=0), 418141cc406Sopenharmony_ci "option %d must have a name", option_num); 419141cc406Sopenharmony_ci } 420141cc406Sopenharmony_ci } 421141cc406Sopenharmony_ci 422141cc406Sopenharmony_ci /* The option name must contain only "a".."z", 423141cc406Sopenharmony_ci "0".."9" and "-" and must start with "a".."z". */ 424141cc406Sopenharmony_ci if (opt->name && opt->name[0]) { 425141cc406Sopenharmony_ci const char *p = opt->name; 426141cc406Sopenharmony_ci 427141cc406Sopenharmony_ci check(ERR, (*p >= 'a' && *p <= 'z'), 428141cc406Sopenharmony_ci "name for option [%d, %s] must start with in letter in [a..z]", 429141cc406Sopenharmony_ci option_num, opt->name); 430141cc406Sopenharmony_ci 431141cc406Sopenharmony_ci p++; 432141cc406Sopenharmony_ci 433141cc406Sopenharmony_ci while(*p) { 434141cc406Sopenharmony_ci check(ERR, ((*p >= 'a' && *p <= 'z') || 435141cc406Sopenharmony_ci (*p == '-') || 436141cc406Sopenharmony_ci (*p >= '0' && *p <= '9')), 437141cc406Sopenharmony_ci "name for option [%d, %s] must only have the letters [-a..z0..9]", 438141cc406Sopenharmony_ci option_num, opt->name); 439141cc406Sopenharmony_ci p++; 440141cc406Sopenharmony_ci } 441141cc406Sopenharmony_ci } 442141cc406Sopenharmony_ci 443141cc406Sopenharmony_ci optval = NULL; 444141cc406Sopenharmony_ci optsize = 0; 445141cc406Sopenharmony_ci 446141cc406Sopenharmony_ci switch(opt->type) { 447141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 448141cc406Sopenharmony_ci check(WRN, (opt->size == sizeof(SANE_Word)), 449141cc406Sopenharmony_ci "size of option %s is incorrect", opt->name); 450141cc406Sopenharmony_ci optval = guards_malloc(opt->size); 451141cc406Sopenharmony_ci optsize = opt->size; 452141cc406Sopenharmony_ci check(WRN, (opt->constraint_type == SANE_CONSTRAINT_NONE), 453141cc406Sopenharmony_ci "invalid constraint type for option [%d, %s] (%d)", option_num, opt->name, opt->constraint_type); 454141cc406Sopenharmony_ci break; 455141cc406Sopenharmony_ci 456141cc406Sopenharmony_ci case SANE_TYPE_INT: 457141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 458141cc406Sopenharmony_ci check(WRN, (opt->size > 0 && (opt->size % sizeof(SANE_Word) == 0)), 459141cc406Sopenharmony_ci "invalid size for option %s", opt->name); 460141cc406Sopenharmony_ci optval = guards_malloc(opt->size); 461141cc406Sopenharmony_ci optsize = opt->size; 462141cc406Sopenharmony_ci check(WRN, (opt->constraint_type == SANE_CONSTRAINT_NONE || 463141cc406Sopenharmony_ci opt->constraint_type == SANE_CONSTRAINT_RANGE || 464141cc406Sopenharmony_ci opt->constraint_type == SANE_CONSTRAINT_WORD_LIST), 465141cc406Sopenharmony_ci "invalid constraint type for option [%d, %s] (%d)", option_num, opt->name, opt->constraint_type); 466141cc406Sopenharmony_ci break; 467141cc406Sopenharmony_ci 468141cc406Sopenharmony_ci case SANE_TYPE_STRING: 469141cc406Sopenharmony_ci check(WRN, (opt->size >= 1), 470141cc406Sopenharmony_ci "size of option [%d, %s] must be at least 1 for the NUL terminator", option_num, opt->name); 471141cc406Sopenharmony_ci check(INF, (opt->unit == SANE_UNIT_NONE), 472141cc406Sopenharmony_ci "unit of option [%d, %s] is not SANE_UNIT_NONE", option_num, opt->name); 473141cc406Sopenharmony_ci check(WRN, (opt->constraint_type == SANE_CONSTRAINT_STRING_LIST || 474141cc406Sopenharmony_ci opt->constraint_type == SANE_CONSTRAINT_NONE), 475141cc406Sopenharmony_ci "invalid constraint type for option [%d, %s] (%d)", option_num, opt->name, opt->constraint_type); 476141cc406Sopenharmony_ci optval = guards_malloc(opt->size); 477141cc406Sopenharmony_ci optsize = opt->size; 478141cc406Sopenharmony_ci break; 479141cc406Sopenharmony_ci 480141cc406Sopenharmony_ci case SANE_TYPE_BUTTON: 481141cc406Sopenharmony_ci case SANE_TYPE_GROUP: 482141cc406Sopenharmony_ci check(INF, (opt->unit == SANE_UNIT_NONE), 483141cc406Sopenharmony_ci "option [%d, %s], unit is not SANE_UNIT_NONE", option_num, opt->name); 484141cc406Sopenharmony_ci check(INF, (opt->size == 0), 485141cc406Sopenharmony_ci "option [%d, %s], size is not 0", option_num, opt->name); 486141cc406Sopenharmony_ci check(WRN, (opt->constraint_type == SANE_CONSTRAINT_NONE), 487141cc406Sopenharmony_ci "invalid constraint type for option [%d, %s] (%d)", option_num, opt->name, opt->constraint_type); 488141cc406Sopenharmony_ci break; 489141cc406Sopenharmony_ci 490141cc406Sopenharmony_ci default: 491141cc406Sopenharmony_ci check(ERR, 0, 492141cc406Sopenharmony_ci "invalid type %d for option %s", 493141cc406Sopenharmony_ci opt->type, opt->name); 494141cc406Sopenharmony_ci break; 495141cc406Sopenharmony_ci } 496141cc406Sopenharmony_ci 497141cc406Sopenharmony_ci if (optval) { 498141cc406Sopenharmony_ci /* This is an option with a value */ 499141cc406Sopenharmony_ci 500141cc406Sopenharmony_ci /* get with NULL info. 501141cc406Sopenharmony_ci * 502141cc406Sopenharmony_ci * The SANE standard is not explicit on that subject. I 503141cc406Sopenharmony_ci * consider that an inactive option shouldn't be read by a 504141cc406Sopenharmony_ci * frontend because its value is meaningless. I think 505141cc406Sopenharmony_ci * that, in that case, SANE_STATUS_INVAL is an appropriate 506141cc406Sopenharmony_ci * return. 507141cc406Sopenharmony_ci */ 508141cc406Sopenharmony_ci guards_set(optval, optsize); 509141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 510141cc406Sopenharmony_ci SANE_ACTION_GET_VALUE, optval, NULL); 511141cc406Sopenharmony_ci guards_check(optval, optsize); 512141cc406Sopenharmony_ci 513141cc406Sopenharmony_ci if (SANE_OPTION_IS_GETTABLE (opt->cap)) { 514141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 515141cc406Sopenharmony_ci "cannot get option [%d, %s] value, although it is active (%s)", option_num, opt->name, sane_strstatus(status)); 516141cc406Sopenharmony_ci } else { 517141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_INVAL), 518141cc406Sopenharmony_ci "was able to get option [%d, %s] value, although it is not active", option_num, opt->name); 519141cc406Sopenharmony_ci } 520141cc406Sopenharmony_ci 521141cc406Sopenharmony_ci /* set with NULL info */ 522141cc406Sopenharmony_ci guards_set(optval, optsize); 523141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 524141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, optval, NULL); 525141cc406Sopenharmony_ci guards_check(optval, optsize); 526141cc406Sopenharmony_ci if (SANE_OPTION_IS_SETTABLE (opt->cap) && SANE_OPTION_IS_ACTIVE (opt->cap)) { 527141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 528141cc406Sopenharmony_ci "cannot set option [%d, %s] value, although it is active and settable (%s)", option_num, opt->name, sane_strstatus(status)); 529141cc406Sopenharmony_ci } else { 530141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_INVAL), 531141cc406Sopenharmony_ci "was able to set option [%d, %s] value, although it is not active or settable", option_num, opt->name); 532141cc406Sopenharmony_ci } 533141cc406Sopenharmony_ci 534141cc406Sopenharmony_ci /* Get with invalid info. Since if is a get, info should be either 535141cc406Sopenharmony_ci * ignored or set to 0. */ 536141cc406Sopenharmony_ci info = 0xdeadbeef; 537141cc406Sopenharmony_ci guards_set(optval, optsize); 538141cc406Sopenharmony_ci status = sane_control_option (device, option_num, SANE_ACTION_GET_VALUE, 539141cc406Sopenharmony_ci optval, &info); 540141cc406Sopenharmony_ci guards_check(optval, optsize); 541141cc406Sopenharmony_ci if (SANE_OPTION_IS_GETTABLE (opt->cap)) { 542141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 543141cc406Sopenharmony_ci "cannot get option [%d, %s] value, although it is active (%s)", option_num, opt->name, sane_strstatus(status)); 544141cc406Sopenharmony_ci } else { 545141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_INVAL), 546141cc406Sopenharmony_ci "was able to get option [%d, %s] value, although it is not active", option_num, opt->name); 547141cc406Sopenharmony_ci } 548141cc406Sopenharmony_ci check(ERR, ((info == (SANE_Int)0xdeadbeef) || (info == 0)), 549141cc406Sopenharmony_ci "when getting option [%d, %s], info was set to %x", option_num, opt->name, info); 550141cc406Sopenharmony_ci 551141cc406Sopenharmony_ci /* Set with invalid info. Info should be reset by the backend. */ 552141cc406Sopenharmony_ci info = 0x10000; 553141cc406Sopenharmony_ci guards_set(optval, optsize); 554141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 555141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, optval, &info); 556141cc406Sopenharmony_ci guards_check(optval, optsize); 557141cc406Sopenharmony_ci if (SANE_OPTION_IS_SETTABLE (opt->cap) && SANE_OPTION_IS_ACTIVE (opt->cap)) { 558141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 559141cc406Sopenharmony_ci "cannot set option [%d, %s] value, although it is active and settable (%s)", option_num, opt->name, sane_strstatus(status)); 560141cc406Sopenharmony_ci 561141cc406Sopenharmony_ci check(ERR, ((info & ~(SANE_INFO_INEXACT | 562141cc406Sopenharmony_ci SANE_INFO_RELOAD_OPTIONS | 563141cc406Sopenharmony_ci SANE_INFO_RELOAD_PARAMS)) == 0), 564141cc406Sopenharmony_ci "sane_control_option set some wrong bit in info (%d)", info); 565141cc406Sopenharmony_ci 566141cc406Sopenharmony_ci if (info & SANE_INFO_RELOAD_PARAMS) { 567141cc406Sopenharmony_ci test_parameters(device, NULL); 568141cc406Sopenharmony_ci } 569141cc406Sopenharmony_ci } else { 570141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_INVAL), 571141cc406Sopenharmony_ci "was able to set option [%d, %s] value, although it is not active or settable", option_num, opt->name); 572141cc406Sopenharmony_ci } 573141cc406Sopenharmony_ci 574141cc406Sopenharmony_ci /* Ask the backend to set the option automatically. */ 575141cc406Sopenharmony_ci guards_set(optval, optsize); 576141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 577141cc406Sopenharmony_ci SANE_ACTION_SET_AUTO, optval, &info); 578141cc406Sopenharmony_ci guards_check(optval, optsize); 579141cc406Sopenharmony_ci if (SANE_OPTION_IS_SETTABLE (opt->cap) && 580141cc406Sopenharmony_ci SANE_OPTION_IS_ACTIVE (opt->cap) && 581141cc406Sopenharmony_ci (opt->cap & SANE_CAP_AUTOMATIC)) { 582141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 583141cc406Sopenharmony_ci "cannot set the option [%d, %s] automatically.", option_num, opt->name); 584141cc406Sopenharmony_ci } else { 585141cc406Sopenharmony_ci check(ERR, (status != SANE_STATUS_GOOD), 586141cc406Sopenharmony_ci "was able to automatically set option [%d, %s], although it is not active or settable or automatically settable", option_num, opt->name); 587141cc406Sopenharmony_ci } 588141cc406Sopenharmony_ci if (info & SANE_INFO_RELOAD_PARAMS) { 589141cc406Sopenharmony_ci test_parameters(device, NULL); 590141cc406Sopenharmony_ci } 591141cc406Sopenharmony_ci } 592141cc406Sopenharmony_ci 593141cc406Sopenharmony_ci if (optval) { 594141cc406Sopenharmony_ci guards_free(optval); 595141cc406Sopenharmony_ci optval = NULL; 596141cc406Sopenharmony_ci } 597141cc406Sopenharmony_ci 598141cc406Sopenharmony_ci /* Some capabilities checks. */ 599141cc406Sopenharmony_ci check(ERR, ((opt->cap & (SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_SELECT)) != 600141cc406Sopenharmony_ci (SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_SELECT)), 601141cc406Sopenharmony_ci "option [%d, %s], SANE_CAP_HARD_SELECT and SANE_CAP_SOFT_SELECT are mutually exclusive", option_num, opt->name); 602141cc406Sopenharmony_ci if (opt->cap & SANE_CAP_SOFT_SELECT) { 603141cc406Sopenharmony_ci check(ERR, ((opt->cap & SANE_CAP_SOFT_DETECT) != 0), 604141cc406Sopenharmony_ci "option [%d, %s], SANE_CAP_SOFT_DETECT must be set if SANE_CAP_SOFT_SELECT is set", option_num, opt->name); 605141cc406Sopenharmony_ci } 606141cc406Sopenharmony_ci if ((opt->cap & (SANE_CAP_SOFT_SELECT | 607141cc406Sopenharmony_ci SANE_CAP_HARD_SELECT | 608141cc406Sopenharmony_ci SANE_CAP_SOFT_DETECT)) == SANE_CAP_SOFT_DETECT) { 609141cc406Sopenharmony_ci check(ERR, (!SANE_OPTION_IS_SETTABLE (opt->cap)), 610141cc406Sopenharmony_ci "option [%d, %s], must not be settable", option_num, opt->name); 611141cc406Sopenharmony_ci } 612141cc406Sopenharmony_ci 613141cc406Sopenharmony_ci if (!SANE_OPTION_IS_SETTABLE (opt->cap)) { 614141cc406Sopenharmony_ci /* Unsettable option. Ignore the rest of the test. */ 615141cc406Sopenharmony_ci continue; 616141cc406Sopenharmony_ci } 617141cc406Sopenharmony_ci 618141cc406Sopenharmony_ci /* Check that will sane_control_option copy the string 619141cc406Sopenharmony_ci * parameter and not just store a pointer to it. */ 620141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_STRING) { 621141cc406Sopenharmony_ci SANE_String val_string2; 622141cc406Sopenharmony_ci char *optstr; 623141cc406Sopenharmony_ci 624141cc406Sopenharmony_ci optstr = guards_malloc(opt->size); 625141cc406Sopenharmony_ci val_string2 = guards_malloc(opt->size); 626141cc406Sopenharmony_ci 627141cc406Sopenharmony_ci /* Poison the current value. */ 628141cc406Sopenharmony_ci strncpy(optstr, "-pOiSoN-", opt->size-1); 629141cc406Sopenharmony_ci optstr[opt->size-1] = 0; 630141cc406Sopenharmony_ci 631141cc406Sopenharmony_ci /* Get the value */ 632141cc406Sopenharmony_ci guards_set(optstr, opt->size); 633141cc406Sopenharmony_ci status = sane_control_option (device, option_num, SANE_ACTION_GET_VALUE, 634141cc406Sopenharmony_ci optstr, NULL); 635141cc406Sopenharmony_ci guards_check(optstr, opt->size); 636141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 637141cc406Sopenharmony_ci "cannot get option [%d, %s] value", option_num, opt->name); 638141cc406Sopenharmony_ci check(FATAL, (strcmp(optstr, "-pOiSoN-") != 0), 639141cc406Sopenharmony_ci "sane_control_option did not set a value"); 640141cc406Sopenharmony_ci 641141cc406Sopenharmony_ci /* Set the value */ 642141cc406Sopenharmony_ci guards_set(optstr, opt->size); 643141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 644141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, optstr, NULL); 645141cc406Sopenharmony_ci guards_check(optstr, opt->size); 646141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 647141cc406Sopenharmony_ci "cannot set option [%d, %s] value", option_num, opt->name); 648141cc406Sopenharmony_ci 649141cc406Sopenharmony_ci /* Poison the returned value. */ 650141cc406Sopenharmony_ci strncpy(optstr, "-pOiSoN-", opt->size-1); 651141cc406Sopenharmony_ci optstr[opt->size-1] = 0; 652141cc406Sopenharmony_ci 653141cc406Sopenharmony_ci /* Read again the value and compare. */ 654141cc406Sopenharmony_ci guards_set(val_string2, opt->size); 655141cc406Sopenharmony_ci status = sane_control_option (device, option_num, SANE_ACTION_GET_VALUE, 656141cc406Sopenharmony_ci val_string2, NULL); 657141cc406Sopenharmony_ci guards_check(val_string2, opt->size); 658141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 659141cc406Sopenharmony_ci "cannot get option [%d, %s] value", option_num, opt->name); 660141cc406Sopenharmony_ci 661141cc406Sopenharmony_ci check(FATAL, (strcmp(optstr, val_string2) != 0), 662141cc406Sopenharmony_ci "sane_control_option did not copy the string parameter for option [%d, %s]", option_num, opt->name); 663141cc406Sopenharmony_ci 664141cc406Sopenharmony_ci guards_free(optstr); 665141cc406Sopenharmony_ci guards_free(val_string2); 666141cc406Sopenharmony_ci } 667141cc406Sopenharmony_ci 668141cc406Sopenharmony_ci /* Try both boolean options. */ 669141cc406Sopenharmony_ci if (opt->type == SANE_TYPE_BOOL) { 670141cc406Sopenharmony_ci SANE_Bool org_v; 671141cc406Sopenharmony_ci SANE_Bool v; 672141cc406Sopenharmony_ci 673141cc406Sopenharmony_ci status = sane_control_option (device, option_num, SANE_ACTION_GET_VALUE, 674141cc406Sopenharmony_ci &org_v, &info); 675141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 676141cc406Sopenharmony_ci "cannot get boolean option [%d, %s] value (%s)", option_num, opt->name, sane_strstatus(status)); 677141cc406Sopenharmony_ci /* Invert the condition. */ 678141cc406Sopenharmony_ci switch(org_v) { 679141cc406Sopenharmony_ci case SANE_FALSE: 680141cc406Sopenharmony_ci v = SANE_TRUE; 681141cc406Sopenharmony_ci break; 682141cc406Sopenharmony_ci case SANE_TRUE: 683141cc406Sopenharmony_ci v = SANE_FALSE; 684141cc406Sopenharmony_ci break; 685141cc406Sopenharmony_ci default: 686141cc406Sopenharmony_ci check(ERR, 0, 687141cc406Sopenharmony_ci "invalid boolean value %d for option [%d, %s]", 688141cc406Sopenharmony_ci org_v, option_num, opt->name); 689141cc406Sopenharmony_ci } 690141cc406Sopenharmony_ci 691141cc406Sopenharmony_ci /* Set the opposite of the current value. */ 692141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 693141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &v, &info); 694141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 695141cc406Sopenharmony_ci "cannot set boolean option [%d, %s] value (%s)", option_num, opt->name, sane_strstatus(status)); 696141cc406Sopenharmony_ci check(ERR, (v != org_v), 697141cc406Sopenharmony_ci "boolean values should be different"); 698141cc406Sopenharmony_ci 699141cc406Sopenharmony_ci if (info & SANE_INFO_RELOAD_PARAMS) { 700141cc406Sopenharmony_ci test_parameters(device, NULL); 701141cc406Sopenharmony_ci } 702141cc406Sopenharmony_ci 703141cc406Sopenharmony_ci /* Set the initial value. */ 704141cc406Sopenharmony_ci v = org_v; 705141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 706141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &v, &info); 707141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 708141cc406Sopenharmony_ci "cannot set boolean option [%d, %s] value (%s)", option_num, opt->name, sane_strstatus(status)); 709141cc406Sopenharmony_ci check(ERR, (v == org_v), 710141cc406Sopenharmony_ci "boolean values should be the same"); 711141cc406Sopenharmony_ci 712141cc406Sopenharmony_ci if (info & SANE_INFO_RELOAD_PARAMS) { 713141cc406Sopenharmony_ci test_parameters(device, NULL); 714141cc406Sopenharmony_ci } 715141cc406Sopenharmony_ci } 716141cc406Sopenharmony_ci 717141cc406Sopenharmony_ci /* Try to set an invalid option. */ 718141cc406Sopenharmony_ci switch(opt->type) { 719141cc406Sopenharmony_ci case SANE_TYPE_BOOL: { 720141cc406Sopenharmony_ci SANE_Word v; /* should be SANE_Bool instead */ 721141cc406Sopenharmony_ci 722141cc406Sopenharmony_ci v = -1; /* invalid value. must be SANE_FALSE or SANE_TRUE */ 723141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 724141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &v, NULL); 725141cc406Sopenharmony_ci check(ERR, (status != SANE_STATUS_GOOD), 726141cc406Sopenharmony_ci "was able to set an invalid value for boolean option [%d, %s]", option_num, opt->name); 727141cc406Sopenharmony_ci 728141cc406Sopenharmony_ci v = 2; /* invalid value. must be SANE_FALSE or SANE_TRUE */ 729141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 730141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &v, NULL); 731141cc406Sopenharmony_ci check(ERR, (status != SANE_STATUS_GOOD), 732141cc406Sopenharmony_ci "was able to set an invalid value for boolean option [%d, %s]", option_num, opt->name); 733141cc406Sopenharmony_ci } 734141cc406Sopenharmony_ci break; 735141cc406Sopenharmony_ci 736141cc406Sopenharmony_ci case SANE_TYPE_FIXED: 737141cc406Sopenharmony_ci case SANE_TYPE_INT: { 738141cc406Sopenharmony_ci SANE_Int *v; 739141cc406Sopenharmony_ci unsigned int i; 740141cc406Sopenharmony_ci 741141cc406Sopenharmony_ci v = guards_malloc(opt->size); 742141cc406Sopenharmony_ci 743141cc406Sopenharmony_ci /* I can only think of a test for 744141cc406Sopenharmony_ci * SANE_CONSTRAINT_RANGE. This tests the behaviour of 745141cc406Sopenharmony_ci * sanei_constrain_value(). */ 746141cc406Sopenharmony_ci if (opt->constraint_type == SANE_CONSTRAINT_RANGE) { 747141cc406Sopenharmony_ci for(i=0; i<opt->size / sizeof(SANE_Int); i++) 748141cc406Sopenharmony_ci v[i] = opt->constraint.range->min - 1; /* invalid range */ 749141cc406Sopenharmony_ci 750141cc406Sopenharmony_ci guards_set(v, opt->size); 751141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 752141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, v, &info); 753141cc406Sopenharmony_ci guards_check(v, opt->size); 754141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD && (info & SANE_INFO_INEXACT) ), 755141cc406Sopenharmony_ci "incorrect return when setting an invalid range value for option [%d, %s] (status %s, info %x)", option_num, opt->name, sane_strstatus(status), info); 756141cc406Sopenharmony_ci 757141cc406Sopenharmony_ci /* Set the corrected value. */ 758141cc406Sopenharmony_ci guards_set(v, opt->size); 759141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 760141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, v, &info); 761141cc406Sopenharmony_ci guards_check(v, opt->size); 762141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD && !(info & SANE_INFO_INEXACT) ), 763141cc406Sopenharmony_ci "incorrect return when setting an invalid range value for option [%d, %s] (status %s, info %x)", option_num, opt->name, sane_strstatus(status), info); 764141cc406Sopenharmony_ci 765141cc406Sopenharmony_ci 766141cc406Sopenharmony_ci for(i=0; i<opt->size / sizeof(SANE_Int); i++) 767141cc406Sopenharmony_ci v[i] = opt->constraint.range->max + 1; /* invalid range */ 768141cc406Sopenharmony_ci 769141cc406Sopenharmony_ci guards_set(v, opt->size); 770141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 771141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, v, &info); 772141cc406Sopenharmony_ci guards_check(v, opt->size); 773141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD && (info & SANE_INFO_INEXACT) ), 774141cc406Sopenharmony_ci "incorrect return when setting an invalid range value for option [%d, %s] (status %s, info %x)", option_num, opt->name, sane_strstatus(status), info); 775141cc406Sopenharmony_ci 776141cc406Sopenharmony_ci /* Set the corrected value. */ 777141cc406Sopenharmony_ci guards_set(v, opt->size); 778141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 779141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, v, &info); 780141cc406Sopenharmony_ci guards_check(v, opt->size); 781141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD && !(info & SANE_INFO_INEXACT) ), 782141cc406Sopenharmony_ci "incorrect return when setting a valid range value for option [%d, %s] (status %s, info %x)", option_num, opt->name, sane_strstatus(status), info); 783141cc406Sopenharmony_ci } 784141cc406Sopenharmony_ci 785141cc406Sopenharmony_ci guards_free(v); 786141cc406Sopenharmony_ci } 787141cc406Sopenharmony_ci break; 788141cc406Sopenharmony_ci 789141cc406Sopenharmony_ci default: 790141cc406Sopenharmony_ci break; 791141cc406Sopenharmony_ci } 792141cc406Sopenharmony_ci 793141cc406Sopenharmony_ci /* TODO: button */ 794141cc406Sopenharmony_ci 795141cc406Sopenharmony_ci /* 796141cc406Sopenharmony_ci * Here starts all the recursive stuff. After the test, it is 797141cc406Sopenharmony_ci * possible that the value is not settable nor active 798141cc406Sopenharmony_ci * anymore. 799141cc406Sopenharmony_ci */ 800141cc406Sopenharmony_ci 801141cc406Sopenharmony_ci /* Try to set every option in a list */ 802141cc406Sopenharmony_ci switch(opt->constraint_type) { 803141cc406Sopenharmony_ci case SANE_CONSTRAINT_WORD_LIST: 804141cc406Sopenharmony_ci check(FATAL, (opt->constraint.word_list != NULL), 805141cc406Sopenharmony_ci "no constraint list for option [%d, %s]", option_num, opt->name); 806141cc406Sopenharmony_ci test_options_word_list (device, option_num, opt, can_do_recursive); 807141cc406Sopenharmony_ci break; 808141cc406Sopenharmony_ci 809141cc406Sopenharmony_ci case SANE_CONSTRAINT_STRING_LIST: 810141cc406Sopenharmony_ci check(FATAL, (opt->constraint.string_list != NULL), 811141cc406Sopenharmony_ci "no constraint list for option [%d, %s]", option_num, opt->name); 812141cc406Sopenharmony_ci test_options_string_list (device, option_num, opt, can_do_recursive); 813141cc406Sopenharmony_ci break; 814141cc406Sopenharmony_ci 815141cc406Sopenharmony_ci case SANE_CONSTRAINT_RANGE: 816141cc406Sopenharmony_ci check(FATAL, (opt->constraint.range != NULL), 817141cc406Sopenharmony_ci "no constraint range for option [%d, %s]", option_num, opt->name); 818141cc406Sopenharmony_ci check(FATAL, (opt->constraint.range->max >= opt->constraint.range->min), 819141cc406Sopenharmony_ci "incorrect range for option [%d, %s] (min=%d > max=%d)", 820141cc406Sopenharmony_ci option_num, opt->name, opt->constraint.range->min, opt->constraint.range->max); 821141cc406Sopenharmony_ci /* Recurse. */ 822141cc406Sopenharmony_ci if (can_do_recursive) { 823141cc406Sopenharmony_ci test_options(device, can_do_recursive-1); 824141cc406Sopenharmony_ci } 825141cc406Sopenharmony_ci break; 826141cc406Sopenharmony_ci 827141cc406Sopenharmony_ci case SANE_CONSTRAINT_NONE: 828141cc406Sopenharmony_ci check(INF, (opt->constraint.range == NULL), 829141cc406Sopenharmony_ci "option [%d, %s] has some constraint value set", option_num, opt->name); 830141cc406Sopenharmony_ci 831141cc406Sopenharmony_ci /* Recurse. */ 832141cc406Sopenharmony_ci if (can_do_recursive) { 833141cc406Sopenharmony_ci test_options(device, can_do_recursive-1); 834141cc406Sopenharmony_ci } 835141cc406Sopenharmony_ci break; 836141cc406Sopenharmony_ci } 837141cc406Sopenharmony_ci 838141cc406Sopenharmony_ci /* End of the test for that option. */ 839141cc406Sopenharmony_ci } 840141cc406Sopenharmony_ci 841141cc406Sopenharmony_ci /* test random non-existing options. */ 842141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, -1); 843141cc406Sopenharmony_ci check(ERR, (opt == NULL), 844141cc406Sopenharmony_ci "was able to get option descriptor for option -1"); 845141cc406Sopenharmony_ci 846141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, num_dev_options+1); 847141cc406Sopenharmony_ci check(ERR, (opt == NULL), 848141cc406Sopenharmony_ci "was able to get option descriptor for option %d", num_dev_options+1); 849141cc406Sopenharmony_ci 850141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, num_dev_options+2); 851141cc406Sopenharmony_ci check(ERR, (opt == NULL), 852141cc406Sopenharmony_ci "was able to get option descriptor for option %d", num_dev_options+2); 853141cc406Sopenharmony_ci 854141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, num_dev_options+50); 855141cc406Sopenharmony_ci check(ERR, (opt == NULL), 856141cc406Sopenharmony_ci "was able to get option descriptor for option %d", num_dev_options+50); 857141cc406Sopenharmony_ci} 858141cc406Sopenharmony_ci 859141cc406Sopenharmony_ci/* Get an option descriptor by the name of the option. */ 860141cc406Sopenharmony_cistatic const SANE_Option_Descriptor *get_optdesc_by_name(SANE_Handle device, const char *name, int *option_num) 861141cc406Sopenharmony_ci{ 862141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt; 863141cc406Sopenharmony_ci SANE_Int num_dev_options; 864141cc406Sopenharmony_ci SANE_Status status; 865141cc406Sopenharmony_ci 866141cc406Sopenharmony_ci /* Get the number of options. */ 867141cc406Sopenharmony_ci status = sane_control_option (device, 0, SANE_ACTION_GET_VALUE, &num_dev_options, 0); 868141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 869141cc406Sopenharmony_ci "cannot get option 0 value (%s)", sane_strstatus(status)); 870141cc406Sopenharmony_ci 871141cc406Sopenharmony_ci for (*option_num = 0; *option_num < num_dev_options; (*option_num)++) { 872141cc406Sopenharmony_ci 873141cc406Sopenharmony_ci /* Get the option descriptor */ 874141cc406Sopenharmony_ci opt = sane_get_option_descriptor (device, *option_num); 875141cc406Sopenharmony_ci check(FATAL, (opt != NULL), 876141cc406Sopenharmony_ci "cannot get option descriptor for option %d", *option_num); 877141cc406Sopenharmony_ci 878141cc406Sopenharmony_ci if (opt->name && strcmp(opt->name, name) == 0) { 879141cc406Sopenharmony_ci return(opt); 880141cc406Sopenharmony_ci } 881141cc406Sopenharmony_ci } 882141cc406Sopenharmony_ci return(NULL); 883141cc406Sopenharmony_ci} 884141cc406Sopenharmony_ci 885141cc406Sopenharmony_ci/* Set the first value for an option. That equates to the minimum for a 886141cc406Sopenharmony_ci * range or the first element in a list. */ 887141cc406Sopenharmony_cistatic void set_min_value(SANE_Handle device, int option_num, 888141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt) 889141cc406Sopenharmony_ci{ 890141cc406Sopenharmony_ci SANE_Status status; 891141cc406Sopenharmony_ci SANE_String val_string; 892141cc406Sopenharmony_ci SANE_Int val_int; 893141cc406Sopenharmony_ci int rc; 894141cc406Sopenharmony_ci 895141cc406Sopenharmony_ci check(BUG, (SANE_OPTION_IS_SETTABLE(opt->cap)), 896141cc406Sopenharmony_ci "option is not settable"); 897141cc406Sopenharmony_ci 898141cc406Sopenharmony_ci switch(opt->constraint_type) { 899141cc406Sopenharmony_ci case SANE_CONSTRAINT_WORD_LIST: 900141cc406Sopenharmony_ci rc = check(ERR, (opt->constraint.word_list[0] > 0), 901141cc406Sopenharmony_ci "no value in the list for option %s", opt->name); 902141cc406Sopenharmony_ci if (!rc) return; 903141cc406Sopenharmony_ci val_int = opt->constraint.word_list[1]; 904141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 905141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &val_int, NULL); 906141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 907141cc406Sopenharmony_ci "cannot set option %s to %d (%s)", opt->name, val_int, sane_strstatus(status)); 908141cc406Sopenharmony_ci break; 909141cc406Sopenharmony_ci 910141cc406Sopenharmony_ci case SANE_CONSTRAINT_STRING_LIST: 911141cc406Sopenharmony_ci rc = check(ERR, (opt->constraint.string_list[0] != NULL), 912141cc406Sopenharmony_ci "no value in the list for option %s", opt->name); 913141cc406Sopenharmony_ci if (!rc) return; 914141cc406Sopenharmony_ci val_string = strdup(opt->constraint.string_list[0]); 915141cc406Sopenharmony_ci assert(val_string); 916141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 917141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, val_string, NULL); 918141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 919141cc406Sopenharmony_ci "cannot set option %s to [%s] (%s)", opt->name, val_string, sane_strstatus(status)); 920141cc406Sopenharmony_ci free(val_string); 921141cc406Sopenharmony_ci break; 922141cc406Sopenharmony_ci 923141cc406Sopenharmony_ci case SANE_CONSTRAINT_RANGE: 924141cc406Sopenharmony_ci val_int = opt->constraint.range->min; 925141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 926141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &val_int, NULL); 927141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 928141cc406Sopenharmony_ci "cannot set option %s to %d (%s)", opt->name, val_int, sane_strstatus(status)); 929141cc406Sopenharmony_ci break; 930141cc406Sopenharmony_ci 931141cc406Sopenharmony_ci default: 932141cc406Sopenharmony_ci abort(); 933141cc406Sopenharmony_ci } 934141cc406Sopenharmony_ci} 935141cc406Sopenharmony_ci 936141cc406Sopenharmony_ci/* Set the last value for an option. That equates to the maximum for a 937141cc406Sopenharmony_ci * range or the last element in a list. */ 938141cc406Sopenharmony_cistatic void set_max_value(SANE_Handle device, int option_num, 939141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt) 940141cc406Sopenharmony_ci{ 941141cc406Sopenharmony_ci SANE_Status status; 942141cc406Sopenharmony_ci SANE_String val_string; 943141cc406Sopenharmony_ci SANE_Int val_int; 944141cc406Sopenharmony_ci int i; 945141cc406Sopenharmony_ci int rc; 946141cc406Sopenharmony_ci 947141cc406Sopenharmony_ci check(BUG, (SANE_OPTION_IS_SETTABLE(opt->cap)), 948141cc406Sopenharmony_ci "option is not settable"); 949141cc406Sopenharmony_ci 950141cc406Sopenharmony_ci switch(opt->constraint_type) { 951141cc406Sopenharmony_ci case SANE_CONSTRAINT_WORD_LIST: 952141cc406Sopenharmony_ci rc = check(ERR, (opt->constraint.word_list[0] > 0), 953141cc406Sopenharmony_ci "no value in the list for option %s", opt->name); 954141cc406Sopenharmony_ci if (!rc) return; 955141cc406Sopenharmony_ci val_int = opt->constraint.word_list[opt->constraint.word_list[0]]; 956141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 957141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &val_int, NULL); 958141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 959141cc406Sopenharmony_ci "cannot set option %s to %d (%s)", opt->name, val_int, sane_strstatus(status)); 960141cc406Sopenharmony_ci break; 961141cc406Sopenharmony_ci 962141cc406Sopenharmony_ci case SANE_CONSTRAINT_STRING_LIST: 963141cc406Sopenharmony_ci rc = check(ERR, (opt->constraint.string_list[0] != NULL), 964141cc406Sopenharmony_ci "no value in the list for option %s", opt->name); 965141cc406Sopenharmony_ci if (!rc) return; 966141cc406Sopenharmony_ci for (i=1; opt->constraint.string_list[i] != NULL; i++); 967141cc406Sopenharmony_ci val_string = strdup(opt->constraint.string_list[i-1]); 968141cc406Sopenharmony_ci assert(val_string); 969141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 970141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, val_string, NULL); 971141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 972141cc406Sopenharmony_ci "cannot set option %s to [%s] (%s)", opt->name, val_string, sane_strstatus(status)); 973141cc406Sopenharmony_ci free(val_string); 974141cc406Sopenharmony_ci break; 975141cc406Sopenharmony_ci 976141cc406Sopenharmony_ci case SANE_CONSTRAINT_RANGE: 977141cc406Sopenharmony_ci val_int = opt->constraint.range->max; 978141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 979141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &val_int, NULL); 980141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 981141cc406Sopenharmony_ci "cannot set option %s to %d (%s)", opt->name, val_int, sane_strstatus(status)); 982141cc406Sopenharmony_ci break; 983141cc406Sopenharmony_ci 984141cc406Sopenharmony_ci default: 985141cc406Sopenharmony_ci abort(); 986141cc406Sopenharmony_ci } 987141cc406Sopenharmony_ci} 988141cc406Sopenharmony_ci 989141cc406Sopenharmony_ci/* Set a random value for an option amongst the possible values. */ 990141cc406Sopenharmony_cistatic void set_random_value(SANE_Handle device, int option_num, 991141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt) 992141cc406Sopenharmony_ci{ 993141cc406Sopenharmony_ci SANE_Status status; 994141cc406Sopenharmony_ci SANE_String val_string; 995141cc406Sopenharmony_ci SANE_Int val_int; 996141cc406Sopenharmony_ci int i; 997141cc406Sopenharmony_ci int rc; 998141cc406Sopenharmony_ci 999141cc406Sopenharmony_ci check(BUG, (SANE_OPTION_IS_SETTABLE(opt->cap)), 1000141cc406Sopenharmony_ci "option is not settable"); 1001141cc406Sopenharmony_ci 1002141cc406Sopenharmony_ci switch(opt->constraint_type) { 1003141cc406Sopenharmony_ci case SANE_CONSTRAINT_WORD_LIST: 1004141cc406Sopenharmony_ci rc = check(ERR, (opt->constraint.word_list[0] > 0), 1005141cc406Sopenharmony_ci "no value in the list for option %s", opt->name); 1006141cc406Sopenharmony_ci if (!rc) return; 1007141cc406Sopenharmony_ci i=1+(rand() % opt->constraint.word_list[0]); 1008141cc406Sopenharmony_ci val_int = opt->constraint.word_list[i]; 1009141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 1010141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &val_int, NULL); 1011141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 1012141cc406Sopenharmony_ci "cannot set option %s to %d (%s)", opt->name, val_int, sane_strstatus(status)); 1013141cc406Sopenharmony_ci break; 1014141cc406Sopenharmony_ci 1015141cc406Sopenharmony_ci case SANE_CONSTRAINT_STRING_LIST: 1016141cc406Sopenharmony_ci rc = check(ERR, (opt->constraint.string_list[0] != NULL), 1017141cc406Sopenharmony_ci "no value in the list for option %s", opt->name); 1018141cc406Sopenharmony_ci if (!rc) return; 1019141cc406Sopenharmony_ci for (i=0; opt->constraint.string_list[i] != NULL; i++); 1020141cc406Sopenharmony_ci i = rand() % i; 1021141cc406Sopenharmony_ci val_string = strdup(opt->constraint.string_list[0]); 1022141cc406Sopenharmony_ci assert(val_string); 1023141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 1024141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, val_string, NULL); 1025141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 1026141cc406Sopenharmony_ci "cannot set option %s to [%s] (%s)", opt->name, val_string, sane_strstatus(status)); 1027141cc406Sopenharmony_ci free(val_string); 1028141cc406Sopenharmony_ci break; 1029141cc406Sopenharmony_ci 1030141cc406Sopenharmony_ci case SANE_CONSTRAINT_RANGE: 1031141cc406Sopenharmony_ci i = opt->constraint.range->max - opt->constraint.range->min; 1032141cc406Sopenharmony_ci i = rand() % i; 1033141cc406Sopenharmony_ci val_int = opt->constraint.range->min + i; 1034141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 1035141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, &val_int, NULL); 1036141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 1037141cc406Sopenharmony_ci "cannot set option %s to %d (%s)", opt->name, val_int, sane_strstatus(status)); 1038141cc406Sopenharmony_ci break; 1039141cc406Sopenharmony_ci 1040141cc406Sopenharmony_ci default: 1041141cc406Sopenharmony_ci abort(); 1042141cc406Sopenharmony_ci } 1043141cc406Sopenharmony_ci} 1044141cc406Sopenharmony_ci 1045141cc406Sopenharmony_ci/*--------------------------------------------------------------------------*/ 1046141cc406Sopenharmony_ci 1047141cc406Sopenharmony_ci/* Returns a string with the value of an option. */ 1048141cc406Sopenharmony_cistatic char *get_option_value(SANE_Handle device, const char *option_name) 1049141cc406Sopenharmony_ci{ 1050141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt; 1051141cc406Sopenharmony_ci void *optval; /* value for the option */ 1052141cc406Sopenharmony_ci int optnum; 1053141cc406Sopenharmony_ci static char str[100]; 1054141cc406Sopenharmony_ci SANE_Status status; 1055141cc406Sopenharmony_ci 1056141cc406Sopenharmony_ci opt = get_optdesc_by_name(device, option_name, &optnum); 1057141cc406Sopenharmony_ci if (opt) { 1058141cc406Sopenharmony_ci 1059141cc406Sopenharmony_ci optval = guards_malloc(opt->size); 1060141cc406Sopenharmony_ci status = sane_control_option (device, optnum, 1061141cc406Sopenharmony_ci SANE_ACTION_GET_VALUE, optval, NULL); 1062141cc406Sopenharmony_ci 1063141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) { 1064141cc406Sopenharmony_ci switch(opt->type) { 1065141cc406Sopenharmony_ci 1066141cc406Sopenharmony_ci case SANE_TYPE_BOOL: 1067141cc406Sopenharmony_ci if (*(SANE_Word*) optval == SANE_FALSE) { 1068141cc406Sopenharmony_ci strcpy(str, "FALSE"); 1069141cc406Sopenharmony_ci } else { 1070141cc406Sopenharmony_ci strcpy(str, "TRUE"); 1071141cc406Sopenharmony_ci } 1072141cc406Sopenharmony_ci break; 1073141cc406Sopenharmony_ci 1074141cc406Sopenharmony_ci case SANE_TYPE_INT: 1075141cc406Sopenharmony_ci sprintf(str, "%d", *(SANE_Word*) optval); 1076141cc406Sopenharmony_ci break; 1077141cc406Sopenharmony_ci 1078141cc406Sopenharmony_ci case SANE_TYPE_FIXED: { 1079141cc406Sopenharmony_ci int i; 1080141cc406Sopenharmony_ci i = SANE_UNFIX(*(SANE_Word*) optval); 1081141cc406Sopenharmony_ci sprintf(str, "%d", i); 1082141cc406Sopenharmony_ci } 1083141cc406Sopenharmony_ci break; 1084141cc406Sopenharmony_ci 1085141cc406Sopenharmony_ci case SANE_TYPE_STRING: 1086141cc406Sopenharmony_ci strcpy(str, optval); 1087141cc406Sopenharmony_ci break; 1088141cc406Sopenharmony_ci 1089141cc406Sopenharmony_ci default: 1090141cc406Sopenharmony_ci str[0] = 0; 1091141cc406Sopenharmony_ci } 1092141cc406Sopenharmony_ci } else { 1093141cc406Sopenharmony_ci /* Shouldn't happen. */ 1094141cc406Sopenharmony_ci strcpy(str, "backend default"); 1095141cc406Sopenharmony_ci } 1096141cc406Sopenharmony_ci 1097141cc406Sopenharmony_ci guards_free(optval); 1098141cc406Sopenharmony_ci 1099141cc406Sopenharmony_ci } else { 1100141cc406Sopenharmony_ci /* The option does not exists. */ 1101141cc406Sopenharmony_ci strcpy(str, "backend default"); 1102141cc406Sopenharmony_ci } 1103141cc406Sopenharmony_ci 1104141cc406Sopenharmony_ci return(str); 1105141cc406Sopenharmony_ci} 1106141cc406Sopenharmony_ci 1107141cc406Sopenharmony_ci/* Display the parameters that used for a scan. */ 1108141cc406Sopenharmony_cistatic char *display_scan_parameters(SANE_Handle device) 1109141cc406Sopenharmony_ci{ 1110141cc406Sopenharmony_ci static char str[150]; 1111141cc406Sopenharmony_ci char *p = str; 1112141cc406Sopenharmony_ci 1113141cc406Sopenharmony_ci *p = 0; 1114141cc406Sopenharmony_ci 1115141cc406Sopenharmony_ci p += sprintf(p, "scan mode=[%s] ", get_option_value(device, SANE_NAME_SCAN_MODE)); 1116141cc406Sopenharmony_ci p += sprintf(p, "resolution=[%s] ", get_option_value(device, SANE_NAME_SCAN_RESOLUTION)); 1117141cc406Sopenharmony_ci 1118141cc406Sopenharmony_ci p += sprintf(p, "tl_x=[%s] ", get_option_value(device, SANE_NAME_SCAN_TL_X)); 1119141cc406Sopenharmony_ci p += sprintf(p, "tl_y=[%s] ", get_option_value(device, SANE_NAME_SCAN_TL_Y)); 1120141cc406Sopenharmony_ci p += sprintf(p, "br_x=[%s] ", get_option_value(device, SANE_NAME_SCAN_BR_X)); 1121141cc406Sopenharmony_ci p += sprintf(p, "br_y=[%s] ", get_option_value(device, SANE_NAME_SCAN_BR_Y)); 1122141cc406Sopenharmony_ci 1123141cc406Sopenharmony_ci return(str); 1124141cc406Sopenharmony_ci} 1125141cc406Sopenharmony_ci 1126141cc406Sopenharmony_ci/* Do a scan to test the correctness of the backend. */ 1127141cc406Sopenharmony_cistatic void test_scan(SANE_Handle device) 1128141cc406Sopenharmony_ci{ 1129141cc406Sopenharmony_ci const SANE_Option_Descriptor *opt; 1130141cc406Sopenharmony_ci SANE_Status status; 1131141cc406Sopenharmony_ci int option_num; 1132141cc406Sopenharmony_ci SANE_Int val_int; 1133141cc406Sopenharmony_ci unsigned char *image = NULL; 1134141cc406Sopenharmony_ci SANE_Parameters params; 1135141cc406Sopenharmony_ci size_t to_read; 1136141cc406Sopenharmony_ci SANE_Int len=0; 1137141cc406Sopenharmony_ci int ask_len; 1138141cc406Sopenharmony_ci int rc; 1139141cc406Sopenharmony_ci int fd; 1140141cc406Sopenharmony_ci 1141141cc406Sopenharmony_ci /* Set the largest scan possible. 1142141cc406Sopenharmony_ci * 1143141cc406Sopenharmony_ci * For that test, the corner 1144141cc406Sopenharmony_ci * position must exists and be SANE_CONSTRAINT_RANGE (this is not 1145141cc406Sopenharmony_ci * a SANE requirement though). 1146141cc406Sopenharmony_ci */ 1147141cc406Sopenharmony_ci opt = get_optdesc_by_name(device, SANE_NAME_SCAN_TL_X, &option_num); 1148141cc406Sopenharmony_ci if (opt) set_min_value(device, option_num, opt); 1149141cc406Sopenharmony_ci 1150141cc406Sopenharmony_ci opt = get_optdesc_by_name(device, SANE_NAME_SCAN_TL_Y, &option_num); 1151141cc406Sopenharmony_ci if (opt) set_min_value(device, option_num, opt); 1152141cc406Sopenharmony_ci 1153141cc406Sopenharmony_ci opt = get_optdesc_by_name(device, SANE_NAME_SCAN_BR_X, &option_num); 1154141cc406Sopenharmony_ci if (opt) set_max_value(device, option_num, opt); 1155141cc406Sopenharmony_ci 1156141cc406Sopenharmony_ci opt = get_optdesc_by_name(device, SANE_NAME_SCAN_BR_Y, &option_num); 1157141cc406Sopenharmony_ci if (opt) set_max_value(device, option_num, opt); 1158141cc406Sopenharmony_ci 1159141cc406Sopenharmony_ci#define IMAGE_SIZE (512 * 1024) 1160141cc406Sopenharmony_ci image = guards_malloc(IMAGE_SIZE); 1161141cc406Sopenharmony_ci 1162141cc406Sopenharmony_ci /* Try a read outside of a scan. */ 1163141cc406Sopenharmony_ci status = sane_read (device, image, len, &len); 1164141cc406Sopenharmony_ci check(ERR, (status != SANE_STATUS_GOOD), 1165141cc406Sopenharmony_ci "it is possible to sane_read outside of a scan"); 1166141cc406Sopenharmony_ci 1167141cc406Sopenharmony_ci /* Try to set the I/O mode outside of a scan. */ 1168141cc406Sopenharmony_ci status = sane_set_io_mode (device, SANE_FALSE); 1169141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_INVAL), 1170141cc406Sopenharmony_ci "it is possible to sane_set_io_mode outside of a scan"); 1171141cc406Sopenharmony_ci status = sane_set_io_mode (device, SANE_TRUE); 1172141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_INVAL || 1173141cc406Sopenharmony_ci status == SANE_STATUS_UNSUPPORTED), 1174141cc406Sopenharmony_ci "it is possible to sane_set_io_mode outside of a scan"); 1175141cc406Sopenharmony_ci 1176141cc406Sopenharmony_ci /* Test sane_get_select_fd outside of a scan. */ 1177141cc406Sopenharmony_ci status = sane_get_select_fd(device, &fd); 1178141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_INVAL || 1179141cc406Sopenharmony_ci status == SANE_STATUS_UNSUPPORTED), 1180141cc406Sopenharmony_ci "sane_get_select_fd outside of a scan returned an invalid status (%s)", 1181141cc406Sopenharmony_ci sane_strstatus (status)); 1182141cc406Sopenharmony_ci 1183141cc406Sopenharmony_ci if (test_level > 2) { 1184141cc406Sopenharmony_ci /* Do a scan, reading byte per byte */ 1185141cc406Sopenharmony_ci check(MSG, 0, "TEST: scan byte per byte - %s", display_scan_parameters(device)); 1186141cc406Sopenharmony_ci 1187141cc406Sopenharmony_ci test_parameters(device, ¶ms); 1188141cc406Sopenharmony_ci status = sane_start (device); 1189141cc406Sopenharmony_ci rc = check(ERR, (status == SANE_STATUS_GOOD), 1190141cc406Sopenharmony_ci "cannot start the scan (%s)", sane_strstatus (status)); 1191141cc406Sopenharmony_ci if (!rc) goto the_end; 1192141cc406Sopenharmony_ci 1193141cc406Sopenharmony_ci /* sane_set_io_mode with SANE_FALSE is always supported. */ 1194141cc406Sopenharmony_ci status = sane_set_io_mode (device, SANE_FALSE); 1195141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 1196141cc406Sopenharmony_ci "sane_set_io_mode with SANE_FALSE must return SANE_STATUS_GOOD"); 1197141cc406Sopenharmony_ci 1198141cc406Sopenharmony_ci /* test sane_set_io_mode with SANE_TRUE. */ 1199141cc406Sopenharmony_ci status = sane_set_io_mode (device, SANE_TRUE); 1200141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD || 1201141cc406Sopenharmony_ci status == SANE_STATUS_UNSUPPORTED), 1202141cc406Sopenharmony_ci "sane_set_io_mode with SANE_TRUE returned an invalid status (%s)", 1203141cc406Sopenharmony_ci sane_strstatus (status)); 1204141cc406Sopenharmony_ci 1205141cc406Sopenharmony_ci /* Put the backend back into blocking mode. */ 1206141cc406Sopenharmony_ci status = sane_set_io_mode (device, SANE_FALSE); 1207141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD), 1208141cc406Sopenharmony_ci "sane_set_io_mode with SANE_FALSE must return SANE_STATUS_GOOD"); 1209141cc406Sopenharmony_ci 1210141cc406Sopenharmony_ci /* Test sane_get_select_fd */ 1211141cc406Sopenharmony_ci fd = 0x76575; /* won't exists */ 1212141cc406Sopenharmony_ci status = sane_get_select_fd(device, &fd); 1213141cc406Sopenharmony_ci check(ERR, (status == SANE_STATUS_GOOD || 1214141cc406Sopenharmony_ci status == SANE_STATUS_UNSUPPORTED), 1215141cc406Sopenharmony_ci "sane_get_select_fd returned an invalid status (%s)", 1216141cc406Sopenharmony_ci sane_strstatus (status)); 1217141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) { 1218141cc406Sopenharmony_ci check(ERR, (fd != 0x76575), 1219141cc406Sopenharmony_ci "sane_get_select_fd didn't set the fd although it should have"); 1220141cc406Sopenharmony_ci check(ERR, (fd >= 0), 1221141cc406Sopenharmony_ci "sane_get_select_fd returned an invalid fd"); 1222141cc406Sopenharmony_ci } 1223141cc406Sopenharmony_ci 1224141cc406Sopenharmony_ci /* Check that it is not possible to set an option. It is probably 1225141cc406Sopenharmony_ci * a requirement stated indirectly in the section 4.4 on code 1226141cc406Sopenharmony_ci * flow. 1227141cc406Sopenharmony_ci */ 1228141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 1229141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, 1230141cc406Sopenharmony_ci &val_int , NULL); 1231141cc406Sopenharmony_ci check(WRN, (status != SANE_STATUS_GOOD), 1232141cc406Sopenharmony_ci "it is possible to set a value during a scan"); 1233141cc406Sopenharmony_ci 1234141cc406Sopenharmony_ci test_parameters(device, ¶ms); 1235141cc406Sopenharmony_ci 1236141cc406Sopenharmony_ci if (params.bytes_per_line != 0 && params.lines != 0) { 1237141cc406Sopenharmony_ci 1238141cc406Sopenharmony_ci to_read = params.bytes_per_line * params.lines; 1239141cc406Sopenharmony_ci while(SANE_TRUE) { 1240141cc406Sopenharmony_ci len = 76457645; /* garbage */ 1241141cc406Sopenharmony_ci guards_set(image, 1); 1242141cc406Sopenharmony_ci status = sane_read (device, image, 1, &len); 1243141cc406Sopenharmony_ci guards_check(image, 1); 1244141cc406Sopenharmony_ci 1245141cc406Sopenharmony_ci if (status == SANE_STATUS_EOF) { 1246141cc406Sopenharmony_ci /* End of scan */ 1247141cc406Sopenharmony_ci check(ERR, (len == 0), 1248141cc406Sopenharmony_ci "the length returned is not 0"); 1249141cc406Sopenharmony_ci break; 1250141cc406Sopenharmony_ci } 1251141cc406Sopenharmony_ci 1252141cc406Sopenharmony_ci rc = check(ERR, (status == SANE_STATUS_GOOD), 1253141cc406Sopenharmony_ci "scan stopped - status is %s", sane_strstatus (status)); 1254141cc406Sopenharmony_ci if (!rc) { 1255141cc406Sopenharmony_ci check(ERR, (len == 0), 1256141cc406Sopenharmony_ci "the length returned is not 0"); 1257141cc406Sopenharmony_ci break; 1258141cc406Sopenharmony_ci } 1259141cc406Sopenharmony_ci 1260141cc406Sopenharmony_ci /* The scanner can only return 1. If it returns 0, we may 1261141cc406Sopenharmony_ci * loop forever. */ 1262141cc406Sopenharmony_ci rc = check(ERR, (len == 1), 1263141cc406Sopenharmony_ci "backend returned 0 bytes - skipping test"); 1264141cc406Sopenharmony_ci if (!rc) { 1265141cc406Sopenharmony_ci break; 1266141cc406Sopenharmony_ci } 1267141cc406Sopenharmony_ci 1268141cc406Sopenharmony_ci to_read -= len; 1269141cc406Sopenharmony_ci } 1270141cc406Sopenharmony_ci 1271141cc406Sopenharmony_ci if (params.lines != -1) { 1272141cc406Sopenharmony_ci check(ERR, (to_read == 0), 1273141cc406Sopenharmony_ci "scan ended, but data was truncated"); 1274141cc406Sopenharmony_ci } 1275141cc406Sopenharmony_ci } 1276141cc406Sopenharmony_ci 1277141cc406Sopenharmony_ci sane_cancel(device); 1278141cc406Sopenharmony_ci } 1279141cc406Sopenharmony_ci 1280141cc406Sopenharmony_ci /* Try a read outside a scan. */ 1281141cc406Sopenharmony_ci ask_len = 1; 1282141cc406Sopenharmony_ci guards_set(image, ask_len); 1283141cc406Sopenharmony_ci status = sane_read (device, image, ask_len, &len); 1284141cc406Sopenharmony_ci guards_check(image, ask_len); 1285141cc406Sopenharmony_ci check(ERR, (status != SANE_STATUS_GOOD), 1286141cc406Sopenharmony_ci "it is possible to sane_read outside a scan"); 1287141cc406Sopenharmony_ci 1288141cc406Sopenharmony_ci 1289141cc406Sopenharmony_ci /* 1290141cc406Sopenharmony_ci * Do a partial scan 1291141cc406Sopenharmony_ci */ 1292141cc406Sopenharmony_ci check(MSG, 0, "TEST: partial scan - %s", display_scan_parameters(device)); 1293141cc406Sopenharmony_ci 1294141cc406Sopenharmony_ci status = sane_start (device); 1295141cc406Sopenharmony_ci rc = check(ERR, (status == SANE_STATUS_GOOD), 1296141cc406Sopenharmony_ci "cannot start the scan (%s)", sane_strstatus (status)); 1297141cc406Sopenharmony_ci if (!rc) goto the_end; 1298141cc406Sopenharmony_ci 1299141cc406Sopenharmony_ci test_parameters(device, ¶ms); 1300141cc406Sopenharmony_ci 1301141cc406Sopenharmony_ci if (params.bytes_per_line != 0 && params.lines != 0) { 1302141cc406Sopenharmony_ci 1303141cc406Sopenharmony_ci len = 10; 1304141cc406Sopenharmony_ci 1305141cc406Sopenharmony_ci guards_set(image, 1); 1306141cc406Sopenharmony_ci status = sane_read (device, image, 1, &len); 1307141cc406Sopenharmony_ci guards_check(image, 1); 1308141cc406Sopenharmony_ci 1309141cc406Sopenharmony_ci check(ERR, (len == 1), 1310141cc406Sopenharmony_ci "sane_read() didn't return 1 byte as requested"); 1311141cc406Sopenharmony_ci } 1312141cc406Sopenharmony_ci 1313141cc406Sopenharmony_ci sane_cancel(device); 1314141cc406Sopenharmony_ci 1315141cc406Sopenharmony_ci 1316141cc406Sopenharmony_ci /* 1317141cc406Sopenharmony_ci * Do a scan, reading random length. 1318141cc406Sopenharmony_ci */ 1319141cc406Sopenharmony_ci check(MSG, 0, "TEST: scan random length - %s", display_scan_parameters(device)); 1320141cc406Sopenharmony_ci 1321141cc406Sopenharmony_ci test_parameters(device, ¶ms); 1322141cc406Sopenharmony_ci 1323141cc406Sopenharmony_ci /* Try a read outside a scan. */ 1324141cc406Sopenharmony_ci ask_len = 20; 1325141cc406Sopenharmony_ci guards_set(image, ask_len); 1326141cc406Sopenharmony_ci status = sane_read (device, image, ask_len, &len); 1327141cc406Sopenharmony_ci guards_check(image, ask_len); 1328141cc406Sopenharmony_ci check(ERR, (status != SANE_STATUS_GOOD), 1329141cc406Sopenharmony_ci "it is possible to sane_read outside a scan"); 1330141cc406Sopenharmony_ci 1331141cc406Sopenharmony_ci status = sane_start (device); 1332141cc406Sopenharmony_ci rc = check(ERR, (status == SANE_STATUS_GOOD), 1333141cc406Sopenharmony_ci "cannot start the scan (%s)", sane_strstatus (status)); 1334141cc406Sopenharmony_ci if (!rc) goto the_end; 1335141cc406Sopenharmony_ci 1336141cc406Sopenharmony_ci /* Check that it is not possible to set an option. */ 1337141cc406Sopenharmony_ci status = sane_control_option (device, option_num, 1338141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, 1339141cc406Sopenharmony_ci &val_int , NULL); 1340141cc406Sopenharmony_ci check(WRN, (status != SANE_STATUS_GOOD), 1341141cc406Sopenharmony_ci "it is possible to set a value during a scan"); 1342141cc406Sopenharmony_ci 1343141cc406Sopenharmony_ci test_parameters(device, ¶ms); 1344141cc406Sopenharmony_ci 1345141cc406Sopenharmony_ci if (params.bytes_per_line != 0 && params.lines != 0) { 1346141cc406Sopenharmony_ci 1347141cc406Sopenharmony_ci to_read = params.bytes_per_line * params.lines; 1348141cc406Sopenharmony_ci srandom(time(NULL)); 1349141cc406Sopenharmony_ci 1350141cc406Sopenharmony_ci while (SANE_TRUE) { 1351141cc406Sopenharmony_ci 1352141cc406Sopenharmony_ci ask_len = rand() & 0x7ffff; /* 0 to 512K-1 */ 1353141cc406Sopenharmony_ci if (ask_len == 0) len = 1; 1354141cc406Sopenharmony_ci len = ask_len + 4978; /* garbage */ 1355141cc406Sopenharmony_ci 1356141cc406Sopenharmony_ci guards_set(image, ask_len); 1357141cc406Sopenharmony_ci status = sane_read (device, image, ask_len, &len); 1358141cc406Sopenharmony_ci guards_check(image, ask_len); 1359141cc406Sopenharmony_ci 1360141cc406Sopenharmony_ci if (status == SANE_STATUS_EOF) { 1361141cc406Sopenharmony_ci /* End of scan */ 1362141cc406Sopenharmony_ci check(ERR, (len == 0), 1363141cc406Sopenharmony_ci "the length returned is not 0"); 1364141cc406Sopenharmony_ci break; 1365141cc406Sopenharmony_ci } 1366141cc406Sopenharmony_ci 1367141cc406Sopenharmony_ci rc = check(ERR, (status == SANE_STATUS_GOOD), 1368141cc406Sopenharmony_ci "scan stopped - status is %s", sane_strstatus (status)); 1369141cc406Sopenharmony_ci if (!rc) { 1370141cc406Sopenharmony_ci check(ERR, (len == 0), 1371141cc406Sopenharmony_ci "the length returned is not 0"); 1372141cc406Sopenharmony_ci break; 1373141cc406Sopenharmony_ci } 1374141cc406Sopenharmony_ci 1375141cc406Sopenharmony_ci /* The scanner cannot return 0. If it returns 0, we may 1376141cc406Sopenharmony_ci * loop forever. */ 1377141cc406Sopenharmony_ci rc = check(ERR, (len > 0), 1378141cc406Sopenharmony_ci "backend didn't return any data - skipping test"); 1379141cc406Sopenharmony_ci if (!rc) { 1380141cc406Sopenharmony_ci break; 1381141cc406Sopenharmony_ci } 1382141cc406Sopenharmony_ci rc = check(ERR, (len <= ask_len), 1383141cc406Sopenharmony_ci "backend returned too much data (%d / %d) - skipping test", 1384141cc406Sopenharmony_ci len, ask_len); 1385141cc406Sopenharmony_ci if (!rc) { 1386141cc406Sopenharmony_ci break; 1387141cc406Sopenharmony_ci } 1388141cc406Sopenharmony_ci 1389141cc406Sopenharmony_ci to_read -= len; 1390141cc406Sopenharmony_ci } 1391141cc406Sopenharmony_ci 1392141cc406Sopenharmony_ci if (params.lines != -1) { 1393141cc406Sopenharmony_ci check(ERR, (to_read == 0), 1394141cc406Sopenharmony_ci "scan ended, but data was truncated"); 1395141cc406Sopenharmony_ci } 1396141cc406Sopenharmony_ci } 1397141cc406Sopenharmony_ci 1398141cc406Sopenharmony_ci sane_cancel(device); 1399141cc406Sopenharmony_ci 1400141cc406Sopenharmony_ci /* Try a read outside a scan. */ 1401141cc406Sopenharmony_ci ask_len = 30; 1402141cc406Sopenharmony_ci guards_set(image, ask_len); 1403141cc406Sopenharmony_ci status = sane_read (device, image, ask_len, &len); 1404141cc406Sopenharmony_ci guards_check(image, ask_len); 1405141cc406Sopenharmony_ci check(ERR, (status != SANE_STATUS_GOOD), 1406141cc406Sopenharmony_ci "it is possible to sane_read outside a scan"); 1407141cc406Sopenharmony_ci 1408141cc406Sopenharmony_ci /* 1409141cc406Sopenharmony_ci * Do a scan with a fixed size and a big buffer 1410141cc406Sopenharmony_ci */ 1411141cc406Sopenharmony_ci check(MSG, 0, "TEST: scan with a big max_len - %s", display_scan_parameters(device)); 1412141cc406Sopenharmony_ci 1413141cc406Sopenharmony_ci test_parameters(device, ¶ms); 1414141cc406Sopenharmony_ci 1415141cc406Sopenharmony_ci status = sane_start (device); 1416141cc406Sopenharmony_ci rc = check(ERR, (status == SANE_STATUS_GOOD), 1417141cc406Sopenharmony_ci "cannot start the scan (%s)", sane_strstatus (status)); 1418141cc406Sopenharmony_ci if (!rc) goto the_end; 1419141cc406Sopenharmony_ci 1420141cc406Sopenharmony_ci test_parameters(device, ¶ms); 1421141cc406Sopenharmony_ci 1422141cc406Sopenharmony_ci if (params.bytes_per_line != 0 && params.lines != 0) { 1423141cc406Sopenharmony_ci 1424141cc406Sopenharmony_ci to_read = params.bytes_per_line * params.lines; 1425141cc406Sopenharmony_ci while(SANE_TRUE) { 1426141cc406Sopenharmony_ci ask_len = IMAGE_SIZE; 1427141cc406Sopenharmony_ci len = rand(); /* garbage */ 1428141cc406Sopenharmony_ci 1429141cc406Sopenharmony_ci guards_set(image, ask_len); 1430141cc406Sopenharmony_ci status = sane_read (device, image, ask_len, &len); 1431141cc406Sopenharmony_ci guards_check(image, ask_len); 1432141cc406Sopenharmony_ci 1433141cc406Sopenharmony_ci if (status == SANE_STATUS_EOF) { 1434141cc406Sopenharmony_ci /* End of scan */ 1435141cc406Sopenharmony_ci check(ERR, (len == 0), 1436141cc406Sopenharmony_ci "the length returned is not 0"); 1437141cc406Sopenharmony_ci break; 1438141cc406Sopenharmony_ci } 1439141cc406Sopenharmony_ci 1440141cc406Sopenharmony_ci rc = check(ERR, (status == SANE_STATUS_GOOD), 1441141cc406Sopenharmony_ci "scan stopped - status is %s", sane_strstatus (status)); 1442141cc406Sopenharmony_ci if (!rc) { 1443141cc406Sopenharmony_ci check(ERR, (len == 0), 1444141cc406Sopenharmony_ci "the length returned is not 0"); 1445141cc406Sopenharmony_ci break; 1446141cc406Sopenharmony_ci } 1447141cc406Sopenharmony_ci 1448141cc406Sopenharmony_ci /* If the scanner return 0, we may loop forever. */ 1449141cc406Sopenharmony_ci rc = check(ERR, (len > 0), 1450141cc406Sopenharmony_ci "backend didn't return any data - skipping test"); 1451141cc406Sopenharmony_ci if (!rc) { 1452141cc406Sopenharmony_ci break; 1453141cc406Sopenharmony_ci } 1454141cc406Sopenharmony_ci 1455141cc406Sopenharmony_ci rc = check(ERR, (len <= ask_len), 1456141cc406Sopenharmony_ci "backend returned too much data (%d / %d) - skipping test", 1457141cc406Sopenharmony_ci len, ask_len); 1458141cc406Sopenharmony_ci if (!rc) { 1459141cc406Sopenharmony_ci break; 1460141cc406Sopenharmony_ci } 1461141cc406Sopenharmony_ci 1462141cc406Sopenharmony_ci to_read -= len; 1463141cc406Sopenharmony_ci } 1464141cc406Sopenharmony_ci 1465141cc406Sopenharmony_ci if (params.lines != -1) { 1466141cc406Sopenharmony_ci check(ERR, (to_read == 0), 1467141cc406Sopenharmony_ci "scan ended, but data was truncated"); 1468141cc406Sopenharmony_ci } 1469141cc406Sopenharmony_ci } 1470141cc406Sopenharmony_ci 1471141cc406Sopenharmony_ci sane_cancel(device); 1472141cc406Sopenharmony_ci 1473141cc406Sopenharmony_ci the_end: 1474141cc406Sopenharmony_ci if (image) guards_free(image); 1475141cc406Sopenharmony_ci} 1476141cc406Sopenharmony_ci 1477141cc406Sopenharmony_ci/* Do several scans at different scan mode and resolution. */ 1478141cc406Sopenharmony_cistatic void test_scans(SANE_Device * device) 1479141cc406Sopenharmony_ci{ 1480141cc406Sopenharmony_ci const SANE_Option_Descriptor *scan_mode_opt; 1481141cc406Sopenharmony_ci const SANE_Option_Descriptor *resolution_mode_opt; 1482141cc406Sopenharmony_ci SANE_Status status; 1483141cc406Sopenharmony_ci int scan_mode_optnum; 1484141cc406Sopenharmony_ci int resolution_mode_optnum; 1485141cc406Sopenharmony_ci SANE_String val_string; 1486141cc406Sopenharmony_ci int i; 1487141cc406Sopenharmony_ci int rc; 1488141cc406Sopenharmony_ci 1489141cc406Sopenharmony_ci /* For that test, the requirements are: 1490141cc406Sopenharmony_ci * SANE_NAME_SCAN_MODE exists and is a SANE_CONSTRAINT_STRING_LIST 1491141cc406Sopenharmony_ci * SANE_NAME_SCAN_RESOLUTION exists and is either a SANE_CONSTRAINT_WORD_LIST or a SANE_CONSTRAINT_RANGE. 1492141cc406Sopenharmony_ci * 1493141cc406Sopenharmony_ci * These are not a SANE requirement, though. 1494141cc406Sopenharmony_ci */ 1495141cc406Sopenharmony_ci 1496141cc406Sopenharmony_ci scan_mode_opt = get_optdesc_by_name(device, SANE_NAME_SCAN_MODE, &scan_mode_optnum); 1497141cc406Sopenharmony_ci if (scan_mode_opt) { 1498141cc406Sopenharmony_ci 1499141cc406Sopenharmony_ci rc = check(INF, (scan_mode_opt->type == SANE_TYPE_STRING), 1500141cc406Sopenharmony_ci "option [%s] is not a SANE_TYPE_STRING - skipping test", SANE_NAME_SCAN_MODE); 1501141cc406Sopenharmony_ci if (!rc) return; 1502141cc406Sopenharmony_ci rc = check(INF, (scan_mode_opt->constraint_type == SANE_CONSTRAINT_STRING_LIST), 1503141cc406Sopenharmony_ci "constraint for option [%s] is not SANE_CONSTRAINT_STRING_LIST - skipping test", SANE_NAME_SCAN_MODE); 1504141cc406Sopenharmony_ci if (!rc) return; 1505141cc406Sopenharmony_ci rc = check(INF, (SANE_OPTION_IS_SETTABLE(scan_mode_opt->cap)), 1506141cc406Sopenharmony_ci "option [%s] is not settable - skipping test", SANE_NAME_SCAN_MODE); 1507141cc406Sopenharmony_ci if (!rc) return; 1508141cc406Sopenharmony_ci } 1509141cc406Sopenharmony_ci 1510141cc406Sopenharmony_ci resolution_mode_opt = get_optdesc_by_name(device, SANE_NAME_SCAN_RESOLUTION, &resolution_mode_optnum); 1511141cc406Sopenharmony_ci if (resolution_mode_opt) { 1512141cc406Sopenharmony_ci rc = check(INF, (SANE_OPTION_IS_SETTABLE(resolution_mode_opt->cap)), 1513141cc406Sopenharmony_ci "option [%s] is not settable - skipping test", SANE_NAME_SCAN_RESOLUTION); 1514141cc406Sopenharmony_ci if (!rc) return; 1515141cc406Sopenharmony_ci } 1516141cc406Sopenharmony_ci 1517141cc406Sopenharmony_ci if (scan_mode_opt) { 1518141cc406Sopenharmony_ci /* Do several scans, with several resolution. */ 1519141cc406Sopenharmony_ci for (i=0; scan_mode_opt->constraint.string_list[i] != NULL; i++) { 1520141cc406Sopenharmony_ci 1521141cc406Sopenharmony_ci val_string = strdup(scan_mode_opt->constraint.string_list[i]); 1522141cc406Sopenharmony_ci assert(val_string); 1523141cc406Sopenharmony_ci 1524141cc406Sopenharmony_ci status = sane_control_option (device, scan_mode_optnum, 1525141cc406Sopenharmony_ci SANE_ACTION_SET_VALUE, val_string, NULL); 1526141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1527141cc406Sopenharmony_ci "cannot set a settable option (status=%s)", sane_strstatus(status)); 1528141cc406Sopenharmony_ci 1529141cc406Sopenharmony_ci free(val_string); 1530141cc406Sopenharmony_ci 1531141cc406Sopenharmony_ci if (resolution_mode_opt) { 1532141cc406Sopenharmony_ci set_min_value(device, resolution_mode_optnum, 1533141cc406Sopenharmony_ci resolution_mode_opt); 1534141cc406Sopenharmony_ci test_scan(device); 1535141cc406Sopenharmony_ci 1536141cc406Sopenharmony_ci set_max_value(device, resolution_mode_optnum, 1537141cc406Sopenharmony_ci resolution_mode_opt); 1538141cc406Sopenharmony_ci test_scan(device); 1539141cc406Sopenharmony_ci 1540141cc406Sopenharmony_ci set_random_value(device, resolution_mode_optnum, 1541141cc406Sopenharmony_ci resolution_mode_opt); 1542141cc406Sopenharmony_ci test_scan(device); 1543141cc406Sopenharmony_ci } else { 1544141cc406Sopenharmony_ci test_scan(device); 1545141cc406Sopenharmony_ci } 1546141cc406Sopenharmony_ci } 1547141cc406Sopenharmony_ci } else { 1548141cc406Sopenharmony_ci if (resolution_mode_opt) { 1549141cc406Sopenharmony_ci set_min_value(device, resolution_mode_optnum, 1550141cc406Sopenharmony_ci resolution_mode_opt); 1551141cc406Sopenharmony_ci test_scan(device); 1552141cc406Sopenharmony_ci 1553141cc406Sopenharmony_ci set_max_value(device, resolution_mode_optnum, 1554141cc406Sopenharmony_ci resolution_mode_opt); 1555141cc406Sopenharmony_ci test_scan(device); 1556141cc406Sopenharmony_ci 1557141cc406Sopenharmony_ci set_random_value(device, resolution_mode_optnum, 1558141cc406Sopenharmony_ci resolution_mode_opt); 1559141cc406Sopenharmony_ci test_scan(device); 1560141cc406Sopenharmony_ci } else { 1561141cc406Sopenharmony_ci test_scan(device); 1562141cc406Sopenharmony_ci } 1563141cc406Sopenharmony_ci } 1564141cc406Sopenharmony_ci} 1565141cc406Sopenharmony_ci 1566141cc406Sopenharmony_ci/** test sane_get_devices 1567141cc406Sopenharmony_ci * test sane_get_device function, if time is greter than 0, 1568141cc406Sopenharmony_ci * loop to let tester plug/unplug device to check for correct 1569141cc406Sopenharmony_ci * hotplug detection 1570141cc406Sopenharmony_ci * @param device_list device list to fill 1571141cc406Sopenharmony_ci * @param time time to loop 1572141cc406Sopenharmony_ci * @return 0 on success 1573141cc406Sopenharmony_ci */ 1574141cc406Sopenharmony_cistatic int test_get_devices(const SANE_Device ***device_list, int time) 1575141cc406Sopenharmony_ci{ 1576141cc406Sopenharmony_ciint loop=0; 1577141cc406Sopenharmony_ciint i; 1578141cc406Sopenharmony_ciconst SANE_Device *dev; 1579141cc406Sopenharmony_ciSANE_Status status; 1580141cc406Sopenharmony_ci 1581141cc406Sopenharmony_ci status = sane_get_devices (device_list, SANE_TRUE); 1582141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1583141cc406Sopenharmony_ci "sane_get_devices() failed (%s)", sane_strstatus (status)); 1584141cc406Sopenharmony_ci 1585141cc406Sopenharmony_ci /* Verify that the SANE doc (or tstbackend) is up to date */ 1586141cc406Sopenharmony_ci for (i=0; (*device_list)[i] != NULL; i++) { 1587141cc406Sopenharmony_ci 1588141cc406Sopenharmony_ci dev = (*device_list)[i]; 1589141cc406Sopenharmony_ci 1590141cc406Sopenharmony_ci check(FATAL, (dev->name != NULL), "device name is NULL"); 1591141cc406Sopenharmony_ci check(FATAL, (dev->vendor != NULL), "device vendor is NULL"); 1592141cc406Sopenharmony_ci check(FATAL, (dev->type != NULL), "device type is NULL"); 1593141cc406Sopenharmony_ci check(FATAL, (dev->model != NULL), "device model is NULL"); 1594141cc406Sopenharmony_ci 1595141cc406Sopenharmony_ci check(INF, ((strcmp(dev->type, "flatbed scanner") == 0) || 1596141cc406Sopenharmony_ci (strcmp(dev->type, "frame grabber") == 0) || 1597141cc406Sopenharmony_ci (strcmp(dev->type, "handheld scanner") == 0) || 1598141cc406Sopenharmony_ci (strcmp(dev->type, "still camera") == 0) || 1599141cc406Sopenharmony_ci (strcmp(dev->type, "video camera") == 0) || 1600141cc406Sopenharmony_ci (strcmp(dev->type, "virtual device") == 0) || 1601141cc406Sopenharmony_ci (strcmp(dev->type, "film scanner") == 0) || 1602141cc406Sopenharmony_ci (strcmp(dev->type, "multi-function peripheral") == 0) || 1603141cc406Sopenharmony_ci (strcmp(dev->type, "sheetfed scanner") == 0)), 1604141cc406Sopenharmony_ci "unknown device type [%s]. Update SANE doc section \"Type Strings\"", dev->type); 1605141cc406Sopenharmony_ci 1606141cc406Sopenharmony_ci check(INF, ( 1607141cc406Sopenharmony_ci (strcmp(dev->vendor, "AGFA") == 0) || 1608141cc406Sopenharmony_ci (strcmp(dev->vendor, "Abaton") == 0) || 1609141cc406Sopenharmony_ci (strcmp(dev->vendor, "Acer") == 0) || 1610141cc406Sopenharmony_ci (strcmp(dev->vendor, "Apple") == 0) || 1611141cc406Sopenharmony_ci (strcmp(dev->vendor, "Artec") == 0) || 1612141cc406Sopenharmony_ci (strcmp(dev->vendor, "Avision") == 0) || 1613141cc406Sopenharmony_ci (strcmp(dev->vendor, "CANON") == 0) || 1614141cc406Sopenharmony_ci (strcmp(dev->vendor, "Connectix") == 0) || 1615141cc406Sopenharmony_ci (strcmp(dev->vendor, "Epson") == 0) || 1616141cc406Sopenharmony_ci (strcmp(dev->vendor, "Fujitsu") == 0) || 1617141cc406Sopenharmony_ci (strcmp(dev->vendor, "Gphoto2") == 0) || 1618141cc406Sopenharmony_ci (strcmp(dev->vendor, "Hewlett-Packard") == 0) || 1619141cc406Sopenharmony_ci (strcmp(dev->vendor, "IBM") == 0) || 1620141cc406Sopenharmony_ci (strcmp(dev->vendor, "Kodak") == 0) || 1621141cc406Sopenharmony_ci (strcmp(dev->vendor, "Lexmark") == 0) || 1622141cc406Sopenharmony_ci (strcmp(dev->vendor, "Logitech") == 0) || 1623141cc406Sopenharmony_ci (strcmp(dev->vendor, "Microtek") == 0) || 1624141cc406Sopenharmony_ci (strcmp(dev->vendor, "Minolta") == 0) || 1625141cc406Sopenharmony_ci (strcmp(dev->vendor, "Mitsubishi") == 0) || 1626141cc406Sopenharmony_ci (strcmp(dev->vendor, "Mustek") == 0) || 1627141cc406Sopenharmony_ci (strcmp(dev->vendor, "NEC") == 0) || 1628141cc406Sopenharmony_ci (strcmp(dev->vendor, "Nikon") == 0) || 1629141cc406Sopenharmony_ci (strcmp(dev->vendor, "Noname") == 0) || 1630141cc406Sopenharmony_ci (strcmp(dev->vendor, "Plustek") == 0) || 1631141cc406Sopenharmony_ci (strcmp(dev->vendor, "Polaroid") == 0) || 1632141cc406Sopenharmony_ci (strcmp(dev->vendor, "Relisys") == 0) || 1633141cc406Sopenharmony_ci (strcmp(dev->vendor, "Ricoh") == 0) || 1634141cc406Sopenharmony_ci (strcmp(dev->vendor, "Sharp") == 0) || 1635141cc406Sopenharmony_ci (strcmp(dev->vendor, "Siemens") == 0) || 1636141cc406Sopenharmony_ci (strcmp(dev->vendor, "Tamarack") == 0) || 1637141cc406Sopenharmony_ci (strcmp(dev->vendor, "UMAX") == 0)), 1638141cc406Sopenharmony_ci "unknown device vendor [%s]. Update SANE doc section \"Vendor Strings\"", dev->vendor); 1639141cc406Sopenharmony_ci } 1640141cc406Sopenharmony_ci 1641141cc406Sopenharmony_ci /* loop on detecting device to let time to plug/unplug scanners */ 1642141cc406Sopenharmony_ci while(loop<time) { 1643141cc406Sopenharmony_ci /* print and free detected device list */ 1644141cc406Sopenharmony_ci check(MSG, 0, "DETECTED DEVICES:"); 1645141cc406Sopenharmony_ci for (i=0; (*device_list)[i] != NULL; i++) { 1646141cc406Sopenharmony_ci dev = (*device_list)[i]; 1647141cc406Sopenharmony_ci check(MSG, 0, "\t%s:%s %s:%s", dev->vendor, dev->name, dev->type, dev->model); 1648141cc406Sopenharmony_ci } 1649141cc406Sopenharmony_ci if(i==0) { 1650141cc406Sopenharmony_ci check(MSG, 0, "\tnone..."); 1651141cc406Sopenharmony_ci } 1652141cc406Sopenharmony_ci sleep(1); 1653141cc406Sopenharmony_ci (*device_list) = NULL; 1654141cc406Sopenharmony_ci status = sane_get_devices (device_list, SANE_TRUE); 1655141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1656141cc406Sopenharmony_ci "sane_get_devices() failed (%s)", sane_strstatus (status)); 1657141cc406Sopenharmony_ci loop++; 1658141cc406Sopenharmony_ci } 1659141cc406Sopenharmony_ci return 0; 1660141cc406Sopenharmony_ci} 1661141cc406Sopenharmony_ci 1662141cc406Sopenharmony_ci/** test test_default 1663141cc406Sopenharmony_ci * test by scanning using default values 1664141cc406Sopenharmony_ci * @param device device to use for the scan 1665141cc406Sopenharmony_ci */ 1666141cc406Sopenharmony_cistatic void test_default(SANE_Device * device) 1667141cc406Sopenharmony_ci{ 1668141cc406Sopenharmony_ci test_scan(device); 1669141cc406Sopenharmony_ci} 1670141cc406Sopenharmony_ci 1671141cc406Sopenharmony_cistatic void usage(const char *execname) 1672141cc406Sopenharmony_ci{ 1673141cc406Sopenharmony_ci printf("Usage: %s [-d backend_name] [-l test_level] [-s] [-r recursion_level] [-g time (s)]\n", execname); 1674141cc406Sopenharmony_ci printf("\t-v\tverbose level\n"); 1675141cc406Sopenharmony_ci printf("\t-d\tbackend name\n"); 1676141cc406Sopenharmony_ci printf("\t-l\tlevel of testing (0=some, 1=0+options, 2=1+scans, 3=longest tests)\n"); 1677141cc406Sopenharmony_ci printf("\t-s\tdo a scan during open/close tests\n"); 1678141cc406Sopenharmony_ci printf("\t-r\trecursion level for option testing (the higher, the longer)\n"); 1679141cc406Sopenharmony_ci printf("\t-g\ttime to loop on sane_get_devices function to test scannet hotplug detection (time is in seconds).\n"); 1680141cc406Sopenharmony_ci} 1681141cc406Sopenharmony_ci 1682141cc406Sopenharmony_ciint 1683141cc406Sopenharmony_cimain (int argc, char **argv) 1684141cc406Sopenharmony_ci{ 1685141cc406Sopenharmony_ci char *devname = NULL; 1686141cc406Sopenharmony_ci SANE_Status status; 1687141cc406Sopenharmony_ci SANE_Int version_code; 1688141cc406Sopenharmony_ci SANE_Handle device; 1689141cc406Sopenharmony_ci int ch; 1690141cc406Sopenharmony_ci int index; 1691141cc406Sopenharmony_ci int i; 1692141cc406Sopenharmony_ci const SANE_Device **device_list; 1693141cc406Sopenharmony_ci int rc; 1694141cc406Sopenharmony_ci int recursion_level; 1695141cc406Sopenharmony_ci int time; 1696141cc406Sopenharmony_ci int default_scan; 1697141cc406Sopenharmony_ci 1698141cc406Sopenharmony_ci printf("tstbackend, Copyright (C) 2002 Frank Zago\n"); 1699141cc406Sopenharmony_ci printf("tstbackend comes with ABSOLUTELY NO WARRANTY\n"); 1700141cc406Sopenharmony_ci printf("This is free software, and you are welcome to redistribute it\n"); 1701141cc406Sopenharmony_ci printf("under certain conditions. See COPYING file for details\n\n"); 1702141cc406Sopenharmony_ci printf("This is tstbackend build %d\n\n", BUILD); 1703141cc406Sopenharmony_ci 1704141cc406Sopenharmony_ci /* Read the command line options. */ 1705141cc406Sopenharmony_ci opterr = 0; 1706141cc406Sopenharmony_ci recursion_level = 5; /* 5 levels or recursion should be enough */ 1707141cc406Sopenharmony_ci test_level = 0; /* basic tests only */ 1708141cc406Sopenharmony_ci time = 0; /* no get devices loop */ 1709141cc406Sopenharmony_ci default_scan = 0; 1710141cc406Sopenharmony_ci 1711141cc406Sopenharmony_ci while ((ch = getopt_long (argc, argv, "-v:d:l:r:g:h:s", basic_options, 1712141cc406Sopenharmony_ci &index)) != EOF) { 1713141cc406Sopenharmony_ci switch(ch) { 1714141cc406Sopenharmony_ci case 'v': 1715141cc406Sopenharmony_ci verbose_level = atoi(optarg); 1716141cc406Sopenharmony_ci break; 1717141cc406Sopenharmony_ci 1718141cc406Sopenharmony_ci case 'd': 1719141cc406Sopenharmony_ci devname = strdup(optarg); 1720141cc406Sopenharmony_ci break; 1721141cc406Sopenharmony_ci 1722141cc406Sopenharmony_ci case 'l': 1723141cc406Sopenharmony_ci test_level = atoi(optarg); 1724141cc406Sopenharmony_ci if (test_level < 0 || test_level > 4) { 1725141cc406Sopenharmony_ci fprintf(stderr, "invalid test_level\n"); 1726141cc406Sopenharmony_ci return(1); 1727141cc406Sopenharmony_ci } 1728141cc406Sopenharmony_ci break; 1729141cc406Sopenharmony_ci 1730141cc406Sopenharmony_ci case 's': 1731141cc406Sopenharmony_ci default_scan = 1; 1732141cc406Sopenharmony_ci break; 1733141cc406Sopenharmony_ci 1734141cc406Sopenharmony_ci case 'r': 1735141cc406Sopenharmony_ci recursion_level = atoi(optarg); 1736141cc406Sopenharmony_ci break; 1737141cc406Sopenharmony_ci 1738141cc406Sopenharmony_ci case 'g': 1739141cc406Sopenharmony_ci time = atoi(optarg); 1740141cc406Sopenharmony_ci break; 1741141cc406Sopenharmony_ci 1742141cc406Sopenharmony_ci case 'h': 1743141cc406Sopenharmony_ci usage(argv[0]); 1744141cc406Sopenharmony_ci return(0); 1745141cc406Sopenharmony_ci 1746141cc406Sopenharmony_ci case '?': 1747141cc406Sopenharmony_ci fprintf(stderr, "invalid option\n"); 1748141cc406Sopenharmony_ci return(1); 1749141cc406Sopenharmony_ci 1750141cc406Sopenharmony_ci default: 1751141cc406Sopenharmony_ci fprintf(stderr, "bug in tstbackend\n"); 1752141cc406Sopenharmony_ci return(1); 1753141cc406Sopenharmony_ci } 1754141cc406Sopenharmony_ci } 1755141cc406Sopenharmony_ci 1756141cc406Sopenharmony_ci /* First test */ 1757141cc406Sopenharmony_ci check(MSG, 0, "TEST: init/exit"); 1758141cc406Sopenharmony_ci for (i=0; i<10; i++) { 1759141cc406Sopenharmony_ci /* Test 1. init/exit with a version code */ 1760141cc406Sopenharmony_ci status = sane_init(&version_code, NULL); 1761141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1762141cc406Sopenharmony_ci "sane_init failed with %s", sane_strstatus (status)); 1763141cc406Sopenharmony_ci check(FATAL, (SANE_VERSION_MAJOR(version_code) == 1), 1764141cc406Sopenharmony_ci "invalid SANE version linked"); 1765141cc406Sopenharmony_ci sane_exit(); 1766141cc406Sopenharmony_ci 1767141cc406Sopenharmony_ci /* Test 2. init/exit without a version code */ 1768141cc406Sopenharmony_ci status = sane_init(NULL, NULL); 1769141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1770141cc406Sopenharmony_ci "sane_init failed with %s", sane_strstatus (status)); 1771141cc406Sopenharmony_ci sane_exit(); 1772141cc406Sopenharmony_ci 1773141cc406Sopenharmony_ci /* Test 3. Init/get_devices/open invalid/exit */ 1774141cc406Sopenharmony_ci status = sane_init(NULL, NULL); 1775141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1776141cc406Sopenharmony_ci "sane_init failed with %s", sane_strstatus (status)); 1777141cc406Sopenharmony_ci 1778141cc406Sopenharmony_ci status = sane_get_devices (&device_list, SANE_TRUE); 1779141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1780141cc406Sopenharmony_ci "sane_get_devices() failed (%s)", sane_strstatus (status)); 1781141cc406Sopenharmony_ci 1782141cc406Sopenharmony_ci status = sane_open ("opihndvses75bvt6fg", &device); 1783141cc406Sopenharmony_ci check(WRN, (status == SANE_STATUS_INVAL), 1784141cc406Sopenharmony_ci "sane_open() failed (%s)", sane_strstatus (status)); 1785141cc406Sopenharmony_ci 1786141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 1787141cc406Sopenharmony_ci sane_close(device); 1788141cc406Sopenharmony_ci 1789141cc406Sopenharmony_ci sane_exit(); 1790141cc406Sopenharmony_ci 1791141cc406Sopenharmony_ci /* Test 4. Init/get_devices/open default/exit */ 1792141cc406Sopenharmony_ci status = sane_init(NULL, NULL); 1793141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1794141cc406Sopenharmony_ci "sane_init failed with %s", sane_strstatus (status)); 1795141cc406Sopenharmony_ci 1796141cc406Sopenharmony_ci status = sane_get_devices (&device_list, SANE_TRUE); 1797141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1798141cc406Sopenharmony_ci "sane_get_devices() failed (%s)", sane_strstatus (status)); 1799141cc406Sopenharmony_ci 1800141cc406Sopenharmony_ci status = sane_open ("", &device); 1801141cc406Sopenharmony_ci if (status == SANE_STATUS_GOOD) 1802141cc406Sopenharmony_ci sane_close(device); 1803141cc406Sopenharmony_ci 1804141cc406Sopenharmony_ci sane_exit(); 1805141cc406Sopenharmony_ci } 1806141cc406Sopenharmony_ci 1807141cc406Sopenharmony_ci status = sane_init (&version_code, NULL); 1808141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1809141cc406Sopenharmony_ci "sane_init failed with %s", sane_strstatus (status)); 1810141cc406Sopenharmony_ci 1811141cc406Sopenharmony_ci /* Check the device list */ 1812141cc406Sopenharmony_ci rc = test_get_devices(&device_list, time); 1813141cc406Sopenharmony_ci if (rc) goto the_exit; 1814141cc406Sopenharmony_ci 1815141cc406Sopenharmony_ci if (!devname) { 1816141cc406Sopenharmony_ci /* If no device name was specified explicitly, we look at the 1817141cc406Sopenharmony_ci environment variable SANE_DEFAULT_DEVICE. If this variable 1818141cc406Sopenharmony_ci is not set, we open the first device we find (if any): */ 1819141cc406Sopenharmony_ci devname = getenv ("SANE_DEFAULT_DEVICE"); 1820141cc406Sopenharmony_ci if (devname) devname = strdup(devname); 1821141cc406Sopenharmony_ci } 1822141cc406Sopenharmony_ci 1823141cc406Sopenharmony_ci if (!devname) { 1824141cc406Sopenharmony_ci if (device_list[0]) { 1825141cc406Sopenharmony_ci devname = strdup(device_list[0]->name); 1826141cc406Sopenharmony_ci } 1827141cc406Sopenharmony_ci } 1828141cc406Sopenharmony_ci 1829141cc406Sopenharmony_ci rc = check(ERR, (devname != NULL), 1830141cc406Sopenharmony_ci "no SANE devices found"); 1831141cc406Sopenharmony_ci if (!rc) goto the_exit; 1832141cc406Sopenharmony_ci 1833141cc406Sopenharmony_ci check(MSG, 0, "using device %s", devname); 1834141cc406Sopenharmony_ci 1835141cc406Sopenharmony_ci /* Test open close */ 1836141cc406Sopenharmony_ci check(MSG, 0, "TEST: open/close"); 1837141cc406Sopenharmony_ci for (i=0; i<10; i++) { 1838141cc406Sopenharmony_ci status = sane_open (devname, &device); 1839141cc406Sopenharmony_ci rc = check(ERR, (status == SANE_STATUS_GOOD), 1840141cc406Sopenharmony_ci "sane_open failed with %s for device %s", sane_strstatus (status), devname); 1841141cc406Sopenharmony_ci if (!rc) goto the_exit; 1842141cc406Sopenharmony_ci 1843141cc406Sopenharmony_ci if (default_scan) { 1844141cc406Sopenharmony_ci test_default (device); 1845141cc406Sopenharmony_ci } 1846141cc406Sopenharmony_ci sane_close (device); 1847141cc406Sopenharmony_ci } 1848141cc406Sopenharmony_ci 1849141cc406Sopenharmony_ci if (test_level < 1) { 1850141cc406Sopenharmony_ci sane_exit(); 1851141cc406Sopenharmony_ci goto the_exit; 1852141cc406Sopenharmony_ci } 1853141cc406Sopenharmony_ci 1854141cc406Sopenharmony_ci 1855141cc406Sopenharmony_ci /* Test options */ 1856141cc406Sopenharmony_ci check(MSG, 0, "TEST: options consistency"); 1857141cc406Sopenharmony_ci status = sane_open (devname, &device); 1858141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1859141cc406Sopenharmony_ci "sane_open failed with %s for device %s", sane_strstatus (status), devname); 1860141cc406Sopenharmony_ci 1861141cc406Sopenharmony_ci test_parameters(device, NULL); 1862141cc406Sopenharmony_ci test_options(device, recursion_level); 1863141cc406Sopenharmony_ci sane_close (device); 1864141cc406Sopenharmony_ci sane_exit(); 1865141cc406Sopenharmony_ci 1866141cc406Sopenharmony_ci if (test_level < 2) { 1867141cc406Sopenharmony_ci goto the_exit; 1868141cc406Sopenharmony_ci } 1869141cc406Sopenharmony_ci 1870141cc406Sopenharmony_ci 1871141cc406Sopenharmony_ci /* Test scans */ 1872141cc406Sopenharmony_ci check(MSG, 0, "TEST: scan test"); 1873141cc406Sopenharmony_ci status = sane_init (&version_code, NULL); 1874141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1875141cc406Sopenharmony_ci "sane_init failed with %s", sane_strstatus (status)); 1876141cc406Sopenharmony_ci status = sane_open (devname, &device); 1877141cc406Sopenharmony_ci check(FATAL, (status == SANE_STATUS_GOOD), 1878141cc406Sopenharmony_ci "sane_open failed with %s for device %s", sane_strstatus (status), devname); 1879141cc406Sopenharmony_ci test_scans(device); 1880141cc406Sopenharmony_ci sane_close (device); 1881141cc406Sopenharmony_ci sane_exit(); 1882141cc406Sopenharmony_ci 1883141cc406Sopenharmony_ci the_exit: 1884141cc406Sopenharmony_ci if (devname) free(devname); 1885141cc406Sopenharmony_ci display_stats(); 1886141cc406Sopenharmony_ci return(0); 1887141cc406Sopenharmony_ci} 1888