2026-08-29 01:50:50 +08:00
|
|
|
#include "c_ArrayList.h"
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <c_Test.h>
|
|
|
|
|
|
|
|
|
|
struct Vector2D {
|
|
|
|
|
double u, v;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* ==============================================================================
|
|
|
|
|
* 🧪 测试全新通用 void* 缓冲区的初始化、自动扩容与随机 Remove 重排全周期行为
|
|
|
|
|
* ============================================================================== */
|
2026-08-29 11:39:28 +08:00
|
|
|
TEST_CASE(test_array_list_full_lifecycle_and_removal)
|
2026-08-29 01:50:50 +08:00
|
|
|
{
|
|
|
|
|
c_ArrayList_t list;
|
|
|
|
|
/* 1. 初始化:装载自定义 Vector2D 结构体,初始最大可容纳元素数量卡死限制为 2 */
|
|
|
|
|
c_err_t init_err = c_ArrayList_Init(&list, sizeof(struct Vector2D), 2);
|
2026-08-29 11:39:28 +08:00
|
|
|
ASSERT_INT_EQ_MSG(init_err, C_ERR_OK, "弹性自愈 ArrayList 初始化成功");
|
|
|
|
|
ASSERT_INT_EQ_MSG(list.size, 0, "有效初始记录必须为 0");
|
2026-08-29 01:50:50 +08:00
|
|
|
|
|
|
|
|
struct Vector2D vec1 = { 11.1, 22.2 };
|
|
|
|
|
struct Vector2D vec2 = { 33.3, 44.4 };
|
|
|
|
|
struct Vector2D vec3 = { 55.5, 66.6 };
|
|
|
|
|
|
|
|
|
|
/* 2. 连续推入数据 */
|
|
|
|
|
c_ArrayList_Add(&list, &vec1);
|
|
|
|
|
c_ArrayList_Add(&list, &vec2);
|
|
|
|
|
|
|
|
|
|
/* 🎯 扩容看点:此时满员,第三次写入将强行逼迫池子在内部启动 2 -> 4 自动翻倍重分配 */
|
|
|
|
|
c_err_t add_err = c_ArrayList_Add(&list, &vec3);
|
2026-08-29 11:39:28 +08:00
|
|
|
ASSERT_INT_EQ_MSG(add_err, C_ERR_OK, "耗尽时追加写入,分配器必须完成全自动无感自愈扩容");
|
|
|
|
|
ASSERT_INT_EQ_MSG(list.size, 3, "当前有效装载数递增至 3");
|
2026-08-29 01:50:50 +08:00
|
|
|
|
|
|
|
|
/* 3. 验证数据内容的物理隔离完整度 */
|
|
|
|
|
struct Vector2D* p_check1 = (struct Vector2D*)c_ArrayList_Get(&list, 1);
|
2026-08-29 11:39:28 +08:00
|
|
|
ASSERT_MSG(p_check1 != NULL, "随机读取索引 1 节点成功");
|
|
|
|
|
ASSERT_DOUBLE_EQ_MSG(p_check1->u, 33.3, "重分配内存迁移后,原有位置 1 的数据必须毫发无损");
|
2026-08-29 01:50:50 +08:00
|
|
|
|
|
|
|
|
/* 4. 🛠️ 高能测试点:随机抹除中间位置 1 的节点 (即删掉 vec2)
|
|
|
|
|
预期结果:原位置 2 的 vec3 ({55.5, 66.6}) 必须在 O(N) 速度下向前平移,填补顶替空位 1 */
|
|
|
|
|
c_err_t remove_err = c_ArrayList_Remove(&list, 1);
|
2026-08-29 11:39:28 +08:00
|
|
|
ASSERT_INT_EQ_MSG(remove_err, C_ERR_OK, "执行中途位置随机移除成功");
|
|
|
|
|
ASSERT_INT_EQ_MSG(list.size, 2, "移除数据后,有效数据计数平滑扣减为 2");
|
2026-08-29 01:50:50 +08:00
|
|
|
|
|
|
|
|
/* 5. 终极完整性断言:现在去 Get 原本的位置 1 */
|
|
|
|
|
struct Vector2D* p_relocated = (struct Vector2D*)c_ArrayList_Get(&list, 1);
|
2026-08-29 11:39:28 +08:00
|
|
|
ASSERT_MSG(p_relocated != NULL, "重新获取平移顶替后的位置 1 节点成功");
|
2026-08-29 01:50:50 +08:00
|
|
|
|
|
|
|
|
/* 核心断言:原位置 2 的数据现在必须完美出现在位置 1 线上,且精度不发生移位错乱! */
|
2026-08-29 11:39:28 +08:00
|
|
|
ASSERT_DOUBLE_EQ_MSG(p_relocated->u, 55.5, "元素向前滑动对齐后,浮点特征完好无损");
|
|
|
|
|
ASSERT_DOUBLE_EQ_MSG(p_relocated->v, 66.6, "元素向前滑动对齐后,浮点特征完好无损");
|
2026-08-29 01:50:50 +08:00
|
|
|
|
|
|
|
|
/* 6. 边界越界捕获安全防御线 */
|
|
|
|
|
void* invalid_ptr = c_ArrayList_Get(&list, 2); /* 此时由于删了一个,索引 2 已变为空旷越界区 */
|
2026-08-29 11:39:28 +08:00
|
|
|
ASSERT_MSG(invalid_ptr == NULL, "越界获取已经被逻辑截断删除的位置必须安全回传 NULL");
|
2026-08-29 01:50:50 +08:00
|
|
|
|
|
|
|
|
c_ArrayList_Destroy(&list);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-29 11:39:28 +08:00
|
|
|
static void test_list_auto_expansion() {
|
|
|
|
|
int data[] = {10, 20, 30};
|
|
|
|
|
c_ArrayList_t list;
|
|
|
|
|
c_ArrayList_Init(&list, sizeof(int), 2);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
|
c_ArrayList_Add(&list, &data[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 验证容量是否翻倍 (2 << 1 = 4)
|
|
|
|
|
ASSERT_INT_EQ_MSG(4, list.capacity, "Capacity should double to 4");
|
|
|
|
|
ASSERT_INT_EQ_MSG(3, list.size, "Size should be 3");
|
|
|
|
|
|
|
|
|
|
// 验证最后一个元素有没有因为扩容导致内存搬移出错
|
|
|
|
|
int* p3 = (int*)c_ArrayList_Get(&list, 2);
|
|
|
|
|
ASSERT_MSG(p3 != NULL, "Expanded element should be accessible");
|
|
|
|
|
ASSERT_INT_EQ_MSG(30, *p3, "Expanded element data corruption");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void test_list_remove_element() {
|
|
|
|
|
int data[] = {11, 22, 33, 44};
|
|
|
|
|
c_ArrayList_t list;
|
|
|
|
|
c_ArrayList_Init(&list, sizeof(int), 2);
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < 4; i++) c_ArrayList_Add(&list, &data[i]);
|
|
|
|
|
|
|
|
|
|
// 删除索引为 1 的元素 (即数字 22)
|
|
|
|
|
c_err_t err = c_ArrayList_Remove(&list, 1);
|
|
|
|
|
ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Remove operational failure");
|
|
|
|
|
ASSERT_INT_EQ_MSG(3, list.size, "Size should decrease to 3");
|
|
|
|
|
|
|
|
|
|
// 此时索引 1 应该变成了 33,索引 2 应该变成了 44
|
|
|
|
|
int* p1 = (int*)c_ArrayList_Get(&list, 1);
|
|
|
|
|
int* p2 = (int*)c_ArrayList_Get(&list, 2);
|
|
|
|
|
|
|
|
|
|
ASSERT_INT_EQ_MSG(33, *p1, "Element forward-shift error at index 1");
|
|
|
|
|
ASSERT_INT_EQ_MSG(44, *p2, "Element forward-shift error at index 2");
|
|
|
|
|
|
|
|
|
|
// 检查获取越界索引是否安全返回 NULL
|
|
|
|
|
ASSERT_MSG(c_ArrayList_Get(&list, 3) == NULL, "Out of bounds should return NULL");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void test_list_zero_initial_capacity() {
|
|
|
|
|
c_ArrayList_t zero_list;
|
|
|
|
|
c_ArrayList_Init(&zero_list, sizeof(int), 0);
|
|
|
|
|
|
|
|
|
|
int val = 99;
|
|
|
|
|
// 如果你没有按照上方提示修复缺陷①,该断言将会失败(期望返回 OK 却返回了 PARAM 错误)
|
|
|
|
|
c_err_t err = c_ArrayList_Add(&zero_list, &val);
|
|
|
|
|
ASSERT_INT_EQ_MSG(C_ERR_OK, err, "Add failed when initial capacity is 0 (Bug ① Triggered!)");
|
|
|
|
|
|
|
|
|
|
c_ArrayList_Destroy(&zero_list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void test_list_auto_shrink() {
|
|
|
|
|
// 1. 连续添加 9 个元素触发扩容
|
|
|
|
|
// 初始化 0 -> 扩容到 4 -> 扩容到 8 -> 扩容到 16
|
|
|
|
|
c_ArrayList_t list;
|
|
|
|
|
c_ArrayList_Init(&list, sizeof(int), 2);
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 9; i++) {
|
|
|
|
|
c_ArrayList_Add(&list, &i);
|
|
|
|
|
}
|
|
|
|
|
ASSERT_INT_EQ_MSG(16, list.capacity, "Capacity should expand up to 16");
|
|
|
|
|
|
|
|
|
|
// 2. 依次删除元素,降低 size 以试图触发 1/4 缩容临界点
|
|
|
|
|
// 当 size 减少到 4 时 (即 16 / 4), 应该触发缩容:16 减半变成 8
|
|
|
|
|
for (int i = 0; i < 5; i++) {
|
|
|
|
|
c_ArrayList_Remove(&list, 0); // 总是移除首个元素
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 此时移除了 5 个,剩下 4 个元素
|
|
|
|
|
ASSERT_INT_EQ_MSG(4, list.size, "Current size should be 4");
|
|
|
|
|
ASSERT_INT_EQ_MSG(8, list.capacity, "Capacity should automatically shrink to 8");
|
|
|
|
|
|
|
|
|
|
// 3. 继续删除,观察是否会由于低于最小阈值(4)而停止缩容
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
|
c_ArrayList_Remove(&list, 0);
|
|
|
|
|
}
|
|
|
|
|
// 此时只剩 1 个元素了 (1 <= 8/4),但由于 MIN_SHRINK_CAPACITY = 4 限制,容量不应该再减半到 2
|
|
|
|
|
ASSERT_INT_EQ_MSG(1, list.size, "Current size should be 1");
|
|
|
|
|
ASSERT_INT_EQ_MSG(2, list.capacity, "Capacity should hold at 2 to prevent thrashing");
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-29 01:50:50 +08:00
|
|
|
int main(void) {
|
2026-08-29 11:39:28 +08:00
|
|
|
TEST_START(BaseArrayListNewSpecificationTestSuite);
|
|
|
|
|
|
|
|
|
|
RUN_TEST(test_array_list_full_lifecycle_and_removal);
|
|
|
|
|
RUN_TEST(test_list_auto_expansion);
|
|
|
|
|
RUN_TEST(test_list_remove_element);
|
|
|
|
|
RUN_TEST(test_list_zero_initial_capacity);
|
|
|
|
|
RUN_TEST(test_list_auto_shrink);
|
|
|
|
|
|
|
|
|
|
TEST_REPORT();
|
|
|
|
|
RETURN_TEST_STATUS;
|
2026-08-29 01:50:50 +08:00
|
|
|
}
|
|
|
|
|
|