#include "app.hpp" #include #include #include // ============================================================ // 单元测试(使用标准库 assert,无外部依赖) // ============================================================ static void testEmployeeManagement() { AttendanceService svc; // 添加员工 Employee e; e.employeeId = "T001"; e.name = "测试员工"; e.department = "测试部"; e.position = "测试工程师"; e.shiftId = "S001"; e.phone = "13900001111"; e.role = RoleType::Employee; svc.addEmployee(e); // 查找 const Employee* found = svc.findEmployee("T001"); assert(found != nullptr); assert(found->name == "测试员工"); assert(found->department == "测试部"); // 脱敏手机号 std::string masked = found->maskedPhone(); assert(masked == "*******1111"); std::cout << "[PASS] testEmployeeManagement: 员工管理正常" << std::endl; } static void testDuplicateEmployee() { AttendanceService svc; Employee e; e.employeeId = "T002"; e.name = "重复测试"; svc.addEmployee(e); bool thrown = false; try { svc.addEmployee(e); } catch (const std::runtime_error&) { thrown = true; } assert(thrown); std::cout << "[PASS] testDuplicateEmployee: 重复添加异常正常" << std::endl; } static void testCheckInAndRecords() { AttendanceService svc; Employee e; e.employeeId = "T003"; e.name = "打卡测试"; e.department = "测试部"; e.shiftId = "S001"; svc.addEmployee(e); // 上班打卡 std::time_t now = std::time(nullptr); auto rec1 = svc.processCheckIn("T003", CheckType::ClockIn, "DEVICE_TEST", now); assert(rec1.employeeId == "T003"); assert(rec1.type == CheckType::ClockIn); assert(rec1.verified == true); assert(!rec1.recordId.empty()); // 下班打卡 auto rec2 = svc.processCheckIn("T003", CheckType::ClockOut, "DEVICE_TEST", now + 28800); // 8h后 assert(rec2.type == CheckType::ClockOut); // 查询记录 auto records = svc.getRecords("T003"); assert(records.size() == 2); assert(records[0].type == CheckType::ClockIn); assert(records[1].type == CheckType::ClockOut); // 未知员工打卡应抛异常 bool thrown = false; try { svc.processCheckIn("UNKNOWN", CheckType::ClockIn, "DEVICE", now); } catch (const std::runtime_error&) { thrown = true; } assert(thrown); std::cout << "[PASS] testCheckInAndRecords: 打卡流程正常" << std::endl; } static void testDailyCalculation() { AttendanceService svc; Employee e; e.employeeId = "T004"; e.name = "核算测试"; e.department = "测试部"; e.shiftId = "S001"; svc.addEmployee(e); // 模拟当日打卡:8:30 上班,18:00 下班 std::time_t now = std::time(nullptr); std::tm* tm = std::localtime(&now); std::tm tm_in = *tm; tm_in.tm_hour = 8; tm_in.tm_min = 30; tm_in.tm_sec = 0; std::time_t tIn = std::mktime(&tm_in); std::tm tm_out = *tm; tm_out.tm_hour = 18; tm_out.tm_min = 0; tm_out.tm_sec = 0; std::time_t tOut = std::mktime(&tm_out); svc.processCheckIn("T004", CheckType::ClockIn, "DEVICE", tIn); svc.processCheckIn("T004", CheckType::ClockOut, "DEVICE", tOut); // 获取核算结果 std::ostringstream oss; oss << std::put_time(tm, "%Y-%m-%d"); std::string today = oss.str(); auto da = svc.calculateDaily("T004", today); assert(!da.dateStr.empty()); assert(da.employeeId == "T004"); assert(da.expectedMinutes > 0); assert(da.actualMinutes > 0); // 实际工时应约为 8.5h - 1h(午休) = 7.5h = 450min,有弹性 // 但至少大于0 assert(da.actualMinutes > 100); std::cout << "[PASS] testDailyCalculation: 核算正常, 出勤 " << da.actualMinutes << " 分钟" << std::endl; } static void testAbnormalDetection() { AttendanceService svc; Employee e; e.employeeId = "T005"; e.name = "异常测试"; e.department = "测试部"; e.shiftId = "S001"; svc.addEmployee(e); // 没有打卡记录 -> 旷工 std::time_t now = std::time(nullptr); std::tm* tm = std::localtime(&now); std::ostringstream oss; oss << std::put_time(tm, "%Y-%m-%d"); std::string today = oss.str(); auto da = svc.calculateDaily("T005", today); assert(da.abnormal == AbnormalFlag::Absenteeism); std::cout << "[PASS] testAbnormalDetection: 无打卡=旷工判定正常" << std::endl; } static void testReportGeneration() { AttendanceService svc; // 添加员工 Employee e1; e1.employeeId = "T006"; e1.name = "报表A"; e1.department = "报表部"; svc.addEmployee(e1); Employee e2; e2.employeeId = "T007"; e2.name = "报表B"; e2.department = "报表部"; svc.addEmployee(e2); // 添加打卡 std::time_t now = std::time(nullptr); std::tm* tm = std::localtime(&now); std::tm tm_in = *tm; tm_in.tm_hour = 9; tm_in.tm_min = 0; std::time_t tIn = std::mktime(&tm_in); std::tm tm_out = *tm; tm_out.tm_hour = 18; tm_out.tm_min = 0; std::time_t tOut = std::mktime(&tm_out); svc.processCheckIn("T006", CheckType::ClockIn, "DEVICE", tIn); svc.processCheckIn("T006", CheckType::ClockOut, "DEVICE", tOut); svc.processCheckIn("T007", CheckType::ClockIn, "DEVICE", tIn); svc.processCheckIn("T007", CheckType::ClockOut, "DEVICE", tOut); // 生成报表 std::ostringstream oss; oss << std::put_time(tm, "%Y-%m-%d"); std::string today = oss.str(); auto report = svc.generateReport("报表部", today, today); assert(!report.empty()); assert(report.size() == 2); std::cout << "[PASS] testReportGeneration: 报表生成正常, 共 " << report.size() << " 条记录" << std::endl; } static void testAlertCreation() { AttendanceService svc; // 创建预警 auto alert = svc.createAlert("T999", AbnormalFlag::Late); assert(!alert.alertId.empty()); assert(alert.employeeId == "T999"); assert(alert.type == AbnormalFlag::Late); assert(alert.status == AlertStatus::Pending); // 查询 auto alerts = svc.getAlerts("T999"); assert(alerts.size() == 1); assert(alerts[0].type == AbnormalFlag::Late); std::cout << "[PASS] testAlertCreation: 预警创建与查询正常" << std::endl; } static void testReportTask() { AttendanceService svc; auto task = svc.createReportTask("ADMIN", "部门X", "2025-01-01", "2025-01-31", ReportFormat::PDF); assert(task.taskId.length() > 0); assert(task.status == "Pending"); assert(task.format == ReportFormat::PDF); svc.completeTask(task.taskId, "/download/test.pdf"); assert(task.status == "Done"); assert(task.downloadUrl == "/download/test.pdf"); std::cout << "[PASS] testReportTask: 报表任务流程正常" << std::endl; } static void testMaskSensitive() { assert(maskSensitive("12345678901", 3, 4) == "123****8901"); assert(maskSensitive("abc", 1, 1) == "abc"); // 太短时不脱敏 assert(maskSensitive("", 0, 0).empty()); std::cout << "[PASS] testMaskSensitive: 脱敏函数正常" << std::endl; } static void testShiftRule() { ShiftRule rule; rule.shiftId = "S999"; rule.startHour = 8; rule.startMin = 30; rule.endHour = 17; rule.endMin = 30; assert(rule.workStartMinutes() == 8 * 60 + 30); // 510 assert(rule.workEndMinutes() == 17 * 60 + 30); // 1050 std::cout << "[PASS] testShiftRule: 排班规则计算正常" << std::endl; } // ============================================================ // 主测试入口 // ============================================================ int main() { std::cout << "============================================" << std::endl; std::cout << " 智能考勤管理系统 - 单元测试" << std::endl; std::cout << "============================================" << std::endl; testEmployeeManagement(); testDuplicateEmployee(); testCheckInAndRecords(); testDailyCalculation(); testAbnormalDetection(); testReportGeneration(); testAlertCreation(); testReportTask(); testMaskSensitive(); testShiftRule(); std::cout << "============================================" << std::endl; std::cout << "所有测试通过!" << std::endl; std::cout << "============================================" << std::endl; return 0; }