Falcon.SugarApi/Falcon.SugarApi.Test/CronExpressionTests.cs
2025-02-24 16:55:32 +08:00

223 lines
9.7 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.

using Falcon.SugarApi.TimedBackgroundTask;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace Falcon.SugarApi.Test
{
[TestClass()]
public class CronExpressionTests
{
[TestMethod]
public void CronExpressionTest() {
var now20250213102512 = new DateTime(2025,2,13,10,25,12);
var cron = new CronExpression("0 30 3 * * 1-5"); // 工作日凌晨3:30:00
var nextTime = cron.GetNextOccurrence(now20250213102512);
Assert.IsTrue(DateToString(nextTime) == "20250214033000");
cron = new CronExpression("");//下一秒触发
nextTime = cron.GetNextOccurrence(now20250213102512);
Assert.IsTrue(DateToString(nextTime) == "20250213102513");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250213102514",nextTime.ToString());
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250213102515",nextTime.ToString());
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250213102516",nextTime.ToString());
cron = new CronExpression("10");//每分钟10秒时触发
nextTime = cron.GetNextOccurrence(now20250213102512);
Assert.IsTrue(DateToString(nextTime) == "20250213102610");
cron = new CronExpression("10 25");//每个小时的25分10秒触发
nextTime = cron.GetNextOccurrence(now20250213102512);
Assert.IsTrue(DateToString(nextTime) == "20250213112510");
cron = new CronExpression("10 25");//每个小时的25分10秒触发
nextTime = cron.GetNextOccurrence(now20250213102512);
Assert.IsTrue(DateToString(nextTime) == "20250213112510");
cron = new CronExpression("10/10 25");//每个小时的25分10秒触发,只有每10秒触发一次
nextTime = cron.GetNextOccurrence(now20250213102512);
Assert.IsTrue(DateToString(nextTime) == "20250213102520");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250213102530");
cron = new CronExpression("0 0 3-5");//每天凌晨3点到5点每小时触发一次
nextTime = cron.GetNextOccurrence(now20250213102512);
Assert.IsTrue(DateToString(nextTime) == "20250214030000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250214040000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250214050000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250215030000");
cron = new CronExpression("0 0 3-5 * * 1-5");//每个工作日凌晨3点到5点每小时触发一次
nextTime = cron.GetNextOccurrence(now20250213102512);
Assert.IsTrue(DateToString(nextTime) == "20250214030000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250214040000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250214050000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250217030000",DateToString(nextTime));
cron = new CronExpression("0 0/30 3-5 * * 1-5");//每个工作日凌晨3点到5点每小时触发两次平均每半小时一次
nextTime = cron.GetNextOccurrence(now20250213102512);
Assert.IsTrue(DateToString(nextTime) == "20250214030000",nextTime.ToString());
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250214033000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250214040000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250214043000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250214050000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250214053000");
nextTime = cron.GetNextOccurrence(nextTime);
Assert.IsTrue(DateToString(nextTime) == "20250217030000");
}
private string? DateToString(DateTime? date) => date?.ToString("yyyyMMddHHmmss");
//-----------------------------
// 基础语法解析测试
//-----------------------------
[TestMethod]
public void TestBasicWildcard() {
var cron = new CronExpression("* * * * * * *");
Assert.AreEqual(60,cron.Seconds.Count,"秒字段应包含0-59");
Assert.AreEqual(12,cron.Months.Count,"月字段应包含1-12");
}
[TestMethod]
public void TestFixedValue() {
var cron = new CronExpression("5 10 3 15 6 2 2026");
Assert.IsTrue(cron.Seconds.Contains(5));
Assert.IsTrue(cron.Minutes.Contains(10));
Assert.IsTrue(cron.Hours.Contains(3));
Assert.IsTrue(cron.DaysOfMonth.Contains(15));
Assert.IsTrue(cron.Months.Contains(6));
Assert.IsTrue(cron.DaysOfWeek.Contains(2));
Assert.IsTrue(cron.Years.Contains(2026));
}
//-----------------------------
// 复杂语法测试
//-----------------------------
[TestMethod]
public void TestRangeAndStep() {
//var cron = new CronExpression("0-30/15 10,20,30 * 1-5 */3 * *");
//CollectionAssert.AreEqual(new[] { 0,15,30 },cron.Seconds);
//CollectionAssert.AreEqual(new[] { 10,20,30 },cron.Minutes);
//CollectionAssert.AreEqual(new[] { 1,2,3,4,5 },cron.DaysOfMonth);
//CollectionAssert.AreEqual(new[] { 1,4,7,10 },cron.Months);
}
//-----------------------------
// 字段省略测试
//-----------------------------
[TestMethod]
public void TestPartialExpression() {
var cron = new CronExpression("30 15 4");
Assert.AreEqual(1,cron.Seconds.Count);
Assert.AreEqual(1,cron.Minutes.Count);
Assert.AreEqual(1,cron.Hours.Count);
Assert.AreEqual(31,cron.DaysOfMonth.Count); // 默认1-31
Assert.AreEqual(12,cron.Months.Count); // 默认1-12
}
//-----------------------------
// 边界值测试
//-----------------------------
[TestMethod]
public void TestBoundaryValues() {
// 最大最小值测试
var cron = new CronExpression("59 59 23 31 12 6 2026");
Assert.IsTrue(cron.Seconds.Contains(59));
Assert.IsTrue(cron.DaysOfMonth.Contains(31));
Assert.IsTrue(cron.Months.Contains(12));
}
//-----------------------------
// 错误处理测试
//-----------------------------
[TestMethod]
public void TestInvalidCharacter() {
try {
var _ = new CronExpression("5a * * * * *");
}
catch(CronAdjustNullException) { }
catch(CronException) { }
}
[TestMethod]
public void TestOutOfRangeValue() {
try {
var _ = new CronExpression("70 * * * * *");
}
catch(CronAdjustNullException) { }
catch(CronException) { }
}
//-----------------------------
// 下次执行时间计算测试
//-----------------------------
[TestMethod]
public void TestNextOccurrence_Basic() {
var baseTime = new DateTime(2025,10,1,12,30,15);
var cron = new CronExpression("30 * * * * * *");
// 下一个30秒
var expected = new DateTime(2025,10,1,12,30,30);
var actual = cron.GetNextOccurrence(baseTime);
Assert.AreEqual(expected,actual);
}
[TestMethod]
public void TestNextOccurrence_MonthRollover() {
var baseTime = new DateTime(2024,12,31,23,59,59);
var cron = new CronExpression("* * * 1 * * *"); // 每月1号
var expected = new DateTime(2025,1,1,0,0,0);
var actual = cron.GetNextOccurrence(baseTime);
Assert.AreEqual(expected,actual);
}
//-----------------------------
// 特殊日期处理测试
//-----------------------------
[TestMethod]
public void TestFebruaryHandling() {
// 测试闰年2月29日
var cron = new CronExpression("0 0 0 29 2 * 2028");
Assert.IsTrue(cron.DaysOfMonth.Contains(29));
var nextTime = cron.GetNextOccurrence(new DateTime(2028,2,28));
Assert.AreEqual(new DateTime(2028,2,29),nextTime.Date);
}
//-----------------------------
// 日期与星期冲突测试
//-----------------------------
[TestMethod]
public void TestDayOfWeekConflict() {
// 每月15号且为星期一2023-10-15是星期日
var cron = new CronExpression("* * * 15 * 1 *");
var baseTime = new DateTime(2023,10,1);
var nextTime = cron.GetNextOccurrence(baseTime);
Assert.AreEqual(2025,nextTime.Year,nextTime.ToString());
Assert.AreEqual(9,nextTime.Month,nextTime.ToString());
Assert.AreEqual(15,nextTime.Day,nextTime.ToString());
Assert.AreEqual(DayOfWeek.Monday,nextTime.DayOfWeek);
}
}
}