/** * @file basic_test.cpp * @brief 基础测试文件 - 使用标准库 assert,无外部依赖 */ #include "app.hpp" #include #include #include #include /// 测试枚举转换函数 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 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(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(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 original = {0x10, 0x20, 0x30, 0x40, 0x50}; std::vector 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; }