1 /* -*- Mode: C; indent-tabs-mode:nil -*- */
2 /*
3 * Unit tests for libusb_set_option
4 * Copyright © 2023 Nathan Hjelm <[email protected]>
5 * Copyright © 2023 Google, LLC. All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "config.h"
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <inttypes.h>
27 #include "libusbi.h"
28 #include "libusb_testlib.h"
29
30 #if defined(_WIN32) && !defined(__CYGWIN__)
31 #include <winbase.h>
32
33 #if defined(ENABLE_LOGGING)
unsetenv(const char * env)34 static int unsetenv(const char *env) {
35 return _putenv_s(env, "");
36 }
37
setenv(const char * env,const char * value,int overwrite)38 static int setenv(const char *env, const char *value, int overwrite) {
39 if (getenv(env) && !overwrite)
40 return 0;
41 return _putenv_s(env, value);
42 }
43 #endif
44 #endif
45
46 #define LIBUSB_TEST_CLEAN_EXIT(code) \
47 do { \
48 if (test_ctx != NULL) { \
49 libusb_exit(test_ctx); \
50 } \
51 unsetenv("LIBUSB_DEBUG"); \
52 return (code); \
53 } while (0)
54
55 /**
56 * Fail the test if the expression does not evaluate to LIBUSB_SUCCESS.
57 */
58 #define LIBUSB_TEST_RETURN_ON_ERROR(expr) \
59 do { \
60 int _result = (expr); \
61 if (LIBUSB_SUCCESS != _result) { \
62 libusb_testlib_logf("Not success (%s) at %s:%d", #expr, \
63 __FILE__, __LINE__); \
64 LIBUSB_TEST_CLEAN_EXIT(TEST_STATUS_FAILURE); \
65 } \
66 } while (0)
67
68 /**
69 * Use relational operator to compare two values and fail the test if the
70 * comparison is false. Intended to compare integer or pointer types.
71 *
72 * Example: LIBUSB_EXPECT(==, 0, 1) -> fail, LIBUSB_EXPECT(==, 0, 0) -> ok.
73 */
74 #define LIBUSB_EXPECT(operator, lhs, rhs) \
75 do { \
76 int64_t _lhs = (int64_t)(intptr_t)(lhs), _rhs = (int64_t)(intptr_t)(rhs); \
77 if (!(_lhs operator _rhs)) { \
78 libusb_testlib_logf("Expected %s (%" PRId64 ") " #operator \
79 " %s (%" PRId64 ") at %s:%d", #lhs, \
80 (int64_t)(intptr_t)_lhs, #rhs, \
81 (int64_t)(intptr_t)_rhs, __FILE__, \
82 __LINE__); \
83 LIBUSB_TEST_CLEAN_EXIT(TEST_STATUS_FAILURE); \
84 } \
85 } while (0)
86
87
test_set_log_level_basic(void)88 static libusb_testlib_result test_set_log_level_basic(void) {
89 #if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
90 libusb_context *test_ctx = NULL;
91
92 /* unset LIBUSB_DEBUG if it is set */
93 unsetenv("LIBUSB_DEBUG");
94
95 /* test basic functionality */
96 LIBUSB_TEST_RETURN_ON_ERROR(libusb_init_context(&test_ctx, /*options=*/NULL,
97 /*num_options=*/0));
98 LIBUSB_TEST_RETURN_ON_ERROR(libusb_set_option(test_ctx,
99 LIBUSB_OPTION_LOG_LEVEL,
100 LIBUSB_LOG_LEVEL_ERROR));
101 LIBUSB_EXPECT(==, test_ctx->debug, LIBUSB_LOG_LEVEL_ERROR);
102 LIBUSB_TEST_RETURN_ON_ERROR(libusb_set_option(test_ctx,
103 LIBUSB_OPTION_LOG_LEVEL,
104 LIBUSB_LOG_LEVEL_NONE));
105 LIBUSB_EXPECT(==, test_ctx->debug, LIBUSB_LOG_LEVEL_NONE);
106
107 LIBUSB_TEST_CLEAN_EXIT(TEST_STATUS_SUCCESS);
108 #else
109 return TEST_STATUS_SKIP;
110 #endif
111 }
112
test_set_log_level_default(void)113 static libusb_testlib_result test_set_log_level_default(void) {
114 #if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
115 libusb_context *test_ctx = NULL;
116
117 /* set the default debug level */
118 LIBUSB_TEST_RETURN_ON_ERROR(libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL,
119 LIBUSB_LOG_LEVEL_ERROR));
120
121 LIBUSB_TEST_RETURN_ON_ERROR(libusb_init_context(&test_ctx, /*options=*/NULL,
122 /*num_options=*/0));
123 /* check that debug level came from the default */
124 LIBUSB_EXPECT(==, test_ctx->debug, LIBUSB_LOG_LEVEL_ERROR);
125
126 /* try to override the old log level. since this was set from the default it
127 * should be possible to change it */
128 LIBUSB_TEST_RETURN_ON_ERROR(libusb_set_option(test_ctx,
129 LIBUSB_OPTION_LOG_LEVEL,
130 LIBUSB_LOG_LEVEL_NONE));
131 LIBUSB_EXPECT(==, test_ctx->debug, LIBUSB_LOG_LEVEL_NONE);
132
133 LIBUSB_TEST_CLEAN_EXIT(TEST_STATUS_SUCCESS);
134 #else
135 return TEST_STATUS_SKIP;
136 #endif
137 }
138
test_set_log_level_env(void)139 static libusb_testlib_result test_set_log_level_env(void) {
140 #if defined(ENABLE_LOGGING)
141 libusb_context *test_ctx = NULL;
142
143 /* check that libusb_set_option does not change the log level when it was set
144 * from the environment. */
145 setenv("LIBUSB_DEBUG", "4", /*overwrite=*/0);
146 LIBUSB_TEST_RETURN_ON_ERROR(libusb_init_context(&test_ctx, /*options=*/NULL,
147 /*num_options=*/0));
148 #ifndef ENABLE_DEBUG_LOGGING
149 LIBUSB_EXPECT(==, test_ctx->debug, 4);
150 #endif
151
152 LIBUSB_TEST_RETURN_ON_ERROR(libusb_set_option(test_ctx,
153 LIBUSB_OPTION_LOG_LEVEL,
154 LIBUSB_LOG_LEVEL_ERROR));
155 /* environment variable should always override LIBUSB_OPTION_LOG_LEVEL if set */
156 #ifndef ENABLE_DEBUG_LOGGING
157 LIBUSB_EXPECT(==, test_ctx->debug, 4);
158 #endif
159
160 LIBUSB_TEST_CLEAN_EXIT(TEST_STATUS_SUCCESS);
161 #else
162 return TEST_STATUS_SKIP;
163 #endif
164 }
165
166
test_no_discovery(void)167 static libusb_testlib_result test_no_discovery(void)
168 {
169 #if defined(__linux__)
170 libusb_context *test_ctx;
171 LIBUSB_TEST_RETURN_ON_ERROR(libusb_init_context(&test_ctx, /*options=*/NULL,
172 /*num_options=*/0));
173 libusb_device **device_list = NULL;
174 ssize_t num_devices = libusb_get_device_list(test_ctx, &device_list);
175 libusb_free_device_list(device_list, /*unref_devices=*/1);
176 libusb_exit(test_ctx);
177 test_ctx = NULL;
178
179 if (num_devices == 0) {
180 libusb_testlib_logf("Warning: no devices found, the test will only verify that setting LIBUSB_OPTION_NO_DEVICE_DISCOVERY succeeds.");
181 }
182
183 LIBUSB_EXPECT(>=, num_devices, 0);
184
185 LIBUSB_TEST_RETURN_ON_ERROR(libusb_set_option(NULL, LIBUSB_OPTION_NO_DEVICE_DISCOVERY));
186 LIBUSB_TEST_RETURN_ON_ERROR(libusb_init_context(&test_ctx, /*options=*/NULL,
187 /*num_options=*/0));
188 device_list = NULL;
189 num_devices = libusb_get_device_list(test_ctx, &device_list);
190 libusb_free_device_list(device_list, /*unref_devices=*/1);
191
192 LIBUSB_EXPECT(==, num_devices, 0);
193 LIBUSB_TEST_CLEAN_EXIT(TEST_STATUS_SUCCESS);
194 #else
195 return TEST_STATUS_SKIP;
196 #endif
197 }
198
199 #if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
test_log_cb(libusb_context * ctx,enum libusb_log_level level,const char * str)200 static void LIBUSB_CALL test_log_cb(libusb_context *ctx, enum libusb_log_level level,
201 const char *str) {
202 UNUSED(ctx);
203 UNUSED(level);
204 UNUSED(str);
205 }
206 #endif
207
208
test_set_log_cb(void)209 static libusb_testlib_result test_set_log_cb(void)
210 {
211 #if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
212 libusb_context *test_ctx = NULL;
213
214 /* set the log callback on the context */
215 LIBUSB_TEST_RETURN_ON_ERROR(libusb_init_context(&test_ctx, /*options=*/NULL,
216 /*num_options=*/0));
217 LIBUSB_TEST_RETURN_ON_ERROR(libusb_set_option(test_ctx, LIBUSB_OPTION_LOG_CB,
218 test_log_cb));
219
220 /* check that debug level came from the default */
221 LIBUSB_EXPECT(==, test_ctx->log_handler, test_log_cb);
222
223 libusb_exit(test_ctx);
224 test_ctx = NULL;
225
226 /* set the log callback for all future contexts */
227 LIBUSB_TEST_RETURN_ON_ERROR(libusb_set_option(/*ctx=*/NULL, LIBUSB_OPTION_LOG_CB,
228 test_log_cb));
229 LIBUSB_TEST_RETURN_ON_ERROR(libusb_init_context(&test_ctx, /*options=*/NULL,
230 /*num_options=*/0));
231 LIBUSB_EXPECT(==, test_ctx->log_handler, test_log_cb);
232
233
234 LIBUSB_TEST_CLEAN_EXIT(TEST_STATUS_SUCCESS);
235 #else
236 return TEST_STATUS_SKIP;
237 #endif
238 }
239
240 static const libusb_testlib_test tests[] = {
241 { "test_set_log_level_basic", &test_set_log_level_basic },
242 { "test_set_log_level_env", &test_set_log_level_env },
243 { "test_no_discovery", &test_no_discovery },
244 /* since default options can't be unset, run this one last */
245 { "test_set_log_level_default", &test_set_log_level_default },
246 { "test_set_log_cb", &test_set_log_cb },
247 LIBUSB_NULL_TEST
248 };
249
main(int argc,char * argv[])250 int main(int argc, char *argv[])
251 {
252 return libusb_testlib_run_tests(argc, argv, tests);
253 }
254