113 lines
3.5 KiB
C
113 lines
3.5 KiB
C
#include "c_KnuthShuffle.h"
|
|||
|
|
#include "c_Test.h"
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <c_StringView.h>
|
||
|
|
|
||
|
|
TEST_CASE(test_c_KnuthShuffle_IntArray) {
|
||
|
|
// 显式播种确保单次测试序列可重现,或调用您的 c_Random_Init()
|
||
|
|
srand(54321);
|
||
|
|
|
||
|
|
int original[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
|
||
|
|
int arr[] = { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };
|
||
|
|
c_size_t num = sizeof(arr) / sizeof(arr[0]);
|
||
|
|
|
||
|
|
// 执行洗牌
|
||
|
|
c_KnuthShuffle(arr, num, sizeof(int));
|
||
|
|
|
||
|
|
// 1. 验证乱序生效性:洗牌后的数组大概率不再与原数组完全相同
|
||
|
|
int match_count = 0;
|
||
|
|
for (size_t i = 0; i < num; i++) {
|
||
|
|
if (arr[i] == original[i]) {
|
||
|
|
match_count++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// 10个元素洗牌后,依然完全对齐原数组的概率极低
|
||
|
|
ASSERT_TRUE(match_count < (int)num);
|
||
|
|
|
||
|
|
// 2. 验证元素守恒性:利用计数桶确保数据没有在交换中丢失或损坏
|
||
|
|
for (size_t i = 0; i < num; i++) {
|
||
|
|
int target = original[i];
|
||
|
|
bool found = false;
|
||
|
|
for (size_t j = 0; j < num; j++) {
|
||
|
|
if (arr[j] == target) {
|
||
|
|
found = true;
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
ASSERT_TRUE(found); // 每一个原数组的元素都必须在洗牌后的数组中存在
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_CASE(test_c_KnuthShuffle_StringViewArray) {
|
||
|
|
c_StringView_t original_sv[] = {
|
||
|
|
c_StringView_FromCStr("A"),
|
||
|
|
c_StringView_FromCStr("B"),
|
||
|
|
c_StringView_FromCStr("C"),
|
||
|
|
c_StringView_FromCStr("D")
|
||
|
|
};
|
||
|
|
|
||
|
|
c_StringView_t sv_arr[] = {
|
||
|
|
c_StringView_FromCStr("A"),
|
||
|
|
c_StringView_FromCStr("B"),
|
||
|
|
c_StringView_FromCStr("C"),
|
||
|
|
c_StringView_FromCStr("D")
|
||
|
|
};
|
||
|
|
c_size_t num = sizeof(sv_arr) / sizeof(sv_arr[0]);
|
||
|
|
|
||
|
|
// 对 StringView 结构体数组执行泛型洗牌
|
||
|
|
c_KnuthShuffle(sv_arr, num, sizeof(c_StringView_t));
|
||
|
|
|
||
|
|
// 验证洗牌后所有的 StringView 依然完好、大小未被破坏
|
||
|
|
for (size_t i = 0; i < num; i++) {
|
||
|
|
c_StringView_t* cur = &sv_arr[i];
|
||
|
|
ASSERT_PTR_NOT_NULL(cur->str);
|
||
|
|
ASSERT_INT_EQ(1, (int)cur->size); // 每个视图长度原本都为 1
|
||
|
|
|
||
|
|
// 确保属于原集合 A, B, C, D 之一
|
||
|
|
char c = cur->str[0];
|
||
|
|
ASSERT_TRUE(c == 'A' || c == 'B' || c == 'C' || c == 'D');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_CASE(test_c_KnuthShuffle_EdgeCases) {
|
||
|
|
int single_arr[] = { 42 };
|
||
|
|
|
||
|
|
// 1. 测试单元素或空元素数组的防御能力(应当安全返回,不崩溃)
|
||
|
|
c_KnuthShuffle(single_arr, 1, sizeof(int));
|
||
|
|
ASSERT_INT_EQ(42, single_arr[0]);
|
||
|
|
|
||
|
|
c_KnuthShuffle(NULL, 0, sizeof(int));
|
||
|
|
ASSERT_TRUE(true); // 代表通过了 NULL 校验
|
||
|
|
}
|
||
|
|
|
||
|
|
TEST_CASE(test_c_KnuthShuffle_UnderflowDefense) {
|
||
|
|
int small_arr[] = { 1, 2 };
|
||
|
|
|
||
|
|
// 压测 2 个元素的无符号边界切换,确保能在一瞬间安全退出
|
||
|
|
c_KnuthShuffle(small_arr, 2, sizeof(int));
|
||
|
|
|
||
|
|
// 修正:分别验证下标 0 和 下标 1 的元素有效性
|
||
|
|
ASSERT_TRUE(small_arr[0] == 1 || small_arr[0] == 2);
|
||
|
|
ASSERT_TRUE(small_arr[1] == 1 || small_arr[1] == 2);
|
||
|
|
|
||
|
|
// 附加校验:洗牌不会凭空克隆元素,两个位置的值必须保持不相等
|
||
|
|
ASSERT_TRUE(small_arr[0] != small_arr[1]);
|
||
|
|
}
|
||
|
|
|
||
|
|
int main(int argc, char** argv){
|
||
|
|
TEST_START(Unit Tests);
|
||
|
|
// 运行普通无环境要求的用例
|
||
|
|
RUN_TEST(test_c_KnuthShuffle_IntArray);
|
||
|
|
RUN_TEST(test_c_KnuthShuffle_StringViewArray);
|
||
|
|
RUN_TEST(test_c_KnuthShuffle_EdgeCases);
|
||
|
|
RUN_TEST(test_c_KnuthShuffle_UnderflowDefense);
|
||
|
|
|
||
|
|
// 打印最终统计报告
|
||
|
|
TEST_REPORT();
|
||
|
|
|
||
|
|
RETURN_TEST_STATUS;
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|