136 lines
4.7 KiB
C
136 lines
4.7 KiB
C
#include "c_BinarySearch.h"
|
|||
|
|
#include "c_Test.h"
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include "c_StringView.h"
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
// ==========================================
|
||
|
|
// 1. 测试用例伴生:基础数据类型比对器
|
||
|
|
// ==========================================
|
||
|
|
static int compare_ints(const void* a, const void* b) {
|
||
|
|
int arg1 = *(const int*)a;
|
||
|
|
int arg2 = *(const int*)b;
|
||
|
|
if (arg1 < arg2) return -1;
|
||
|
|
if (arg1 > arg2) return 1;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 自定义结构体与对应的比对器
|
||
|
|
typedef struct {
|
||
|
|
uint32_t id;
|
||
|
|
uint32_t value;
|
||
|
|
} TestItem_t;
|
||
|
|
|
||
|
|
static int compare_items_by_id(const void* key, const void* elem) {
|
||
|
|
uint32_t key_id = *(const uint32_t*)key; // 查找时通常可以直接传入 ID 变量的地址作为 key
|
||
|
|
uint32_t elem_id = ((const TestItem_t*)elem)->id;
|
||
|
|
if (key_id < elem_id) return -1;
|
||
|
|
if (key_id > elem_id) return 1;
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 适配 c_StringView_t 的比对器(对之前 Cmp 函数的外壳包裹)
|
||
|
|
static int compare_string_views(const void* key, const void* elem) {
|
||
|
|
return c_StringView_Cmp((c_StringView_t*)key, (c_StringView_t*)elem);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ==========================================
|
||
|
|
// 2. 核心测试用例
|
||
|
|
// ==========================================
|
||
|
|
|
||
|
|
TEST_CASE(test_c_BinarySearch_IntArray) {
|
||
|
|
int sorted_ints[] = { 2, 5, 8, 12, 16, 23, 38, 56, 72, 91 };
|
||
|
|
c_size_t array_len = sizeof(sorted_ints) / sizeof(sorted_ints[0]);
|
||
|
|
|
||
|
|
// 1. 查找存在的元素
|
||
|
|
int target_exist = 23;
|
||
|
|
const int* result1 = (const int*)c_BinarySearch(&target_exist, sorted_ints, array_len, sizeof(int), compare_ints);
|
||
|
|
ASSERT_PTR_NOT_NULL(result1);
|
||
|
|
ASSERT_INT_EQ(23, *result1);
|
||
|
|
ASSERT_LL_EQ(5, result1 - sorted_ints); // 校验指针偏移,确定下标为 5
|
||
|
|
|
||
|
|
// 2. 查找不存在的元素
|
||
|
|
int target_missing = 40;
|
||
|
|
const int* result2 = (const int*)c_BinarySearch(&target_missing, sorted_ints, array_len, sizeof(int), compare_ints);
|
||
|
|
ASSERT_TRUE(result2 == NULL);
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_CASE(test_c_BinarySearch_StructArray) {
|
||
|
|
// 模拟数据库索引项或符号表,已按 ID 升序排好
|
||
|
|
TestItem_t items[] = {
|
||
|
|
{ 1001, 55 },
|
||
|
|
{ 1005, 99 },
|
||
|
|
{ 1012, 12 },
|
||
|
|
{ 1045, 78 }
|
||
|
|
};
|
||
|
|
c_size_t array_len = sizeof(items) / sizeof(items[0]);
|
||
|
|
|
||
|
|
// 查找 ID 为 1012 的结构体数据
|
||
|
|
uint32_t search_id = 1012;
|
||
|
|
const TestItem_t* match = (const TestItem_t*)c_BinarySearch(&search_id, items, array_len, sizeof(TestItem_t), compare_items_by_id);
|
||
|
|
|
||
|
|
ASSERT_PTR_NOT_NULL(match);
|
||
|
|
ASSERT_INT_EQ(1012, (int)match->id);
|
||
|
|
ASSERT_INT_EQ(12, (int)match->value); // 成功提取对应的值
|
||
|
|
ASSERT_LL_EQ(2, match - items); // 下标确认
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_CASE(test_c_BinarySearch_StringViewArray) {
|
||
|
|
// 复用之前的有序 StringView 数组进行查找
|
||
|
|
c_StringView_t sv_array[] = {
|
||
|
|
c_StringView_FromCStr("apple"),
|
||
|
|
c_StringView_FromCStr("banana"),
|
||
|
|
c_StringView_FromCStr("cherry"),
|
||
|
|
c_StringView_FromCStr("date")
|
||
|
|
};
|
||
|
|
c_size_t array_len = sizeof(sv_array) / sizeof(sv_array[0]);
|
||
|
|
|
||
|
|
c_StringView_t target = c_StringView_FromCStr("banana");
|
||
|
|
const c_StringView_t* match = (const c_StringView_t*)c_BinarySearch(&target, sv_array, array_len, sizeof(c_StringView_t), compare_string_views);
|
||
|
|
|
||
|
|
ASSERT_PTR_NOT_NULL(match);
|
||
|
|
ASSERT_INT_EQ(6, (int)match->size);
|
||
|
|
ASSERT_TRUE(memcmp(match->str, "banana", 6) == 0);
|
||
|
|
ASSERT_LL_EQ(1, match - sv_array); // 确认位于数组第 1 项
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_CASE(test_c_BinarySearch_EdgeAndNull) {
|
||
|
|
int single_elem[] = { 42 };
|
||
|
|
int target = 42;
|
||
|
|
|
||
|
|
// 1. 空参数安全防御
|
||
|
|
ASSERT_TRUE(c_BinarySearch(NULL, single_elem, 1, sizeof(int), compare_ints) == NULL);
|
||
|
|
ASSERT_TRUE(c_BinarySearch(&target, NULL, 1, sizeof(int), compare_ints) == NULL);
|
||
|
|
ASSERT_TRUE(c_BinarySearch(&target, single_elem, 1, sizeof(int), NULL) == NULL);
|
||
|
|
ASSERT_TRUE(c_BinarySearch(&target, single_elem, 0, sizeof(int), compare_ints) == NULL);
|
||
|
|
|
||
|
|
// 2. 单元素数组边界查找
|
||
|
|
const int* match = (const int*)c_BinarySearch(&target, single_elem, 1, sizeof(int), compare_ints);
|
||
|
|
ASSERT_PTR_NOT_NULL(match);
|
||
|
|
ASSERT_INT_EQ(42, *match);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||
|
|
/* */
|
||
|
|
|
||
|
|
int main(int argc, char** argv){
|
||
|
|
|
||
|
|
TEST_START(Unit Tests);
|
||
|
|
|
||
|
|
// 运行普通无环境要求的用例
|
||
|
|
RUN_TEST(test_c_BinarySearch_IntArray);
|
||
|
|
RUN_TEST(test_c_BinarySearch_StructArray);
|
||
|
|
RUN_TEST(test_c_BinarySearch_StringViewArray);
|
||
|
|
RUN_TEST(test_c_BinarySearch_EdgeAndNull);
|
||
|
|
|
||
|
|
// 打印最终统计报告
|
||
|
|
TEST_REPORT();
|
||
|
|
|
||
|
|
RETURN_TEST_STATUS;
|
||
|
|
}
|