Files
ClawdDotNet/tests/ClawdDotNet.Core.Tests/Tasks/TaskboardExtensionTests.cs
T
RichardandClaude Opus 5.5 77062facc9 Stufe 4c (#764): Bezeichner auf Englisch - Typen, Methoden, Felder, Parameter, Locals, Testnamen
Mit Roslyn umbenannt (Verweise folgen, Zeichenketten bleiben unberuehrt).
Nicht umbenannt, weil gespeichert oder ueber die API gebunden (Stufe 4e):
Properties, Record-Parameter, Enum-Member sowie die Parameter der
Endpunkt-Handler (Routen-/Query-Bindung ueber den Namen). Die JSON-Felder
anonymer Objekte bleiben ausdruecklich benannt (JsonFilter: pfad).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 13:18:43 +02:00

110 lines
4.1 KiB
C#

using ClawdDotNet.Core.Tasks;
using Shouldly;
namespace ClawdDotNet.Core.Tests.Tasks;
/// <summary>
/// Checking schedules, next run and runs per day (#594, #595, #597) as well as the hint
/// about growing context (#598).
/// </summary>
public sealed class TaskboardExtensionTests
{
private static DateTime Utc(int y, int mo, int d, int h, int mi) => new(y, mo, d, h, mi, 0, DateTimeKind.Utc);
private static TaskWhen Cron(string value, string tz = "Europe/Berlin")
=> new() { Kind = TaskWhenKind.Cron, Value = value, TimeZone = tz };
// ─── #597 checking schedules ───
[Fact]
public void Valid_schedule_with_range_and_step_passes_the_check()
=> TaskSchedule.ValidateWhen(Cron("0 7-22/3 * * *")).ShouldBeNull();
[Fact]
public void Broken_cron_expression_is_named()
=> TaskSchedule.ValidateWhen(Cron("0 7-22/x * * *")).ShouldNotBeNull().ShouldContain("'x' ist keine Zahl");
[Fact]
public void Unknown_time_zone_is_named()
=> TaskSchedule.ValidateWhen(Cron("0 9 * * *", "Phantasie/Ort")).ShouldNotBeNull().ShouldContain("Phantasie/Ort");
[Theory]
[InlineData(TaskWhenKind.Every, "30m", true)]
[InlineData(TaskWhenKind.Every, "halbstündlich", false)]
[InlineData(TaskWhenKind.At, "2026-09-15T08:00", true)]
[InlineData(TaskWhenKind.At, "morgen früh", false)]
public void Interval_and_time_are_checked(TaskWhenKind kind, string value, bool valid)
=> (TaskSchedule.ValidateWhen(new TaskWhen { Kind = kind, Value = value, TimeZone = "Europe/Berlin" }) is null)
.ShouldBe(valid);
// ─── #594 next run ───
[Fact]
public void Next_run_of_a_cron_schedule_in_Berlin_time()
{
var task = new TaskItem { Id = "t-7e0bbe", When = Cron("0 7-22/3 * * *") };
// 12:30 Berlin (CEST) -> next occurrence 13:00 Berlin = 11:00 UTC
TaskSchedule.NextOccurrenceUtc(task, Utc(2026, 9, 14, 10, 30)).ShouldBe(Utc(2026, 9, 14, 11, 0));
}
[Fact]
public void Next_run_of_an_interval_counts_from_the_last_run()
{
var task = new TaskItem
{
Id = "t-1",
When = new TaskWhen { Kind = TaskWhenKind.Every, Value = "2h", TimeZone = "" },
LastOccurrence = "2026-09-14T09:00:00.0000000Z"
};
TaskSchedule.NextOccurrenceUtc(task, Utc(2026, 9, 14, 10, 0)).ShouldBe(Utc(2026, 9, 14, 11, 0));
}
[Fact]
public void One_off_task_is_pending_until_it_ran()
{
var now = Utc(2026, 9, 14, 10, 0);
TaskSchedule.NextOccurrenceUtc(new TaskItem { Id = "t-1" }, now).ShouldBe(now);
TaskSchedule.NextOccurrenceUtc(new TaskItem { Id = "t-1", LastOccurrence = "x" }, now).ShouldBeNull();
}
// ─── #595 runs per day ───
[Fact]
public void Runs_per_day_from_cron_and_interval()
{
var now = Utc(2026, 9, 14, 10, 0);
TaskSchedule.RunsPerDay(new TaskItem { When = Cron("0 7-22/3 * * *") }, now).ShouldBe(6);
TaskSchedule.RunsPerDay(new TaskItem { When = Cron("5 * * * *") }, now).ShouldBe(24);
TaskSchedule.RunsPerDay(new TaskItem { When = new TaskWhen { Kind = TaskWhenKind.Every, Value = "30m" } }, now).ShouldBe(48);
TaskSchedule.RunsPerDay(new TaskItem(), now).ShouldBe(0);
}
// ─── #598 hint ───
[Fact]
public void Recurring_in_chat_history_gets_the_hint()
=> TaskHints.GrowingContext(new TaskItem { Assignee = "@nachrichten", When = Cron("0 7-22/3 * * *") })
.ShouldNotBeNull().ShouldContain("@new:nachrichten");
[Theory]
[InlineData("@new:nachrichten", true)]
[InlineData("@nachrichten", false)]
[InlineData("@human", true)]
public void No_hint_for_fresh_runs_one_off_and_human_tasks(string assignee, bool recurring)
=> TaskHints.GrowingContext(new TaskItem
{
Assignee = assignee,
When = recurring ? Cron("5 * * * *") : null
}).ShouldBeNull();
[Fact]
public void No_hint_for_tool_jobs()
=> TaskHints.GrowingContext(new TaskItem
{
Assignee = "@telegram", Type = TaskItemType.ToolJob, When = Cron("* * * * *")
}).ShouldBeNull();
}