task_auto_plan1/tests/basic_test.cpp

286 lines
8.3 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.

#include "app.hpp"
#include <cassert>
#include <iostream>
#include <cstring>
// ============================================================
// 单元测试(使用标准库 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;
}