mirror of https://github.com/nirenjan/libx52.git
test: Add tests for x52evtest and x52joytest
This change adds additional code coverage test cases for the evtest and joytest modules.lipc-refactor
parent
fdf884cb1c
commit
772017661d
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Saitek X52 Pro MFD & LED driver - Event test axis denoise helpers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ev_denoise.h"
|
||||||
|
|
||||||
|
int32_t evtest_axis_denoise_mask(int32_t axis_max)
|
||||||
|
{
|
||||||
|
return ~(axis_max >> 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool evtest_axis_changed(int32_t last, int32_t curr, int32_t mask, bool denoise_enabled)
|
||||||
|
{
|
||||||
|
if (last == curr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!denoise_enabled) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return (last & mask) != (curr & mask);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* Saitek X52 Pro MFD & LED driver - Event test axis denoise helpers
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EVTEST_EV_DENOISE_H
|
||||||
|
#define EVTEST_EV_DENOISE_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int32_t evtest_axis_denoise_mask(int32_t axis_max);
|
||||||
|
|
||||||
|
bool evtest_axis_changed(int32_t last, int32_t curr, int32_t mask, bool denoise_enabled);
|
||||||
|
|
||||||
|
#endif /* EVTEST_EV_DENOISE_H */
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
/*
|
||||||
|
* Saitek X52 Pro MFD & LED driver - Event test axis denoise unit tests
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <cmocka.h>
|
||||||
|
|
||||||
|
#include "ev_denoise.h"
|
||||||
|
|
||||||
|
static void test_mask_small_max_all_bits(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
/* (max >> 6) == 0 => mask is ~0 => -1 as int32_t */
|
||||||
|
assert_int_equal(evtest_axis_denoise_mask(0), -1);
|
||||||
|
assert_int_equal(evtest_axis_denoise_mask(63), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_mask_large_max_clears_low_bits(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
int32_t max = 1023;
|
||||||
|
int32_t mask = evtest_axis_denoise_mask(max);
|
||||||
|
|
||||||
|
/* 1023 >> 6 == 15; ~15 as int32_t is -16 (low four bits clear in mask) */
|
||||||
|
assert_int_equal(mask, (int32_t) ~15);
|
||||||
|
assert_int_not_equal(mask, -1);
|
||||||
|
/* Noise within cleared low bits should not matter when masked */
|
||||||
|
assert_int_equal(100 & mask, 101 & mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (max >> 6) is 0 for max in [0, 63] and becomes 1 at max == 64, so the mask
|
||||||
|
* flips from all bits set (-1) to clearing the least significant bit (-2).
|
||||||
|
*/
|
||||||
|
static void test_mask_boundary_63_vs_64(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
|
||||||
|
assert_int_equal(evtest_axis_denoise_mask(63), -1);
|
||||||
|
assert_int_equal(evtest_axis_denoise_mask(64), -2);
|
||||||
|
assert_int_equal(evtest_axis_denoise_mask(64), (int32_t) ~(64 >> 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_axis_changed_mask_boundary_lsb_noise(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
int32_t mask63 = evtest_axis_denoise_mask(63);
|
||||||
|
int32_t mask64 = evtest_axis_denoise_mask(64);
|
||||||
|
|
||||||
|
/* Adjacent values differing only in bit 0: masked equal with -2, not with -1 */
|
||||||
|
assert_int_equal(100 & mask64, 101 & mask64);
|
||||||
|
assert_int_not_equal(100 & mask63, 101 & mask63);
|
||||||
|
|
||||||
|
assert_false(evtest_axis_changed(100, 101, mask64, true));
|
||||||
|
assert_true(evtest_axis_changed(100, 101, mask63, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_mask_4095_and_axis_changed_low_six_bits(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
int32_t max = 4095;
|
||||||
|
int32_t mask = evtest_axis_denoise_mask(max);
|
||||||
|
|
||||||
|
/* 4095 >> 6 == 63; ~63 as int32_t is -64 (low six bits clear in mask) */
|
||||||
|
assert_int_equal(mask, (int32_t) ~63);
|
||||||
|
assert_int_equal(mask, -64);
|
||||||
|
|
||||||
|
assert_int_equal(0 & mask, 31 & mask);
|
||||||
|
assert_false(evtest_axis_changed(0, 31, mask, true));
|
||||||
|
|
||||||
|
assert_int_not_equal(0 & mask, 64 & mask);
|
||||||
|
assert_true(evtest_axis_changed(0, 64, mask, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_axis_changed_equal_raw(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
assert_false(evtest_axis_changed(500, 500, -1, true));
|
||||||
|
assert_false(evtest_axis_changed(500, 500, -1, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_axis_changed_unequal_denoise_off(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
assert_true(evtest_axis_changed(100, 101, -1, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_axis_changed_equal_after_mask_denoise_on(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
int32_t mask = evtest_axis_denoise_mask(1023);
|
||||||
|
|
||||||
|
assert_false(evtest_axis_changed(100, 101, mask, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_axis_changed_still_change_after_mask(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
int32_t mask = evtest_axis_denoise_mask(1023);
|
||||||
|
|
||||||
|
assert_true(evtest_axis_changed(96, 112, mask, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_axis_changed_full_mask_any_raw_diff(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
/* With mask -1, (v & -1) == v, so any raw difference is a change */
|
||||||
|
assert_true(evtest_axis_changed(10, 11, -1, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(test_mask_small_max_all_bits),
|
||||||
|
cmocka_unit_test(test_mask_large_max_clears_low_bits),
|
||||||
|
cmocka_unit_test(test_mask_boundary_63_vs_64),
|
||||||
|
cmocka_unit_test(test_axis_changed_mask_boundary_lsb_noise),
|
||||||
|
cmocka_unit_test(test_mask_4095_and_axis_changed_low_six_bits),
|
||||||
|
cmocka_unit_test(test_axis_changed_equal_raw),
|
||||||
|
cmocka_unit_test(test_axis_changed_unequal_denoise_off),
|
||||||
|
cmocka_unit_test(test_axis_changed_equal_after_mask_denoise_on),
|
||||||
|
cmocka_unit_test(test_axis_changed_still_change_after_mask),
|
||||||
|
cmocka_unit_test(test_axis_changed_full_mask_any_raw_diff),
|
||||||
|
};
|
||||||
|
|
||||||
|
cmocka_set_message_output(CM_OUTPUT_TAP);
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
#include <libx52/libx52io.h>
|
#include <libx52/libx52io.h>
|
||||||
|
#include "ev_denoise.h"
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -97,7 +98,7 @@ int main(void)
|
||||||
* ~(max >> 6) which will do nothing for the axis with a small
|
* ~(max >> 6) which will do nothing for the axis with a small
|
||||||
* range, but reduce the noise on those with a larger range.
|
* range, but reduce the noise on those with a larger range.
|
||||||
*/
|
*/
|
||||||
denoise_mask[i] = ~(max >> 6);
|
denoise_mask[i] = evtest_axis_denoise_mask(max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,18 +144,8 @@ int main(void)
|
||||||
/* Get the current timeval - we don't need a timezone */
|
/* Get the current timeval - we don't need a timezone */
|
||||||
gettimeofday(&tv, NULL);
|
gettimeofday(&tv, NULL);
|
||||||
for (int axis = 0; axis < LIBX52IO_AXIS_MAX; axis++) {
|
for (int axis = 0; axis < LIBX52IO_AXIS_MAX; axis++) {
|
||||||
if (last.axis[axis] != curr.axis[axis]) {
|
if (evtest_axis_changed(last.axis[axis], curr.axis[axis],
|
||||||
/* Account for denoising */
|
denoise_mask[axis], denoise)) {
|
||||||
if (denoise) {
|
|
||||||
int32_t last_v = last.axis[axis] & denoise_mask[axis];
|
|
||||||
int32_t curr_v = curr.axis[axis] & denoise_mask[axis];
|
|
||||||
|
|
||||||
if (last_v == curr_v) {
|
|
||||||
/* Within the noise threshold */
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf(_("Event @ %ld.%06ld: %s, value %d\n"),
|
printf(_("Event @ %ld.%06ld: %s, value %d\n"),
|
||||||
(long int)tv.tv_sec, (long int)tv.tv_usec,
|
(long int)tv.tv_sec, (long int)tv.tv_usec,
|
||||||
libx52io_axis_to_str(axis), curr.axis[axis]);
|
libx52io_axis_to_str(axis), curr.axis[axis]);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
# x52evtest
|
# x52evtest
|
||||||
executable('x52evtest', 'ev_test.c',
|
executable('x52evtest', ['ev_test.c', 'ev_denoise.c'],
|
||||||
install: true,
|
install: true,
|
||||||
include_directories: includes,
|
include_directories: includes,
|
||||||
dependencies: [dep_intl],
|
dependencies: [dep_intl],
|
||||||
link_with: [lib_libx52io])
|
link_with: [lib_libx52io])
|
||||||
|
|
||||||
|
ev_denoise_test = executable('ev-denoise-test', ['ev_denoise_test.c', 'ev_denoise.c'],
|
||||||
|
build_by_default: false,
|
||||||
|
dependencies: [dep_cmocka],
|
||||||
|
include_directories: includes,
|
||||||
|
)
|
||||||
|
test('ev-denoise', ev_denoise_test, protocol: 'tap')
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Saitek X52 Pro MFD & LED driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <libx52/libx52.h>
|
||||||
|
|
||||||
|
/* Opaque device: any unique non-NULL address is enough for joytest. */
|
||||||
|
static char joytest_mock_dev_storage;
|
||||||
|
|
||||||
|
int libx52_init(libx52_device **dev)
|
||||||
|
{
|
||||||
|
if (!dev) {
|
||||||
|
return LIBX52_ERROR_INVALID_PARAM;
|
||||||
|
}
|
||||||
|
*dev = (libx52_device *)&joytest_mock_dev_storage;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libx52_exit(libx52_device *dev)
|
||||||
|
{
|
||||||
|
(void)dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *libx52_strerror(libx52_error_code error)
|
||||||
|
{
|
||||||
|
(void)error;
|
||||||
|
// We don't actually use this in the mock, but it's required by the API
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_check_feature(libx52_device *x52, libx52_feature feature)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)feature;
|
||||||
|
// This is needed to satisfy the API, assume that the device supports LED control
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_set_text(libx52_device *x52, uint8_t line, const char *text, uint8_t length)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)line;
|
||||||
|
(void)text;
|
||||||
|
(void)length;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_set_led_state(libx52_device *x52, libx52_led_id led, libx52_led_state state)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)led;
|
||||||
|
(void)state;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_set_clock(libx52_device *x52, time_t t, int local)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)t;
|
||||||
|
(void)local;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_set_clock_timezone(libx52_device *x52, libx52_clock_id clock, int offset)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)clock;
|
||||||
|
(void)offset;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_set_clock_format(libx52_device *x52, libx52_clock_id clock, libx52_clock_format format)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)clock;
|
||||||
|
(void)format;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_set_date_format(libx52_device *x52, libx52_date_format format)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)format;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_set_brightness(libx52_device *x52, uint8_t mfd, uint16_t brightness)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)mfd;
|
||||||
|
(void)brightness;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_set_shift(libx52_device *x52, uint8_t state)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)state;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_set_blink(libx52_device *x52, uint8_t state)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
(void)state;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libx52_update(libx52_device *x52)
|
||||||
|
{
|
||||||
|
(void)x52;
|
||||||
|
return LIBX52_SUCCESS;
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,52 @@
|
||||||
# x52test
|
joytest_sources = files(
|
||||||
executable('x52test',
|
|
||||||
'x52_test.c',
|
'x52_test.c',
|
||||||
|
'x52_test_args.c',
|
||||||
'x52_test_mfd.c',
|
'x52_test_mfd.c',
|
||||||
'x52_test_led.c',
|
'x52_test_led.c',
|
||||||
'x52_test_clock.c',
|
'x52_test_clock.c',
|
||||||
|
)
|
||||||
|
|
||||||
|
joytest_libx52_mock = static_library('joytest-libx52-mock',
|
||||||
|
'libx52_mock.c',
|
||||||
|
include_directories: includes,
|
||||||
|
)
|
||||||
|
|
||||||
|
# x52test
|
||||||
|
exe_x52test = executable('x52test',
|
||||||
|
joytest_sources,
|
||||||
install: true,
|
install: true,
|
||||||
dependencies: [dep_intl],
|
dependencies: [dep_intl],
|
||||||
include_directories: includes,
|
include_directories: includes,
|
||||||
link_with: [lib_libx52])
|
link_with: [lib_libx52])
|
||||||
|
|
||||||
|
exe_x52test_mock = executable('x52test-mock',
|
||||||
|
joytest_sources,
|
||||||
|
install: false,
|
||||||
|
dependencies: [dep_intl],
|
||||||
|
include_directories: includes,
|
||||||
|
link_with: [joytest_libx52_mock],
|
||||||
|
)
|
||||||
|
|
||||||
|
sh = find_program('sh')
|
||||||
|
test('x52test-mock',
|
||||||
|
sh,
|
||||||
|
args: [
|
||||||
|
'-c',
|
||||||
|
'printf "\n" | env NO_DELAY=1 @0@'.format(exe_x52test_mock.full_path()),
|
||||||
|
],
|
||||||
|
depends: exe_x52test_mock,
|
||||||
|
protocol: 'exitcode',
|
||||||
|
timeout: 60,
|
||||||
|
)
|
||||||
|
|
||||||
|
test('x52test-help', exe_x52test, args: ['help'], protocol: 'exitcode')
|
||||||
|
test('x52test-help-dashdash', exe_x52test, args: ['--help'], protocol: 'exitcode')
|
||||||
|
test('x52test-bad-arg', exe_x52test, args: ['not-a-test-id'], protocol: 'exitcode', should_fail: true)
|
||||||
|
|
||||||
|
x52test_args_test = executable('x52test-args-test',
|
||||||
|
['x52_test_args_test.c', 'x52_test_args.c'],
|
||||||
|
build_by_default: false,
|
||||||
|
dependencies: [dep_cmocka],
|
||||||
|
include_directories: includes,
|
||||||
|
)
|
||||||
|
test('x52test-args', x52test_args_test, protocol: 'tap')
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Saitek X52 Pro MFD & LED driver
|
* Saitek X52 Pro MFD & LED driver
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2015 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
* Copyright (C) 2012-2026 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||||
*/
|
*/
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
#include <libx52/libx52.h>
|
#include <libx52/libx52.h>
|
||||||
#include "x52_test_common.h"
|
#include "x52_test_common.h"
|
||||||
|
#include "x52_test_args.h"
|
||||||
|
|
||||||
libx52_device *dev;
|
libx52_device *dev;
|
||||||
int test_exit;
|
int test_exit;
|
||||||
bool nodelay;
|
bool nodelay;
|
||||||
|
|
@ -186,11 +188,7 @@ static void usage(void)
|
||||||
puts("");
|
puts("");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct test_map {
|
const struct x52test_cmd tests[] = {
|
||||||
const char *cmd;
|
|
||||||
int test_bitmap;
|
|
||||||
};
|
|
||||||
const struct test_map tests[] = {
|
|
||||||
#define X(en, cmd, desc) { #cmd, TEST_ ##en },
|
#define X(en, cmd, desc) { #cmd, TEST_ ##en },
|
||||||
TESTS
|
TESTS
|
||||||
#undef X
|
#undef X
|
||||||
|
|
@ -199,10 +197,8 @@ const struct test_map tests[] = {
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int test_list;
|
struct x52test_argv_result parsed;
|
||||||
int i;
|
int ret = 0;
|
||||||
const struct test_map *test;
|
|
||||||
int found;
|
|
||||||
|
|
||||||
/* Initialize gettext */
|
/* Initialize gettext */
|
||||||
#if ENABLE_NLS
|
#if ENABLE_NLS
|
||||||
|
|
@ -212,50 +208,28 @@ int main(int argc, char **argv)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Usage: x52test [list of tests] */
|
/* Usage: x52test [list of tests] */
|
||||||
if (argc == 1) {
|
x52test_parse_argv(argc, argv, tests, TEST_ALL, &parsed);
|
||||||
/* Run all tests, if none specified */
|
|
||||||
test_list = TEST_ALL;
|
if (parsed.status == X52TEST_ARGV_HELP) {
|
||||||
} else {
|
printf(_("Usage: %s [list of tests]\n\n"), argv[0]);
|
||||||
/* Initialize the test list to run no tests, the commands
|
usage();
|
||||||
* will enable the selective tests
|
return 0;
|
||||||
*/
|
|
||||||
test_list = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 1; i < argc; i++) {
|
if (parsed.status == X52TEST_ARGV_UNKNOWN) {
|
||||||
if (!strcmp(argv[i], "help") ||
|
printf(_("Unrecognized test identifier: %s\n\n"), argv[parsed.bad_arg_index]);
|
||||||
!strcmp(argv[i], "--help")) {
|
usage();
|
||||||
|
return 1;
|
||||||
/* Display help string and exit */
|
|
||||||
printf(_("Usage: %s [list of tests]\n\n"), argv[0]);
|
|
||||||
usage();
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
found = 0;
|
|
||||||
for (test = tests; test->cmd; test++) {
|
|
||||||
if (!strcmp(argv[i], test->cmd)) {
|
|
||||||
test_list |= test->test_bitmap;
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (found == 0) {
|
|
||||||
printf(_("Unrecognized test identifier: %s\n\n"), argv[i]);
|
|
||||||
usage();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize the nodelay variable */
|
/* Initialize the nodelay variable */
|
||||||
nodelay = (getenv("LD_PRELOAD") != NULL || getenv("NO_DELAY") != NULL);
|
nodelay = (getenv("LD_PRELOAD") != NULL || getenv("NO_DELAY") != NULL);
|
||||||
|
|
||||||
if (test_list) {
|
if (parsed.test_bitmap) {
|
||||||
i = run_tests(test_list);
|
ret = run_tests(parsed.test_bitmap);
|
||||||
} else {
|
} else {
|
||||||
puts(_("Not running any tests"));
|
puts(_("Not running any tests"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return i;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Saitek X52 Pro MFD & LED driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "x52_test_args.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void x52test_parse_argv(int argc, char **argv, const struct x52test_cmd *cmds,
|
||||||
|
int test_all_bitmap, struct x52test_argv_result *out)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const struct x52test_cmd *c;
|
||||||
|
|
||||||
|
out->status = X52TEST_ARGV_OK;
|
||||||
|
out->bad_arg_index = 0;
|
||||||
|
|
||||||
|
if (argc == 1) {
|
||||||
|
out->test_bitmap = test_all_bitmap;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->test_bitmap = 0;
|
||||||
|
|
||||||
|
for (i = 1; i < argc; i++) {
|
||||||
|
if (!strcmp(argv[i], "help") || !strcmp(argv[i], "--help")) {
|
||||||
|
out->status = X52TEST_ARGV_HELP;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int found = 0;
|
||||||
|
|
||||||
|
for (c = cmds; c->cmd; c++) {
|
||||||
|
if (!strcmp(argv[i], c->cmd)) {
|
||||||
|
out->test_bitmap |= c->test_bitmap;
|
||||||
|
found = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
out->status = X52TEST_ARGV_UNKNOWN;
|
||||||
|
out->bad_arg_index = i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Saitek X52 Pro MFD & LED driver
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef X52_TEST_ARGS_H
|
||||||
|
#define X52_TEST_ARGS_H
|
||||||
|
|
||||||
|
enum x52test_argv_status {
|
||||||
|
X52TEST_ARGV_OK,
|
||||||
|
X52TEST_ARGV_HELP,
|
||||||
|
X52TEST_ARGV_UNKNOWN,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct x52test_cmd {
|
||||||
|
const char *cmd;
|
||||||
|
int test_bitmap;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct x52test_argv_result {
|
||||||
|
enum x52test_argv_status status;
|
||||||
|
int test_bitmap;
|
||||||
|
int bad_arg_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
void x52test_parse_argv(int argc, char **argv, const struct x52test_cmd *cmds,
|
||||||
|
int test_all_bitmap, struct x52test_argv_result *out);
|
||||||
|
|
||||||
|
#endif /* X52_TEST_ARGS_H */
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
/*
|
||||||
|
* Saitek X52 Pro MFD & LED driver - x52test argv parsing unit tests
|
||||||
|
*
|
||||||
|
* Copyright (C) 2026 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <cmocka.h>
|
||||||
|
|
||||||
|
#include "x52_test_args.h"
|
||||||
|
|
||||||
|
#define BIT_A (1 << 0)
|
||||||
|
#define BIT_B (1 << 1)
|
||||||
|
#define BIT_C (1 << 2)
|
||||||
|
#define TEST_ALL_SYN (BIT_A | BIT_B | BIT_C)
|
||||||
|
|
||||||
|
static const struct x52test_cmd syn_cmds[] = {
|
||||||
|
{ "a", BIT_A },
|
||||||
|
{ "b", BIT_B },
|
||||||
|
{ "c", BIT_C },
|
||||||
|
{ NULL, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static void test_argc_one_is_test_all(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(1, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_OK);
|
||||||
|
assert_int_equal(r.test_bitmap, TEST_ALL_SYN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_single_cmd(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", (char *)"b", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(2, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_OK);
|
||||||
|
assert_int_equal(r.test_bitmap, BIT_B);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_multi_cmd_ors(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", (char *)"a", (char *)"c", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(3, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_OK);
|
||||||
|
assert_int_equal(r.test_bitmap, BIT_A | BIT_C);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_duplicate_cmd_ors_same_bit(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", (char *)"a", (char *)"a", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(3, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_OK);
|
||||||
|
assert_int_equal(r.test_bitmap, BIT_A);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_help_keyword(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", (char *)"help", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(2, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_HELP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_dashdash_help(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", (char *)"--help", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(2, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_HELP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_help_after_other_arg(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", (char *)"a", (char *)"help", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(3, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_HELP);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_help_before_other_arg(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", (char *)"help", (char *)"a", (char *)"b", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(4, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_HELP);
|
||||||
|
assert_int_equal(r.test_bitmap, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_unknown_bad_index(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", (char *)"a", (char *)"nope", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(3, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_UNKNOWN);
|
||||||
|
assert_int_equal(r.bad_arg_index, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_unknown_first_arg_index(void **state)
|
||||||
|
{
|
||||||
|
(void)state;
|
||||||
|
char *argv[] = { (char *)"prog", (char *)"xyz", NULL };
|
||||||
|
struct x52test_argv_result r;
|
||||||
|
|
||||||
|
x52test_parse_argv(2, argv, syn_cmds, TEST_ALL_SYN, &r);
|
||||||
|
assert_int_equal(r.status, X52TEST_ARGV_UNKNOWN);
|
||||||
|
assert_int_equal(r.bad_arg_index, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test(test_argc_one_is_test_all),
|
||||||
|
cmocka_unit_test(test_single_cmd),
|
||||||
|
cmocka_unit_test(test_multi_cmd_ors),
|
||||||
|
cmocka_unit_test(test_duplicate_cmd_ors_same_bit),
|
||||||
|
cmocka_unit_test(test_help_keyword),
|
||||||
|
cmocka_unit_test(test_dashdash_help),
|
||||||
|
cmocka_unit_test(test_help_after_other_arg),
|
||||||
|
cmocka_unit_test(test_help_before_other_arg),
|
||||||
|
cmocka_unit_test(test_unknown_bad_index),
|
||||||
|
cmocka_unit_test(test_unknown_first_arg_index),
|
||||||
|
};
|
||||||
|
|
||||||
|
cmocka_set_message_output(CM_OUTPUT_TAP);
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: libx52 0.3.3\n"
|
"Project-Id-Version: libx52 0.3.3\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n"
|
"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n"
|
||||||
"POT-Creation-Date: 2026-04-04 23:11-0700\n"
|
"POT-Creation-Date: 2026-04-20 21:55-0700\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
|
@ -261,26 +261,26 @@ msgstr ""
|
||||||
msgid "No state change"
|
msgid "No state change"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: evtest/ev_test.c:110
|
#: evtest/ev_test.c:111
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Device ID: vendor 0x%04x product 0x%04x version 0x%04x\n"
|
msgid "Device ID: vendor 0x%04x product 0x%04x version 0x%04x\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: evtest/ev_test.c:114
|
#: evtest/ev_test.c:115
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Device name: \"%s %s\"\n"
|
msgid "Device name: \"%s %s\"\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: evtest/ev_test.c:117
|
#: evtest/ev_test.c:118
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Serial number: \"%s\"\n"
|
msgid "Serial number: \"%s\"\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: evtest/ev_test.c:118
|
#: evtest/ev_test.c:119
|
||||||
msgid "Testing (interrupt to exit)\n"
|
msgid "Testing (interrupt to exit)\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: evtest/ev_test.c:158 evtest/ev_test.c:166
|
#: evtest/ev_test.c:149 evtest/ev_test.c:157
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Event @ %ld.%06ld: %s, value %d\n"
|
msgid "Event @ %ld.%06ld: %s, value %d\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
||||||
15
po/xx_PL.po
15
po/xx_PL.po
|
|
@ -7,7 +7,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: libx52 0.3.3\n"
|
"Project-Id-Version: libx52 0.3.3\n"
|
||||||
"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n"
|
"Report-Msgid-Bugs-To: https://github.com/nirenjan/libx52/issues\n"
|
||||||
"POT-Creation-Date: 2026-04-04 23:11-0700\n"
|
"POT-Creation-Date: 2026-04-20 21:55-0700\n"
|
||||||
"PO-Revision-Date: 2026-04-04 12:00-0700\n"
|
"PO-Revision-Date: 2026-04-04 12:00-0700\n"
|
||||||
"Last-Translator: Nirenjan Krishnan <nirenjan@gmail.com>\n"
|
"Last-Translator: Nirenjan Krishnan <nirenjan@gmail.com>\n"
|
||||||
"Language-Team: Dummy Language for testing i18n\n"
|
"Language-Team: Dummy Language for testing i18n\n"
|
||||||
|
|
@ -261,26 +261,26 @@ msgstr "Unableay otay itewray eventay"
|
||||||
msgid "No state change"
|
msgid "No state change"
|
||||||
msgstr "Onay atestay angechay"
|
msgstr "Onay atestay angechay"
|
||||||
|
|
||||||
#: evtest/ev_test.c:110
|
#: evtest/ev_test.c:111
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Device ID: vendor 0x%04x product 0x%04x version 0x%04x\n"
|
msgid "Device ID: vendor 0x%04x product 0x%04x version 0x%04x\n"
|
||||||
msgstr "Eviceday IDay: endorvay 0x%04x oductpray 0x%04x ersionvay 0x%04x\n"
|
msgstr "Eviceday IDay: endorvay 0x%04x oductpray 0x%04x ersionvay 0x%04x\n"
|
||||||
|
|
||||||
#: evtest/ev_test.c:114
|
#: evtest/ev_test.c:115
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Device name: \"%s %s\"\n"
|
msgid "Device name: \"%s %s\"\n"
|
||||||
msgstr "Eviceday amenay: \"%s %s\"\n"
|
msgstr "Eviceday amenay: \"%s %s\"\n"
|
||||||
|
|
||||||
#: evtest/ev_test.c:117
|
#: evtest/ev_test.c:118
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Serial number: \"%s\"\n"
|
msgid "Serial number: \"%s\"\n"
|
||||||
msgstr "Erialsay umbernay: \"%s\"\n"
|
msgstr "Erialsay umbernay: \"%s\"\n"
|
||||||
|
|
||||||
#: evtest/ev_test.c:118
|
#: evtest/ev_test.c:119
|
||||||
msgid "Testing (interrupt to exit)\n"
|
msgid "Testing (interrupt to exit)\n"
|
||||||
msgstr "Estingtay (interruptay otay exitay)\n"
|
msgstr "Estingtay (interruptay otay exitay)\n"
|
||||||
|
|
||||||
#: evtest/ev_test.c:158 evtest/ev_test.c:166
|
#: evtest/ev_test.c:149 evtest/ev_test.c:157
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Event @ %ld.%06ld: %s, value %d\n"
|
msgid "Event @ %ld.%06ld: %s, value %d\n"
|
||||||
msgstr "Eventay @ %ld.%06ld: %s, aluevay %d\n"
|
msgstr "Eventay @ %ld.%06ld: %s, aluevay %d\n"
|
||||||
|
|
@ -838,8 +838,7 @@ msgstr ""
|
||||||
#: daemon/keyboard_layout.c:83
|
#: daemon/keyboard_layout.c:83
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "Could not load keyboard layout from %s/x52d (%s)"
|
msgid "Could not load keyboard layout from %s/x52d (%s)"
|
||||||
msgstr ""
|
msgstr "ouldCay otnay oadlay eyboardkay ayoutlay omfray %s/x52d (%s)"
|
||||||
"ouldCay otnay oadlay eyboardkay ayoutlay omfray %s/x52d (%s)"
|
|
||||||
|
|
||||||
#: daemon/keyboard_layout.c:92
|
#: daemon/keyboard_layout.c:92
|
||||||
#, c-format
|
#, c-format
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue