mirror of
https://gitlab.freedesktop.org/libinput/libinput.git
synced 2025-12-20 02:10:07 +01:00
This avoids mixing up milliseconds and usec, both by failing if we're providing just a number somewhere we expect usecs and also by making the API blindingly obvious that we're in usecs now. Part-of: <https://gitlab.freedesktop.org/libinput/libinput/-/merge_requests/1373>
3412 lines
88 KiB
C
3412 lines
88 KiB
C
/*
|
|
* Copyright © 2014 Red Hat, Inc.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice (including the next
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
* Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include <config.h>
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <valgrind/valgrind.h>
|
|
|
|
#include "util-bits.h"
|
|
#include "util-files.h"
|
|
#include "util-input-event.h"
|
|
#include "util-list.h"
|
|
#include "util-macros.h"
|
|
#include "util-matrix.h"
|
|
#include "util-mem.h"
|
|
#include "util-newtype.h"
|
|
#include "util-prop-parsers.h"
|
|
#include "util-range.h"
|
|
#include "util-ratelimit.h"
|
|
#include "util-stringbuf.h"
|
|
#include "util-strings.h"
|
|
#include "util-time.h"
|
|
|
|
#include "evdev-frame.h"
|
|
#include "litest-runner.h"
|
|
#include "litest.h"
|
|
|
|
#define TEST_VERSIONSORT
|
|
#include "libinput-versionsort.h"
|
|
|
|
START_TEST(auto_test)
|
|
{
|
|
/* This one is just a compile test */
|
|
auto tv = usec_to_timeval(usec_from_uint64_t(0));
|
|
tv.tv_sec = 0;
|
|
litest_assert_int_eq(tv.tv_sec, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(mkdir_p_test)
|
|
{
|
|
const char *testdir = "/tmp/litest_mkdir_test";
|
|
litest_assert_neg_errno_success(mkdir_p("/"));
|
|
|
|
rmdir(testdir);
|
|
litest_assert_neg_errno_success(mkdir_p(testdir));
|
|
/* EEXIST is not an error */
|
|
litest_assert_neg_errno_success(mkdir_p(testdir));
|
|
rmdir(testdir);
|
|
|
|
int ret = mkdir_p("/proc/foo");
|
|
litest_assert_msg(ret == -ENOENT || ret == -EACCES,
|
|
"mkdir_p(\"/proc/foo\") returned %d\n",
|
|
ret);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(rmdir_r_test)
|
|
{
|
|
const char *testdir = "/tmp/litest_rmdir_test";
|
|
_autofree_ char *path = strdup_printf("%s/foo/bar/baz", testdir);
|
|
mkdir_p(path);
|
|
|
|
_autofree_ char *f1 = strdup_printf("%s/remain", testdir);
|
|
_autofree_ char *f2 = strdup_printf("%s/foo/remove", testdir);
|
|
_autofree_ char *f3 = strdup_printf("%s/foo/bar/to-remove", testdir);
|
|
_autofree_ char *f4 = strdup_printf("%s/foo/bar/baz/wipeme", testdir);
|
|
|
|
litest_assert_errno_success(close(open(f1, O_WRONLY | O_CREAT, 0644)));
|
|
litest_assert_errno_success(close(open(f2, O_WRONLY | O_CREAT, 0644)));
|
|
litest_assert_errno_success(close(open(f3, O_WRONLY | O_CREAT, 0644)));
|
|
litest_assert_errno_success(close(open(f4, O_WRONLY | O_CREAT, 0644)));
|
|
|
|
struct stat st;
|
|
litest_assert_errno_success(stat(f1, &st));
|
|
litest_assert_errno_success(stat(f2, &st));
|
|
litest_assert_errno_success(stat(f3, &st));
|
|
litest_assert_errno_success(stat(f4, &st));
|
|
|
|
_autofree_ char *rmpath = strdup_printf("%s/foo/", testdir);
|
|
int rc = rmdir_r(rmpath);
|
|
litest_assert_neg_errno_success(rc);
|
|
|
|
litest_assert_errno_success(stat(f1, &st));
|
|
litest_assert_errno_success(stat(testdir, &st));
|
|
|
|
rc = stat(f2, &st) < 0 ? -errno : 0;
|
|
litest_assert_int_eq(rc, -ENOENT);
|
|
rc = stat(f3, &st) < 0 ? -errno : 0;
|
|
litest_assert_int_eq(rc, -ENOENT);
|
|
rc = stat(f4, &st) < 0 ? -errno : 0;
|
|
litest_assert_int_eq(rc, -ENOENT);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(tmpdir_test)
|
|
{
|
|
_autofree_ char *tmpdir_path = NULL;
|
|
{
|
|
_destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
|
|
|
|
tmpdir_path = safe_strdup(tmpdir->path);
|
|
|
|
_autofree_ char *f1 = strdup_printf("%s/wipeme", tmpdir_path);
|
|
litest_assert_errno_success(close(open(f1, O_WRONLY | O_CREAT, 0644)));
|
|
}
|
|
struct stat st;
|
|
int rc = stat(tmpdir_path, &st) < 0 ? -errno : 0;
|
|
litest_assert_int_eq(rc, -ENOENT);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(find_files_test)
|
|
{
|
|
_autofree_ char *dirname = strdup("/tmp/litest_find_files_test.XXXXXX");
|
|
mkdtemp(dirname);
|
|
|
|
_autofree_ char *d1 = strdup_printf("%s/d1", dirname);
|
|
_autofree_ char *d2 = strdup_printf("%s/d2", dirname);
|
|
_autofree_ char *d3 = strdup_printf("%s/d3", dirname);
|
|
|
|
litest_assert_neg_errno_success(mkdir_p(d1));
|
|
litest_assert_neg_errno_success(mkdir_p(d2));
|
|
litest_assert_neg_errno_success(mkdir_p(d3));
|
|
|
|
/* clang-format off */
|
|
struct f {
|
|
const char *name;
|
|
const char *dir1;
|
|
const char *dir2;
|
|
const char *dir3;
|
|
char *expected;
|
|
} files[] = {
|
|
{ "10-abc.suf", d1, d2, d3 },
|
|
{ "20-def.suf", d1, NULL, d3 },
|
|
{ "30-ghi.suf", d1, d2, NULL },
|
|
{ "40-jkl.suf", NULL, d2, NULL },
|
|
{ "50-mno.suf", NULL, d2, d3 },
|
|
{ "60-pgr.suf", NULL, NULL, d3 },
|
|
{ "70-abc.suf", NULL, NULL, d3 },
|
|
{ "21-xyz.fix", NULL, NULL, d3 },
|
|
{ "35-uvw.fix", NULL, d2, d3 },
|
|
{ "70-rst.fix", d1, NULL, d3 },
|
|
{ NULL },
|
|
};
|
|
/* clang-format on */
|
|
for (struct f *f = files; f->name; f++) {
|
|
if (f->dir1) {
|
|
_autofree_ char *path =
|
|
strdup_printf("%s/%s", f->dir1, f->name);
|
|
close(open(path, O_WRONLY | O_CREAT, 0644));
|
|
f->expected = steal(&path);
|
|
}
|
|
if (f->dir2) {
|
|
_autofree_ char *path =
|
|
strdup_printf("%s/%s", f->dir2, f->name);
|
|
close(open(path, O_WRONLY | O_CREAT, 0644));
|
|
if (!f->expected)
|
|
f->expected = steal(&path);
|
|
}
|
|
if (f->dir3) {
|
|
_autofree_ char *path =
|
|
strdup_printf("%s/%s", f->dir3, f->name);
|
|
close(open(path, O_WRONLY | O_CREAT, 0644));
|
|
if (!f->expected)
|
|
f->expected = steal(&path);
|
|
}
|
|
}
|
|
|
|
const char *dirs[] = { d1, d2, d3, NULL };
|
|
size_t nfiles;
|
|
_autostrvfree_ char **paths = list_files(dirs, "suf", &nfiles);
|
|
litest_assert_int_eq(nfiles, (size_t)7);
|
|
litest_assert_str_eq(paths[0], files[0].expected);
|
|
litest_assert_str_eq(paths[1], files[1].expected);
|
|
litest_assert_str_eq(paths[2], files[2].expected);
|
|
litest_assert_str_eq(paths[3], files[3].expected);
|
|
litest_assert_str_eq(paths[4], files[4].expected);
|
|
litest_assert_str_eq(paths[5], files[5].expected);
|
|
litest_assert_str_eq(paths[6], files[6].expected);
|
|
litest_assert_str_eq(paths[7], NULL);
|
|
|
|
for (struct f *f = files; f->name; f++) {
|
|
if (f->dir1) {
|
|
_autofree_ char *path =
|
|
strdup_printf("%s/%s", f->dir1, f->name);
|
|
unlink(path);
|
|
}
|
|
if (f->dir2) {
|
|
_autofree_ char *path =
|
|
strdup_printf("%s/%s", f->dir2, f->name);
|
|
unlink(path);
|
|
}
|
|
if (f->dir3) {
|
|
_autofree_ char *path =
|
|
strdup_printf("%s/%s", f->dir3, f->name);
|
|
unlink(path);
|
|
}
|
|
free(f->expected);
|
|
}
|
|
rmdir(d1);
|
|
rmdir(d2);
|
|
rmdir(d3);
|
|
rmdir(dirname);
|
|
|
|
const char *empty[] = { NULL };
|
|
_autostrvfree_ char **empty_path = list_files(empty, "suf", &nfiles);
|
|
litest_assert_int_eq(nfiles, (size_t)0);
|
|
litest_assert_ptr_notnull(empty_path);
|
|
litest_assert_ptr_null(empty_path[0]);
|
|
|
|
_autostrvfree_ char **also_empty_path = list_files(NULL, "suf", &nfiles);
|
|
litest_assert_int_eq(nfiles, (size_t)0);
|
|
litest_assert_ptr_notnull(also_empty_path);
|
|
litest_assert_ptr_null(also_empty_path[0]);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(array_for_each)
|
|
{
|
|
int ai[6];
|
|
char ac[10];
|
|
struct as {
|
|
int a;
|
|
char b;
|
|
int *ptr;
|
|
} as[32];
|
|
|
|
for (size_t i = 0; i < 6; i++)
|
|
ai[i] = 20 + i;
|
|
for (size_t i = 0; i < 10; i++)
|
|
ac[i] = 100 + i;
|
|
for (size_t i = 0; i < 32; i++) {
|
|
as[i].a = 10 + i;
|
|
as[i].b = 20 + i;
|
|
as[i].ptr = (int *)0xab + i;
|
|
}
|
|
|
|
int iexpected = 20;
|
|
ARRAY_FOR_EACH(ai, entry) {
|
|
litest_assert_int_eq(*entry, iexpected);
|
|
++iexpected;
|
|
}
|
|
litest_assert_int_eq(iexpected, 26);
|
|
|
|
int cexpected = 100;
|
|
ARRAY_FOR_EACH(ac, entry) {
|
|
litest_assert_int_eq(*entry, cexpected);
|
|
++cexpected;
|
|
}
|
|
litest_assert_int_eq(cexpected, 110);
|
|
|
|
struct as sexpected = {
|
|
.a = 10,
|
|
.b = 20,
|
|
.ptr = (int *)0xab,
|
|
};
|
|
ARRAY_FOR_EACH(as, entry) {
|
|
litest_assert_int_eq(entry->a, sexpected.a);
|
|
litest_assert_int_eq(entry->b, sexpected.b);
|
|
litest_assert_ptr_eq(entry->ptr, sexpected.ptr);
|
|
++sexpected.a;
|
|
++sexpected.b;
|
|
++sexpected.ptr;
|
|
}
|
|
litest_assert_int_eq(sexpected.a, 42);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(bitfield_helpers)
|
|
{
|
|
/* This value has a bit set on all of the word boundaries we want to
|
|
* test: 0, 1, 7, 8, 31, 32, and 33
|
|
*/
|
|
unsigned char read_bitfield[] = { 0x83, 0x1, 0x0, 0x80, 0x3 };
|
|
unsigned char write_bitfield[ARRAY_LENGTH(read_bitfield)] = { 0 };
|
|
size_t i;
|
|
|
|
/* Now check that the bitfield we wrote to came out to be the same as
|
|
* the bitfield we were writing from */
|
|
for (i = 0; i < ARRAY_LENGTH(read_bitfield) * 8; i++) {
|
|
switch (i) {
|
|
case 0:
|
|
case 1:
|
|
case 7:
|
|
case 8:
|
|
case 31:
|
|
case 32:
|
|
case 33:
|
|
litest_assert(bit_is_set(read_bitfield, i));
|
|
set_bit(write_bitfield, i);
|
|
break;
|
|
default:
|
|
litest_assert(!bit_is_set(read_bitfield, i));
|
|
clear_bit(write_bitfield, i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
litest_assert_int_eq(
|
|
memcmp(read_bitfield, write_bitfield, sizeof(read_bitfield)),
|
|
0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(bitmask_test)
|
|
{
|
|
{
|
|
bitmask_t mask1 = bitmask_from_u32(0x12345678U);
|
|
litest_assert(bitmask_as_u32(mask1) == 0x12345678U);
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0);
|
|
litest_assert_int_eq(bitmask_as_u32(mask2), 0U);
|
|
|
|
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
|
litest_assert_int_eq(bitmask_as_u32(mask3), 0xFFFFFFFFU);
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_new();
|
|
litest_assert(bitmask_is_empty(mask1));
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0x00000001U);
|
|
litest_assert(!bitmask_is_empty(mask2));
|
|
|
|
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
|
litest_assert(!bitmask_is_empty(mask3));
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_from_u32(0x0000000FU);
|
|
bitmask_t bits1 = bitmask_from_u32(0x00000003U);
|
|
litest_assert(bitmask_any(mask1, bits1));
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
|
bitmask_t bits2 = bitmask_from_u32(0x000000F0U);
|
|
litest_assert(!bitmask_any(mask2, bits2));
|
|
|
|
bitmask_t mask3 = bitmask_from_u32(0x00000000U);
|
|
bitmask_t bits3 = bitmask_from_u32(0x00000001U);
|
|
litest_assert(!bitmask_any(mask3, bits3));
|
|
|
|
bitmask_t mask4 = bitmask_from_u32(0xFFFFFFFFU);
|
|
bitmask_t bits4 = bitmask_from_u32(0xFFFFFFFFU);
|
|
litest_assert(bitmask_any(mask4, bits4));
|
|
|
|
bitmask_t mask5 = bitmask_from_u32(0x10000000U);
|
|
bitmask_t bits5 = bitmask_from_u32(0x10000000U);
|
|
litest_assert(bitmask_any(mask5, bits5));
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_from_u32(0x0000000FU);
|
|
bitmask_t bits1 = bitmask_from_u32(0x00000003U);
|
|
litest_assert(bitmask_all(mask1, bits1));
|
|
litest_assert(!bitmask_all(bits1, mask1));
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
|
bitmask_t bits2 = bitmask_from_u32(0x0000000FU);
|
|
litest_assert(bitmask_all(mask2, bits2));
|
|
litest_assert(bitmask_all(bits2, mask2));
|
|
|
|
bitmask_t mask3 = bitmask_from_u32(0x00000000U);
|
|
bitmask_t bits3 = bitmask_from_u32(0x00000000U);
|
|
litest_assert(!bitmask_all(mask3, bits3)); /* zero is special */
|
|
|
|
bitmask_t mask4 = bitmask_from_u32(0xFFFFFFFFU);
|
|
bitmask_t bits4 = bitmask_from_u32(0xFFFFFFFFU);
|
|
litest_assert(bitmask_all(mask4, bits4));
|
|
|
|
bitmask_t mask5 = bitmask_from_u32(0x10000000U);
|
|
bitmask_t bits5 = bitmask_from_u32(0x10000000U);
|
|
litest_assert(bitmask_all(mask5, bits5));
|
|
}
|
|
{
|
|
|
|
bitmask_t mask1 = bitmask_from_u32(0x0000000FU);
|
|
bitmask_t bits1 = bitmask_from_u32(0x000000F0U);
|
|
litest_assert(!bitmask_merge(&mask1, bits1));
|
|
litest_assert_int_eq(mask1.mask, 0x000000FFU);
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
|
bitmask_t bits2 = bitmask_from_u32(0x0000000FU);
|
|
litest_assert(bitmask_merge(&mask2, bits2));
|
|
litest_assert_int_eq(mask2.mask, 0x0000000FU);
|
|
|
|
bitmask_t mask3 = bitmask_new();
|
|
bitmask_t bits3 = bitmask_from_u32(0xFFFFFFFFU);
|
|
litest_assert(!bitmask_merge(&mask3, bits3));
|
|
litest_assert_int_eq(mask3.mask, 0xFFFFFFFFU);
|
|
|
|
bitmask_t mask4 = bitmask_from_u32(0x80000000U);
|
|
bitmask_t bits4 = bitmask_from_u32(0x00000001U);
|
|
litest_assert(!bitmask_merge(&mask4, bits4));
|
|
litest_assert_int_eq(mask4.mask, 0x80000001U);
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_from_u32(0x000000FFU);
|
|
bitmask_t bits1 = bitmask_from_u32(0x0000000FU);
|
|
litest_assert(bitmask_clear(&mask1, bits1));
|
|
litest_assert_int_eq(mask1.mask, 0x000000F0U);
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
|
bitmask_t bits2 = bitmask_from_u32(0x0000000FU);
|
|
litest_assert(bitmask_clear(&mask2, bits2));
|
|
litest_assert_int_eq(mask2.mask, 0x00000000U);
|
|
|
|
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
|
bitmask_t bits3 = bitmask_from_u32(0x00000000U);
|
|
litest_assert(!bitmask_clear(&mask3, bits3)); /* zero is special */
|
|
litest_assert_int_eq(mask3.mask, 0xFFFFFFFFU);
|
|
|
|
bitmask_t mask4 = bitmask_from_u32(0xFFFFFFFFU);
|
|
bitmask_t bits4 = bitmask_from_u32(0xFFFFFFFFU);
|
|
litest_assert(bitmask_clear(&mask4, bits4));
|
|
litest_assert_int_eq(mask4.mask, 0x0U);
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_from_u32(0x00000001U);
|
|
litest_assert(bitmask_bit_is_set(mask1, 0));
|
|
litest_assert(!bitmask_bit_is_set(mask1, 1));
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0x80000000U);
|
|
litest_assert(bitmask_bit_is_set(mask2, 31));
|
|
litest_assert(!bitmask_bit_is_set(mask2, 0));
|
|
|
|
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
|
litest_assert(bitmask_bit_is_set(mask3, 0));
|
|
litest_assert(bitmask_bit_is_set(mask3, 31));
|
|
litest_assert(bitmask_bit_is_set(mask3, 16));
|
|
|
|
bitmask_t mask4 = bitmask_new();
|
|
litest_assert(!bitmask_bit_is_set(mask4, 0));
|
|
litest_assert(!bitmask_bit_is_set(mask4, 1));
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_new();
|
|
litest_assert(!bitmask_set_bit(&mask1, 0));
|
|
litest_assert_int_eq(mask1.mask, 0x00000001U);
|
|
|
|
litest_assert(bitmask_set_bit(&mask1, 0));
|
|
litest_assert_int_eq(mask1.mask, 0x00000001U);
|
|
|
|
litest_assert(!bitmask_set_bit(&mask1, 31));
|
|
litest_assert_int_eq(mask1.mask, 0x80000001U);
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0x0000000FU);
|
|
litest_assert(!bitmask_set_bit(&mask2, 4));
|
|
litest_assert_int_eq(mask2.mask, 0x0000001FU);
|
|
litest_assert(bitmask_set_bit(&mask2, 4));
|
|
litest_assert_int_eq(mask2.mask, 0x0000001FU);
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_from_u32(0xFFFFFFFFU);
|
|
litest_assert(bitmask_clear_bit(&mask1, 0));
|
|
litest_assert_int_eq(mask1.mask, 0xFFFFFFFEU);
|
|
|
|
litest_assert(!bitmask_clear_bit(&mask1, 0));
|
|
litest_assert_int_eq(mask1.mask, 0xFFFFFFFEU);
|
|
|
|
litest_assert(bitmask_clear_bit(&mask1, 31));
|
|
litest_assert_int_eq(mask1.mask, 0x7FFFFFFEU);
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0x0000001FU);
|
|
litest_assert(bitmask_clear_bit(&mask2, 4));
|
|
litest_assert_int_eq(mask2.mask, 0x0000000FU);
|
|
litest_assert(!bitmask_clear_bit(&mask2, 4));
|
|
litest_assert_int_eq(mask2.mask, 0x0000000FU);
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_from_bit(0);
|
|
litest_assert_int_eq(mask1.mask, 0x00000001U);
|
|
|
|
bitmask_t mask2 = bitmask_from_bit(31);
|
|
litest_assert_int_eq(mask2.mask, 0x80000000U);
|
|
|
|
bitmask_t mask3 = bitmask_from_bit(16);
|
|
litest_assert_int_eq(mask3.mask, 0x00010000U);
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_from_u32(0x12345678U);
|
|
litest_assert_int_eq(mask1.mask, 0x12345678U);
|
|
|
|
bitmask_t mask2 = bitmask_from_u32(0);
|
|
litest_assert_int_eq(mask2.mask, 0U);
|
|
|
|
bitmask_t mask3 = bitmask_from_u32(0xFFFFFFFFU);
|
|
litest_assert_int_eq(mask3.mask, 0xFFFFFFFFU);
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_from_bits(1, 2, 5);
|
|
litest_assert_int_eq(mask1.mask, bit(1) | bit(2) | bit(5));
|
|
|
|
bitmask_t mask2 = bitmask_from_bits(0);
|
|
litest_assert_int_eq(mask2.mask, bit(0));
|
|
}
|
|
{
|
|
bitmask_t mask1 = bitmask_from_masks(0x1, 0x2, 0x8);
|
|
litest_assert_int_eq(mask1.mask, 0x0000000BU);
|
|
|
|
bitmask_t mask2 = bitmask_from_masks(0x0);
|
|
litest_assert_int_eq(mask2.mask, 0x00000000U);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(matrix_helpers)
|
|
{
|
|
struct matrix m1, m2, m3;
|
|
float f[6] = { 1, 2, 3, 4, 5, 6 };
|
|
int x, y;
|
|
int row, col;
|
|
|
|
matrix_init_identity(&m1);
|
|
|
|
for (row = 0; row < 3; row++) {
|
|
for (col = 0; col < 3; col++) {
|
|
litest_assert_int_eq(m1.val[row][col], (row == col) ? 1 : 0);
|
|
}
|
|
}
|
|
litest_assert(matrix_is_identity(&m1));
|
|
|
|
matrix_from_farray6(&m2, f);
|
|
litest_assert_int_eq(m2.val[0][0], 1);
|
|
litest_assert_int_eq(m2.val[0][1], 2);
|
|
litest_assert_int_eq(m2.val[0][2], 3);
|
|
litest_assert_int_eq(m2.val[1][0], 4);
|
|
litest_assert_int_eq(m2.val[1][1], 5);
|
|
litest_assert_int_eq(m2.val[1][2], 6);
|
|
litest_assert_int_eq(m2.val[2][0], 0);
|
|
litest_assert_int_eq(m2.val[2][1], 0);
|
|
litest_assert_int_eq(m2.val[2][2], 1);
|
|
|
|
x = 100;
|
|
y = 5;
|
|
matrix_mult_vec(&m1, &x, &y);
|
|
litest_assert_int_eq(x, 100);
|
|
litest_assert_int_eq(y, 5);
|
|
|
|
matrix_mult(&m3, &m1, &m1);
|
|
litest_assert(matrix_is_identity(&m3));
|
|
|
|
matrix_init_scale(&m2, 2, 4);
|
|
litest_assert_int_eq(m2.val[0][0], 2);
|
|
litest_assert_int_eq(m2.val[0][1], 0);
|
|
litest_assert_int_eq(m2.val[0][2], 0);
|
|
litest_assert_int_eq(m2.val[1][0], 0);
|
|
litest_assert_int_eq(m2.val[1][1], 4);
|
|
litest_assert_int_eq(m2.val[1][2], 0);
|
|
litest_assert_int_eq(m2.val[2][0], 0);
|
|
litest_assert_int_eq(m2.val[2][1], 0);
|
|
litest_assert_int_eq(m2.val[2][2], 1);
|
|
|
|
matrix_mult_vec(&m2, &x, &y);
|
|
litest_assert_int_eq(x, 200);
|
|
litest_assert_int_eq(y, 20);
|
|
|
|
matrix_init_translate(&m2, 10, 100);
|
|
litest_assert_int_eq(m2.val[0][0], 1);
|
|
litest_assert_int_eq(m2.val[0][1], 0);
|
|
litest_assert_int_eq(m2.val[0][2], 10);
|
|
litest_assert_int_eq(m2.val[1][0], 0);
|
|
litest_assert_int_eq(m2.val[1][1], 1);
|
|
litest_assert_int_eq(m2.val[1][2], 100);
|
|
litest_assert_int_eq(m2.val[2][0], 0);
|
|
litest_assert_int_eq(m2.val[2][1], 0);
|
|
litest_assert_int_eq(m2.val[2][2], 1);
|
|
|
|
matrix_mult_vec(&m2, &x, &y);
|
|
litest_assert_int_eq(x, 210);
|
|
litest_assert_int_eq(y, 120);
|
|
|
|
matrix_to_farray6(&m2, f);
|
|
litest_assert_int_eq(f[0], 1);
|
|
litest_assert_int_eq(f[1], 0);
|
|
litest_assert_int_eq(f[2], 10);
|
|
litest_assert_int_eq(f[3], 0);
|
|
litest_assert_int_eq(f[4], 1);
|
|
litest_assert_int_eq(f[5], 100);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(ratelimit_helpers)
|
|
{
|
|
struct ratelimit rl;
|
|
unsigned int i, j;
|
|
|
|
/* 10 attempts every 1000ms */
|
|
ratelimit_init(&rl, usec_from_millis(1000), 10);
|
|
|
|
for (j = 0; j < 3; ++j) {
|
|
/* a burst of 9 attempts must succeed */
|
|
for (i = 0; i < 9; ++i) {
|
|
litest_assert_enum_eq(ratelimit_test(&rl), RATELIMIT_PASS);
|
|
}
|
|
|
|
/* the 10th attempt reaches the threshold */
|
|
litest_assert_enum_eq(ratelimit_test(&rl), RATELIMIT_THRESHOLD);
|
|
|
|
/* ..then further attempts must fail.. */
|
|
litest_assert_enum_eq(ratelimit_test(&rl), RATELIMIT_EXCEEDED);
|
|
|
|
/* ..regardless of how often we try. */
|
|
for (i = 0; i < 100; ++i) {
|
|
litest_assert_enum_eq(ratelimit_test(&rl), RATELIMIT_EXCEEDED);
|
|
}
|
|
|
|
/* ..even after waiting 20ms */
|
|
msleep(100);
|
|
for (i = 0; i < 100; ++i) {
|
|
litest_assert_enum_eq(ratelimit_test(&rl), RATELIMIT_EXCEEDED);
|
|
}
|
|
|
|
/* but after 1000ms the counter is reset */
|
|
msleep(950); /* +50ms to account for time drifts */
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
struct parser_test {
|
|
char *tag;
|
|
int expected_value;
|
|
};
|
|
|
|
START_TEST(dpi_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct parser_test tests[] = {
|
|
{ "450 *1800 3200", 1800 },
|
|
{ "*450 1800 3200", 450 },
|
|
{ "450 1800 *3200", 3200 },
|
|
{ "450 1800 3200", 3200 },
|
|
{ "450 1800 failboat", 0 },
|
|
{ "450 1800 *failboat", 0 },
|
|
{ "0 450 1800 *3200", 0 },
|
|
{ "450@37 1800@12 *3200@6", 3200 },
|
|
{ "450@125 1800@125 *3200@125 ", 3200 },
|
|
{ "450@125 *1800@125 3200@125", 1800 },
|
|
{ "*this @string fails", 0 },
|
|
{ "12@34 *45@", 0 },
|
|
{ "12@a *45@", 0 },
|
|
{ "12@a *45@25", 0 },
|
|
{ " * 12, 450, 800", 0 },
|
|
{ " *12, 450, 800", 12 },
|
|
{ "*12, *450, 800", 12 },
|
|
{ "*-23412, 450, 800", 0 },
|
|
{ "112@125, 450@125, 800@125, 900@-125", 0 },
|
|
{ "", 0 },
|
|
{ " ", 0 },
|
|
{ "* ", 0 },
|
|
{ NULL, 0 },
|
|
};
|
|
/* clang-format on */
|
|
int i, dpi;
|
|
|
|
for (i = 0; tests[i].tag != NULL; i++) {
|
|
dpi = parse_mouse_dpi_property(tests[i].tag);
|
|
litest_assert_int_eq(dpi, tests[i].expected_value);
|
|
}
|
|
|
|
dpi = parse_mouse_dpi_property(NULL);
|
|
litest_assert_int_eq(dpi, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(wheel_click_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct parser_test tests[] = {
|
|
{ "1", 1 },
|
|
{ "10", 10 },
|
|
{ "-12", -12 },
|
|
{ "360", 360 },
|
|
|
|
{ "0", 0 },
|
|
{ "-0", 0 },
|
|
{ "a", 0 },
|
|
{ "10a", 0 },
|
|
{ "10-", 0 },
|
|
{ "sadfasfd", 0 },
|
|
{ "361", 0 },
|
|
{ NULL, 0 },
|
|
};
|
|
/* clang-format on */
|
|
|
|
int i, angle;
|
|
|
|
for (i = 0; tests[i].tag != NULL; i++) {
|
|
angle = parse_mouse_wheel_click_angle_property(tests[i].tag);
|
|
litest_assert_int_eq(angle, tests[i].expected_value);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(wheel_click_count_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct parser_test tests[] = {
|
|
{ "1", 1 },
|
|
{ "10", 10 },
|
|
{ "-12", -12 },
|
|
{ "360", 360 },
|
|
|
|
{ "0", 0 },
|
|
{ "-0", 0 },
|
|
{ "a", 0 },
|
|
{ "10a", 0 },
|
|
{ "10-", 0 },
|
|
{ "sadfasfd", 0 },
|
|
{ "361", 0 },
|
|
{ NULL, 0 }
|
|
};
|
|
/* clang-format on */
|
|
|
|
int i, angle;
|
|
|
|
for (i = 0; tests[i].tag != NULL; i++) {
|
|
angle = parse_mouse_wheel_click_count_property(tests[i].tag);
|
|
litest_assert_int_eq(angle, tests[i].expected_value);
|
|
}
|
|
|
|
angle = parse_mouse_wheel_click_count_property(NULL);
|
|
litest_assert_int_eq(angle, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(dimension_prop_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct parser_test_dimension {
|
|
char *tag;
|
|
bool success;
|
|
size_t x, y;
|
|
} tests[] = {
|
|
{ "10x10", true, 10, 10 },
|
|
{ "1x20", true, 1, 20 },
|
|
{ "1x8000", true, 1, 8000 },
|
|
{ "238492x428210", true, 238492, 428210 },
|
|
{ "0x0", false, 0, 0 },
|
|
{ "-10x10", false, 0, 0 },
|
|
{ "-1", false, 0, 0 },
|
|
{ "1x-99", false, 0, 0 },
|
|
{ "0", false, 0, 0 },
|
|
{ "100", false, 0, 0 },
|
|
{ "", false, 0, 0 },
|
|
{ "abd", false, 0, 0 },
|
|
{ "xabd", false, 0, 0 },
|
|
{ "0xaf", false, 0, 0 },
|
|
{ "0x0x", false, 0, 0 },
|
|
{ "x10", false, 0, 0 },
|
|
{ NULL, false, 0, 0 },
|
|
};
|
|
/* clang-format on */
|
|
int i;
|
|
size_t x, y;
|
|
bool success;
|
|
|
|
for (i = 0; tests[i].tag != NULL; i++) {
|
|
x = y = 0xad;
|
|
success = parse_dimension_property(tests[i].tag, &x, &y);
|
|
litest_assert(success == tests[i].success);
|
|
if (success) {
|
|
litest_assert_int_eq(x, tests[i].x);
|
|
litest_assert_int_eq(y, tests[i].y);
|
|
} else {
|
|
litest_assert_int_eq(x, 0xadU);
|
|
litest_assert_int_eq(y, 0xadU);
|
|
}
|
|
}
|
|
|
|
success = parse_dimension_property(NULL, &x, &y);
|
|
litest_assert(success == false);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(reliability_prop_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct parser_test_reliability {
|
|
char *tag;
|
|
bool success;
|
|
enum switch_reliability reliability;
|
|
} tests[] = {
|
|
{ "reliable", true, RELIABILITY_RELIABLE },
|
|
{ "unreliable", true, RELIABILITY_UNRELIABLE },
|
|
{ "write_open", true, RELIABILITY_WRITE_OPEN },
|
|
{ "", false, 0 },
|
|
{ "0", false, 0 },
|
|
{ "1", false, 0 },
|
|
{ NULL, false, 0, },
|
|
};
|
|
/* clang-format on */
|
|
enum switch_reliability r;
|
|
bool success;
|
|
int i;
|
|
|
|
for (i = 0; tests[i].tag != NULL; i++) {
|
|
r = 0xaf;
|
|
success = parse_switch_reliability_property(tests[i].tag, &r);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_int_eq(r, tests[i].reliability);
|
|
else
|
|
litest_assert_int_eq(r, 0xafU);
|
|
}
|
|
|
|
success = parse_switch_reliability_property(NULL, &r);
|
|
litest_assert(success == true);
|
|
litest_assert_enum_eq(r, RELIABILITY_RELIABLE);
|
|
|
|
success = parse_switch_reliability_property("foo", NULL);
|
|
litest_assert(success == false);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(calibration_prop_parser)
|
|
{
|
|
#define DEFAULT_VALUES { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0 }
|
|
const float untouched[6] = DEFAULT_VALUES;
|
|
/* clang-format off */
|
|
struct parser_test_calibration {
|
|
char *prop;
|
|
bool success;
|
|
float values[6];
|
|
} tests[] = {
|
|
{ "", false, DEFAULT_VALUES },
|
|
{ "banana", false, DEFAULT_VALUES },
|
|
{ "1 2 3 a 5 6", false, DEFAULT_VALUES },
|
|
{ "2", false, DEFAULT_VALUES },
|
|
{ "2 3 4 5 6", false, DEFAULT_VALUES },
|
|
{ "1 2 3 4 5 6", true, DEFAULT_VALUES },
|
|
{ "6.00012 3.244 4.238 5.2421 6.0134 8.860", true,
|
|
{ 6.00012, 3.244, 4.238, 5.2421, 6.0134, 8.860 }},
|
|
{ "0xff 2 3 4 5 6", false, DEFAULT_VALUES },
|
|
{ NULL, false, DEFAULT_VALUES },
|
|
};
|
|
/* clang-format on */
|
|
bool success;
|
|
float calibration[6];
|
|
int rc;
|
|
int i;
|
|
|
|
for (i = 0; tests[i].prop != NULL; i++) {
|
|
memcpy(calibration, untouched, sizeof(calibration));
|
|
|
|
success = parse_calibration_property(tests[i].prop, calibration);
|
|
litest_assert_int_eq(success, tests[i].success);
|
|
if (success)
|
|
rc = memcmp(tests[i].values, calibration, sizeof(calibration));
|
|
else
|
|
rc = memcmp(untouched, calibration, sizeof(calibration));
|
|
litest_assert_int_eq(rc, 0);
|
|
}
|
|
|
|
memcpy(calibration, untouched, sizeof(calibration));
|
|
|
|
success = parse_calibration_property(NULL, calibration);
|
|
litest_assert(success == false);
|
|
rc = memcmp(untouched, calibration, sizeof(calibration));
|
|
litest_assert_int_eq(rc, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(range_prop_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct parser_test_range {
|
|
char *tag;
|
|
bool success;
|
|
int hi, lo;
|
|
} tests[] = {
|
|
{ "10:8", true, 10, 8 },
|
|
{ "100:-1", true, 100, -1 },
|
|
{ "-203813:-502023", true, -203813, -502023 },
|
|
{ "238492:28210", true, 238492, 28210 },
|
|
{ "none", true, 0, 0 },
|
|
{ "0:0", false, 0, 0 },
|
|
{ "", false, 0, 0 },
|
|
{ "abcd", false, 0, 0 },
|
|
{ "10:30:10", false, 0, 0 },
|
|
{ NULL, false, 0, 0 },
|
|
};
|
|
/* clang-format on */
|
|
int i;
|
|
int hi, lo;
|
|
bool success;
|
|
|
|
for (i = 0; tests[i].tag != NULL; i++) {
|
|
hi = lo = 0xad;
|
|
success = parse_range_property(tests[i].tag, &hi, &lo);
|
|
litest_assert(success == tests[i].success);
|
|
if (success) {
|
|
litest_assert_int_eq(hi, tests[i].hi);
|
|
litest_assert_int_eq(lo, tests[i].lo);
|
|
} else {
|
|
litest_assert_int_eq(hi, 0xad);
|
|
litest_assert_int_eq(lo, 0xad);
|
|
}
|
|
}
|
|
|
|
success = parse_range_property(NULL, NULL, NULL);
|
|
litest_assert(success == false);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(boolean_prop_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct parser_test_range {
|
|
char *tag;
|
|
bool success;
|
|
bool b;
|
|
} tests[] = {
|
|
{ "0", true, false },
|
|
{ "1", true, true },
|
|
{ "-1", false, false },
|
|
{ "2", false, false },
|
|
{ "abcd", false, false },
|
|
{ NULL, false, false },
|
|
};
|
|
/* clang-format on */
|
|
int i;
|
|
bool success, b;
|
|
|
|
for (i = 0; tests[i].tag != NULL; i++) {
|
|
b = false;
|
|
success = parse_boolean_property(tests[i].tag, &b);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_int_eq(b, tests[i].b);
|
|
else
|
|
litest_assert_int_eq(b, false);
|
|
}
|
|
|
|
success = parse_boolean_property(NULL, NULL);
|
|
litest_assert(success == false);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(evcode_prop_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct parser_test_tuple {
|
|
const char *prop;
|
|
bool success;
|
|
size_t nevents;
|
|
struct input_event events[20];
|
|
} tests[] = {
|
|
{ "+EV_KEY", true, 1, {{ .type = EV_KEY, .code = 0xffff, .value = 1 }} },
|
|
{ "-EV_ABS;", true, 1, {{ .type = EV_ABS, .code = 0xffff, .value = 0 }} },
|
|
{ "+ABS_X;", true, 1, {{ .type = EV_ABS, .code = ABS_X, .value = 1 }} },
|
|
{ "-SW_TABLET_MODE;", true, 1, {{ .type = EV_SW, .code = SW_TABLET_MODE, .value = 0 }} },
|
|
{ "+EV_SW", true, 1, {{ .type = EV_SW, .code = 0xffff, .value = 1 }} },
|
|
{ "-ABS_Y", true, 1, {{ .type = EV_ABS, .code = ABS_Y, .value = 0 }} },
|
|
{ "+EV_ABS:0x00", true, 1, {{ .type = EV_ABS, .code = ABS_X, .value = 1 }} },
|
|
{ "-EV_ABS:01", true, 1, {{ .type = EV_ABS, .code = ABS_Y, .value = 0 }} },
|
|
{ "+ABS_TILT_X;-ABS_TILT_Y;", true, 2,
|
|
{{ .type = EV_ABS, .code = ABS_TILT_X, .value = 1 },
|
|
{ .type = EV_ABS, .code = ABS_TILT_Y, .value = 0}} },
|
|
{ "+BTN_TOOL_DOUBLETAP;+EV_KEY;-KEY_A", true, 3,
|
|
{{ .type = EV_KEY, .code = BTN_TOOL_DOUBLETAP, .value = 1 } ,
|
|
{ .type = EV_KEY, .code = 0xffff, .value = 1 },
|
|
{ .type = EV_KEY, .code = KEY_A, .value = 0 }} },
|
|
{ "+REL_Y;-ABS_Z;+BTN_STYLUS", true, 3,
|
|
{{ .type = EV_REL, .code = REL_Y, .value = 1},
|
|
{ .type = EV_ABS, .code = ABS_Z, .value = 0},
|
|
{ .type = EV_KEY, .code = BTN_STYLUS, .value = 1 }} },
|
|
{ "-REL_Y;+EV_KEY:0x123;-BTN_STYLUS", true, 3,
|
|
{{ .type = EV_REL, .code = REL_Y, .value = 0 },
|
|
{ .type = EV_KEY, .code = 0x123, .value = 1 },
|
|
{ .type = EV_KEY, .code = BTN_STYLUS, .value = 0 }} },
|
|
{ .prop = "", .success = false },
|
|
{ .prop = "+", .success = false },
|
|
{ .prop = "-", .success = false },
|
|
{ .prop = "!", .success = false },
|
|
{ .prop = "+EV_FOO", .success = false },
|
|
{ .prop = "+EV_KEY;-EV_FOO", .success = false },
|
|
{ .prop = "+BTN_STYLUS;-EV_FOO", .success = false },
|
|
{ .prop = "-BTN_UNKNOWN", .success = false },
|
|
{ .prop = "+BTN_UNKNOWN;+EV_KEY", .success = false },
|
|
{ .prop = "-PR_UNKNOWN", .success = false },
|
|
{ .prop = "-BTN_STYLUS;+PR_UNKNOWN;-ABS_X", .success = false },
|
|
{ .prop = "-EV_REL:0xffff", .success = false },
|
|
{ .prop = "-EV_REL:0x123.", .success = false },
|
|
{ .prop = "-EV_REL:ffff", .success = false },
|
|
{ .prop = "-EV_REL:blah", .success = false },
|
|
{ .prop = "+KEY_A:0x11", .success = false },
|
|
{ .prop = "+EV_KEY:0x11 ", .success = false },
|
|
{ .prop = "+EV_KEY:0x11not", .success = false },
|
|
{ .prop = "none", .success = false },
|
|
{ .prop = NULL },
|
|
};
|
|
/* clang-format on */
|
|
struct parser_test_tuple *t;
|
|
|
|
for (int i = 0; tests[i].prop; i++) {
|
|
bool success;
|
|
struct input_event events[32];
|
|
size_t nevents = ARRAY_LENGTH(events);
|
|
|
|
t = &tests[i];
|
|
success = parse_evcode_property(t->prop, events, &nevents);
|
|
litest_assert(success == t->success);
|
|
if (!success)
|
|
continue;
|
|
|
|
litest_assert_int_eq(nevents, t->nevents);
|
|
for (size_t j = 0; j < nevents; j++) {
|
|
unsigned int type = events[j].type;
|
|
unsigned int code = events[j].code;
|
|
int value = events[j].value;
|
|
litest_assert_int_eq(t->events[j].type, type);
|
|
litest_assert_int_eq(t->events[j].code, code);
|
|
litest_assert_int_eq(t->events[j].value, value);
|
|
}
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(input_prop_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct parser_test_val {
|
|
const char *prop;
|
|
bool success;
|
|
size_t nvals;
|
|
struct input_prop values[20];
|
|
} tests[] = {
|
|
{ "+INPUT_PROP_BUTTONPAD", true, 1, {{ INPUT_PROP_BUTTONPAD, true }}},
|
|
{ "+INPUT_PROP_BUTTONPAD;-INPUT_PROP_POINTER", true, 2,
|
|
{ { INPUT_PROP_BUTTONPAD, true },
|
|
{ INPUT_PROP_POINTER, false }}},
|
|
{ "+INPUT_PROP_BUTTONPAD;-0x00;+0x03", true, 3,
|
|
{ { INPUT_PROP_BUTTONPAD, true },
|
|
{ INPUT_PROP_POINTER, false },
|
|
{ INPUT_PROP_SEMI_MT, true }}},
|
|
{ .prop = "", .success = false },
|
|
{ .prop = "0xff", .success = false },
|
|
{ .prop = "INPUT_PROP", .success = false },
|
|
{ .prop = "INPUT_PROP_FOO", .success = false },
|
|
{ .prop = "INPUT_PROP_FOO;INPUT_PROP_FOO", .success = false },
|
|
{ .prop = "INPUT_PROP_POINTER;INPUT_PROP_FOO", .success = false },
|
|
{ .prop = "none", .success = false },
|
|
{ .prop = NULL },
|
|
};
|
|
/* clang-format on */
|
|
struct parser_test_val *t;
|
|
|
|
for (int i = 0; tests[i].prop; i++) {
|
|
bool success;
|
|
struct input_prop props[32];
|
|
size_t nprops = ARRAY_LENGTH(props);
|
|
|
|
t = &tests[i];
|
|
success = parse_input_prop_property(t->prop, props, &nprops);
|
|
litest_assert(success == t->success);
|
|
if (!success)
|
|
continue;
|
|
|
|
litest_assert_int_eq(nprops, t->nvals);
|
|
for (size_t j = 0; j < t->nvals; j++) {
|
|
litest_assert_int_eq(t->values[j].prop, props[j].prop);
|
|
litest_assert_int_eq(t->values[j].enabled, props[j].enabled);
|
|
}
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(evdev_abs_parser)
|
|
{
|
|
/* clang-format off */
|
|
struct test {
|
|
uint32_t which;
|
|
const char *prop;
|
|
int min, max, res, fuzz, flat;
|
|
|
|
} tests[] = {
|
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX),
|
|
.prop = "1:2",
|
|
.min = 1, .max = 2 },
|
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX),
|
|
.prop = "1:2:",
|
|
.min = 1, .max = 2 },
|
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX|ABS_MASK_RES),
|
|
.prop = "10:20:30",
|
|
.min = 10, .max = 20, .res = 30 },
|
|
{ .which = (ABS_MASK_RES),
|
|
.prop = "::100",
|
|
.res = 100 },
|
|
{ .which = (ABS_MASK_MIN),
|
|
.prop = "10:",
|
|
.min = 10 },
|
|
{ .which = (ABS_MASK_MAX|ABS_MASK_RES),
|
|
.prop = ":10:1001",
|
|
.max = 10, .res = 1001 },
|
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX|ABS_MASK_RES|ABS_MASK_FUZZ),
|
|
.prop = "1:2:3:4",
|
|
.min = 1, .max = 2, .res = 3, .fuzz = 4},
|
|
{ .which = (ABS_MASK_MIN|ABS_MASK_MAX|ABS_MASK_RES|ABS_MASK_FUZZ|ABS_MASK_FLAT),
|
|
.prop = "1:2:3:4:5",
|
|
.min = 1, .max = 2, .res = 3, .fuzz = 4, .flat = 5},
|
|
{ .which = (ABS_MASK_MIN|ABS_MASK_RES|ABS_MASK_FUZZ|ABS_MASK_FLAT),
|
|
.prop = "1::3:4:50",
|
|
.min = 1, .res = 3, .fuzz = 4, .flat = 50},
|
|
{ .which = ABS_MASK_FUZZ|ABS_MASK_FLAT,
|
|
.prop = ":::5:60",
|
|
.fuzz = 5, .flat = 60},
|
|
{ .which = ABS_MASK_FUZZ,
|
|
.prop = ":::5:",
|
|
.fuzz = 5 },
|
|
{ .which = ABS_MASK_RES, .prop = "::12::",
|
|
.res = 12 },
|
|
/* Malformed property but parsing this one makes us more
|
|
* future proof */
|
|
{ .which = (ABS_MASK_RES|ABS_MASK_FUZZ|ABS_MASK_FLAT),
|
|
.prop = "::12:1:2:3:4:5:6",
|
|
.res = 12, .fuzz = 1, .flat = 2 },
|
|
{ .which = 0, .prop = ":::::" },
|
|
{ .which = 0, .prop = ":" },
|
|
{ .which = 0, .prop = "" },
|
|
{ .which = 0, .prop = ":asb::::" },
|
|
{ .which = 0, .prop = "foo" },
|
|
};
|
|
/* clang-format on */
|
|
|
|
ARRAY_FOR_EACH(tests, t) {
|
|
struct input_absinfo abs;
|
|
uint32_t mask;
|
|
|
|
mask = parse_evdev_abs_prop(t->prop, &abs);
|
|
litest_assert_int_eq(mask, t->which);
|
|
|
|
if (t->which & ABS_MASK_MIN)
|
|
litest_assert_int_eq(abs.minimum, t->min);
|
|
if (t->which & ABS_MASK_MAX)
|
|
litest_assert_int_eq(abs.maximum, t->max);
|
|
if (t->which & ABS_MASK_RES)
|
|
litest_assert_int_eq(abs.resolution, t->res);
|
|
if (t->which & ABS_MASK_FUZZ)
|
|
litest_assert_int_eq(abs.fuzz, t->fuzz);
|
|
if (t->which & ABS_MASK_FLAT)
|
|
litest_assert_int_eq(abs.flat, t->flat);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(time_conversion)
|
|
{
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_uint64_t(0)), 0U);
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_uint64_t(12345)), 12345U);
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_uint64_t(999999)), 999999U);
|
|
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_millis(0)), 0U);
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_millis(1)), 1000U);
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_millis(10)), 10000U);
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_millis(1000)), 1000000U);
|
|
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_seconds(0)), 0U);
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_seconds(1)), 1000000U);
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_seconds(10)), 10000000U);
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_seconds(60)), 60000000U);
|
|
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_hours(0)), 0ULL);
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_hours(1)), 3600000000ULL);
|
|
|
|
{
|
|
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_timeval(&tv)), 0U);
|
|
|
|
tv.tv_sec = 1;
|
|
tv.tv_usec = 0;
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_timeval(&tv)),
|
|
1000000U);
|
|
|
|
tv.tv_sec = 1;
|
|
tv.tv_usec = 234567;
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_timeval(&tv)),
|
|
1234567U);
|
|
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 999999;
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_timeval(&tv)), 999999U);
|
|
}
|
|
|
|
{
|
|
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_timespec(&ts)), 0U);
|
|
|
|
ts.tv_sec = 1;
|
|
ts.tv_nsec = 0;
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_timespec(&ts)),
|
|
1000000U);
|
|
|
|
ts.tv_sec = 1;
|
|
ts.tv_nsec = 234567000;
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_timespec(&ts)),
|
|
1234567U);
|
|
|
|
ts.tv_sec = 0;
|
|
ts.tv_nsec = 999999000;
|
|
litest_assert_int_eq(usec_as_uint64_t(usec_from_timespec(&ts)),
|
|
999999U);
|
|
}
|
|
|
|
litest_assert_int_eq(usec_to_millis(usec_from_uint64_t(0)), 0U);
|
|
litest_assert_int_eq(usec_to_millis(usec_from_uint64_t(1000)), 1U);
|
|
litest_assert_int_eq(usec_to_millis(usec_from_uint64_t(10000)), 10U);
|
|
litest_assert_int_eq(usec_to_millis(usec_from_uint64_t(123456)), 123U);
|
|
litest_assert_int_eq(usec_to_millis(usec_from_uint64_t(999)), 0U);
|
|
|
|
litest_assert_int_eq(usec_to_seconds(usec_from_uint64_t(0)), 0U);
|
|
litest_assert_int_eq(usec_to_seconds(usec_from_uint64_t(1000000)), 1U);
|
|
litest_assert_int_eq(usec_to_seconds(usec_from_uint64_t(5000000)), 5U);
|
|
litest_assert_int_eq(usec_to_seconds(usec_from_uint64_t(60000000)), 60U);
|
|
litest_assert_int_eq(usec_to_seconds(usec_from_uint64_t(999999)), 0U);
|
|
|
|
litest_assert_int_eq(usec_to_minutes(usec_from_uint64_t(0)), 0U);
|
|
litest_assert_int_eq(usec_to_minutes(usec_from_uint64_t(60000000)), 1U);
|
|
litest_assert_int_eq(usec_to_minutes(usec_from_uint64_t(120000000)), 2U);
|
|
litest_assert_int_eq(usec_to_minutes(usec_from_uint64_t(3600000000)), 60U);
|
|
litest_assert_int_eq(usec_to_minutes(usec_from_uint64_t(59999999)), 0U);
|
|
|
|
litest_assert_int_eq(usec_to_hours(usec_from_uint64_t(0)), 0U);
|
|
litest_assert_int_eq(usec_to_hours(usec_from_uint64_t(3600000000)), 1U);
|
|
litest_assert_int_eq(usec_to_hours(usec_from_uint64_t(7200000000)), 2U);
|
|
litest_assert_int_eq(usec_to_hours(usec_from_uint64_t(86400000000)), 24U);
|
|
litest_assert_int_eq(usec_to_hours(usec_from_uint64_t(3599999999)), 0U);
|
|
|
|
{
|
|
struct timeval tv;
|
|
|
|
tv = usec_to_timeval(usec_from_uint64_t(0));
|
|
litest_assert_int_eq(tv.tv_sec, 0);
|
|
litest_assert_int_eq(tv.tv_usec, 0);
|
|
|
|
tv = usec_to_timeval(usec_from_uint64_t(1000000));
|
|
litest_assert_int_eq(tv.tv_sec, 1);
|
|
litest_assert_int_eq(tv.tv_usec, 0);
|
|
|
|
tv = usec_to_timeval(usec_from_uint64_t(1234567));
|
|
litest_assert_int_eq(tv.tv_sec, 1);
|
|
litest_assert_int_eq(tv.tv_usec, 234567);
|
|
|
|
tv = usec_to_timeval(usec_from_uint64_t(999999));
|
|
litest_assert_int_eq(tv.tv_sec, 0);
|
|
litest_assert_int_eq(tv.tv_usec, 999999);
|
|
}
|
|
|
|
{
|
|
struct timespec ts;
|
|
|
|
ts = usec_to_timespec(usec_from_uint64_t(0));
|
|
litest_assert_int_eq(ts.tv_sec, 0);
|
|
litest_assert_int_eq(ts.tv_nsec, 0);
|
|
|
|
ts = usec_to_timespec(usec_from_uint64_t(1000000));
|
|
litest_assert_int_eq(ts.tv_sec, 1);
|
|
litest_assert_int_eq(ts.tv_nsec, 0);
|
|
|
|
ts = usec_to_timespec(usec_from_uint64_t(1234567));
|
|
litest_assert_int_eq(ts.tv_sec, 1);
|
|
litest_assert_int_eq(ts.tv_nsec, 234567000);
|
|
|
|
ts = usec_to_timespec(usec_from_uint64_t(999999));
|
|
litest_assert_int_eq(ts.tv_sec, 0);
|
|
litest_assert_int_eq(ts.tv_nsec, 999999000);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(human_time)
|
|
{
|
|
/* clang-format off */
|
|
struct ht_tests {
|
|
usec_t interval;
|
|
unsigned int value;
|
|
const char *unit;
|
|
} tests[] = {
|
|
{ usec_from_uint64_t(0), 0, "us" },
|
|
{ usec_from_uint64_t(123), 123, "us" },
|
|
{ usec_from_millis(5), 5, "ms" },
|
|
{ usec_from_millis(100), 100, "ms" },
|
|
{ usec_from_seconds(5), 5, "s" },
|
|
{ usec_from_seconds(100), 100, "s" },
|
|
{ usec_from_seconds(120), 2, "min" },
|
|
{ usec_mul(usec_from_seconds(60), 5), 5, "min" },
|
|
{ usec_mul(usec_from_seconds(60), 120), 2, "h" },
|
|
{ usec_mul(usec_from_seconds(60), 5 * 60), 5, "h" },
|
|
{ usec_mul(usec_from_seconds(60), 48 * 60), 2, "d" },
|
|
{ usec_mul(usec_from_seconds(60), 1000 * 24 * 60), 1000, "d" },
|
|
{ usec_from_uint64_t(0), 0, NULL },
|
|
};
|
|
/* clang-format on */
|
|
for (int i = 0; tests[i].unit != NULL; i++) {
|
|
struct human_time ht;
|
|
|
|
ht = to_human_time(tests[i].interval);
|
|
litest_assert_int_eq(ht.value, tests[i].value);
|
|
litest_assert_str_eq(ht.unit, tests[i].unit);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
struct atoi_test {
|
|
char *str;
|
|
bool success;
|
|
int val;
|
|
};
|
|
|
|
START_TEST(safe_atoi_test)
|
|
{
|
|
/* clang-format off */
|
|
struct atoi_test tests[] = {
|
|
{ "10", true, 10 },
|
|
{ "20", true, 20 },
|
|
{ "-1", true, -1 },
|
|
{ "2147483647", true, 2147483647 },
|
|
{ "-2147483648", true, -2147483648 },
|
|
{ "4294967295", false, 0 },
|
|
{ "0x0", false, 0 },
|
|
{ "-10x10", false, 0 },
|
|
{ "1x-99", false, 0 },
|
|
{ "", false, 0 },
|
|
{ "abd", false, 0 },
|
|
{ "xabd", false, 0 },
|
|
{ "0xaf", false, 0 },
|
|
{ "0x0x", false, 0 },
|
|
{ "x10", false, 0 },
|
|
{ NULL, false, 0 },
|
|
};
|
|
/* clang-format on */
|
|
int v;
|
|
bool success;
|
|
|
|
for (int i = 0; tests[i].str != NULL; i++) {
|
|
v = 0xad;
|
|
success = safe_atoi(tests[i].str, &v);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_int_eq(v, tests[i].val);
|
|
else
|
|
litest_assert_int_eq(v, 0xad);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(safe_atoi_base_16_test)
|
|
{
|
|
/* clang-format off */
|
|
struct atoi_test tests[] = {
|
|
{ "10", true, 0x10 },
|
|
{ "20", true, 0x20 },
|
|
{ "-1", true, -1 },
|
|
{ "0x10", true, 0x10 },
|
|
{ "0xff", true, 0xff },
|
|
{ "abc", true, 0xabc },
|
|
{ "-10", true, -0x10 },
|
|
{ "0x0", true, 0 },
|
|
{ "0", true, 0 },
|
|
{ "0x-99", false, 0 },
|
|
{ "0xak", false, 0 },
|
|
{ "0x", false, 0 },
|
|
{ "x10", false, 0 },
|
|
{ NULL, false, 0 },
|
|
};
|
|
/* clang-format on */
|
|
|
|
int v;
|
|
bool success;
|
|
|
|
for (int i = 0; tests[i].str != NULL; i++) {
|
|
v = 0xad;
|
|
success = safe_atoi_base(tests[i].str, &v, 16);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_int_eq(v, tests[i].val);
|
|
else
|
|
litest_assert_int_eq(v, 0xad);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(safe_atoi_base_8_test)
|
|
{
|
|
/* clang-format off */
|
|
struct atoi_test tests[] = {
|
|
{ "7", true, 07 },
|
|
{ "10", true, 010 },
|
|
{ "20", true, 020 },
|
|
{ "-1", true, -1 },
|
|
{ "010", true, 010 },
|
|
{ "0ff", false, 0 },
|
|
{ "abc", false, 0},
|
|
{ "0xabc", false, 0},
|
|
{ "-10", true, -010 },
|
|
{ "0", true, 0 },
|
|
{ "00", true, 0 },
|
|
{ "0x0", false, 0 },
|
|
{ "0x-99", false, 0 },
|
|
{ "0xak", false, 0 },
|
|
{ "0x", false, 0 },
|
|
{ "x10", false, 0 },
|
|
{ NULL, false, 0 },
|
|
};
|
|
/* clang-format on */
|
|
|
|
int v;
|
|
bool success;
|
|
|
|
for (int i = 0; tests[i].str != NULL; i++) {
|
|
v = 0xad;
|
|
success = safe_atoi_base(tests[i].str, &v, 8);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_int_eq(v, tests[i].val);
|
|
else
|
|
litest_assert_int_eq(v, 0xad);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
struct atou_test {
|
|
char *str;
|
|
bool success;
|
|
unsigned int val;
|
|
};
|
|
|
|
START_TEST(safe_atou_test)
|
|
{
|
|
/* clang-format off */
|
|
struct atou_test tests[] = {
|
|
{ "10", true, 10 },
|
|
{ "20", true, 20 },
|
|
{ "-1", false, 0 },
|
|
{ "2147483647", true, 2147483647 },
|
|
{ "-2147483648", false, 0},
|
|
{ "0x0", false, 0 },
|
|
{ "-10x10", false, 0 },
|
|
{ "1x-99", false, 0 },
|
|
{ "", false, 0 },
|
|
{ "abd", false, 0 },
|
|
{ "xabd", false, 0 },
|
|
{ "0xaf", false, 0 },
|
|
{ "0x0x", false, 0 },
|
|
{ "x10", false, 0 },
|
|
{ NULL, false, 0 },
|
|
};
|
|
/* clang-format on */
|
|
unsigned int v;
|
|
bool success;
|
|
|
|
for (int i = 0; tests[i].str != NULL; i++) {
|
|
v = 0xad;
|
|
success = safe_atou(tests[i].str, &v);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_int_eq(v, tests[i].val);
|
|
else
|
|
litest_assert_int_eq(v, 0xadU);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(safe_atou_base_16_test)
|
|
{
|
|
/* clang-format off */
|
|
struct atou_test tests[] = {
|
|
{ "10", true, 0x10 },
|
|
{ "20", true, 0x20 },
|
|
{ "-1", false, 0 },
|
|
{ "0x10", true, 0x10 },
|
|
{ "0xff", true, 0xff },
|
|
{ "abc", true, 0xabc },
|
|
{ "-10", false, 0 },
|
|
{ "0x0", true, 0 },
|
|
{ "0", true, 0 },
|
|
{ "0x-99", false, 0 },
|
|
{ "0xak", false, 0 },
|
|
{ "0x", false, 0 },
|
|
{ "x10", false, 0 },
|
|
{ NULL, false, 0 },
|
|
};
|
|
/* clang-format on */
|
|
|
|
unsigned int v;
|
|
bool success;
|
|
|
|
for (int i = 0; tests[i].str != NULL; i++) {
|
|
v = 0xad;
|
|
success = safe_atou_base(tests[i].str, &v, 16);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_int_eq(v, tests[i].val);
|
|
else
|
|
litest_assert_int_eq(v, 0xadU);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(safe_atou_base_8_test)
|
|
{
|
|
/* clang-format off */
|
|
struct atou_test tests[] = {
|
|
{ "7", true, 07 },
|
|
{ "10", true, 010 },
|
|
{ "20", true, 020 },
|
|
{ "-1", false, 0 },
|
|
{ "010", true, 010 },
|
|
{ "0ff", false, 0 },
|
|
{ "abc", false, 0},
|
|
{ "0xabc", false, 0},
|
|
{ "-10", false, 0 },
|
|
{ "0", true, 0 },
|
|
{ "00", true, 0 },
|
|
{ "0x0", false, 0 },
|
|
{ "0x-99", false, 0 },
|
|
{ "0xak", false, 0 },
|
|
{ "0x", false, 0 },
|
|
{ "x10", false, 0 },
|
|
{ NULL, false, 0 },
|
|
};
|
|
/* clang-format on */
|
|
|
|
unsigned int v;
|
|
bool success;
|
|
|
|
for (int i = 0; tests[i].str != NULL; i++) {
|
|
v = 0xad;
|
|
success = safe_atou_base(tests[i].str, &v, 8);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_int_eq(v, tests[i].val);
|
|
else
|
|
litest_assert_int_eq(v, 0xadU);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
struct atou64_test {
|
|
char *str;
|
|
bool success;
|
|
uint64_t val;
|
|
};
|
|
|
|
START_TEST(safe_atou64_test)
|
|
{
|
|
/* clang-format off */
|
|
struct atou64_test tests[] = {
|
|
{ "10", true, 10 },
|
|
{ "20", true, 20 },
|
|
{ "-1", false, 0 },
|
|
{ "9999999999", true, 9999999999 },
|
|
{ "2147483647", true, 2147483647 },
|
|
{ "-2147483648", false, 0},
|
|
{ "0x0", false, 0 },
|
|
{ "-10x10", false, 0 },
|
|
{ "1x-99", false, 0 },
|
|
{ "", false, 0 },
|
|
{ "abd", false, 0 },
|
|
{ "xabd", false, 0 },
|
|
{ "0xaf", false, 0 },
|
|
{ "0x0x", false, 0 },
|
|
{ "x10", false, 0 },
|
|
{ NULL, false, 0 },
|
|
};
|
|
/* clang-format on */
|
|
uint64_t v;
|
|
bool success;
|
|
|
|
for (int i = 0; tests[i].str != NULL; i++) {
|
|
v = 0xad;
|
|
success = safe_atou64(tests[i].str, &v);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_int_eq(v, tests[i].val);
|
|
else
|
|
litest_assert_int_eq(v, 0xadU);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(safe_atod_test)
|
|
{
|
|
/* clang-format off */
|
|
struct atod_test {
|
|
char *str;
|
|
bool success;
|
|
double val;
|
|
} tests[] = {
|
|
{ "10", true, 10 },
|
|
{ "20", true, 20 },
|
|
{ "-1", true, -1 },
|
|
{ "2147483647", true, 2147483647 },
|
|
{ "-2147483648", true, -2147483648 },
|
|
{ "4294967295", true, 4294967295 },
|
|
{ "0x0", false, 0 },
|
|
{ "0x10", false, 0 },
|
|
{ "0xaf", false, 0 },
|
|
{ "x80", false, 0 },
|
|
{ "0.0", true, 0.0 },
|
|
{ "0.1", true, 0.1 },
|
|
{ "1.2", true, 1.2 },
|
|
{ "-324.9", true, -324.9 },
|
|
{ "9324.9", true, 9324.9 },
|
|
{ "NAN", false, 0 },
|
|
{ "INFINITY", false, 0 },
|
|
{ "-10x10", false, 0 },
|
|
{ "1x-99", false, 0 },
|
|
{ "", false, 0 },
|
|
{ "abd", false, 0 },
|
|
{ "xabd", false, 0 },
|
|
{ "0x0x", false, 0 },
|
|
{ NULL, false, 0 },
|
|
};
|
|
/* clang-format on */
|
|
double v;
|
|
bool success;
|
|
|
|
for (int i = 0; tests[i].str != NULL; i++) {
|
|
v = 0xad;
|
|
success = safe_atod(tests[i].str, &v);
|
|
litest_assert(success == tests[i].success);
|
|
if (success)
|
|
litest_assert_double_eq(v, tests[i].val);
|
|
else
|
|
litest_assert_int_eq(v, 0xad);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strsplit_test)
|
|
{
|
|
/* clang-format off */
|
|
struct strsplit_test {
|
|
const char *string;
|
|
const char *delim;
|
|
const char *results[10];
|
|
const size_t nresults;
|
|
} tests[] = {
|
|
{ "one two three", " ", { "one", "two", "three", NULL }, 3 },
|
|
{ "one two\tthree", " \t", { "one", "two", "three", NULL }, 3 },
|
|
{ "one", " ", { "one", NULL }, 1 },
|
|
{ "one two ", " ", { "one", "two", NULL }, 2 },
|
|
{ "one two", " ", { "one", "two", NULL }, 2 },
|
|
{ " one two", " ", { "one", "two", NULL }, 2 },
|
|
{ "one", "\t \r", { "one", NULL }, 1 },
|
|
{ "one two three", " t", { "one", "wo", "hree", NULL }, 3 },
|
|
{ " one two three", "te", { " on", " ", "wo ", "hr", NULL }, 4 },
|
|
{ "one", "ne", { "o", NULL }, 1 },
|
|
{ "onene", "ne", { "o", NULL }, 1 },
|
|
{ "+1-2++3--4++-+5-+-", "+-", { "1", "2", "3", "4", "5", NULL }, 5 },
|
|
/* special cases */
|
|
{ "", " ", { NULL }, 0 },
|
|
{ " ", " ", { NULL }, 0 },
|
|
{ " ", " ", { NULL }, 0 },
|
|
{ "oneoneone", "one", { NULL} , 0 },
|
|
{ NULL, NULL, { NULL }, 0},
|
|
};
|
|
/* clang-format on */
|
|
struct strsplit_test *t = tests;
|
|
|
|
while (t->string) {
|
|
size_t nelem;
|
|
char **strv = strv_from_string(t->string, t->delim, &nelem);
|
|
|
|
for (size_t idx = 0; idx < t->nresults; idx++)
|
|
litest_assert_str_eq(t->results[idx], strv[idx]);
|
|
|
|
litest_assert_int_eq(nelem, t->nresults);
|
|
|
|
/* When there are no elements validate return value is Null,
|
|
otherwise validate result array is Null terminated. */
|
|
if (t->nresults == 0)
|
|
litest_assert_ptr_eq(strv, NULL);
|
|
else
|
|
litest_assert_ptr_eq(strv[t->nresults], NULL);
|
|
|
|
strv_free(strv);
|
|
t++;
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
struct strv_test_data {
|
|
const char *terminate_at;
|
|
unsigned char bitmask[1];
|
|
};
|
|
|
|
static int
|
|
strv_test_set_bitmask(const char *str, size_t index, void *data)
|
|
{
|
|
struct strv_test_data *td = data;
|
|
|
|
if (streq(str, td->terminate_at))
|
|
return index + 1;
|
|
|
|
set_bit(td->bitmask, index);
|
|
|
|
return 0;
|
|
}
|
|
|
|
START_TEST(strv_for_each_test)
|
|
{
|
|
/* clang-format off */
|
|
struct test_data {
|
|
const char *terminator;
|
|
int index;
|
|
unsigned int bitmask;
|
|
} test_data[] = {
|
|
{ "one", 1, 0x0 },
|
|
{ "two", 2, 0x1 },
|
|
{ "three", 3, 0x3 },
|
|
{ "four", 4, 0x7 },
|
|
{ "five", 5, 0xf },
|
|
{ "does-not-exist", 0, 0x1f },
|
|
{ NULL, 0, 0x1f },
|
|
{ NULL, 0 },
|
|
};
|
|
/* clang-format on */
|
|
const char *array[] = { "one", "two", "three", "four", "five", NULL };
|
|
struct test_data *t = test_data;
|
|
|
|
while (t->terminator || t->bitmask) {
|
|
const int max = 3;
|
|
struct strv_test_data td = {
|
|
.terminate_at = t->terminator,
|
|
.bitmask = { 0 },
|
|
};
|
|
|
|
int rc = strv_for_each(array, strv_test_set_bitmask, &td);
|
|
litest_assert_int_eq(rc, t->index);
|
|
litest_assert_int_eq(td.bitmask[0], t->bitmask);
|
|
|
|
struct strv_test_data tdmax = {
|
|
.terminate_at = t->terminator,
|
|
.bitmask = { 0 },
|
|
};
|
|
|
|
rc = strv_for_each_n(array, max, strv_test_set_bitmask, &tdmax);
|
|
if (max < t->index)
|
|
litest_assert_int_eq(rc, 0);
|
|
else
|
|
litest_assert_int_eq(rc, t->index);
|
|
litest_assert_int_eq(tdmax.bitmask[0], t->bitmask & ((1 << max) - 1));
|
|
|
|
t++;
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
__attribute__((format(printf, 1, 0))) static char **
|
|
test_strv_appendv(char *format, ...)
|
|
{
|
|
va_list args;
|
|
va_start(args, format);
|
|
char **strv = NULL;
|
|
strv = strv_append_vprintf(strv, "%s %d", args);
|
|
va_end(args);
|
|
return strv;
|
|
}
|
|
|
|
START_TEST(strv_append_test)
|
|
{
|
|
{
|
|
char *test_strv1[] = { "a", "b", "c", NULL };
|
|
char **test_strv2 = NULL;
|
|
|
|
litest_assert_int_eq(strv_len(test_strv1), 4U);
|
|
litest_assert_int_eq(strv_len(test_strv2), 0U);
|
|
}
|
|
{
|
|
char **strv = NULL;
|
|
char *dup = safe_strdup("test");
|
|
strv = strv_append_take(strv, &dup);
|
|
litest_assert_ptr_null(dup);
|
|
litest_assert_ptr_notnull(strv);
|
|
litest_assert_str_eq(strv[0], "test");
|
|
litest_assert_ptr_eq(strv[1], NULL);
|
|
litest_assert_int_eq(strv_len(strv), 2U);
|
|
|
|
char *dup2 = safe_strdup("test2");
|
|
strv = strv_append_take(strv, &dup2);
|
|
litest_assert_ptr_null(dup2);
|
|
litest_assert_str_eq(strv[1], "test2");
|
|
litest_assert_ptr_eq(strv[2], NULL);
|
|
litest_assert_int_eq(strv_len(strv), 3U);
|
|
|
|
strv = strv_append_take(strv, NULL);
|
|
litest_assert_int_eq(strv_len(strv), 3U);
|
|
strv_free(strv);
|
|
}
|
|
{
|
|
char **strv = NULL;
|
|
strv = strv_append_strdup(strv, "banana");
|
|
litest_assert(strv != NULL);
|
|
litest_assert_str_eq(strv[0], "banana");
|
|
litest_assert_ptr_null(strv[1]);
|
|
litest_assert_int_eq(strv_len(strv), 2U);
|
|
strv_free(strv);
|
|
}
|
|
{
|
|
char **strv = test_strv_appendv("%s %d", "apple", 2);
|
|
litest_assert_ptr_notnull(strv);
|
|
litest_assert_str_eq(strv[0], "apple 2");
|
|
litest_assert_ptr_null(strv[1]);
|
|
litest_assert_int_eq(strv_len(strv), 2U);
|
|
strv_free(strv);
|
|
}
|
|
{
|
|
char **strv = NULL;
|
|
strv = strv_append_printf(strv, "coco%s", "nut");
|
|
litest_assert_ptr_notnull(strv);
|
|
litest_assert_str_eq(strv[0], "coconut");
|
|
litest_assert_ptr_null(strv[1]);
|
|
litest_assert_int_eq(strv_len(strv), 2U);
|
|
strv_free(strv);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strv_find_test)
|
|
{
|
|
char *strv[] = { "a", "b", "c", NULL };
|
|
|
|
bool rc;
|
|
size_t index;
|
|
|
|
rc = strv_find(strv, "a", &index);
|
|
litest_assert(rc);
|
|
litest_assert_int_eq(index, 0U);
|
|
|
|
rc = strv_find(strv, "b", &index);
|
|
litest_assert(rc);
|
|
litest_assert_int_eq(index, 1U);
|
|
|
|
rc = strv_find(strv, "a", NULL);
|
|
litest_assert(rc);
|
|
|
|
index = 0xffff;
|
|
rc = strv_find(strv, "d", &index);
|
|
litest_assert(!rc);
|
|
litest_assert_int_eq(index, 0xffffU);
|
|
|
|
rc = strv_find(strv, "d", NULL);
|
|
litest_assert(!rc);
|
|
|
|
rc = strv_find(NULL, "a", &index);
|
|
litest_assert(!rc);
|
|
litest_assert_int_eq(index, 0xffffU);
|
|
|
|
rc = strv_find(NULL, NULL, &index);
|
|
litest_assert(!rc);
|
|
litest_assert_int_eq(index, 0xffffU);
|
|
|
|
rc = strv_find(strv, NULL, &index);
|
|
litest_assert(!rc);
|
|
litest_assert_int_eq(index, 0xffffU);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strv_find_substring_test)
|
|
{
|
|
char *strv[] = { "a", "bc", "cccc", NULL };
|
|
|
|
bool rc;
|
|
size_t index;
|
|
|
|
rc = strv_find_substring(strv, "a", &index);
|
|
litest_assert(rc);
|
|
litest_assert_int_eq(index, 0U);
|
|
|
|
rc = strv_find_substring(strv, "b", &index);
|
|
litest_assert(rc);
|
|
litest_assert_int_eq(index, 1U);
|
|
|
|
rc = strv_find_substring(strv, "c", &index);
|
|
litest_assert(rc);
|
|
litest_assert_int_eq(index, 1U);
|
|
|
|
rc = strv_find_substring(strv, "a", NULL);
|
|
litest_assert(rc);
|
|
|
|
index = 0xffff;
|
|
rc = strv_find_substring(strv, "d", &index);
|
|
litest_assert(!rc);
|
|
litest_assert_int_eq(index, 0xffffU);
|
|
|
|
rc = strv_find_substring(strv, "d", NULL);
|
|
litest_assert(!rc);
|
|
|
|
rc = strv_find_substring(NULL, "a", &index);
|
|
litest_assert(!rc);
|
|
litest_assert_int_eq(index, 0xffffU);
|
|
|
|
rc = strv_find_substring(NULL, NULL, &index);
|
|
litest_assert(!rc);
|
|
litest_assert_int_eq(index, 0xffffU);
|
|
|
|
rc = strv_find_substring(strv, NULL, &index);
|
|
litest_assert(!rc);
|
|
litest_assert_int_eq(index, 0xffffU);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(double_array_from_string_test)
|
|
{
|
|
/* clang-format off */
|
|
struct double_array_from_string_test {
|
|
const char *string;
|
|
const char *delim;
|
|
const double array[10];
|
|
const size_t len;
|
|
const bool result;
|
|
} tests[] = {
|
|
{ "1 2 3", " ", { 1, 2, 3 }, 3 },
|
|
{ "1", " ", { 1 }, 1 },
|
|
{ "1,2.5,", ",", { 1, 2.5 }, 2 },
|
|
{ "1.0 2", " ", { 1, 2.0 }, 2 },
|
|
{ " 1 2", " ", { 1, 2 }, 2 },
|
|
{ " ; 1;2 3.5 ;;4.1", "; ", { 1, 2, 3.5, 4.1 }, 4 },
|
|
/* special cases */
|
|
{ "1 two", " ", { 0 }, 0 },
|
|
{ "one two", " ", { 0 }, 0 },
|
|
{ "one 2", " ", { 0 }, 0 },
|
|
{ "", " ", { 0 }, 0 },
|
|
{ " ", " ", { 0 }, 0 },
|
|
{ " ", " ", { 0 }, 0 },
|
|
{ "", " ", { 0 }, 0 },
|
|
{ "oneoneone", "one", { 0 }, 0 },
|
|
{ NULL, NULL, { 0 }, 0 },
|
|
};
|
|
/* clang-format on */
|
|
struct double_array_from_string_test *t = tests;
|
|
|
|
while (t->string) {
|
|
size_t len;
|
|
double *array = double_array_from_string(t->string, t->delim, &len);
|
|
litest_assert_int_eq(len, t->len);
|
|
|
|
for (size_t idx = 0; idx < len; idx++) {
|
|
litest_assert_ptr_notnull(array);
|
|
litest_assert_double_eq(array[idx], t->array[idx]);
|
|
}
|
|
|
|
free(array);
|
|
t++;
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strargv_test)
|
|
{
|
|
/* clang-format off */
|
|
struct argv_test {
|
|
int argc;
|
|
char *argv[10];
|
|
int expected;
|
|
} tests[] = {
|
|
{ 0, {NULL}, 0 },
|
|
{ 1, {"hello", "World"}, 1 },
|
|
{ 2, {"hello", "World"}, 2 },
|
|
{ 2, {"", " "}, 2 },
|
|
{ 2, {"", NULL}, 0 },
|
|
{ 2, {NULL, NULL}, 0 },
|
|
{ 1, {NULL, NULL}, 0 },
|
|
{ 3, {"hello", NULL, "World"}, 0 },
|
|
};
|
|
/* clang-format on */
|
|
|
|
ARRAY_FOR_EACH(tests, t) {
|
|
char **strv = strv_from_argv(t->argc, t->argv);
|
|
|
|
if (t->expected == 0) {
|
|
litest_assert(strv == NULL);
|
|
} else {
|
|
int count = 0;
|
|
char **s = strv;
|
|
while (*s) {
|
|
litest_assert_str_eq(*s, t->argv[count]);
|
|
count++;
|
|
s++;
|
|
}
|
|
litest_assert_int_eq(t->expected, count);
|
|
strv_free(strv);
|
|
}
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(kvsplit_double_test)
|
|
{
|
|
/* clang-format off */
|
|
struct kvsplit_dbl_test {
|
|
const char *string;
|
|
const char *psep;
|
|
const char *kvsep;
|
|
ssize_t nresults;
|
|
struct {
|
|
double a;
|
|
double b;
|
|
} results[32];
|
|
} tests[] = {
|
|
{ "1:2;3:4;5:6", ";", ":", 3, { {1, 2}, {3, 4}, {5, 6}}},
|
|
{ "1.0x2.3 -3.2x4.5 8.090909x-6.00", " ", "x", 3, { {1.0, 2.3}, {-3.2, 4.5}, {8.090909, -6}}},
|
|
|
|
{ "1:2", "x", ":", 1, {{1, 2}}},
|
|
{ "1:2", ":", "x", -1, {}},
|
|
{ "1:2", NULL, "x", -1, {}},
|
|
{ "1:2", "", "x", -1, {}},
|
|
{ "1:2", "x", NULL, -1, {}},
|
|
{ "1:2", "x", "", -1, {}},
|
|
{ "a:b", "x", ":", -1, {}},
|
|
{ "", " ", "x", -1, {}},
|
|
{ "1.2.3.4.5", ".", "", -1, {}},
|
|
{ NULL },
|
|
};
|
|
/* clang-format on */
|
|
struct kvsplit_dbl_test *t = tests;
|
|
|
|
while (t->string) {
|
|
struct key_value_double *result = NULL;
|
|
ssize_t npairs;
|
|
|
|
npairs = kv_double_from_string(t->string, t->psep, t->kvsep, &result);
|
|
litest_assert_int_eq(npairs, t->nresults);
|
|
|
|
for (ssize_t i = 0; i < npairs; i++) {
|
|
litest_assert_double_eq(t->results[i].a, result[i].key);
|
|
litest_assert_double_eq(t->results[i].b, result[i].value);
|
|
}
|
|
|
|
free(result);
|
|
t++;
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strjoin_test)
|
|
{
|
|
/* clang-format off */
|
|
struct strjoin_test {
|
|
char *strv[10];
|
|
const char *joiner;
|
|
const char *result;
|
|
} tests[] = {
|
|
{ { "one", "two", "three", NULL }, " ", "one two three" },
|
|
{ { "one", NULL }, "x", "one" },
|
|
{ { "one", "two", NULL }, "x", "onextwo" },
|
|
{ { "one", "two", NULL }, ",", "one,two" },
|
|
{ { "one", "two", NULL }, ", ", "one, two" },
|
|
{ { "one", "two", NULL }, "one", "oneonetwo" },
|
|
{ { "one", "two", NULL }, NULL, NULL },
|
|
{ { "", "", "", NULL }, " ", " " },
|
|
{ { "a", "b", "c", NULL }, "", "abc" },
|
|
{ { "", "b", "c", NULL }, "x", "xbxc" },
|
|
{ { "", "", "", NULL }, "", "" },
|
|
{ { NULL }, NULL, NULL },
|
|
};
|
|
/* clang-format on */
|
|
struct strjoin_test *t = tests;
|
|
struct strjoin_test nulltest = { { NULL }, "x", NULL };
|
|
|
|
while (t->strv[0]) {
|
|
char *str;
|
|
str = strv_join(t->strv, t->joiner);
|
|
if (t->result == NULL)
|
|
litest_assert(str == NULL);
|
|
else
|
|
litest_assert_str_eq(str, t->result);
|
|
free(str);
|
|
t++;
|
|
}
|
|
|
|
litest_assert(strv_join(nulltest.strv, "x") == NULL);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strstrip_test)
|
|
{
|
|
/* clang-format off */
|
|
struct strstrip_test {
|
|
const char *string;
|
|
const char *expected;
|
|
const char *what;
|
|
} tests[] = {
|
|
{ "foo", "foo", "1234" },
|
|
{ "\"bar\"", "bar", "\"" },
|
|
{ "'bar'", "bar", "'" },
|
|
{ "\"bar\"", "\"bar\"", "'" },
|
|
{ "'bar'", "'bar'", "\"" },
|
|
{ "\"bar\"", "bar", "\"" },
|
|
{ "\"\"", "", "\"" },
|
|
{ "\"foo\"bar\"", "foo\"bar", "\"" },
|
|
{ "\"'foo\"bar\"", "foo\"bar", "\"'" },
|
|
{ "abcfooabcbarbca", "fooabcbar", "abc" },
|
|
{ "xxxxfoo", "foo", "x" },
|
|
{ "fooyyyy", "foo", "y" },
|
|
{ "xxxxfooyyyy", "foo", "xy" },
|
|
{ "x xfooy y", " xfooy ", "xy" },
|
|
{ " foo\n", "foo", " \n" },
|
|
{ "", "", "abc" },
|
|
{ "", "", "" },
|
|
{ NULL , NULL, NULL },
|
|
};
|
|
/* clang-format on */
|
|
struct strstrip_test *t = tests;
|
|
|
|
while (t->string) {
|
|
char *str;
|
|
str = strstrip(t->string, t->what);
|
|
litest_assert_str_eq(str, t->expected);
|
|
free(str);
|
|
t++;
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strendswith_test)
|
|
{
|
|
/* clang-format off */
|
|
struct strendswith_test {
|
|
const char *string;
|
|
const char *suffix;
|
|
bool expected;
|
|
} tests[] = {
|
|
{ "foobar", "bar", true },
|
|
{ "foobar", "foo", false },
|
|
{ "foobar", "foobar", true },
|
|
{ "foo", "foobar", false },
|
|
{ "foobar", "", false },
|
|
{ "", "", false },
|
|
{ "", "foo", false },
|
|
{ NULL, NULL, false },
|
|
};
|
|
/* clang-format on */
|
|
|
|
for (struct strendswith_test *t = tests; t->string; t++) {
|
|
litest_assert_int_eq(strendswith(t->string, t->suffix), t->expected);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strstartswith_test)
|
|
{
|
|
/* clang-format off */
|
|
struct strstartswith_test {
|
|
const char *string;
|
|
const char *suffix;
|
|
bool expected;
|
|
} tests[] = {
|
|
{ "foobar", "foo", true },
|
|
{ "foobar", "bar", false },
|
|
{ "foobar", "foobar", true },
|
|
{ "foo", "foobar", false },
|
|
{ "foo", "", false },
|
|
{ "", "", false },
|
|
{ "foo", "", false },
|
|
{ NULL, NULL, false },
|
|
};
|
|
/* clang-format on */
|
|
|
|
for (struct strstartswith_test *t = tests; t->string; t++) {
|
|
litest_assert_int_eq(strstartswith(t->string, t->suffix), t->expected);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strsanitize_test)
|
|
{
|
|
/* clang-format off */
|
|
struct strsanitize_test {
|
|
const char *string;
|
|
const char *expected;
|
|
} tests[] = {
|
|
{ "foobar", "foobar" },
|
|
{ "", "" },
|
|
{ "%", "%%" },
|
|
{ "%%%%", "%%%%%%%%" },
|
|
{ "x %s", "x %%s" },
|
|
{ "x %", "x %%" },
|
|
{ "%sx", "%%sx" },
|
|
{ "%s%s", "%%s%%s" },
|
|
{ NULL, NULL },
|
|
};
|
|
/* clang-format on */
|
|
|
|
for (struct strsanitize_test *t = tests; t->string; t++) {
|
|
char *sanitized = str_sanitize(t->string);
|
|
litest_assert_str_eq(sanitized, t->expected);
|
|
free(sanitized);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(list_test_insert)
|
|
{
|
|
struct list_test {
|
|
int val;
|
|
struct list node;
|
|
} tests[] = {
|
|
{ .val = 1 },
|
|
{ .val = 2 },
|
|
{ .val = 3 },
|
|
{ .val = 4 },
|
|
};
|
|
struct list_test *t;
|
|
struct list head;
|
|
int val;
|
|
|
|
list_init(&head);
|
|
|
|
ARRAY_FOR_EACH(tests, t) {
|
|
list_insert(&head, &t->node);
|
|
}
|
|
|
|
val = 4;
|
|
list_for_each(t, &head, node) {
|
|
litest_assert_int_eq(t->val, val);
|
|
val--;
|
|
}
|
|
|
|
litest_assert_int_eq(val, 0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(list_test_append)
|
|
{
|
|
struct list_test {
|
|
int val;
|
|
struct list node;
|
|
} tests[] = {
|
|
{ .val = 1 },
|
|
{ .val = 2 },
|
|
{ .val = 3 },
|
|
{ .val = 4 },
|
|
};
|
|
struct list_test *t;
|
|
struct list head;
|
|
int val;
|
|
|
|
list_init(&head);
|
|
|
|
ARRAY_FOR_EACH(tests, t) {
|
|
list_append(&head, &t->node);
|
|
}
|
|
|
|
val = 1;
|
|
list_for_each(t, &head, node) {
|
|
litest_assert_int_eq(t->val, val);
|
|
val++;
|
|
}
|
|
litest_assert_int_eq(val, 5);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(list_test_chain)
|
|
{
|
|
struct list_test {
|
|
int val;
|
|
struct list node;
|
|
} tests[] = {
|
|
{ .val = 1 },
|
|
{ .val = 2 },
|
|
{ .val = 3 },
|
|
{ .val = 4 },
|
|
};
|
|
struct list l1, l2;
|
|
struct list_test *t;
|
|
int val;
|
|
|
|
list_init(&l1);
|
|
list_init(&l2);
|
|
|
|
list_chain(&l1, &l2);
|
|
litest_assert(list_empty(&l2));
|
|
|
|
list_append(&l2, &tests[0].node);
|
|
list_append(&l2, &tests[1].node);
|
|
list_chain(&l1, &l2);
|
|
litest_assert(list_empty(&l2));
|
|
|
|
val = 1;
|
|
list_for_each_safe(t, &l1, node) {
|
|
litest_assert_int_eq(t->val, val);
|
|
val++;
|
|
list_remove(&t->node);
|
|
}
|
|
litest_assert_int_eq(val, 3);
|
|
|
|
list_append(&l1, &tests[0].node);
|
|
list_append(&l1, &tests[1].node);
|
|
list_append(&l2, &tests[2].node);
|
|
list_append(&l2, &tests[3].node);
|
|
|
|
list_chain(&l1, &l2);
|
|
litest_assert(list_empty(&l2));
|
|
|
|
val = 1;
|
|
list_for_each(t, &l1, node) {
|
|
litest_assert_int_eq(t->val, val);
|
|
val++;
|
|
}
|
|
litest_assert_int_eq(val, 5);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(list_test_foreach)
|
|
{
|
|
struct list_test {
|
|
int val;
|
|
struct list node;
|
|
} tests[] = {
|
|
{ .val = 1 },
|
|
{ .val = 2 },
|
|
{ .val = 3 },
|
|
{ .val = 4 },
|
|
};
|
|
struct list_test *t;
|
|
struct list head;
|
|
|
|
list_init(&head);
|
|
|
|
ARRAY_FOR_EACH(tests, t) {
|
|
list_append(&head, &t->node);
|
|
}
|
|
|
|
/* Make sure both loop macros are a single line statement */
|
|
if (false)
|
|
list_for_each(t, &head, node) {
|
|
litest_abort_msg("We should not get here");
|
|
}
|
|
|
|
if (false)
|
|
list_for_each_safe(t, &head, node) {
|
|
litest_abort_msg("We should not get here");
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(list_test_first_last)
|
|
{
|
|
struct list_test {
|
|
int val;
|
|
struct list node;
|
|
} tests[] = {
|
|
{ .val = 1 },
|
|
{ .val = 2 },
|
|
{ .val = 3 },
|
|
{ .val = 4 },
|
|
};
|
|
struct list head;
|
|
|
|
list_init(&head);
|
|
|
|
ARRAY_FOR_EACH(tests, t) {
|
|
list_append(&head, &t->node);
|
|
}
|
|
|
|
struct list_test *first;
|
|
struct list_test *last;
|
|
|
|
first = list_first_entry(&head, first, node);
|
|
last = list_last_entry(&head, last, node);
|
|
litest_assert_ptr_eq(first, &tests[0]);
|
|
litest_assert_ptr_eq(last, &tests[3]);
|
|
|
|
struct list_test *second;
|
|
struct list_test *penultimate;
|
|
|
|
second = list_first_entry(&first->node, first, node);
|
|
penultimate = list_last_entry(&last->node, last, node);
|
|
litest_assert_ptr_eq(second, &tests[1]);
|
|
litest_assert_ptr_eq(penultimate, &tests[2]);
|
|
|
|
/* Now remove nodes */
|
|
|
|
/* No change expected */
|
|
list_remove(&tests[2].node);
|
|
first = list_first_entry(&head, first, node);
|
|
last = list_last_entry(&head, last, node);
|
|
litest_assert_ptr_eq(first, &tests[0]);
|
|
litest_assert_ptr_eq(last, &tests[3]);
|
|
|
|
list_remove(&tests[3].node);
|
|
first = list_first_entry(&head, first, node);
|
|
last = list_last_entry(&head, last, node);
|
|
litest_assert_ptr_eq(first, &tests[0]);
|
|
litest_assert_ptr_eq(last, &tests[1]);
|
|
|
|
list_remove(&tests[0].node);
|
|
first = list_first_entry(&head, first, node);
|
|
last = list_last_entry(&head, last, node);
|
|
litest_assert_ptr_eq(first, &tests[1]);
|
|
litest_assert_ptr_eq(last, &tests[1]);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strverscmp_test)
|
|
{
|
|
litest_assert_int_eq(libinput_strverscmp("", ""), 0);
|
|
litest_assert_int_gt(libinput_strverscmp("0.0.1", ""), 0);
|
|
litest_assert_int_lt(libinput_strverscmp("", "0.0.1"), 0);
|
|
litest_assert_int_eq(libinput_strverscmp("0.0.1", "0.0.1"), 0);
|
|
litest_assert_int_eq(libinput_strverscmp("0.0.1", "0.0.2"), -1);
|
|
litest_assert_int_eq(libinput_strverscmp("0.0.2", "0.0.1"), 1);
|
|
litest_assert_int_eq(libinput_strverscmp("0.0.1", "0.1.0"), -1);
|
|
litest_assert_int_eq(libinput_strverscmp("0.1.0", "0.0.1"), 1);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(streq_test)
|
|
{
|
|
litest_assert(streq("", "") == true);
|
|
litest_assert(streq(NULL, NULL) == true);
|
|
litest_assert(streq("0.0.1", "") == false);
|
|
litest_assert(streq("foo", NULL) == false);
|
|
litest_assert(streq(NULL, "foo") == false);
|
|
litest_assert(streq("0.0.1", "0.0.1") == true);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(strneq_test)
|
|
{
|
|
litest_assert(strneq("", "", 1) == true);
|
|
litest_assert(strneq(NULL, NULL, 1) == true);
|
|
litest_assert(strneq("0.0.1", "", 6) == false);
|
|
litest_assert(strneq("foo", NULL, 5) == false);
|
|
litest_assert(strneq(NULL, "foo", 5) == false);
|
|
litest_assert(strneq("0.0.1", "0.0.1", 6) == true);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(basename_test)
|
|
{
|
|
struct test {
|
|
const char *path;
|
|
const char *expected;
|
|
} tests[] = {
|
|
{ "a", "a" },
|
|
{ "foo.c", "foo.c" },
|
|
{ "foo", "foo" },
|
|
{ "/path/to/foo.h", "foo.h" },
|
|
{ "../bar.foo", "bar.foo" },
|
|
{ "./bar.foo.baz", "bar.foo.baz" },
|
|
{ "./", NULL },
|
|
{ "/", NULL },
|
|
{ "/bar/", NULL },
|
|
{ "/bar", "bar" },
|
|
{ "", NULL },
|
|
};
|
|
|
|
ARRAY_FOR_EACH(tests, t) {
|
|
const char *result = safe_basename(t->path);
|
|
if (t->expected == NULL)
|
|
litest_assert(result == NULL);
|
|
else
|
|
litest_assert_str_eq(result, t->expected);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(trunkname_test)
|
|
{
|
|
struct test {
|
|
const char *path;
|
|
const char *expected;
|
|
} tests[] = {
|
|
{ "foo.c", "foo" },
|
|
{ "/path/to/foo.h", "foo" },
|
|
{ "/path/to/foo", "foo" },
|
|
{ "../bar.foo", "bar" },
|
|
{ "./bar.foo.baz", "bar.foo" },
|
|
{ "./", "" },
|
|
{ "/", "" },
|
|
{ "/bar/", "" },
|
|
{ "/bar", "bar" },
|
|
{ "", "" },
|
|
};
|
|
|
|
ARRAY_FOR_EACH(tests, t) {
|
|
char *result = trunkname(t->path);
|
|
litest_assert_str_eq(result, t->expected);
|
|
free(result);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(absinfo_normalize_value_test)
|
|
{
|
|
struct input_absinfo abs = {
|
|
.minimum = 0,
|
|
.maximum = 100,
|
|
};
|
|
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, -100), 0.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, -1), 0.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, 0), 0.0);
|
|
litest_assert_double_gt(absinfo_normalize_value(&abs, 1), 0.0);
|
|
litest_assert_double_lt(absinfo_normalize_value(&abs, 99), 1.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, 100), 1.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, 101), 1.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, 200), 1.0);
|
|
|
|
abs.minimum = -50;
|
|
abs.maximum = 50;
|
|
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, -51), 0.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, -50), 0.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, 0), 0.5);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, 50), 1.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, 51), 1.0);
|
|
|
|
abs.minimum = -50;
|
|
abs.maximum = 0;
|
|
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, -51), 0.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, -50), 0.0);
|
|
litest_assert_double_gt(absinfo_normalize_value(&abs, -49), 0.0);
|
|
litest_assert_double_lt(absinfo_normalize_value(&abs, -1), 1.0);
|
|
litest_assert_double_eq(absinfo_normalize_value(&abs, 0), 1.0);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(range_test)
|
|
{
|
|
struct range incl = range_init_inclusive(1, 100);
|
|
litest_assert_int_eq(incl.lower, 1);
|
|
litest_assert_int_eq(incl.upper, 101);
|
|
|
|
struct range excl = range_init_exclusive(1, 100);
|
|
litest_assert_int_eq(excl.lower, 1);
|
|
litest_assert_int_eq(excl.upper, 100);
|
|
|
|
struct range zero = range_init_exclusive(0, 0);
|
|
litest_assert_int_eq(zero.lower, 0);
|
|
litest_assert_int_eq(zero.upper, 0);
|
|
|
|
struct range empty = range_init_empty();
|
|
litest_assert_int_eq(empty.lower, 0);
|
|
litest_assert_int_eq(empty.upper, -1);
|
|
|
|
litest_assert(range_is_valid(&incl));
|
|
litest_assert(range_is_valid(&excl));
|
|
litest_assert(!range_is_valid(&zero));
|
|
litest_assert(!range_is_valid(&empty));
|
|
|
|
int expected = 1;
|
|
int r = 0;
|
|
range_for_each(&incl, r) {
|
|
litest_assert_int_eq(r, expected);
|
|
expected++;
|
|
}
|
|
litest_assert_int_eq(r, 101);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(stringbuf_test)
|
|
{
|
|
struct stringbuf buf;
|
|
struct stringbuf *b = &buf;
|
|
int rc;
|
|
|
|
stringbuf_init(b);
|
|
litest_assert_int_eq(b->len, 0u);
|
|
|
|
rc = stringbuf_append_string(b, "foo");
|
|
litest_assert_neg_errno_success(rc);
|
|
rc = stringbuf_append_string(b, "bar");
|
|
litest_assert_neg_errno_success(rc);
|
|
rc = stringbuf_append_string(b, "baz");
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_str_eq(b->data, "foobarbaz");
|
|
litest_assert_int_eq(b->len, strlen("foobarbaz"));
|
|
|
|
rc = stringbuf_ensure_space(b, 500);
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_ge(b->sz, 500u);
|
|
|
|
rc = stringbuf_ensure_size(b, 0);
|
|
litest_assert_neg_errno_success(rc);
|
|
rc = stringbuf_ensure_size(b, 1024);
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_ge(b->sz, 1024u);
|
|
|
|
char *data = stringbuf_steal(b);
|
|
litest_assert_str_eq(data, "foobarbaz");
|
|
litest_assert_int_eq(b->sz, 0u);
|
|
litest_assert_int_eq(b->len, 0u);
|
|
litest_assert_ptr_null(b->data);
|
|
free(data);
|
|
|
|
const char *str = "1234567890";
|
|
rc = stringbuf_append_string(b, str);
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_str_eq(b->data, str);
|
|
litest_assert_int_eq(b->len, 10u);
|
|
stringbuf_reset(b);
|
|
|
|
/* intentional double-reset */
|
|
stringbuf_reset(b);
|
|
|
|
int pipefd[2];
|
|
rc = pipe2(pipefd, O_CLOEXEC | O_NONBLOCK);
|
|
litest_assert_neg_errno_success(rc);
|
|
|
|
str = "foo bar baz";
|
|
char *compare = NULL;
|
|
for (int i = 0; i < 100; i++) {
|
|
rc = write(pipefd[1], str, strlen(str));
|
|
litest_assert_neg_errno_success(rc);
|
|
|
|
rc = stringbuf_append_from_fd(b, pipefd[0], 64);
|
|
litest_assert_neg_errno_success(rc);
|
|
|
|
char *expected = strdup_printf("%s%s", compare ? compare : "", str);
|
|
litest_assert_ptr_notnull(expected);
|
|
litest_assert_str_eq(b->data, expected);
|
|
|
|
free(compare);
|
|
compare = expected;
|
|
}
|
|
free(compare);
|
|
close(pipefd[0]);
|
|
close(pipefd[1]);
|
|
stringbuf_reset(b);
|
|
|
|
rc = pipe2(pipefd, O_CLOEXEC | O_NONBLOCK);
|
|
litest_assert_neg_errno_success(rc);
|
|
|
|
const size_t stride = 256;
|
|
const size_t maxsize = 4096;
|
|
|
|
for (size_t i = 0; i < maxsize; i += stride) {
|
|
char buf[stride];
|
|
memset(buf, i / stride, sizeof(buf));
|
|
rc = write(pipefd[1], buf, sizeof(buf));
|
|
litest_assert_neg_errno_success(rc);
|
|
}
|
|
|
|
stringbuf_append_from_fd(b, pipefd[0], 0);
|
|
litest_assert_int_eq(b->len, maxsize);
|
|
litest_assert_int_ge(b->sz, maxsize);
|
|
|
|
for (size_t i = 0; i < maxsize; i += stride) {
|
|
char buf[stride];
|
|
memset(buf, i / stride, sizeof(buf));
|
|
litest_assert_int_eq(memcmp(buf, b->data + i, sizeof(buf)), 0);
|
|
}
|
|
|
|
close(pipefd[0]);
|
|
close(pipefd[1]);
|
|
stringbuf_reset(b);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(multivalue_test)
|
|
{
|
|
{
|
|
struct multivalue v = multivalue_new_string("test");
|
|
litest_assert_int_eq(v.type, 's');
|
|
litest_assert_str_eq(v.value.s, "test");
|
|
|
|
const char *s;
|
|
multivalue_extract_typed(&v, 's', &s);
|
|
litest_assert_str_eq(s, "test");
|
|
litest_assert_ptr_eq(s, (const char *)v.value.s);
|
|
multivalue_extract(&v, &s);
|
|
litest_assert_str_eq(s, "test");
|
|
litest_assert_ptr_eq(s, (const char *)v.value.s);
|
|
|
|
struct multivalue copy = multivalue_copy(&v);
|
|
litest_assert_int_eq(copy.type, v.type);
|
|
litest_assert_str_eq(copy.value.s, v.value.s);
|
|
char *p1 = copy.value.s;
|
|
char *p2 = v.value.s;
|
|
litest_assert_ptr_ne(p1, p2);
|
|
|
|
char *str = multivalue_as_str(&v);
|
|
litest_assert_str_eq(str, "test");
|
|
free(str);
|
|
}
|
|
|
|
{
|
|
struct multivalue v = multivalue_new_char('x');
|
|
litest_assert_int_eq(v.type, 'c');
|
|
litest_assert_int_eq(v.value.c, 'x');
|
|
|
|
char c;
|
|
multivalue_extract_typed(&v, 'c', &c);
|
|
litest_assert_int_eq(c, 'x');
|
|
multivalue_extract(&v, &c);
|
|
litest_assert_int_eq(c, 'x');
|
|
|
|
struct multivalue copy = multivalue_copy(&v);
|
|
litest_assert_int_eq(copy.type, v.type);
|
|
litest_assert_int_eq(copy.value.c, v.value.c);
|
|
|
|
char *str = multivalue_as_str(&v);
|
|
litest_assert_str_eq(str, "x");
|
|
free(str);
|
|
}
|
|
|
|
{
|
|
struct multivalue v = multivalue_new_u32(0x1234);
|
|
litest_assert_int_eq(v.type, 'u');
|
|
litest_assert_int_eq(v.value.u, 0x1234u);
|
|
|
|
uint32_t c;
|
|
multivalue_extract_typed(&v, 'u', &c);
|
|
litest_assert_int_eq(c, 0x1234u);
|
|
multivalue_extract(&v, &c);
|
|
litest_assert_int_eq(c, 0x1234u);
|
|
|
|
struct multivalue copy = multivalue_copy(&v);
|
|
litest_assert_int_eq(copy.type, v.type);
|
|
litest_assert_int_eq(copy.value.u, v.value.u);
|
|
|
|
char *str = multivalue_as_str(&v);
|
|
litest_assert_str_eq(str, "4660");
|
|
free(str);
|
|
}
|
|
|
|
{
|
|
struct multivalue v = multivalue_new_i32(-123);
|
|
litest_assert_int_eq(v.type, 'i');
|
|
litest_assert_int_eq(v.value.i, -123);
|
|
|
|
int32_t c;
|
|
multivalue_extract_typed(&v, 'i', &c);
|
|
litest_assert_int_eq(c, -123);
|
|
multivalue_extract(&v, &c);
|
|
litest_assert_int_eq(c, -123);
|
|
|
|
struct multivalue copy = multivalue_copy(&v);
|
|
litest_assert_int_eq(copy.type, v.type);
|
|
litest_assert_int_eq(copy.value.i, v.value.i);
|
|
|
|
char *str = multivalue_as_str(&v);
|
|
litest_assert_str_eq(str, "-123");
|
|
free(str);
|
|
}
|
|
|
|
{
|
|
struct multivalue v = multivalue_new_bool(true);
|
|
litest_assert_int_eq(v.type, 'b');
|
|
litest_assert_int_eq(v.value.b, true);
|
|
|
|
bool c;
|
|
multivalue_extract_typed(&v, 'b', &c);
|
|
litest_assert_int_eq(c, true);
|
|
multivalue_extract(&v, &c);
|
|
litest_assert_int_eq(c, true);
|
|
|
|
struct multivalue copy = multivalue_copy(&v);
|
|
litest_assert_int_eq(copy.type, v.type);
|
|
litest_assert_int_eq(copy.value.b, v.value.b);
|
|
|
|
char *str = multivalue_as_str(&v);
|
|
litest_assert_str_eq(str, "true");
|
|
free(str);
|
|
}
|
|
|
|
{
|
|
struct multivalue v = multivalue_new_double(0.1234);
|
|
litest_assert_int_eq(v.type, 'd');
|
|
litest_assert_double_eq(v.value.d, 0.1234);
|
|
|
|
double c;
|
|
multivalue_extract_typed(&v, 'd', &c);
|
|
litest_assert_double_eq(c, 0.1234);
|
|
multivalue_extract(&v, &c);
|
|
litest_assert_double_eq(c, 0.1234);
|
|
|
|
struct multivalue copy = multivalue_copy(&v);
|
|
litest_assert_int_eq(copy.type, v.type);
|
|
litest_assert_double_eq(copy.value.d, v.value.d);
|
|
|
|
char *str = multivalue_as_str(&v);
|
|
litest_assert_str_eq(str, "0.123400");
|
|
free(str);
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
DECLARE_NEWTYPE(newint, int);
|
|
DECLARE_NEWTYPE(newdouble, double);
|
|
|
|
START_TEST(newtype_test)
|
|
{
|
|
{
|
|
newint_t n1 = newint_from_int(1);
|
|
newint_t n2 = newint_from_int(2);
|
|
|
|
litest_assert_int_eq(newint(n1), 1);
|
|
litest_assert_int_eq(newint_as_int(n1), 1);
|
|
litest_assert_int_eq(newint(n2), 2);
|
|
litest_assert_int_eq(newint_as_int(n2), 2);
|
|
|
|
litest_assert_int_eq(newint_cmp(n1, n2), -1);
|
|
litest_assert_int_eq(newint_cmp(n1, n1), 0);
|
|
litest_assert_int_eq(newint_cmp(n2, n1), 1);
|
|
|
|
newint_t copy = newint_copy(n1);
|
|
litest_assert_int_eq(newint_cmp(n1, copy), 0);
|
|
|
|
newint_t min = newint_min(n1, n2);
|
|
newint_t max = newint_max(n1, n2);
|
|
litest_assert_int_eq(newint_cmp(min, n1), 0);
|
|
litest_assert_int_eq(newint_cmp(max, n2), 0);
|
|
|
|
litest_assert(newint_gt(n1, 0));
|
|
litest_assert(newint_eq(n1, 1));
|
|
litest_assert(newint_ge(n1, 1));
|
|
litest_assert(newint_le(n1, 1));
|
|
litest_assert(newint_ne(n1, 2));
|
|
litest_assert(newint_lt(n1, 2));
|
|
|
|
litest_assert(!newint_gt(n1, 1));
|
|
litest_assert(!newint_eq(n1, 0));
|
|
litest_assert(!newint_ge(n1, 2));
|
|
litest_assert(!newint_le(n1, 0));
|
|
litest_assert(!newint_ne(n1, 1));
|
|
litest_assert(!newint_lt(n1, 1));
|
|
}
|
|
{
|
|
newdouble_t n1 = newdouble_from_double(1.2);
|
|
newdouble_t n2 = newdouble_from_double(2.3);
|
|
|
|
litest_assert_double_eq(newdouble(n1), 1.2);
|
|
litest_assert_double_eq(newdouble_as_double(n1), 1.2);
|
|
litest_assert_double_eq(newdouble(n2), 2.3);
|
|
litest_assert_double_eq(newdouble_as_double(n2), 2.3);
|
|
|
|
litest_assert_int_eq(newdouble_cmp(n1, n2), -1);
|
|
litest_assert_int_eq(newdouble_cmp(n1, n1), 0);
|
|
litest_assert_int_eq(newdouble_cmp(n2, n1), 1);
|
|
|
|
newdouble_t copy = newdouble_copy(n1);
|
|
litest_assert_int_eq(newdouble_cmp(n1, copy), 0);
|
|
|
|
newdouble_t min = newdouble_min(n1, n2);
|
|
newdouble_t max = newdouble_max(n1, n2);
|
|
litest_assert_int_eq(newdouble_cmp(min, n1), 0);
|
|
litest_assert_int_eq(newdouble_cmp(max, n2), 0);
|
|
|
|
litest_assert(newdouble_gt(n1, 0.0));
|
|
litest_assert(newdouble_eq(n1, 1.2));
|
|
litest_assert(newdouble_ge(n1, 1.2));
|
|
litest_assert(newdouble_le(n1, 1.2));
|
|
litest_assert(newdouble_ne(n1, 2.3));
|
|
litest_assert(newdouble_lt(n1, 2.3));
|
|
|
|
litest_assert(!newdouble_gt(n1, 1.2));
|
|
litest_assert(!newdouble_eq(n1, 0.0));
|
|
litest_assert(!newdouble_ge(n1, 2.3));
|
|
litest_assert(!newdouble_le(n1, 0.0));
|
|
litest_assert(!newdouble_ne(n1, 1.2));
|
|
litest_assert(!newdouble_lt(n1, 1.2));
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
struct sunref {};
|
|
struct sdestroy {};
|
|
struct sfree {};
|
|
|
|
static void
|
|
sunref_unref(struct sunref *s)
|
|
{
|
|
free(s);
|
|
}
|
|
static void
|
|
sdestroy_destroy(struct sdestroy *s)
|
|
{
|
|
free(s);
|
|
}
|
|
static void
|
|
sfree_free(struct sfree *s)
|
|
{
|
|
free(s);
|
|
}
|
|
|
|
DEFINE_UNREF_CLEANUP_FUNC(sunref);
|
|
DEFINE_DESTROY_CLEANUP_FUNC(sdestroy);
|
|
DEFINE_FREE_CLEANUP_FUNC(sfree);
|
|
|
|
START_TEST(attribute_cleanup)
|
|
{
|
|
/* These tests will likely only show up in valgrind,
|
|
* the various asserts are just to shut up the compiler
|
|
* about unused variables
|
|
*/
|
|
{
|
|
_autofree_ char *autofree = zalloc(64);
|
|
litest_assert(autofree);
|
|
}
|
|
{
|
|
_autofree_ char *stolen = zalloc(64);
|
|
free(steal(&stolen));
|
|
}
|
|
{
|
|
_autoclose_ int fd = open("/proc/self/cmdline", O_RDONLY);
|
|
litest_assert_int_ge(fd, 0);
|
|
|
|
_autoclose_ int badfd = -1;
|
|
litest_assert_int_eq(badfd, -1);
|
|
|
|
_autoclose_ int stealfd = open("/proc/self/cmdline", O_RDONLY);
|
|
steal_fd(&stealfd);
|
|
litest_assert_int_eq(stealfd, -1);
|
|
}
|
|
{
|
|
_autostrvfree_ char **strv = zalloc(3 * sizeof(*strv));
|
|
for (int i = 0; i < 2; i++) {
|
|
strv[i] = strdup_printf("element %d", i);
|
|
}
|
|
|
|
_autostrvfree_ char **badstrv = NULL;
|
|
litest_assert_ptr_null(badstrv);
|
|
}
|
|
{
|
|
_autofclose_ FILE *fp = fopen("/proc/self/cmdline", "r");
|
|
litest_assert_ptr_notnull(fp);
|
|
|
|
_autofclose_ FILE *badfd = NULL;
|
|
litest_assert_ptr_null(badfd);
|
|
}
|
|
{
|
|
_unref_(sunref) *s = zalloc(sizeof(*s));
|
|
}
|
|
{
|
|
_destroy_(sdestroy) *s = zalloc(sizeof(*s));
|
|
}
|
|
{
|
|
_free_(sfree) *s = zalloc(sizeof(*s));
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(macros_expand)
|
|
{
|
|
#define _A1(_1) _1, #_1
|
|
#define _A2(_1, _2) _1, _2
|
|
#define A(...) _VARIABLE_MACRO(_A, __VA_ARGS__)
|
|
char buf[64];
|
|
snprintf(buf, sizeof(buf), "%d:%s", A(0));
|
|
litest_assert_str_eq(buf, "0:0");
|
|
snprintf(buf, sizeof(buf), "%d:%s", A(100));
|
|
litest_assert_str_eq(buf, "100:100");
|
|
snprintf(buf, sizeof(buf), "%d:%s", A(100, "hundred"));
|
|
litest_assert_str_eq(buf, "100:hundred");
|
|
#undef _A1
|
|
#undef _A2
|
|
#undef A
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(evdev_frames)
|
|
{
|
|
#define U(u_) evdev_usage_from_uint32_t(u_)
|
|
{
|
|
evdev_frame_unref(NULL); /* unref on NULL is permitted */
|
|
}
|
|
{
|
|
_unref_(evdev_frame) *frame = evdev_frame_new(3);
|
|
litest_assert_int_eq(evdev_frame_get_count(frame), 1U); /* SYN_REPORT */
|
|
|
|
litest_assert_ptr_eq(evdev_frame_ref(frame), frame);
|
|
litest_assert_ptr_eq(evdev_frame_unref(frame), NULL);
|
|
}
|
|
{
|
|
_unref_(evdev_frame) *frame = evdev_frame_new(3);
|
|
struct evdev_event toobig[] = {
|
|
{
|
|
.usage = U(EVDEV_ABS_X),
|
|
.value = 1,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_ABS_Y),
|
|
.value = 2,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_ABS_Z),
|
|
.value = 3,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_SYN_REPORT),
|
|
.value = 0,
|
|
},
|
|
};
|
|
|
|
int rc = evdev_frame_set(frame, toobig, ARRAY_LENGTH(toobig));
|
|
litest_assert_int_eq(rc, -ENOMEM);
|
|
}
|
|
{
|
|
struct evdev_event events[] = {
|
|
{
|
|
.usage = U(EVDEV_ABS_X),
|
|
.value = 1,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_ABS_Y),
|
|
.value = 2,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_SYN_REPORT),
|
|
.value = 0,
|
|
},
|
|
};
|
|
|
|
_unref_(evdev_frame) *frame = evdev_frame_new(3);
|
|
int rc = evdev_frame_set(frame, events, ARRAY_LENGTH(events));
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_eq(evdev_frame_get_count(frame),
|
|
ARRAY_LENGTH(events));
|
|
litest_assert_int_eq(frame->max_size, ARRAY_LENGTH(events));
|
|
|
|
size_t nevents;
|
|
rc = memcmp(evdev_frame_get_events(frame, &nevents),
|
|
events,
|
|
sizeof(events));
|
|
litest_assert_int_eq(rc, 0);
|
|
litest_assert_int_eq(nevents, ARRAY_LENGTH(events));
|
|
|
|
/* Already full, can't append */
|
|
rc = evdev_frame_append(frame, events, 1);
|
|
litest_assert_int_eq(rc, -ENOMEM);
|
|
}
|
|
{
|
|
struct evdev_event events[] = {
|
|
{
|
|
.usage = U(EVDEV_ABS_X),
|
|
.value = 1,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_ABS_Y),
|
|
.value = 2,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_SYN_REPORT),
|
|
.value = 0,
|
|
},
|
|
};
|
|
|
|
_unref_(evdev_frame) *frame = evdev_frame_new(3);
|
|
int rc = evdev_frame_set(frame, events, 1);
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_eq(evdev_frame_get_count(frame),
|
|
2U); /* we appended SYN_REPORT */
|
|
rc = evdev_frame_append(frame, events + 1, 1);
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_eq(evdev_frame_get_count(frame),
|
|
3U); /* we appended SYN_REPORT */
|
|
rc = evdev_frame_append(frame, events + 2, 1);
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_eq(evdev_frame_get_count(frame),
|
|
3U); /* SYN_REPORT already there */
|
|
}
|
|
{
|
|
struct evdev_event interrupted[] = {
|
|
{
|
|
.usage = U(EVDEV_ABS_X),
|
|
.value = 1,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_ABS_Y),
|
|
.value = 2,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_SYN_REPORT),
|
|
.value = 0,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_ABS_RX),
|
|
.value = 1,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_ABS_RY),
|
|
.value = 2,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_SYN_REPORT),
|
|
.value = 0,
|
|
},
|
|
};
|
|
|
|
_unref_(evdev_frame) *frame = evdev_frame_new(5);
|
|
int rc = evdev_frame_set(frame, interrupted, ARRAY_LENGTH(interrupted));
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_eq(evdev_frame_get_count(frame), 3U);
|
|
|
|
rc = evdev_frame_set(frame, &interrupted[2], 1);
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_eq(evdev_frame_get_count(frame), 1U);
|
|
|
|
rc = evdev_frame_set(frame,
|
|
&interrupted[1],
|
|
ARRAY_LENGTH(interrupted) - 1);
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_eq(evdev_frame_get_count(frame), 2U);
|
|
|
|
/* We never appended a timestamp */
|
|
litest_assert(usec_cmp(evdev_frame_get_time(frame),
|
|
usec_from_uint64_t(0)) == 0);
|
|
}
|
|
{
|
|
struct evdev_event events[] = {
|
|
{
|
|
.usage = U(EVDEV_ABS_X),
|
|
.value = 1,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_ABS_Y),
|
|
.value = 2,
|
|
},
|
|
{
|
|
.usage = U(EVDEV_SYN_REPORT),
|
|
.value = 0,
|
|
},
|
|
};
|
|
|
|
_unref_(evdev_frame) *frame = evdev_frame_new(3);
|
|
int rc = evdev_frame_append_one(frame, U(EVDEV_ABS_X), 1);
|
|
litest_assert_neg_errno_success(rc);
|
|
rc = evdev_frame_append_one(frame, U(EVDEV_ABS_Y), 2);
|
|
litest_assert_neg_errno_success(rc);
|
|
rc = evdev_frame_append_one(frame, U(EV_SYN), 0);
|
|
litest_assert_neg_errno_success(rc);
|
|
|
|
litest_assert_int_eq(evdev_frame_get_count(frame),
|
|
ARRAY_LENGTH(events));
|
|
litest_assert_int_eq(frame->max_size, ARRAY_LENGTH(events));
|
|
|
|
size_t nevents;
|
|
rc = memcmp(evdev_frame_get_events(frame, &nevents),
|
|
events,
|
|
sizeof(events));
|
|
litest_assert_int_eq(rc, 0);
|
|
litest_assert_int_eq(nevents, ARRAY_LENGTH(events));
|
|
|
|
/* Already full, can't append */
|
|
rc = evdev_frame_append_one(frame, U(EVDEV_ABS_Z), 1);
|
|
litest_assert_int_eq(rc, -ENOMEM);
|
|
|
|
/* Appending SYN_REPORT is a noop */
|
|
rc = evdev_frame_append_one(frame, U(EVDEV_SYN_REPORT), 0);
|
|
litest_assert_neg_errno_success(rc);
|
|
litest_assert_int_eq(evdev_frame_get_count(frame),
|
|
ARRAY_LENGTH(events));
|
|
litest_assert_int_eq(frame->max_size, ARRAY_LENGTH(events));
|
|
}
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(infmask_test)
|
|
{
|
|
/* Test empty mask */
|
|
infmask_t empty = infmask_new();
|
|
litest_assert(infmask_is_empty(&empty));
|
|
litest_assert(!infmask_bit_is_set(&empty, 0));
|
|
litest_assert(!infmask_bit_is_set(&empty, 100));
|
|
infmask_reset(&empty);
|
|
|
|
/* Test single bit operations */
|
|
infmask_t single = infmask_new();
|
|
litest_assert(!infmask_set_bit(&single, 5));
|
|
litest_assert(infmask_bit_is_set(&single, 5));
|
|
litest_assert(!infmask_bit_is_set(&single, 4));
|
|
litest_assert(!infmask_bit_is_set(&single, 6));
|
|
litest_assert(!infmask_is_empty(&single));
|
|
litest_assert(infmask_clear_bit(&single, 5));
|
|
litest_assert(!infmask_bit_is_set(&single, 5));
|
|
litest_assert(infmask_is_empty(&single));
|
|
infmask_reset(&single);
|
|
|
|
/* Test from_bit constructor */
|
|
infmask_t from_bit = infmask_from_bit(7);
|
|
litest_assert(infmask_bit_is_set(&from_bit, 7));
|
|
litest_assert(!infmask_bit_is_set(&from_bit, 6));
|
|
litest_assert(!infmask_bit_is_set(&from_bit, 8));
|
|
infmask_reset(&from_bit);
|
|
|
|
/* Test from_bits constructor */
|
|
infmask_t from_bits = infmask_from_bits(1, 3, 5);
|
|
litest_assert(infmask_bit_is_set(&from_bits, 1));
|
|
litest_assert(!infmask_bit_is_set(&from_bits, 2));
|
|
litest_assert(infmask_bit_is_set(&from_bits, 3));
|
|
litest_assert(!infmask_bit_is_set(&from_bits, 4));
|
|
litest_assert(infmask_bit_is_set(&from_bits, 5));
|
|
infmask_reset(&from_bits);
|
|
|
|
/* Test high bit operations */
|
|
infmask_t high = infmask_new();
|
|
litest_assert(!infmask_set_bit(&high, 100));
|
|
litest_assert(infmask_bit_is_set(&high, 100));
|
|
litest_assert(!infmask_bit_is_set(&high, 99));
|
|
litest_assert(!infmask_bit_is_set(&high, 101));
|
|
litest_assert(infmask_clear_bit(&high, 100));
|
|
litest_assert(!infmask_bit_is_set(&high, 100));
|
|
infmask_reset(&high);
|
|
|
|
/* Test any/all operations */
|
|
infmask_t mask1 = infmask_from_bits(1, 2, 3);
|
|
infmask_t mask2 = infmask_from_bits(2, 3, 4);
|
|
infmask_t mask3 = infmask_from_bits(2, 3);
|
|
|
|
litest_assert(infmask_any(&mask1, &mask2));
|
|
litest_assert(!infmask_all(&mask1, &mask2));
|
|
litest_assert(infmask_all(&mask1, &mask3));
|
|
litest_assert(infmask_any(&mask1, &mask3));
|
|
|
|
infmask_reset(&mask1);
|
|
infmask_reset(&mask2);
|
|
infmask_reset(&mask3);
|
|
|
|
/* Test merge operation */
|
|
infmask_t merge1 = infmask_from_bits(1, 2);
|
|
infmask_t merge2 = infmask_from_bits(2, 3);
|
|
litest_assert(!infmask_merge(&merge1, &merge2));
|
|
litest_assert(infmask_bit_is_set(&merge1, 1));
|
|
litest_assert(infmask_bit_is_set(&merge1, 2));
|
|
litest_assert(infmask_bit_is_set(&merge1, 3));
|
|
infmask_reset(&merge1);
|
|
infmask_reset(&merge2);
|
|
|
|
/* Test clear operation */
|
|
infmask_t clear1 = infmask_from_bits(1, 2, 3);
|
|
infmask_t clear2 = infmask_from_bits(2, 3);
|
|
litest_assert(infmask_clear(&clear1, &clear2));
|
|
litest_assert(infmask_bit_is_set(&clear1, 1));
|
|
litest_assert(!infmask_bit_is_set(&clear1, 2));
|
|
litest_assert(!infmask_bit_is_set(&clear1, 3));
|
|
infmask_reset(&clear1);
|
|
infmask_reset(&clear2);
|
|
|
|
/* Test growing behavior */
|
|
infmask_t grow = infmask_new();
|
|
litest_assert(!infmask_set_bit(&grow, 5));
|
|
litest_assert(grow.nmasks == 1);
|
|
litest_assert(!infmask_set_bit(&grow, 35));
|
|
litest_assert(grow.nmasks == 2);
|
|
litest_assert(!infmask_set_bit(&grow, 65));
|
|
litest_assert(grow.nmasks == 3);
|
|
litest_assert(infmask_bit_is_set(&grow, 5));
|
|
litest_assert(infmask_bit_is_set(&grow, 35));
|
|
litest_assert(infmask_bit_is_set(&grow, 65));
|
|
infmask_reset(&grow);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(evdev_mask_test)
|
|
{
|
|
_destroy_(evdev_mask) *mask = evdev_mask_new();
|
|
|
|
evdev_mask_reset(mask);
|
|
|
|
litest_assert(bitmask_is_empty(mask->ev));
|
|
litest_assert(bitmask_is_empty(mask->rel));
|
|
litest_assert(bitmask_is_empty(mask->sw));
|
|
litest_assert(infmask_is_empty(&mask->key));
|
|
litest_assert(infmask_is_empty(&mask->btn));
|
|
litest_assert(infmask_is_empty(&mask->abs));
|
|
|
|
evdev_mask_set_enum(mask, EVDEV_BTN_TOOL_PEN);
|
|
evdev_mask_set_enum(mask, EVDEV_BTN_TOOL_AIRBRUSH);
|
|
|
|
litest_assert(bitmask_bit_is_set(mask->ev, EV_KEY));
|
|
|
|
/* Verify these are in btn, not key */
|
|
litest_assert(!infmask_is_empty(&mask->btn));
|
|
litest_assert(infmask_is_empty(&mask->key));
|
|
|
|
litest_assert(evdev_mask_is_set(mask, evdev_usage_from(EVDEV_BTN_TOOL_PEN)));
|
|
litest_assert(
|
|
!evdev_mask_is_set(mask, evdev_usage_from(EVDEV_BTN_TOOL_RUBBER)));
|
|
litest_assert(
|
|
evdev_mask_is_set(mask, evdev_usage_from(EVDEV_BTN_TOOL_AIRBRUSH)));
|
|
|
|
/* Test regular key (should go into key field) */
|
|
evdev_mask_set_enum(mask, EVDEV_KEY_ESC);
|
|
litest_assert(!infmask_is_empty(&mask->key));
|
|
litest_assert(evdev_mask_is_set(mask, evdev_usage_from(EVDEV_KEY_ESC)));
|
|
|
|
evdev_mask_set_enum(mask, EVDEV_REL_X);
|
|
litest_assert(bitmask_bit_is_set(mask->ev, EV_REL));
|
|
litest_assert(bitmask_bit_is_set(mask->rel, REL_X));
|
|
litest_assert(evdev_mask_is_set(mask, evdev_usage_from(EVDEV_REL_X)));
|
|
|
|
evdev_mask_set_enum(mask, EVDEV_ABS_X);
|
|
litest_assert(bitmask_bit_is_set(mask->ev, EV_ABS));
|
|
litest_assert(!infmask_is_empty(&mask->abs));
|
|
litest_assert(evdev_mask_is_set(mask, evdev_usage_from(EVDEV_ABS_X)));
|
|
}
|
|
END_TEST
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
struct litest_runner *runner = litest_runner_new();
|
|
|
|
/* not worth forking the tests here */
|
|
litest_runner_set_num_parallel(runner, 0);
|
|
|
|
#define ADD_TEST(func_) do { \
|
|
struct litest_runner_test_description tdesc = { \
|
|
.func = func_, \
|
|
};\
|
|
snprintf(tdesc.name, sizeof(tdesc.name), # func_); \
|
|
litest_runner_add_test(runner, &tdesc); \
|
|
} while(0)
|
|
|
|
ADD_TEST(auto_test);
|
|
ADD_TEST(mkdir_p_test);
|
|
ADD_TEST(rmdir_r_test);
|
|
ADD_TEST(tmpdir_test);
|
|
ADD_TEST(find_files_test);
|
|
|
|
ADD_TEST(array_for_each);
|
|
|
|
ADD_TEST(bitfield_helpers);
|
|
ADD_TEST(bitmask_test);
|
|
ADD_TEST(matrix_helpers);
|
|
ADD_TEST(ratelimit_helpers);
|
|
ADD_TEST(dpi_parser);
|
|
ADD_TEST(wheel_click_parser);
|
|
ADD_TEST(wheel_click_count_parser);
|
|
ADD_TEST(dimension_prop_parser);
|
|
ADD_TEST(reliability_prop_parser);
|
|
ADD_TEST(calibration_prop_parser);
|
|
ADD_TEST(range_prop_parser);
|
|
ADD_TEST(boolean_prop_parser);
|
|
ADD_TEST(evcode_prop_parser);
|
|
ADD_TEST(input_prop_parser);
|
|
ADD_TEST(evdev_abs_parser);
|
|
ADD_TEST(safe_atoi_test);
|
|
ADD_TEST(safe_atoi_base_16_test);
|
|
ADD_TEST(safe_atoi_base_8_test);
|
|
ADD_TEST(safe_atou_test);
|
|
ADD_TEST(safe_atou_base_16_test);
|
|
ADD_TEST(safe_atou_base_8_test);
|
|
ADD_TEST(safe_atou64_test);
|
|
ADD_TEST(safe_atod_test);
|
|
ADD_TEST(strsplit_test);
|
|
ADD_TEST(strv_for_each_test);
|
|
ADD_TEST(strv_append_test);
|
|
ADD_TEST(strv_find_test);
|
|
ADD_TEST(strv_find_substring_test);
|
|
ADD_TEST(double_array_from_string_test);
|
|
ADD_TEST(strargv_test);
|
|
ADD_TEST(kvsplit_double_test);
|
|
ADD_TEST(strjoin_test);
|
|
ADD_TEST(strstrip_test);
|
|
ADD_TEST(strendswith_test);
|
|
ADD_TEST(strstartswith_test);
|
|
ADD_TEST(strsanitize_test);
|
|
ADD_TEST(time_conversion);
|
|
ADD_TEST(human_time);
|
|
|
|
ADD_TEST(list_test_insert);
|
|
ADD_TEST(list_test_append);
|
|
ADD_TEST(list_test_foreach);
|
|
ADD_TEST(list_test_first_last);
|
|
ADD_TEST(list_test_chain);
|
|
ADD_TEST(strverscmp_test);
|
|
ADD_TEST(streq_test);
|
|
ADD_TEST(strneq_test);
|
|
ADD_TEST(trunkname_test);
|
|
ADD_TEST(basename_test);
|
|
|
|
ADD_TEST(absinfo_normalize_value_test);
|
|
|
|
ADD_TEST(range_test);
|
|
ADD_TEST(stringbuf_test);
|
|
ADD_TEST(multivalue_test);
|
|
|
|
ADD_TEST(newtype_test);
|
|
ADD_TEST(attribute_cleanup);
|
|
ADD_TEST(macros_expand);
|
|
|
|
ADD_TEST(evdev_frames);
|
|
|
|
ADD_TEST(infmask_test);
|
|
|
|
ADD_TEST(evdev_mask_test);
|
|
|
|
enum litest_runner_result result = litest_runner_run_tests(runner);
|
|
litest_runner_destroy(runner);
|
|
|
|
if (result == LITEST_SKIP)
|
|
return 77;
|
|
|
|
return result - LITEST_PASS;
|
|
}
|