215 lines
8.0 KiB
C++
215 lines
8.0 KiB
C++
|
|
#include "../include/employee.hpp"
|
|||
|
|
#include "../include/schedule.hpp"
|
|||
|
|
#include "../include/checkin.hpp"
|
|||
|
|
#include "../include/attendance.hpp"
|
|||
|
|
#include "../include/alert.hpp"
|
|||
|
|
#include <cassert>
|
|||
|
|
#include <iostream>
|
|||
|
|
|
|||
|
|
using namespace AttendanceSystem;
|
|||
|
|
|
|||
|
|
void test_employee() {
|
|||
|
|
std::cout << "测试 Employee 类..." << std::endl;
|
|||
|
|
|
|||
|
|
// 测试默认构造函数
|
|||
|
|
Employee emp1;
|
|||
|
|
assert(!emp1.isValid()); // 默认构造的对象应该无效
|
|||
|
|
|
|||
|
|
// 测试带参构造函数
|
|||
|
|
Employee emp2("EMP001", "张三", "DEPT001", "软件工程师", "13800138001", "zhangsan@example.com");
|
|||
|
|
assert(emp2.isValid());
|
|||
|
|
assert(emp2.getId() == "EMP001");
|
|||
|
|
assert(emp2.getName() == "张三");
|
|||
|
|
assert(emp2.getDepartmentId() == "DEPT001");
|
|||
|
|
assert(emp2.getPosition() == "软件工程师");
|
|||
|
|
assert(emp2.getMobile() == "13800138001");
|
|||
|
|
assert(emp2.getEmail() == "zhangsan@example.com");
|
|||
|
|
|
|||
|
|
// 测试无效数据
|
|||
|
|
Employee emp3("", "李四", "DEPT001", "", "", "");
|
|||
|
|
assert(!emp3.isValid());
|
|||
|
|
|
|||
|
|
std::cout << "Employee 测试通过!" << std::endl;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void test_schedule_rule() {
|
|||
|
|
std::cout << "测试 ScheduleRule 类..." << std::endl;
|
|||
|
|
|
|||
|
|
// 测试白班规则
|
|||
|
|
ScheduleRule rule1("RULE001", "白班", 9, 0, 18, 0, 60, 30);
|
|||
|
|
assert(rule1.isValid());
|
|||
|
|
assert(rule1.getRuleId() == "RULE001");
|
|||
|
|
assert(rule1.getShiftName() == "白班");
|
|||
|
|
assert(rule1.getStartHour() == 9);
|
|||
|
|
assert(rule1.getStartMinute() == 0);
|
|||
|
|
assert(rule1.getEndHour() == 18);
|
|||
|
|
assert(rule1.getEndMinute() == 0);
|
|||
|
|
assert(rule1.getBreakDuration() == 60);
|
|||
|
|
assert(rule1.getOvertimeThreshold() == 30);
|
|||
|
|
|
|||
|
|
// 测试工作时间计算
|
|||
|
|
int workDuration = rule1.calculateWorkDuration();
|
|||
|
|
assert(workDuration == 8 * 60); // 9:00-18:00,减去60分钟休息,应该是8小时
|
|||
|
|
|
|||
|
|
// 测试加班判断
|
|||
|
|
assert(!rule1.isOvertime(17, 30)); // 17:30下班,不算加班
|
|||
|
|
assert(rule1.isOvertime(18, 45)); // 18:45下班,超过阈值30分钟,算加班
|
|||
|
|
|
|||
|
|
// 测试版本控制
|
|||
|
|
ScheduleRule rule2 = rule1.createNewVersion();
|
|||
|
|
assert(rule2.getVersion() == 2); // 新版本号应该是2
|
|||
|
|
|
|||
|
|
// 测试无效规则
|
|||
|
|
ScheduleRule rule3("", "", 25, 70, -1, 70, -10, -20); // 无效时间
|
|||
|
|
assert(!rule3.isValid());
|
|||
|
|
|
|||
|
|
std::cout << "ScheduleRule 测试通过!" << std::endl;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void test_checkin_record() {
|
|||
|
|
std::cout << "测试 CheckInRecord 类..." << std::endl;
|
|||
|
|
|
|||
|
|
// 创建时间戳
|
|||
|
|
std::time_t now = std::time(nullptr);
|
|||
|
|
std::tm* tm_now = std::localtime(&now);
|
|||
|
|
tm_now->tm_hour = 9;
|
|||
|
|
tm_now->tm_min = 15;
|
|||
|
|
tm_now->tm_sec = 0;
|
|||
|
|
std::time_t checkInTime = std::mktime(tm_now);
|
|||
|
|
|
|||
|
|
// 测试GPS打卡
|
|||
|
|
Location location(39.9042, 116.4074);
|
|||
|
|
CheckInRecord record1("REC001", "EMP001", CheckInMethod::GPS_LOCATION, checkInTime, location);
|
|||
|
|
assert(record1.isValid());
|
|||
|
|
assert(record1.getRecordId() == "REC001");
|
|||
|
|
assert(record1.getEmployeeId() == "EMP001");
|
|||
|
|
assert(record1.getMethod() == CheckInMethod::GPS_LOCATION);
|
|||
|
|
assert(record1.getTimestamp() == checkInTime);
|
|||
|
|
assert(record1.getLocation().latitude == 39.9042);
|
|||
|
|
assert(record1.getLocation().longitude == 116.4074);
|
|||
|
|
|
|||
|
|
// 测试人脸识别打卡
|
|||
|
|
CheckInRecord record2("REC002", "EMP002", CheckInMethod::FACE_RECOGNITION, checkInTime, Location());
|
|||
|
|
assert(record2.isValid());
|
|||
|
|
assert(record2.getMethodString() == "人脸识别");
|
|||
|
|
|
|||
|
|
// 测试是否迟到/早退
|
|||
|
|
assert(!record1.isLate(9, 0)); // 9:15打卡,期望9:00,不算迟到
|
|||
|
|
assert(!record1.isLate(8, 30)); // 9:15打卡,期望8:30,不算迟到
|
|||
|
|
|
|||
|
|
// 创建一个早一点的打卡记录
|
|||
|
|
tm_now->tm_hour = 8;
|
|||
|
|
tm_now->tm_min = 30;
|
|||
|
|
std::time_t earlyTime = std::mktime(tm_now);
|
|||
|
|
CheckInRecord record3("REC003", "EMP003", CheckInMethod::CARD_SWIPE, earlyTime, Location());
|
|||
|
|
assert(!record3.isEarlyLeave(17, 30)); // 8:30打卡,期望17:30下班,不算早退
|
|||
|
|
|
|||
|
|
std::cout << "CheckInRecord 测试通过!" << std::endl;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void test_attendance_result() {
|
|||
|
|
std::cout << "测试 AttendanceResult 类..." << std::endl;
|
|||
|
|
|
|||
|
|
// 创建时间戳
|
|||
|
|
std::time_t now = std::time(nullptr);
|
|||
|
|
|
|||
|
|
// 测试正常考勤
|
|||
|
|
AttendanceResult result1("RES001", "EMP001", now, AttendanceStatus::NORMAL, 480, "正常上班");
|
|||
|
|
assert(result1.isValid());
|
|||
|
|
assert(result1.getResultId() == "RES001");
|
|||
|
|
assert(result1.getEmployeeId() == "EMP001");
|
|||
|
|
assert(result1.getStatus() == AttendanceStatus::NORMAL);
|
|||
|
|
assert(result1.getDuration() == 480); // 8小时
|
|||
|
|
assert(result1.getRemarks() == "正常上班");
|
|||
|
|
assert(!result1.shouldDeductSalary()); // 正常不应该扣款
|
|||
|
|
assert(!result1.shouldPayOvertime()); // 正常不是加班
|
|||
|
|
|
|||
|
|
// 测试迟到考勤
|
|||
|
|
AttendanceResult result2("RES002", "EMP002", now, AttendanceStatus::LATE, 15, "迟到15分钟");
|
|||
|
|
assert(result2.getStatusString() == "迟到");
|
|||
|
|
assert(result2.shouldDeductSalary()); // 迟到应该扣款
|
|||
|
|
|
|||
|
|
// 测试加班考勤
|
|||
|
|
AttendanceResult result3("RES003", "EMP003", now, AttendanceStatus::OVERTIME, 60, "加班1小时");
|
|||
|
|
assert(result3.shouldPayOvertime()); // 加班应该支付加班费
|
|||
|
|
|
|||
|
|
// 测试无效数据
|
|||
|
|
AttendanceResult result4("", "", 0, AttendanceStatus::NORMAL, -10, "");
|
|||
|
|
assert(!result4.isValid());
|
|||
|
|
|
|||
|
|
std::cout << "AttendanceResult 测试通过!" << std::endl;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void test_alert_event() {
|
|||
|
|
std::cout << "测试 AlertEvent 类..." << std::endl;
|
|||
|
|
|
|||
|
|
std::time_t now = std::time(nullptr);
|
|||
|
|
|
|||
|
|
// 测试未打卡异常
|
|||
|
|
AlertEvent alert1("ALERT001", "EMP001", AlertType::NO_CHECK_IN, now, "员工今日未打卡");
|
|||
|
|
assert(alert1.isValid());
|
|||
|
|
assert(alert1.getEventId() == "ALERT001");
|
|||
|
|
assert(alert1.getEmployeeId() == "EMP001");
|
|||
|
|
assert(alert1.getAlertType() == AlertType::NO_CHECK_IN);
|
|||
|
|
assert(alert1.getReason() == "员工今日未打卡");
|
|||
|
|
assert(!alert1.isHandled());
|
|||
|
|
|
|||
|
|
// 测试通知渠道
|
|||
|
|
alert1.addNotificationChannel(NotificationChannel::IN_APP_MESSAGE);
|
|||
|
|
alert1.addNotificationChannel(NotificationChannel::SMS);
|
|||
|
|
assert(alert1.isNotifiedByChannel(NotificationChannel::IN_APP_MESSAGE));
|
|||
|
|
assert(alert1.isNotifiedByChannel(NotificationChannel::SMS));
|
|||
|
|
assert(!alert1.isNotifiedByChannel(NotificationChannel::EMAIL));
|
|||
|
|
|
|||
|
|
// 测试移除通知渠道
|
|||
|
|
alert1.removeNotificationChannel(NotificationChannel::SMS);
|
|||
|
|
assert(!alert1.isNotifiedByChannel(NotificationChannel::SMS));
|
|||
|
|
|
|||
|
|
// 测试异常处理
|
|||
|
|
alert1.handle("ADMIN001", "已电话联系确认");
|
|||
|
|
assert(alert1.isHandled());
|
|||
|
|
assert(alert1.getHandlerId() == "ADMIN001");
|
|||
|
|
assert(alert1.getHandleRemarks() == "已电话联系确认");
|
|||
|
|
|
|||
|
|
// 测试严重性判断
|
|||
|
|
AlertEvent alert2("ALERT002", "EMP002", AlertType::CONTINUOUS_ABSENCE, now, "连续缺勤3天");
|
|||
|
|
assert(alert2.isCritical()); // 连续缺勤是严重异常
|
|||
|
|
|
|||
|
|
AlertEvent alert3("ALERT003", "EMP003", AlertType::CHECK_IN_TIME_DEVIATION, now, "打卡时间偏离");
|
|||
|
|
assert(alert3.needsImmediateAttention()); // 需要立即处理
|
|||
|
|
|
|||
|
|
std::cout << "AlertEvent 测试通过!" << std::endl;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int main() {
|
|||
|
|
std::cout << "开始运行智能考勤管理系统测试..." << std::endl;
|
|||
|
|
std::cout << "========================================\n" << std::endl;
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
test_employee();
|
|||
|
|
std::cout << std::endl;
|
|||
|
|
|
|||
|
|
test_schedule_rule();
|
|||
|
|
std::cout << std::endl;
|
|||
|
|
|
|||
|
|
test_checkin_record();
|
|||
|
|
std::cout << std::endl;
|
|||
|
|
|
|||
|
|
test_attendance_result();
|
|||
|
|
std::cout << std::endl;
|
|||
|
|
|
|||
|
|
test_alert_event();
|
|||
|
|
std::cout << std::endl;
|
|||
|
|
|
|||
|
|
std::cout << "========================================\n" << std::endl;
|
|||
|
|
std::cout << "所有测试通过!" << std::endl;
|
|||
|
|
return 0;
|
|||
|
|
|
|||
|
|
} catch (const std::exception& e) {
|
|||
|
|
std::cerr << "测试异常:" << e.what() << std::endl;
|
|||
|
|
return 1;
|
|||
|
|
} catch (...) {
|
|||
|
|
std::cerr << "未知测试异常!" << std::endl;
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
}
|