This commit is contained in:
张成
2025-12-19 22:24:23 +08:00
parent abe2ae3c3a
commit 10aff2f266
12 changed files with 1101 additions and 147 deletions

View File

@@ -0,0 +1,249 @@
/**
* 账号工具函数测试
*/
const {
calculateRemainingDays,
isAuthorizationValid,
addRemainingDays,
addRemainingDaysToAccounts
} = require('../utils/account_utils');
// 测试剩余天数计算
function testCalculateRemainingDays() {
console.log('\n===== 测试剩余天数计算 =====');
try {
const dayjs = require('dayjs');
// 测试 1: 未来有效期
const futureDate = dayjs().subtract(5, 'day').toDate();
const remaining1 = calculateRemainingDays(futureDate, 30);
console.log('✓ 未来有效期 (5天前授权30天):', remaining1, '天');
console.assert(remaining1 === 25, `期望25天实际${remaining1}`);
// 测试 2: 已过期
const pastDate = dayjs().subtract(40, 'day').toDate();
const remaining2 = calculateRemainingDays(pastDate, 30);
console.log('✓ 已过期 (40天前授权30天):', remaining2, '天');
console.assert(remaining2 === 0, `期望0天实际${remaining2}`);
// 测试 3: 今天到期
const todayDate = dayjs().startOf('day').toDate();
const remaining3 = calculateRemainingDays(todayDate, 0);
console.log('✓ 今天到期:', remaining3, '天');
// 测试 4: 空值处理
const remaining4 = calculateRemainingDays(null, 30);
console.log('✓ 空授权日期:', remaining4, '天');
console.assert(remaining4 === 0, '空值应返回0');
const remaining5 = calculateRemainingDays(futureDate, 0);
console.log('✓ 0天授权:', remaining5, '天');
console.assert(remaining5 === 0, '0天授权应返回0');
return true;
} catch (error) {
console.error('✗ 剩余天数计算测试失败:', error.message);
return false;
}
}
// 测试授权有效性检查
function testIsAuthorizationValid() {
console.log('\n===== 测试授权有效性检查 =====');
try {
const dayjs = require('dayjs');
// 测试 1: 有效授权
const validDate = dayjs().subtract(5, 'day').toDate();
const isValid = isAuthorizationValid(validDate, 30);
console.log('✓ 有效授权 (5天前授权30天):', isValid ? '有效' : '无效');
console.assert(isValid === true, '应该是有效的');
// 测试 2: 过期授权
const expiredDate = dayjs().subtract(40, 'day').toDate();
const isExpired = isAuthorizationValid(expiredDate, 30);
console.log('✓ 过期授权 (40天前授权30天):', isExpired ? '有效' : '无效');
console.assert(isExpired === false, '应该是无效的');
// 测试 3: 空值处理
const isNull = isAuthorizationValid(null, 30);
console.log('✓ 空授权日期:', isNull ? '有效' : '无效');
console.assert(isNull === false, '空值应该无效');
return true;
} catch (error) {
console.error('✗ 授权有效性检查测试失败:', error.message);
return false;
}
}
// 测试添加剩余天数
function testAddRemainingDays() {
console.log('\n===== 测试添加剩余天数 =====');
try {
const dayjs = require('dayjs');
// 测试 1: 普通对象
const account1 = {
id: 1,
sn_code: 'SN001',
authorization_date: dayjs().subtract(5, 'day').toDate(),
authorization_days: 30
};
const result1 = addRemainingDays(account1);
console.log('✓ 普通对象添加剩余天数:', result1.remaining_days, '天');
console.assert(result1.remaining_days === 25, `期望25天实际${result1.remaining_days}`);
// 测试 2: Sequelize实例模拟
const account2 = {
id: 2,
sn_code: 'SN002',
authorization_date: dayjs().subtract(10, 'day').toDate(),
authorization_days: 15,
toJSON: function() {
return {
id: this.id,
sn_code: this.sn_code,
authorization_date: this.authorization_date,
authorization_days: this.authorization_days
};
}
};
const result2 = addRemainingDays(account2);
console.log('✓ Sequelize实例添加剩余天数:', result2.remaining_days, '天');
console.assert(result2.remaining_days === 5, `期望5天实际${result2.remaining_days}`);
return true;
} catch (error) {
console.error('✗ 添加剩余天数测试失败:', error.message);
return false;
}
}
// 测试批量添加剩余天数
function testAddRemainingDaysToAccounts() {
console.log('\n===== 测试批量添加剩余天数 =====');
try {
const dayjs = require('dayjs');
const accounts = [
{
id: 1,
authorization_date: dayjs().subtract(5, 'day').toDate(),
authorization_days: 30
},
{
id: 2,
authorization_date: dayjs().subtract(10, 'day').toDate(),
authorization_days: 15
},
{
id: 3,
authorization_date: dayjs().subtract(50, 'day').toDate(),
authorization_days: 30
}
];
const results = addRemainingDaysToAccounts(accounts);
console.log('✓ 批量添加剩余天数:');
results.forEach((acc, index) => {
console.log(` 账号${index + 1}: ${acc.remaining_days}`);
});
console.assert(results.length === 3, '数组长度应该是3');
console.assert(results[0].remaining_days === 25, '第1个账号剩余天数错误');
console.assert(results[1].remaining_days === 5, '第2个账号剩余天数错误');
console.assert(results[2].remaining_days === 0, '第3个账号剩余天数错误');
// 测试空数组
const emptyResults = addRemainingDaysToAccounts([]);
console.log('✓ 空数组处理:', emptyResults.length === 0 ? '正确' : '错误');
return true;
} catch (error) {
console.error('✗ 批量添加剩余天数测试失败:', error.message);
return false;
}
}
// 测试时区处理
function testTimezoneHandling() {
console.log('\n===== 测试时区处理 =====');
try {
const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');
dayjs.extend(utc);
// 创建不同时区的日期
const localDate = dayjs().subtract(5, 'day').toDate();
const utcDate = dayjs().utc().subtract(5, 'day').toDate();
const remaining1 = calculateRemainingDays(localDate, 30);
const remaining2 = calculateRemainingDays(utcDate, 30);
console.log('✓ 本地时区日期剩余天数:', remaining1, '天');
console.log('✓ UTC时区日期剩余天数:', remaining2, '天');
// 剩余天数应该接近可能相差1天因为时区转换
const diff = Math.abs(remaining1 - remaining2);
console.log('✓ 时区差异:', diff, '天');
console.assert(diff <= 1, '时区差异应该不超过1天');
return true;
} catch (error) {
console.error('✗ 时区处理测试失败:', error.message);
return false;
}
}
// 运行所有测试
async function runAllTests() {
console.log('\n==================== 开始测试 ====================\n');
const results = [];
results.push(testCalculateRemainingDays());
results.push(testIsAuthorizationValid());
results.push(testAddRemainingDays());
results.push(testAddRemainingDaysToAccounts());
results.push(testTimezoneHandling());
console.log('\n==================== 测试总结 ====================\n');
const passed = results.filter(r => r).length;
const total = results.length;
console.log(`测试通过: ${passed}/${total}`);
if (passed === total) {
console.log('\n✓ 所有测试通过!\n');
process.exit(0);
} else {
console.log('\n✗ 部分测试失败\n');
process.exit(1);
}
}
// 执行测试
if (require.main === module) {
runAllTests().catch(error => {
console.error('测试执行失败:', error);
process.exit(1);
});
}
module.exports = {
testCalculateRemainingDays,
testIsAuthorizationValid,
testAddRemainingDays,
testAddRemainingDaysToAccounts,
testTimezoneHandling
};

