mirror of https://github.com/nirenjan/libx52.git
Merge branch 'cmocka-tests'
commit
4311c020a0
|
@ -36,14 +36,15 @@ addons:
|
|||
- libudev-dev
|
||||
- autopoint
|
||||
- faketime
|
||||
- libcmocka-dev
|
||||
homebrew:
|
||||
packages:
|
||||
- libusb
|
||||
- gettext
|
||||
|
||||
# Ensure that gettext is available on OSX
|
||||
# Ensure that build dependencies are available on OSX
|
||||
before_script:
|
||||
- if [ "$TRAVIS_OS_NAME" = osx ]; then brew install libusb gettext ; fi
|
||||
- if [ "$TRAVIS_OS_NAME" = osx ]; then brew install libusb gettext cmocka ; fi
|
||||
|
||||
# Enable parallel make
|
||||
env:
|
||||
|
|
17
configure.ac
17
configure.ac
|
@ -17,6 +17,17 @@ LT_INIT
|
|||
PKG_PROG_PKG_CONFIG
|
||||
PKG_INSTALLDIR
|
||||
AX_COMPILER_FLAGS
|
||||
AC_CANONICAL_HOST
|
||||
|
||||
AC_MSG_NOTICE([Detected host OS is ${host_os}])
|
||||
build_linux=no
|
||||
# Detect target system
|
||||
case "${host_os}" in
|
||||
linux*)
|
||||
build_linux=yes
|
||||
;;
|
||||
esac
|
||||
AM_CONDITIONAL([LINUX], [test "x${build_linux}" = "xyes"])
|
||||
|
||||
# Internationalization
|
||||
AM_GNU_GETTEXT([external])
|
||||
|
@ -62,6 +73,12 @@ AM_COND_IF([HAVE_DOXYGEN],
|
|||
[AC_CONFIG_FILES([Doxyfile])],
|
||||
[AC_MSG_WARN(["Doxygen not found; continuing without doxygen support"])])
|
||||
|
||||
# cmocka unit tests
|
||||
AX_PKG_CHECK_MODULES([CMOCKA], [cmocka >= 1.1], [], [have_cmocka=yes], [have_cmocka=no])
|
||||
AM_CONDITIONAL([HAVE_CMOCKA], [test "x$have_cmocka" = xyes])
|
||||
AM_COND_IF([HAVE_CMOCKA], [],
|
||||
[AC_MSG_WARN(["cmocka not found; disabling unit test build"])])
|
||||
|
||||
# Check for the presence of tm_gmtoff in struct tm. If we have this, then we
|
||||
# can use it to determine the true GMT offset
|
||||
AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,
|
||||
|
|
|
@ -31,25 +31,28 @@ x52include_HEADERS = libx52.h
|
|||
# pkg-config files
|
||||
pkgconfig_DATA = libx52.pc
|
||||
|
||||
check_PROGRAMS = test_offset test_led test_blink_shift
|
||||
|
||||
test_offset_SOURCES = test_offset.c test_common.c
|
||||
test_offset_CFLAGS = @LIBUSB_CFLAGS@
|
||||
test_offset_LDADD = libx52.la
|
||||
|
||||
test_led_SOURCES = test_led.c test_common.c
|
||||
test_led_CFLAGS = @LIBUSB_CFLAGS@
|
||||
test_led_LDADD = libx52.la
|
||||
|
||||
test_blink_shift_SOURCES = test_blink_shift.c test_common.c
|
||||
test_blink_shift_CFLAGS = @LIBUSB_CFLAGS@
|
||||
test_blink_shift_LDADD = libx52.la
|
||||
|
||||
if HAVE_CMOCKA
|
||||
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) $(top_srcdir)/tap-driver.sh
|
||||
TESTS = test_offset test_led test_blink_shift
|
||||
TESTS = libx52test
|
||||
check_PROGRAMS = libx52test
|
||||
|
||||
nodist_libx52test_SOURCES = test_libx52.c
|
||||
libx52test_SOURCES = $(libx52_la_SOURCES)
|
||||
libx52test_CFLAGS = @LIBUSB_CFLAGS@ -DLOCALEDIR='"$(localedir)"' -I $(top_srcdir)
|
||||
libx52test_CFLAGS += -Dlibusb_control_transfer=__wrap_libusb_control_transfer
|
||||
libx52test_LDFLAGS = @CMOCKA_LIBS@ @LIBUSB_LIBS@
|
||||
libx52test_LDADD = libx52.la
|
||||
|
||||
CLEANFILES = test_libx52.c
|
||||
test_libx52.c: $(srcdir)/x52_test_gen.py $(srcdir)/x52_tests.json
|
||||
$(AM_V_GEN) $(PYTHON) $(srcdir)/x52_test_gen.py $(srcdir)/x52_tests.json > $@
|
||||
endif
|
||||
|
||||
# Extra files that need to be in the distribution
|
||||
EXTRA_DIST = libx52.h x52_commands.h x52_common.h test_common.h README.md
|
||||
EXTRA_DIST = libx52.h x52_commands.h x52_common.h README.md
|
||||
|
||||
# Add test files to the distribution
|
||||
EXTRA_DIST += x52_test_gen.py x52_tests.json
|
||||
|
||||
# Add documentation files to the distribution
|
||||
EXTRA_DIST += \
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver
|
||||
* Test program for validating blink and shift functionality
|
||||
*
|
||||
* Copyright (C) 2020 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "x52_common.h"
|
||||
#include "test_common.h"
|
||||
#include "x52_commands.h"
|
||||
|
||||
typedef int (*blink_shift_fn)(libx52_device *, uint8_t);
|
||||
|
||||
TEST_STRUCT (
|
||||
blink_shift_fn func;
|
||||
uint8_t state;
|
||||
struct ivpair data[2];
|
||||
)
|
||||
|
||||
#define on 1
|
||||
#define off 0
|
||||
|
||||
#define x52_shift_indicator 0xfd
|
||||
#define x52_shift_on 0x51
|
||||
#define x52_shift_off 0x50
|
||||
|
||||
#define x52_blink_indicator 0xb4
|
||||
#define x52_blink_on 0x51
|
||||
#define x52_blink_off 0x50
|
||||
|
||||
#define TEST(func, state) { #func "/" #state, libx52_set_ ## func, state, {{ x52_ ## func ## _indicator, x52_ ## func ## _ ## state}, {0, 0}}}
|
||||
|
||||
TEST_CASES = {
|
||||
TEST(blink, on),
|
||||
TEST(blink, off),
|
||||
TEST(shift, on),
|
||||
TEST(shift, off),
|
||||
};
|
||||
|
||||
TEST_FUNC()
|
||||
{
|
||||
TEST_INIT();
|
||||
int rc = (*test.func)(dev, test.state);
|
||||
|
||||
if (rc != LIBX52_SUCCESS) {
|
||||
PRINT_FAIL();
|
||||
printf("# Expected success, got %d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
TEST_VERIFY(test.data);
|
||||
}
|
||||
|
||||
TEST_MAIN()
|
|
@ -1,155 +0,0 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver
|
||||
* Common functionality for test programs
|
||||
*
|
||||
* Copyright (C) 2020 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "x52_common.h"
|
||||
#include "test_common.h"
|
||||
|
||||
#define MAX_DIAGS 32
|
||||
#define MAX_DIAG_SZ 256
|
||||
static int diag_count;
|
||||
static char diagnostic[MAX_DIAGS][MAX_DIAG_SZ];
|
||||
|
||||
#define ADD_DIAG(fmt_str, ...) do { \
|
||||
if (diag_count < MAX_DIAGS) { \
|
||||
snprintf(diagnostic[diag_count], MAX_DIAG_SZ, fmt_str, ##__VA_ARGS__); \
|
||||
diag_count++; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
/* Test vendor command function */
|
||||
int x52_test_vendor_command(libx52_device *dev, uint16_t index, uint16_t value)
|
||||
{
|
||||
struct x52_vendor_data *vdata = (struct x52_vendor_data *)dev->hdl;
|
||||
struct ivpair data = {index, value};
|
||||
|
||||
if (vdata->written < MAX_SZ) {
|
||||
vdata->data[vdata->written] = data;
|
||||
vdata->written++;
|
||||
}
|
||||
|
||||
return LIBX52_SUCCESS;
|
||||
}
|
||||
|
||||
/* Check expected data */
|
||||
bool x52_test_assert_expected(libx52_device *dev, struct ivpair *data)
|
||||
{
|
||||
int written = 0;
|
||||
struct x52_vendor_data *vdata = (struct x52_vendor_data *)dev->hdl;
|
||||
|
||||
while((data[written].index != 0 || data[written].value != 0) && written < vdata->written) {
|
||||
if ((data[written].index != vdata->data[written].index) ||
|
||||
(data[written].value != vdata->data[written].value)) {
|
||||
ADD_DIAG("Mismatched data at position %d:", written);
|
||||
ADD_DIAG("\tExpected: {%04x, %04x}", data[written].index, data[written].value);
|
||||
ADD_DIAG("\tObserved: {%04x, %04x}", vdata->data[written].index, vdata->data[written].value);
|
||||
return false;
|
||||
}
|
||||
|
||||
written++;
|
||||
}
|
||||
|
||||
if (data[written].index != 0 || data[written].value != 0) {
|
||||
ADD_DIAG("data written %d", written);
|
||||
ADD_DIAG("Insufficient data written, got only %d, additional expected:", written);
|
||||
while (data[written].index != 0 && data[written].value != 0) {
|
||||
ADD_DIAG("\t%04x %04x", data[written].index, data[written].value);
|
||||
written++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (vdata->written > written) {
|
||||
ADD_DIAG("More data written, expected only %d, got %d", written, vdata->written);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void x52_test_print_diagnostics(void)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < diag_count; i++) {
|
||||
printf("# %s\n", diagnostic[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void _x52_test_print_data(struct ivpair *data)
|
||||
{
|
||||
while (data->index != 0 || data->value != 0) {
|
||||
printf("%04x/%04x ", data->index, data->value);
|
||||
data++;
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
void x52_test_print_observed_data(libx52_device *dev)
|
||||
{
|
||||
struct x52_vendor_data *vdata = (struct x52_vendor_data *)dev->hdl;
|
||||
printf("Observed: ");
|
||||
_x52_test_print_data(vdata->data);
|
||||
}
|
||||
|
||||
void x52_test_print_expected_data(struct ivpair *data)
|
||||
{
|
||||
printf("Expected: ");
|
||||
_x52_test_print_data(data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize libx52, close any device handles, create a dummy handle
|
||||
* and override the vendor command function.
|
||||
*/
|
||||
libx52_device *x52_test_init(void)
|
||||
{
|
||||
libx52_device *dev;
|
||||
struct x52_vendor_data *vdata;
|
||||
int rc;
|
||||
|
||||
rc = libx52_init(&dev);
|
||||
if (rc != LIBX52_SUCCESS) {
|
||||
fputs(libx52_strerror(rc), stderr);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
(void)libx52_disconnect(dev);
|
||||
|
||||
/* Allocate memory for vendor data */
|
||||
vdata = calloc(1, sizeof(*vdata));
|
||||
if (vdata == NULL) {
|
||||
perror("vendor data calloc");
|
||||
libx52_exit(dev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Reset the diagnostics buffers */
|
||||
memset(diagnostic, 0, sizeof(diagnostic));
|
||||
diag_count = 0;
|
||||
|
||||
/* We don't need the device handle in test code, repurpose it */
|
||||
dev->hdl = (libusb_device_handle *)vdata;
|
||||
|
||||
/* Setup vendor command function */
|
||||
dev->vendor_cmd_fn = x52_test_vendor_command;
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
void x52_test_cleanup(libx52_device *dev)
|
||||
{
|
||||
free(dev->hdl);
|
||||
dev->hdl = NULL;
|
||||
libx52_exit(dev);
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver
|
||||
* Common functionality for test programs
|
||||
*
|
||||
* Copyright (C) 2020 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#ifndef _TEST_COMMON_H
|
||||
#define _TEST_COMMON_H
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "x52_common.h"
|
||||
|
||||
/* ivpair is a pair of index and value fields that are passed to the
|
||||
* test vendor command function.
|
||||
*/
|
||||
struct ivpair {
|
||||
uint16_t index;
|
||||
uint16_t value;
|
||||
};
|
||||
|
||||
#define MAX_SZ 100
|
||||
struct x52_vendor_data {
|
||||
int written;
|
||||
struct ivpair data[MAX_SZ];
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize libx52, close any device handles, create a dummy handle
|
||||
* and override the vendor command function.
|
||||
*/
|
||||
libx52_device *x52_test_init(void);
|
||||
|
||||
/*
|
||||
* Check if expected data matches with written data. Terminate expected
|
||||
* data with a pair of NULLs
|
||||
*/
|
||||
bool x52_test_assert_expected(libx52_device *dev, struct ivpair *data);
|
||||
|
||||
/* Print diagnostics to screen */
|
||||
void x52_test_print_diagnostics(void);
|
||||
|
||||
/* Cleanup test data */
|
||||
void x52_test_cleanup(libx52_device *dev);
|
||||
|
||||
void x52_test_print_observed_data(libx52_device *dev);
|
||||
void x52_test_print_expected_data(struct ivpair *data);
|
||||
|
||||
#define PRINT_FAIL() printf("not ok %d %s\n", tc_id+1, test.test_case_id)
|
||||
#define PRINT_PASS() printf("ok %d %s\n", tc_id+1, test.test_case_id)
|
||||
#define TEST_STRUCT(...) struct test_case { \
|
||||
const char *test_case_id; \
|
||||
__VA_ARGS__ \
|
||||
};
|
||||
|
||||
#define TEST_CASES const struct test_case test_cases[]
|
||||
#define TEST_FUNC() void run_test(int tc_id)
|
||||
#define TEST_INIT() \
|
||||
struct libx52_device *dev = x52_test_init(); \
|
||||
struct test_case test = test_cases[tc_id];
|
||||
|
||||
#define TEST_VERIFY(data) do { \
|
||||
int test_rc; \
|
||||
test_rc = libx52_update(dev); \
|
||||
if (test_rc != LIBX52_SUCCESS) { \
|
||||
PRINT_FAIL(); \
|
||||
printf("# libx52_update failed, rc = %d\n", test_rc); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
if (!x52_test_assert_expected(dev, data)) { \
|
||||
PRINT_FAIL(); \
|
||||
x52_test_print_diagnostics(); \
|
||||
x52_test_print_expected_data(data); \
|
||||
x52_test_print_observed_data(dev); \
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
PRINT_PASS(); \
|
||||
x52_test_cleanup(dev); \
|
||||
} while(0)
|
||||
|
||||
#define TEST_MAIN() int main() { \
|
||||
int i; \
|
||||
size_t tc_count = sizeof(test_cases) / sizeof(test_cases[0]); \
|
||||
printf("1..%lu\n", tc_count); \
|
||||
for (i = 0; i < tc_count; i++) { \
|
||||
run_test(i); \
|
||||
} \
|
||||
}
|
||||
|
||||
#endif // !defined _TEST_COMMON_H
|
|
@ -1,122 +0,0 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver
|
||||
* Test program for validating LED sets
|
||||
*
|
||||
* Copyright (C) 2020 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "x52_common.h"
|
||||
#include "test_common.h"
|
||||
#include "x52_commands.h"
|
||||
|
||||
TEST_STRUCT (
|
||||
libx52_led_id led_id;
|
||||
libx52_led_state state;
|
||||
int retval;
|
||||
struct ivpair data[3];
|
||||
)
|
||||
|
||||
#define X52_LED_CMD 0xb8
|
||||
#define UNSUPPORTED(led, state) { #led "/" #state " unsupported", LIBX52_LED_ ## led, LIBX52_LED_STATE_ ## state, LIBX52_ERROR_NOT_SUPPORTED}
|
||||
#define OFF_MONO(led) { #led "/Off", LIBX52_LED_## led, LIBX52_LED_STATE_OFF, LIBX52_SUCCESS, {{X52_LED_CMD, ((LIBX52_LED_ ## led) << 8)}, {0, 0}}}
|
||||
#define ON(led) { #led "/On", LIBX52_LED_## led, LIBX52_LED_STATE_ON, LIBX52_SUCCESS, {{X52_LED_CMD, ((LIBX52_LED_ ## led) << 8) | 1}, {0, 0}}}
|
||||
#define OFF_COLOR(led) { #led "/Off", LIBX52_LED_## led, LIBX52_LED_STATE_OFF, LIBX52_SUCCESS, {{X52_LED_CMD, ((LIBX52_LED_ ## led + 0) << 8)}, {X52_LED_CMD, ((LIBX52_LED_ ## led + 1) << 8)}, {0, 0}}}
|
||||
#define RED(led) { #led "/Red", LIBX52_LED_## led, LIBX52_LED_STATE_RED, LIBX52_SUCCESS, {{X52_LED_CMD, ((LIBX52_LED_ ## led + 0) << 8) | 1}, {X52_LED_CMD, ((LIBX52_LED_ ## led + 1) << 8) | 0}, {0, 0}}}
|
||||
#define AMBER(led) { #led "/Amber", LIBX52_LED_## led, LIBX52_LED_STATE_AMBER, LIBX52_SUCCESS, {{X52_LED_CMD, ((LIBX52_LED_ ## led + 0) << 8) | 1}, {X52_LED_CMD, ((LIBX52_LED_ ## led + 1) << 8) | 1}, {0, 0}}}
|
||||
#define GREEN(led) { #led "/Green", LIBX52_LED_## led, LIBX52_LED_STATE_GREEN, LIBX52_SUCCESS, {{X52_LED_CMD, ((LIBX52_LED_ ## led + 0) << 8) | 0}, {X52_LED_CMD, ((LIBX52_LED_ ## led + 1) << 8) | 1}, {0, 0}}}
|
||||
|
||||
TEST_CASES = {
|
||||
OFF_MONO(FIRE),
|
||||
ON(FIRE),
|
||||
UNSUPPORTED(FIRE, RED),
|
||||
UNSUPPORTED(FIRE, AMBER),
|
||||
UNSUPPORTED(FIRE, GREEN),
|
||||
|
||||
OFF_COLOR(A),
|
||||
UNSUPPORTED(A, ON),
|
||||
RED(A),
|
||||
AMBER(A),
|
||||
GREEN(A),
|
||||
|
||||
OFF_COLOR(B),
|
||||
UNSUPPORTED(B, ON),
|
||||
RED(B),
|
||||
AMBER(B),
|
||||
GREEN(B),
|
||||
|
||||
OFF_COLOR(D),
|
||||
UNSUPPORTED(D, ON),
|
||||
RED(D),
|
||||
AMBER(D),
|
||||
GREEN(D),
|
||||
|
||||
OFF_COLOR(E),
|
||||
UNSUPPORTED(E, ON),
|
||||
RED(E),
|
||||
AMBER(E),
|
||||
GREEN(E),
|
||||
|
||||
OFF_COLOR(T1),
|
||||
UNSUPPORTED(T1, ON),
|
||||
RED(T1),
|
||||
AMBER(T1),
|
||||
GREEN(T1),
|
||||
|
||||
OFF_COLOR(T2),
|
||||
UNSUPPORTED(T2, ON),
|
||||
RED(T2),
|
||||
AMBER(T2),
|
||||
GREEN(T2),
|
||||
|
||||
OFF_COLOR(T3),
|
||||
UNSUPPORTED(T3, ON),
|
||||
RED(T3),
|
||||
AMBER(T3),
|
||||
GREEN(T3),
|
||||
|
||||
OFF_COLOR(POV),
|
||||
UNSUPPORTED(POV, ON),
|
||||
RED(POV),
|
||||
AMBER(POV),
|
||||
GREEN(POV),
|
||||
|
||||
OFF_COLOR(CLUTCH),
|
||||
UNSUPPORTED(CLUTCH, ON),
|
||||
RED(CLUTCH),
|
||||
AMBER(CLUTCH),
|
||||
GREEN(CLUTCH),
|
||||
|
||||
OFF_MONO(THROTTLE),
|
||||
ON(THROTTLE),
|
||||
UNSUPPORTED(THROTTLE, RED),
|
||||
UNSUPPORTED(THROTTLE, AMBER),
|
||||
UNSUPPORTED(THROTTLE, GREEN),
|
||||
};
|
||||
|
||||
|
||||
TEST_FUNC()
|
||||
{
|
||||
TEST_INIT();
|
||||
|
||||
/* Set the X52Pro flag in dev->flags, otherwise libx52_set_led_state will
|
||||
* always return not supported
|
||||
*/
|
||||
dev->flags = 1;
|
||||
|
||||
int rc = libx52_set_led_state(dev, test.led_id, test.state);
|
||||
|
||||
if (rc != test.retval) {
|
||||
PRINT_FAIL();
|
||||
printf("# Expected retval %d, got %d\n", test.retval, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
TEST_VERIFY(test.data);
|
||||
}
|
||||
|
||||
TEST_MAIN()
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Saitek X52 Pro MFD & LED driver
|
||||
* Test program for validating offset calculation
|
||||
*
|
||||
* Copyright (C) 2020 Nirenjan Krishnan (nirenjan@nirenjan.org)
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-only WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "x52_common.h"
|
||||
#include "test_common.h"
|
||||
|
||||
TEST_STRUCT (
|
||||
int offset_primary;
|
||||
int offset_secondary;
|
||||
libx52_clock_id clock_id;
|
||||
uint16_t x52_clock;
|
||||
uint16_t x52_offset;
|
||||
)
|
||||
|
||||
#define TEST(id, o1, o23, offs) {id, o1, o23, LIBX52_CLOCK_2, 0xc1, offs}, {id, o1, o23, LIBX52_CLOCK_3, 0xc2, offs}
|
||||
|
||||
TEST_CASES = {
|
||||
TEST("Etc/UTC+24|Etc/UTC-24", -1440, +1440, 0),
|
||||
TEST("Etc/UTC-24|Etc/UTC+24", +1440, -1440, 0x0400), // Negative 0
|
||||
TEST("Honolulu|Auckland", -600, +720, 0x0478), // -2 hours
|
||||
TEST("Auckland|Honolulu", +720, -600, 0x0078), // +2 hours
|
||||
TEST("Etc/UTC+12|Etc/UTC-14", -720, +840, 0x078), // +2 hours
|
||||
TEST("Etc/UTC-14|Etc/UTC+12", +840, -720, 0x478), // -2 hours
|
||||
TEST("PDT|UTC", -420, 0, 0x1a4), // +7 hours
|
||||
TEST("UTC|PDT", 0, -420, 0x5a4), // -7 hours
|
||||
TEST("PST|UTC", -480, 0, 0x1e0), // +8 hours
|
||||
TEST("UTC|PST", 0, -480, 0x5e0), // -8 hours
|
||||
TEST("Etc/UTC+12|Etc/UTC-12", -720, +720, 0),
|
||||
TEST("Etc/UTC-12|Etc/UTC+12", +720, -720, 0x0400),
|
||||
};
|
||||
|
||||
TEST_FUNC()
|
||||
{
|
||||
TEST_INIT();
|
||||
int rc;
|
||||
struct ivpair data[2] = { 0 };
|
||||
|
||||
dev->timezone[LIBX52_CLOCK_1] = test.offset_primary;
|
||||
rc = libx52_set_clock_timezone(dev, test.clock_id, test.offset_secondary);
|
||||
if (rc != LIBX52_SUCCESS) {
|
||||
PRINT_FAIL();
|
||||
printf("# set_clock_timezone failed, rc = %d\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
data[0].index = test.x52_clock;
|
||||
data[0].value = test.x52_offset;
|
||||
TEST_VERIFY(data);
|
||||
}
|
||||
|
||||
TEST_MAIN();
|
|
@ -25,8 +25,6 @@
|
|||
#define X52_MFD_LINES 3
|
||||
#define X52_MFD_CLOCKS 3
|
||||
|
||||
typedef int (*x52_vendor_command)(libx52_device *x52, uint16_t index, uint16_t value);
|
||||
|
||||
struct x52_mfd_line {
|
||||
uint8_t text[X52_MFD_LINE_SIZE];
|
||||
uint8_t length;
|
||||
|
@ -53,7 +51,6 @@ struct libx52_device {
|
|||
|
||||
int timezone[X52_MFD_CLOCKS];
|
||||
libx52_clock_format time_format[X52_MFD_CLOCKS];
|
||||
x52_vendor_command vendor_cmd_fn;
|
||||
};
|
||||
|
||||
/** Flag bits */
|
||||
|
@ -108,6 +105,5 @@ static inline uint32_t tst_bit(uint32_t *value, uint32_t bit)
|
|||
}
|
||||
|
||||
int _x52_translate_libusb_error(enum libusb_error errcode);
|
||||
int _x52_vendor_command(libx52_device *x52, uint16_t index, uint16_t value);
|
||||
|
||||
#endif /* !defined X52JOY_COMMON_H */
|
||||
|
|
|
@ -66,11 +66,18 @@ int _x52_translate_libusb_error(enum libusb_error errcode)
|
|||
};
|
||||
}
|
||||
|
||||
int _x52_vendor_command(libx52_device *x52, uint16_t index, uint16_t value)
|
||||
int libx52_vendor_command(libx52_device *x52, uint16_t index, uint16_t value)
|
||||
{
|
||||
int j;
|
||||
int rc = 0;
|
||||
|
||||
/* It is possible for the vendor command to be called when the joystick
|
||||
* is not connected. Check for this and return an appropriate error.
|
||||
*/
|
||||
if (!x52->hdl) {
|
||||
return LIBX52_ERROR_NO_DEVICE;
|
||||
}
|
||||
|
||||
/* Allow retry in case of failure */
|
||||
for (j = 0; j < 3; j++) {
|
||||
rc = libusb_control_transfer(x52->hdl,
|
||||
|
@ -82,22 +89,6 @@ int _x52_vendor_command(libx52_device *x52, uint16_t index, uint16_t value)
|
|||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libx52_vendor_command(libx52_device *x52, uint16_t index, uint16_t value)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/* It is possible for the vendor command to be called when the joystick
|
||||
* is not connected. Check for this and return an appropriate error.
|
||||
*/
|
||||
if (!x52->hdl || !x52->vendor_cmd_fn) {
|
||||
return LIBX52_ERROR_NO_DEVICE;
|
||||
}
|
||||
|
||||
rc = (*(x52->vendor_cmd_fn))(x52, index, value);
|
||||
|
||||
/* Handle device removal */
|
||||
if (rc == LIBUSB_ERROR_NO_DEVICE) {
|
||||
/* Physical device has likely been disconnected, disconnect the virtual
|
||||
|
|
|
@ -61,7 +61,6 @@ int libx52_disconnect(libx52_device *dev)
|
|||
libusb_close(dev->hdl);
|
||||
dev->hdl = NULL;
|
||||
dev->flags = 0;
|
||||
dev->vendor_cmd_fn = NULL;
|
||||
}
|
||||
|
||||
return LIBX52_SUCCESS;
|
||||
|
@ -103,9 +102,6 @@ int libx52_connect(libx52_device *dev)
|
|||
|
||||
dev->hdl = hdl;
|
||||
|
||||
/* Use default vendor command function */
|
||||
dev->vendor_cmd_fn = _x52_vendor_command;
|
||||
|
||||
if (libx52_device_is_x52pro(desc.idProduct)) {
|
||||
set_bit(&(dev->flags), X52_FLAG_IS_PRO);
|
||||
}
|
||||
|
|
|
@ -116,19 +116,21 @@ static int x52pro_set_led_state(libx52_device *x52, libx52_led_id led, libx52_le
|
|||
|
||||
int libx52_set_led_state(libx52_device *x52, libx52_led_id led, libx52_led_state state)
|
||||
{
|
||||
int rc;
|
||||
if (!x52) {
|
||||
return LIBX52_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
if (tst_bit(&x52->flags, X52_FLAG_IS_PRO)) {
|
||||
rc = libx52_check_feature(x52, LIBX52_FEATURE_LED);
|
||||
if (rc == LIBX52_SUCCESS) {
|
||||
return x52pro_set_led_state(x52, led, state);
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, we only support setting the LEDs on the X52 Pro model.
|
||||
* The non-Pro X52 does not support setting individual LED states.
|
||||
* Calling this API on a non-Pro model will return a not supported error.
|
||||
*/
|
||||
return LIBX52_ERROR_NOT_SUPPORTED;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int libx52_set_brightness(libx52_device *x52, uint8_t mfd, uint16_t brightness)
|
||||
|
|
|
@ -0,0 +1,231 @@
|
|||
#!/usr/bin/env python3
|
||||
"""libx52 test generator program, writes test program to stdout"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
|
||||
_TEST_FILE_HEADER = """/*
|
||||
* libx52 test program
|
||||
*
|
||||
* This file is automatically generated. DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "x52_common.h"
|
||||
|
||||
static int group_setup(void **state)
|
||||
{
|
||||
libx52_device *dev;
|
||||
int rc;
|
||||
|
||||
rc = libx52_init(&dev);
|
||||
if (rc != LIBX52_SUCCESS) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Disconnect any potentially connected joysticks */
|
||||
(void)libx52_disconnect(dev);
|
||||
|
||||
/* Create a dummy handle so that libx52_update doesn't abort early */
|
||||
dev->hdl = (void *)(uintptr_t)(-1);
|
||||
|
||||
*state = dev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int group_teardown(void **state)
|
||||
{
|
||||
libx52_device *dev = *state;
|
||||
|
||||
dev->hdl = NULL;
|
||||
libx52_exit(dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_setup(void **state)
|
||||
{
|
||||
libx52_device *dev = *state;
|
||||
void *context = dev->ctx;
|
||||
void *handle = dev->hdl;
|
||||
memset(dev, 0, sizeof(*dev));
|
||||
dev->ctx = context;
|
||||
dev->hdl = handle;
|
||||
/* Set flags to 1 to indicate that we are testing X52 Pro */
|
||||
dev->flags = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __wrap_libusb_control_transfer(libusb_device_handle *dev_handle,
|
||||
uint8_t request_type,
|
||||
uint8_t bRequest,
|
||||
uint16_t wValue,
|
||||
uint16_t wIndex,
|
||||
unsigned char *data,
|
||||
uint16_t wLength,
|
||||
unsigned int timeout)
|
||||
{
|
||||
function_called();
|
||||
check_expected(wIndex);
|
||||
check_expected(wValue);
|
||||
assert_int_equal(request_type,
|
||||
LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE | LIBUSB_ENDPOINT_OUT);
|
||||
assert_int_equal(bRequest, 0x91);
|
||||
assert_null(data);
|
||||
assert_int_equal(wLength, 0);
|
||||
assert_int_equal(timeout, 5000);
|
||||
|
||||
return mock();
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
_TEST_FUNCTION_HEADER = """
|
||||
static void {}(void **state)
|
||||
{{
|
||||
libx52_device *dev = *state;
|
||||
int rc;
|
||||
"""
|
||||
|
||||
_TEST_FUNCTION_FOOTER_NORMAL = """
|
||||
assert_int_equal(rc, LIBX52_SUCCESS);
|
||||
|
||||
rc = libx52_update(dev);
|
||||
assert_int_equal(rc, LIBX52_SUCCESS);
|
||||
}
|
||||
"""
|
||||
|
||||
_TEST_FUNCTION_FOOTER_ERROR = """
|
||||
assert_int_equal(rc, LIBX52_ERROR_{});
|
||||
}}
|
||||
"""
|
||||
|
||||
class Test():
|
||||
"""Test case class, single test"""
|
||||
|
||||
def __init__(self, group, obj):
|
||||
"""Load test case from an object"""
|
||||
self.function = group.function
|
||||
self.name = group.name
|
||||
self.params_prefix = group.params_prefix
|
||||
self.params = obj["params"]
|
||||
self.setup_hook = group.setup_hook + obj.get("setup_hook", [])
|
||||
self.fields = group.fields.copy()
|
||||
self.fields.update(obj.get("fields", {}))
|
||||
|
||||
if len(self.params_prefix) < len(self.params):
|
||||
self.params_prefix.extend([''] * (len(self.params) - len(self.params_prefix)))
|
||||
|
||||
self.output = obj.get("output", [])
|
||||
self.retval = obj.get("retval", "")
|
||||
|
||||
def definition(self):
|
||||
test_name = self.name + '_' + '_'.join(p.strip('"').replace('-','_') for p in self.params)
|
||||
return test_name.lower()
|
||||
|
||||
def print(self):
|
||||
print(_TEST_FUNCTION_HEADER.format(self.definition()))
|
||||
|
||||
if self.fields:
|
||||
for arg, val in self.fields.items():
|
||||
print(" dev->{} = {};".format(arg, val))
|
||||
|
||||
if self.setup_hook:
|
||||
# Setup hook is an array of C commands that need to be executed
|
||||
# prior to setting up the wrapper and running the tests
|
||||
for hook in self.setup_hook:
|
||||
print(" {}".format(hook))
|
||||
|
||||
if self.output:
|
||||
print(" expect_function_calls(__wrap_libusb_control_transfer, {});".format(len(self.output)))
|
||||
print(" will_return_count(__wrap_libusb_control_transfer, LIBUSB_SUCCESS, {});".format(len(self.output)))
|
||||
|
||||
for idx, val in self.output:
|
||||
print(" expect_value(__wrap_libusb_control_transfer, wIndex, 0x{});".format(idx))
|
||||
print(" expect_value(__wrap_libusb_control_transfer, wValue, 0x{});".format(val))
|
||||
|
||||
params = ', '.join(''.join(p) for p in zip(self.params_prefix, self.params))
|
||||
print(" rc = {}(dev, {});".format(self.function, params))
|
||||
|
||||
if self.retval:
|
||||
print(_TEST_FUNCTION_FOOTER_ERROR.format(self.retval))
|
||||
else:
|
||||
print(_TEST_FUNCTION_FOOTER_NORMAL);
|
||||
|
||||
_TEST_GROUP_HEADER = "const struct CMUnitTest tests[] = {"
|
||||
_TEST_GROUP_FOOTER = "};"
|
||||
|
||||
class TestGroup():
|
||||
"""Test group class, contains multiple tests"""
|
||||
|
||||
def __init__(self, name, obj):
|
||||
"""Load test cases from an object"""
|
||||
self.name = name
|
||||
self.function = obj["function"]
|
||||
self.fields = obj.get("fields", {})
|
||||
self.setup_hook = obj.get("setup_hook", [])
|
||||
self.params_prefix = obj.get("params_prefix", [])
|
||||
self.tests = []
|
||||
for test in obj["tests"]:
|
||||
self.tests.append(Test(self, test))
|
||||
|
||||
def definition(self):
|
||||
return self.name.lower() + "_tests"
|
||||
|
||||
def print(self):
|
||||
"""Print the test group"""
|
||||
for test in self.tests:
|
||||
test.print()
|
||||
|
||||
_MAIN = """
|
||||
int main(void)
|
||||
{
|
||||
cmocka_set_message_output(CM_OUTPUT_TAP);
|
||||
cmocka_run_group_tests(tests, group_setup, group_teardown);
|
||||
return 0;
|
||||
}
|
||||
"""
|
||||
|
||||
class TestSuite():
|
||||
"""Test suite class, contains multiple test cases"""
|
||||
|
||||
def __init__(self, file):
|
||||
"""Load test suite"""
|
||||
with open(file, 'r') as infile:
|
||||
self.data = json.load(infile)
|
||||
self.groups = []
|
||||
for group, obj in self.data.items():
|
||||
self.groups.append(TestGroup(group, obj))
|
||||
|
||||
def print(self):
|
||||
print(_TEST_FILE_HEADER)
|
||||
|
||||
for group in self.groups:
|
||||
group.print()
|
||||
|
||||
print(_TEST_GROUP_HEADER)
|
||||
for group in self.groups:
|
||||
for test in group.tests:
|
||||
print(" cmocka_unit_test_setup({}, test_setup),".format(test.definition()))
|
||||
print(_TEST_GROUP_FOOTER)
|
||||
print(_MAIN)
|
||||
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
sys.stderr.write('Usage: %s <test-definitions>\n' %
|
||||
sys.argv[0])
|
||||
sys.exit(1)
|
||||
|
||||
TestSuite(sys.argv[1]).print()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue