task_auto_plan1/tests/basic_test.cpp

215 lines
6.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file basic_test.cpp
* @brief 基础测试文件 - 使用标准库 assert无外部依赖
*/
#include "app.hpp"
#include <cassert>
#include <iostream>
#include <vector>
#include <string>
/// 测试枚举转换函数
static void testEnumToString() {
std::cout << "[TEST] 枚举转换函数..." << std::endl;
assert(checkinMethodToString(CheckinMethod::FACE) == "人脸识别");
assert(checkinMethodToString(CheckinMethod::GPS) == "GPS定位");
assert(checkinMethodToString(CheckinMethod::CARD) == "工牌刷卡");
assert(attendanceStatusToString(AttendanceStatus::NORMAL) == "正常");
assert(attendanceStatusToString(AttendanceStatus::LATE) == "迟到");
assert(attendanceStatusToString(AttendanceStatus::EARLY) == "早退");
assert(attendanceStatusToString(AttendanceStatus::ABSENT) == "缺勤");
assert(attendanceStatusToString(AttendanceStatus::OVERTIME) == "加班");
assert(alertTypeToString(AlertType::UNCHECKED) == "未打卡");
assert(alertTypeToString(AlertType::EARLY) == "早退预警");
assert(alertTypeToString(AlertType::LATE) == "迟到预警");
assert(alertTypeToString(AlertType::MISSING) == "连续缺勤");
std::cout << " PASS" << std::endl;
}
/// 测试记录ID生成
static void testGenerateRecordId() {
std::cout << "[TEST] recordId生成..." << std::endl;
std::string id1 = generateRecordId();
std::string id2 = generateRecordId();
assert(!id1.empty());
assert(!id2.empty());
assert(id1 != id2); // 两次生成的ID应该不同
assert(id1.substr(0, 2) == "CK");
std::cout << " PASS: id1=" << id1 << ", id2=" << id2 << std::endl;
}
/// 测试打卡处理
static void testProcessCheckin() {
std::cout << "[TEST] 打卡处理..." << std::endl;
GeoLocation loc = {39.9042, 116.4074};
std::vector<uint8_t> face = {0x01, 0x02, 0x03};
int64_t ts = 1700000000000LL; // 固定时间戳
// 人脸打卡
CheckinRecord rec1 = processCheckin("EMP001", CheckinMethod::FACE, ts, loc, face);
assert(rec1.employeeId == "EMP001");
assert(rec1.status == CheckinStatus::SUCCESS);
assert(!rec1.recordId.empty());
// GPS打卡
CheckinRecord rec2 = processCheckin("EMP002", CheckinMethod::GPS, ts, loc, {});
assert(rec2.employeeId == "EMP002");
assert(rec2.status == CheckinStatus::SUCCESS);
// 工牌刷卡
CheckinRecord rec3 = processCheckin("EMP003", CheckinMethod::CARD, ts, loc, {});
assert(rec3.employeeId == "EMP003");
assert(rec3.status == CheckinStatus::SUCCESS);
std::cout << " PASS: 三种打卡方式均成功" << std::endl;
}
/// 测试考勤计算
static void testCalculateAttendance() {
std::cout << "[TEST] 考勤计算..." << std::endl;
ShiftRule shift;
shift.shiftName = "早班";
shift.startHour = 9;
shift.startMinute = 0;
shift.endHour = 18;
shift.endMinute = 0;
shift.breakDuration = 60;
shift.overtimeThreshold = 30;
// 场景1: 准时打卡 (9:00)
{
struct tm tm_in = {};
tm_in.tm_year = 2025 - 1900;
tm_in.tm_mon = 0;
tm_in.tm_mday = 15;
tm_in.tm_hour = 9;
tm_in.tm_min = 0;
time_t sec = mktime(&tm_in);
CheckinRecord rec;
rec.employeeId = "EMP001";
rec.timestamp = static_cast<int64_t>(sec) * 1000;
AttendanceResult res = calculateAttendance(rec, shift);
assert(res.lateMinutes == 0);
assert(res.status == AttendanceStatus::NORMAL || res.status == AttendanceStatus::NORMAL);
}
// 场景2: 迟到 (9:45)
{
struct tm tm_in = {};
tm_in.tm_year = 2025 - 1900;
tm_in.tm_mon = 0;
tm_in.tm_mday = 15;
tm_in.tm_hour = 9;
tm_in.tm_min = 45;
time_t sec = mktime(&tm_in);
CheckinRecord rec;
rec.employeeId = "EMP002";
rec.timestamp = static_cast<int64_t>(sec) * 1000;
AttendanceResult res = calculateAttendance(rec, shift);
assert(res.lateMinutes > 0);
assert(res.status == AttendanceStatus::LATE);
}
std::cout << " PASS: 正常与迟到判定正确" << std::endl;
}
/// 测试异常检测
static void testDetectAnomaly() {
std::cout << "[TEST] 异常检测..." << std::endl;
// 正常情况 - 不应生成预警
{
AttendanceResult normal;
normal.employeeId = "EMP001";
normal.date = "2025-01-15";
normal.lateMinutes = 0;
normal.absent = false;
AlertNotification alert = detectAnomaly(normal);
assert(alert.alertType == AlertType::UNCHECKED);
assert(alert.reason == "正常");
}
// 迟到超过30分钟 - 应生成迟到预警
{
AttendanceResult late;
late.employeeId = "EMP002";
late.date = "2025-01-15";
late.lateMinutes = 45;
late.absent = false;
AlertNotification alert = detectAnomaly(late);
assert(alert.alertType == AlertType::LATE);
assert(!alert.notifiedChannels.empty());
}
std::cout << " PASS" << std::endl;
}
/// 测试报表生成
static void testGenerateReport() {
std::cout << "[TEST] 报表生成..." << std::endl;
ReportRequest req;
req.dimension = ReportDimension::MONTH;
req.startDate = "2025-01-01";
req.endDate = "2025-01-31";
req.format = ExportFormat::EXCEL;
ReportResponse resp = generateReport(req);
assert(resp.success);
assert(!resp.reportUrl.empty());
assert(resp.fileSize > 0);
std::cout << " PASS: URL=" << resp.reportUrl << std::endl;
}
/// 测试加密模块
static void testEncryption() {
std::cout << "[TEST] 人脸特征加密..." << std::endl;
std::vector<uint8_t> original = {0x10, 0x20, 0x30, 0x40, 0x50};
std::vector<uint8_t> encrypted = encryptFaceFeature(original);
assert(encrypted.size() == original.size());
// 加密后应该与原文不同
bool different = false;
for (size_t i = 0; i < original.size(); i++) {
if (encrypted[i] != original[i]) {
different = true;
break;
}
}
assert(different);
std::cout << " PASS: 加密后数据已变更" << std::endl;
}
/// 主测试入口
int main() {
std::cout << "========== 考勤系统单元测试 ==========" << std::endl;
testEnumToString();
testGenerateRecordId();
testProcessCheckin();
testCalculateAttendance();
testDetectAnomaly();
testGenerateReport();
testEncryption();
std::cout << "\n========== 所有测试通过! ==========" << std::endl;
return 0;
}