View File

@@ -0,0 +1,207 @@
/**
* 加密工具函数测试
*/
const {
hashPassword,
verifyPassword,
generateToken,
generateDeviceId,
validateDeviceId,
maskPhone,
maskEmail,
maskSensitiveData
} = require('../utils/crypto_utils');
// 测试密码加密和验证
async function testPasswordEncryption() {
console.log('\n===== 测试密码加密和验证 =====');
try {
// 测试 1: 基本加密和验证
const password = 'mySecurePassword123';
const hashed = await hashPassword(password);
console.log('✓ 密码加密成功:', hashed.substring(0, 20) + '...');
// 验证正确密码
const isValid = await verifyPassword(password, hashed);
console.log('✓ 正确密码验证:', isValid ? '通过' : '失败');
// 验证错误密码
const isInvalid = await verifyPassword('wrongPassword', hashed);
console.log('✓ 错误密码验证:', isInvalid ? '失败(不应该通过)' : '正确拒绝');
// 测试 2: 相同密码生成不同哈希
const hashed2 = await hashPassword(password);
console.log('✓ 相同密码生成不同哈希:', hashed !== hashed2 ? '是' : '否');
// 测试 3: 空密码处理
try {
await hashPassword('');
console.log('✗ 空密码应该抛出错误');
} catch (error) {
console.log('✓ 空密码正确抛出错误');
}
return true;
} catch (error) {
console.error('✗ 密码加密测试失败:', error.message);
return false;
}
}
// 测试设备ID生成和验证
function testDeviceId() {
console.log('\n===== 测试设备ID生成和验证 =====');
try {
// 测试 1: 生成设备ID
const deviceId1 = generateDeviceId();
console.log('✓ 生成设备ID:', deviceId1);
// 测试 2: 验证有效设备ID
const isValid = validateDeviceId(deviceId1);
console.log('✓ 验证有效设备ID:', isValid ? '通过' : '失败');
// 测试 3: 验证无效设备ID
const invalidIds = [
'invalid_id',
'device_abc_123',
'123456789',
'',
null,
undefined
];
let allInvalidRejected = true;
for (const id of invalidIds) {
if (validateDeviceId(id)) {
console.log('✗ 无效ID未被拒绝:', id);
allInvalidRejected = false;
}
}
if (allInvalidRejected) {
console.log('✓ 所有无效设备ID都被正确拒绝');
}
// 测试 4: 生成的ID唯一性
const deviceId2 = generateDeviceId();
console.log('✓ 生成的ID是唯一的:', deviceId1 !== deviceId2 ? '是' : '否');
return true;
} catch (error) {
console.error('✗ 设备ID测试失败:', error.message);
return false;
}
}
// 测试数据脱敏
function testDataMasking() {
console.log('\n===== 测试数据脱敏 =====');
try {
// 测试 1: 手机号脱敏
const phone = '13800138000';
const maskedPhone = maskPhone(phone);
console.log('✓ 手机号脱敏:', phone, '->', maskedPhone);
console.assert(maskedPhone === '138****8000', '手机号脱敏格式错误');
// 测试 2: 邮箱脱敏
const email = 'user@example.com';
const maskedEmail = maskEmail(email);
console.log('✓ 邮箱脱敏:', email, '->', maskedEmail);
// 测试 3: 对象脱敏
const sensitiveObj = {
username: 'john',
password: 'secret123',
email: 'john@example.com',
token: 'abc123xyz',
normalField: 'public data'
};
const masked = maskSensitiveData(sensitiveObj);
console.log('✓ 对象脱敏:');
console.log(' 原始:', sensitiveObj);
console.log(' 脱敏:', masked);
// 验证敏感字段被屏蔽
console.assert(masked.password === '***MASKED***', 'password未被屏蔽');
console.assert(masked.token === '***MASKED***', 'token未被屏蔽');
console.assert(masked.normalField === 'public data', '普通字段被修改');
return true;
} catch (error) {
console.error('✗ 数据脱敏测试失败:', error.message);
return false;
}
}
// 测试Token生成
function testTokenGeneration() {
console.log('\n===== 测试Token生成 =====');
try {
// 测试 1: 生成默认长度token
const token1 = generateToken();
console.log('✓ 生成默认token (64字符):', token1.substring(0, 20) + '...');
console.assert(token1.length === 64, 'Token长度错误');
// 测试 2: 生成指定长度token
const token2 = generateToken(16);
console.log('✓ 生成16字节token (32字符):', token2);
console.assert(token2.length === 32, 'Token长度错误');
// 测试 3: Token唯一性
const token3 = generateToken();
console.log('✓ Token唯一性:', token1 !== token3 ? '是' : '否');
return true;
} catch (error) {
console.error('✗ Token生成测试失败:', error.message);
return false;
}
}
// 运行所有测试
async function runAllTests() {
console.log('\n==================== 开始测试 ====================\n');
const results = [];
results.push(await testPasswordEncryption());
results.push(testDeviceId());
results.push(testDataMasking());
results.push(testTokenGeneration());
console.log('\n==================== 测试总结 ====================\n');
const passed = results.filter(r => r).length;
const total = results.length;
console.log(`测试通过: ${passed}/${total}`);
if (passed === total) {
console.log('\n✓ 所有测试通过!\n');
process.exit(0);
} else {
console.log('\n✗ 部分测试失败\n');
process.exit(1);
}
}
// 执行测试
if (require.main === module) {
runAllTests().catch(error => {
console.error('测试执行失败:', error);
process.exit(1);
});
}
module.exports = {
testPasswordEncryption,
testDeviceId,
testDataMasking,
testTokenGeneration
};