/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2014 Intel Corporation */ #include #include #include #include #include #include #include #include #include "test.h" struct fbarray_testsuite_params { struct rte_fbarray arr; int start; int end; }; static struct fbarray_testsuite_params param; static struct fbarray_testsuite_params unaligned; #define FBARRAY_TEST_ARR_NAME "fbarray_autotest" #define FBARRAY_TEST_LEN 256 #define FBARRAY_UNALIGNED_TEST_ARR_NAME "fbarray_unaligned_autotest" #define FBARRAY_UNALIGNED_TEST_LEN 60 #define FBARRAY_TEST_ELT_SZ (sizeof(int)) static int autotest_setup(void) { int ret; ret = rte_fbarray_init(¶m.arr, FBARRAY_TEST_ARR_NAME, FBARRAY_TEST_LEN, FBARRAY_TEST_ELT_SZ); if (ret) { printf("Failed to initialize test array\n"); return -1; } ret = rte_fbarray_init(&unaligned.arr, FBARRAY_UNALIGNED_TEST_ARR_NAME, FBARRAY_UNALIGNED_TEST_LEN, FBARRAY_TEST_ELT_SZ); if (ret) { printf("Failed to initialize unaligned test array\n"); rte_fbarray_destroy(¶m.arr); return -1; } return 0; } static void autotest_teardown(void) { rte_fbarray_destroy(¶m.arr); rte_fbarray_destroy(&unaligned.arr); } static int init_aligned(void) { int i; for (i = param.start; i <= param.end; i++) { if (rte_fbarray_set_used(¶m.arr, i)) return -1; } return 0; } static int init_unaligned(void) { int i; for (i = unaligned.start; i <= unaligned.end; i++) { if (rte_fbarray_set_used(&unaligned.arr, i)) return -1; } return 0; } static void reset_aligned(void) { int i; for (i = 0; i < FBARRAY_TEST_LEN; i++) rte_fbarray_set_free(¶m.arr, i); /* reset param as well */ param.start = -1; param.end = -1; } static void reset_unaligned(void) { int i; for (i = 0; i < FBARRAY_UNALIGNED_TEST_LEN; i++) rte_fbarray_set_free(&unaligned.arr, i); /* reset param as well */ unaligned.start = -1; unaligned.end = -1; } static int first_msk_test_setup(void) { /* put all within first mask */ param.start = 3; param.end = 10; return init_aligned(); } static int cross_msk_test_setup(void) { /* put all within second and third mask */ param.start = 70; param.end = 160; return init_aligned(); } static int multi_msk_test_setup(void) { /* put all within first and last mask */ param.start = 3; param.end = FBARRAY_TEST_LEN - 20; return init_aligned(); } static int last_msk_test_setup(void) { /* put all within last mask */ param.start = FBARRAY_TEST_LEN - 20; param.end = FBARRAY_TEST_LEN - 1; return init_aligned(); } static int full_msk_test_setup(void) { /* fill entire mask */ param.start = 0; param.end = FBARRAY_TEST_LEN - 1; return init_aligned(); } static int lookahead_test_setup(void) { /* set index 64 as used */ param.start = 64; param.end = 64; return init_aligned(); } static int lookbehind_test_setup(void) { /* set index 63 as used */ param.start = 63; param.end = 63; return init_aligned(); } static int unaligned_test_setup(void) { unaligned.start = 0; /* leave one free bit at the end */ unaligned.end = FBARRAY_UNALIGNED_TEST_LEN - 2; return init_unaligned(); } static int test_invalid(void) { struct rte_fbarray dummy; /* invalid parameters */ TEST_ASSERT_FAIL(rte_fbarray_attach(NULL), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT_FAIL(rte_fbarray_detach(NULL), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT_FAIL(rte_fbarray_destroy(NULL), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno valuey\n"); TEST_ASSERT_FAIL(rte_fbarray_init(NULL, "fail", 16, 16), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT_FAIL(rte_fbarray_init(&dummy, NULL, 16, 16), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT_FAIL(rte_fbarray_init(&dummy, "fail", 0, 16), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT_FAIL(rte_fbarray_init(&dummy, "fail", 16, 0), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); /* len must not be greater than INT_MAX */ TEST_ASSERT_FAIL(rte_fbarray_init(&dummy, "fail", INT_MAX + 1U, 16), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT_NULL(rte_fbarray_get(NULL, 0), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_idx(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_set_free(NULL, 0), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_set_used(NULL, 0), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_contig_free(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_contig_used(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_rev_contig_free(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_rev_contig_used(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_free(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_used(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_free(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_used(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_free(NULL, 0, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_used(NULL, 0, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_n_free(NULL, 0, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_n_used(NULL, 0, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_is_used(NULL, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT_SUCCESS(rte_fbarray_init(&dummy, "success", FBARRAY_TEST_LEN, 8), "Failed to initialize valid fbarray\n"); /* test API for handling invalid parameters with a valid fbarray */ TEST_ASSERT_NULL(rte_fbarray_get(&dummy, FBARRAY_TEST_LEN), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_idx(&dummy, NULL) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_set_free(&dummy, FBARRAY_TEST_LEN), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_set_used(&dummy, FBARRAY_TEST_LEN), "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_contig_free(&dummy, FBARRAY_TEST_LEN) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_contig_used(&dummy, FBARRAY_TEST_LEN) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_rev_contig_free(&dummy, FBARRAY_TEST_LEN) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_rev_contig_used(&dummy, FBARRAY_TEST_LEN) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_free(&dummy, FBARRAY_TEST_LEN) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_used(&dummy, FBARRAY_TEST_LEN) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_free(&dummy, FBARRAY_TEST_LEN) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_used(&dummy, FBARRAY_TEST_LEN) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_free(&dummy, FBARRAY_TEST_LEN, 1) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_free(&dummy, 0, FBARRAY_TEST_LEN + 1) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_free(&dummy, 0, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_used(&dummy, FBARRAY_TEST_LEN, 1) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_used(&dummy, 0, FBARRAY_TEST_LEN + 1) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_used(&dummy, 0, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_n_free(&dummy, FBARRAY_TEST_LEN, 1) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_n_free(&dummy, 0, FBARRAY_TEST_LEN + 1) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_n_free(&dummy, 0, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_n_used(&dummy, FBARRAY_TEST_LEN, 1) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_n_used(&dummy, 0, FBARRAY_TEST_LEN + 1) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_n_used(&dummy, 0, 0) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_is_used(&dummy, FBARRAY_TEST_LEN) < 0, "Call succeeded with invalid parameters\n"); TEST_ASSERT_EQUAL(rte_errno, EINVAL, "Wrong errno value\n"); TEST_ASSERT_SUCCESS(rte_fbarray_destroy(&dummy), "Failed to destroy valid fbarray\n"); return TEST_SUCCESS; } static int check_free(void) { const int idx = 0; const int last_idx = FBARRAY_TEST_LEN - 1; /* ensure we can find a free spot */ TEST_ASSERT_EQUAL(rte_fbarray_find_next_free(¶m.arr, idx), idx, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_next_n_free(¶m.arr, idx, 1), idx, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_contig_free(¶m.arr, idx), FBARRAY_TEST_LEN, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_free(¶m.arr, idx), idx, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_n_free(¶m.arr, idx, 1), idx, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_free(¶m.arr, idx), 1, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_free(¶m.arr, last_idx), last_idx, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_n_free(¶m.arr, last_idx, 1), last_idx, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_free(¶m.arr, last_idx), FBARRAY_TEST_LEN, "Free space not found where expected\n"); /* ensure we can't find any used spots */ TEST_ASSERT(rte_fbarray_find_next_used(¶m.arr, idx) < 0, "Used space found where none was expected\n"); TEST_ASSERT_EQUAL(rte_errno, ENOENT, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_used(¶m.arr, idx, 1) < 0, "Used space found where none was expected\n"); TEST_ASSERT_EQUAL(rte_errno, ENOENT, "Wrong errno value\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_contig_used(¶m.arr, idx), 0, "Used space found where none was expected\n"); TEST_ASSERT(rte_fbarray_find_prev_used(¶m.arr, last_idx) < 0, "Used space found where none was expected\n"); TEST_ASSERT_EQUAL(rte_errno, ENOENT, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_prev_n_used(¶m.arr, last_idx, 1) < 0, "Used space found where none was expected\n"); TEST_ASSERT_EQUAL(rte_errno, ENOENT, "Wrong errno value\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_used(¶m.arr, last_idx), 0, "Used space found where none was expected\n"); return 0; } static int check_used_one(void) { const int idx = 0; const int last_idx = FBARRAY_TEST_LEN - 1; /* check that we can find used spots now */ TEST_ASSERT_EQUAL(rte_fbarray_find_next_used(¶m.arr, idx), idx, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_next_n_used(¶m.arr, idx, 1), idx, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_contig_used(¶m.arr, idx), 1, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_used(¶m.arr, last_idx), idx, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_n_used(¶m.arr, last_idx, 1), idx, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_used(¶m.arr, idx), 1, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_used(¶m.arr, last_idx), idx, "Used space not found where expected\n"); /* check if further indices are still free */ TEST_ASSERT(rte_fbarray_find_next_used(¶m.arr, idx + 1) < 0, "Used space not found where none was expected\n"); TEST_ASSERT_EQUAL(rte_errno, ENOENT, "Wrong errno value\n"); TEST_ASSERT(rte_fbarray_find_next_n_used(¶m.arr, idx + 1, 1) < 0, "Used space not found where none was expected\n"); TEST_ASSERT_EQUAL(rte_errno, ENOENT, "Wrong errno value\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_contig_used(¶m.arr, idx + 1), 0, "Used space not found where none was expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_contig_free(¶m.arr, idx + 1), FBARRAY_TEST_LEN - 1, "Used space not found where none was expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_used(¶m.arr, last_idx), 0, "Used space not found where none was expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_n_used(¶m.arr, last_idx, 1), 0, "Used space not found where none was expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_used(¶m.arr, last_idx), 0, "Used space not found where none was expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_free(¶m.arr, last_idx), FBARRAY_TEST_LEN - 1, "Used space not found where none was expected\n"); return 0; } static int test_basic(void) { const int idx = 0; int i; /* check array count */ TEST_ASSERT_EQUAL(param.arr.count, 0, "Wrong element count\n"); /* ensure we can find a free spot */ if (check_free()) return TEST_FAILED; /* check if used */ TEST_ASSERT_EQUAL(rte_fbarray_is_used(¶m.arr, idx), 0, "Used space found where not expected\n"); /* mark as used */ TEST_ASSERT_SUCCESS(rte_fbarray_set_used(¶m.arr, idx), "Failed to set as used\n"); /* check if used again */ TEST_ASSERT_NOT_EQUAL(rte_fbarray_is_used(¶m.arr, idx), 0, "Used space not found where expected\n"); if (check_used_one()) return TEST_FAILED; /* check array count */ TEST_ASSERT_EQUAL(param.arr.count, 1, "Wrong element count\n"); /* check if getting pointers works for every element */ for (i = 0; i < FBARRAY_TEST_LEN; i++) { void *td = rte_fbarray_get(¶m.arr, i); TEST_ASSERT_NOT_NULL(td, "Invalid pointer returned\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_idx(¶m.arr, td), i, "Wrong index returned\n"); } /* mark as free */ TEST_ASSERT_SUCCESS(rte_fbarray_set_free(¶m.arr, idx), "Failed to set as free\n"); /* check array count */ TEST_ASSERT_EQUAL(param.arr.count, 0, "Wrong element count\n"); /* check if used */ TEST_ASSERT_EQUAL(rte_fbarray_is_used(¶m.arr, idx), 0, "Used space found where not expected\n"); if (check_free()) return TEST_FAILED; reset_aligned(); return TEST_SUCCESS; } static int test_biggest(struct rte_fbarray *arr, int first, int last) { int lo_free_space_first, lo_free_space_last, lo_free_space_len; int hi_free_space_first, hi_free_space_last, hi_free_space_len; int max_free_space_first, max_free_space_last, max_free_space_len; int len = last - first + 1; /* first and last must either be both -1, or both not -1 */ TEST_ASSERT((first == -1) == (last == -1), "Invalid arguments provided\n"); /* figure out what we expect from the low chunk of free space */ if (first == -1) { /* special case: if there are no occupied elements at all, * consider both free spaces to consume the entire array. */ lo_free_space_first = 0; lo_free_space_last = arr->len - 1; lo_free_space_len = arr->len; /* if there's no used space, length should be invalid */ len = -1; } else if (first == 0) { /* if occupied items start at 0, there's no free space */ lo_free_space_first = -1; lo_free_space_last = -1; lo_free_space_len = 0; } else { lo_free_space_first = 0; lo_free_space_last = first - 1; lo_free_space_len = lo_free_space_last - lo_free_space_first + 1; } /* figure out what we expect from the high chunk of free space */ if (last == -1) { /* special case: if there are no occupied elements at all, * consider both free spaces to consume the entire array. */ hi_free_space_first = 0; hi_free_space_last = arr->len - 1; hi_free_space_len = arr->len; /* if there's no used space, length should be invalid */ len = -1; } else if (last == ((int)arr->len - 1)) { /* if occupied items end at array len, there's no free space */ hi_free_space_first = -1; hi_free_space_last = -1; hi_free_space_len = 0; } else { hi_free_space_first = last + 1; hi_free_space_last = arr->len - 1; hi_free_space_len = hi_free_space_last - hi_free_space_first + 1; } /* find which one will be biggest */ if (lo_free_space_len > hi_free_space_len) { max_free_space_first = lo_free_space_first; max_free_space_last = lo_free_space_last; max_free_space_len = lo_free_space_len; } else { /* if they are equal, we'll just use the high chunk */ max_free_space_first = hi_free_space_first; max_free_space_last = hi_free_space_last; max_free_space_len = hi_free_space_len; } /* check used regions - these should produce identical results */ TEST_ASSERT_EQUAL(rte_fbarray_find_biggest_used(arr, 0), first, "Used space index is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_biggest_used(arr, arr->len - 1), first, "Used space index is wrong\n"); /* len may be -1, but function will return error anyway */ TEST_ASSERT_EQUAL(rte_fbarray_find_contig_used(arr, first), len, "Used space length is wrong\n"); /* check if biggest free region is the one we expect to find. It can be * -1 if there's no free space - we've made sure we use one or the * other, even if both are invalid. */ TEST_ASSERT_EQUAL(rte_fbarray_find_biggest_free(arr, 0), max_free_space_first, "Biggest free space index is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_biggest_free(arr, arr->len - 1), max_free_space_first, "Biggest free space index is wrong\n"); /* if biggest region exists, check its length */ if (max_free_space_first != -1) { TEST_ASSERT_EQUAL(rte_fbarray_find_contig_free(arr, max_free_space_first), max_free_space_len, "Biggest free space length is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_free(arr, max_free_space_last), max_free_space_len, "Biggest free space length is wrong\n"); } /* find if we see what we expect to see in the low region. if there is * no free space, the function should still match expected value, as * we've set it to -1. we're scanning backwards to avoid accidentally * hitting the high free space region. if there is no occupied space, * there's nothing to do. */ if (last != -1) { TEST_ASSERT_EQUAL(rte_fbarray_find_rev_biggest_free(arr, last), lo_free_space_first, "Low free space index is wrong\n"); } if (lo_free_space_first != -1) { /* if low free region exists, check its length */ TEST_ASSERT_EQUAL(rte_fbarray_find_contig_free(arr, lo_free_space_first), lo_free_space_len, "Low free space length is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_free(arr, lo_free_space_last), lo_free_space_len, "Low free space length is wrong\n"); } /* find if we see what we expect to see in the high region. if there is * no free space, the function should still match expected value, as * we've set it to -1. we're scanning forwards to avoid accidentally * hitting the low free space region. if there is no occupied space, * there's nothing to do. */ if (first != -1) { TEST_ASSERT_EQUAL(rte_fbarray_find_biggest_free(arr, first), hi_free_space_first, "High free space index is wrong\n"); } /* if high free region exists, check its length */ if (hi_free_space_first != -1) { TEST_ASSERT_EQUAL(rte_fbarray_find_contig_free(arr, hi_free_space_first), hi_free_space_len, "High free space length is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_free(arr, hi_free_space_last), hi_free_space_len, "High free space length is wrong\n"); } return 0; } static int ensure_correct(struct rte_fbarray *arr, int first, int last, bool used) { int i, len = last - first + 1; for (i = 0; i < len; i++) { int cur = first + i; int cur_len = len - i; if (used) { TEST_ASSERT_EQUAL(rte_fbarray_find_contig_used(arr, cur), cur_len, "Used space length is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_used(arr, last), len, "Used space length is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_used(arr, cur), i + 1, "Used space length is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_next_used(arr, cur), cur, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_next_n_used(arr, cur, 1), cur, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_next_n_used(arr, cur, cur_len), cur, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_used(arr, cur), cur, "Used space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_n_used(arr, last, cur_len), cur, "Used space not found where expected\n"); } else { TEST_ASSERT_EQUAL(rte_fbarray_find_contig_free(arr, cur), cur_len, "Free space length is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_free(arr, last), len, "Free space length is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_rev_contig_free(arr, cur), i + 1, "Free space length is wrong\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_next_free(arr, cur), cur, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_next_n_free(arr, cur, 1), cur, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_next_n_free(arr, cur, cur_len), cur, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_free(arr, cur), cur, "Free space not found where expected\n"); TEST_ASSERT_EQUAL(rte_fbarray_find_prev_n_free(arr, last, cur_len), cur, "Free space not found where expected\n"); } } return 0; } static int test_find(void) { TEST_ASSERT_EQUAL((int)param.arr.count, param.end - param.start + 1, "Wrong element count\n"); /* ensure space is free before start */ if (ensure_correct(¶m.arr, 0, param.start - 1, false)) return TEST_FAILED; /* ensure space is occupied where it's supposed to be */ if (ensure_correct(¶m.arr, param.start, param.end, true)) return TEST_FAILED; /* ensure space after end is free as well */ if (ensure_correct(¶m.arr, param.end + 1, FBARRAY_TEST_LEN - 1, false)) return TEST_FAILED; /* test if find_biggest API's work correctly */ if (test_biggest(¶m.arr, param.start, param.end)) return TEST_FAILED; return TEST_SUCCESS; } static int test_find_unaligned(void) { TEST_ASSERT_EQUAL((int)unaligned.arr.count, unaligned.end - unaligned.start + 1, "Wrong element count\n"); /* ensure space is free before start */ if (ensure_correct(&unaligned.arr, 0, unaligned.start - 1, false)) return TEST_FAILED; /* ensure space is occupied where it's supposed to be */ if (ensure_correct(&unaligned.arr, unaligned.start, unaligned.end, true)) return TEST_FAILED; /* ensure space after end is free as well */ if (ensure_correct(&unaligned.arr, unaligned.end + 1, FBARRAY_UNALIGNED_TEST_LEN - 1, false)) return TEST_FAILED; /* test if find_biggest API's work correctly */ if (test_biggest(&unaligned.arr, unaligned.start, unaligned.end)) return TEST_FAILED; return TEST_SUCCESS; } static int test_empty(void) { TEST_ASSERT_EQUAL((int)param.arr.count, 0, "Wrong element count\n"); /* ensure space is free */ if (ensure_correct(¶m.arr, 0, FBARRAY_TEST_LEN - 1, false)) return TEST_FAILED; /* test if find_biggest API's work correctly */ if (test_biggest(¶m.arr, param.start, param.end)) return TEST_FAILED; return TEST_SUCCESS; } static int test_lookahead(void) { int ret; /* run regular test first */ ret = test_find(); if (ret != TEST_SUCCESS) return ret; /* test if we can find free chunk while not starting with 0 */ TEST_ASSERT_EQUAL(rte_fbarray_find_next_n_free(¶m.arr, 1, param.start), param.start + 1, "Free chunk index is wrong\n"); return TEST_SUCCESS; } static int test_lookbehind(void) { int ret, free_len = 2; /* run regular test first */ ret = test_find(); if (ret != TEST_SUCCESS) return ret; /* test if we can find free chunk while crossing mask boundary */ TEST_ASSERT_EQUAL(rte_fbarray_find_prev_n_free(¶m.arr, param.start + 1, free_len), param.start - free_len, "Free chunk index is wrong\n"); return TEST_SUCCESS; } static int test_lookahead_mask(void) { /* * There is a certain type of lookahead behavior we want to test here, * namely masking of bits that were scanned with lookahead but that we * know do not match our criteria. This is achieved in following steps: * * 0. Look for a big enough chunk of free space (say, 62 elements) * 1. Trigger lookahead by breaking a run somewhere inside mask 0 * (indices 0-63) * 2. Fail lookahead by breaking the run somewhere inside mask 1 * (indices 64-127) * 3. Ensure that we can still find free space in mask 1 afterwards */ /* break run on first mask */ rte_fbarray_set_used(¶m.arr, 61); /* break run on second mask */ rte_fbarray_set_used(¶m.arr, 70); /* we expect to find free space at 71 */ TEST_ASSERT_EQUAL(rte_fbarray_find_next_n_free(¶m.arr, 0, 62), 71, "Free chunk index is wrong\n"); return TEST_SUCCESS; } static int test_lookbehind_mask(void) { /* * There is a certain type of lookbehind behavior we want to test here, * namely masking of bits that were scanned with lookbehind but that we * know do not match our criteria. This is achieved in two steps: * * 0. Look for a big enough chunk of free space (say, 62 elements) * 1. Trigger lookbehind by breaking a run somewhere inside mask 2 * (indices 128-191) * 2. Fail lookbehind by breaking the run somewhere inside mask 1 * (indices 64-127) * 3. Ensure that we can still find free space in mask 1 afterwards */ /* break run on mask 2 */ rte_fbarray_set_used(¶m.arr, 130); /* break run on mask 1 */ rte_fbarray_set_used(¶m.arr, 70); /* start from 190, we expect to find free space at 8 */ TEST_ASSERT_EQUAL(rte_fbarray_find_prev_n_free(¶m.arr, 190, 62), 8, "Free chunk index is wrong\n"); return TEST_SUCCESS; } static struct unit_test_suite fbarray_test_suite = { .suite_name = "fbarray autotest", .setup = autotest_setup, .teardown = autotest_teardown, .unit_test_cases = { TEST_CASE(test_invalid), TEST_CASE(test_basic), TEST_CASE_ST(first_msk_test_setup, reset_aligned, test_find), TEST_CASE_ST(cross_msk_test_setup, reset_aligned, test_find), TEST_CASE_ST(multi_msk_test_setup, reset_aligned, test_find), TEST_CASE_ST(last_msk_test_setup, reset_aligned, test_find), TEST_CASE_ST(full_msk_test_setup, reset_aligned, test_find), /* empty test does not need setup */ TEST_CASE_ST(NULL, reset_aligned, test_empty), TEST_CASE_ST(lookahead_test_setup, reset_aligned, test_lookahead), TEST_CASE_ST(lookbehind_test_setup, reset_aligned, test_lookbehind), /* setup for these tests is more complex so do it in test func */ TEST_CASE_ST(NULL, reset_aligned, test_lookahead_mask), TEST_CASE_ST(NULL, reset_aligned, test_lookbehind_mask), TEST_CASE_ST(unaligned_test_setup, reset_unaligned, test_find_unaligned), TEST_CASES_END() } }; static int test_fbarray(void) { return unit_test_suite_runner(&fbarray_test_suite); } REGISTER_TEST_COMMAND(fbarray_autotest, test_fbarray);