Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ namespace Orbit.Application.Tests.Commands.Calendar;

public class SetSelectedCalendarsCommandHandlerTests
{
private static readonly string[] SingleCalendarSelection = new[] { "cal_a" };
private static readonly string[] TwoCalendarSelection = new[] { "cal_a", "cal_b" };
private static readonly string[] SelectionWithEmptyId = new[] { "cal_a", "" };

private readonly IGenericRepository<User> _userRepo = Substitute.For<IGenericRepository<User>>();
private readonly IUnitOfWork _unitOfWork = Substitute.For<IUnitOfWork>();
private readonly SetSelectedCalendarsCommandHandler _handler;
Expand All @@ -34,7 +38,7 @@ public async Task Handle_UserNotFound_ReturnsFailure()
StubUser(null);

var result = await _handler.Handle(
new SetSelectedCalendarsCommand(Guid.NewGuid(), new[] { "cal_a" }), CancellationToken.None);
new SetSelectedCalendarsCommand(Guid.NewGuid(), SingleCalendarSelection), CancellationToken.None);

result.IsFailure.Should().BeTrue();
await _unitOfWork.DidNotReceive().SaveChangesAsync(Arg.Any<CancellationToken>());
Expand All @@ -47,18 +51,18 @@ public async Task Handle_SetsSelectionAndPersists()
StubUser(user);

var result = await _handler.Handle(
new SetSelectedCalendarsCommand(user.Id, new[] { "cal_a", "cal_b" }), CancellationToken.None);
new SetSelectedCalendarsCommand(user.Id, TwoCalendarSelection), CancellationToken.None);

result.IsSuccess.Should().BeTrue();
user.GetSelectedCalendarIds().Should().BeEquivalentTo(new[] { "cal_a", "cal_b" });
user.GetSelectedCalendarIds().Should().BeEquivalentTo(TwoCalendarSelection);
await _unitOfWork.Received(1).SaveChangesAsync(Arg.Any<CancellationToken>());
}

[Fact]
public async Task Handle_EmptyList_ClearsSelectionToDefault()
{
var user = CreateUser();
user.SetSelectedCalendars(new[] { "cal_a" });
user.SetSelectedCalendars(SingleCalendarSelection);
StubUser(user);

var result = await _handler.Handle(
Expand All @@ -75,7 +79,7 @@ public void Validator_RejectsEmptyId()
var validator = new SetSelectedCalendarsCommandValidator();

var result = validator.Validate(
new SetSelectedCalendarsCommand(Guid.NewGuid(), new[] { "cal_a", "" }));
new SetSelectedCalendarsCommand(Guid.NewGuid(), SelectionWithEmptyId));

result.IsValid.Should().BeFalse();
}
Expand All @@ -98,7 +102,7 @@ public void Validator_AcceptsValidSelection()
var validator = new SetSelectedCalendarsCommandValidator();

var result = validator.Validate(
new SetSelectedCalendarsCommand(Guid.NewGuid(), new[] { "cal_a", "cal_b" }));
new SetSelectedCalendarsCommand(Guid.NewGuid(), TwoCalendarSelection));

result.IsValid.Should().BeTrue();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ public class ProcessUserChatCommandHandlerTests

private static readonly Guid UserId = Guid.NewGuid();
private static readonly DateOnly Today = new(2026, 4, 3);
private static readonly string[] ExpectedOrderedToolNames = new[] { "assign_tags", "create_habit", "delete_habit" };
private static readonly string[] GamificationTodaySurfaces = new[] { "gamification", "today" };
private static readonly string[] HabitsSurfaces = new[] { "habits" };

private static Habit CreateHabit(string title, bool isCompleted = false)
{
Expand Down Expand Up @@ -646,7 +649,7 @@ public async Task Handle_SendsToolsInDeterministicOrdinalOrder()
await _aiIntentService.Received(1).SendWithToolsAsync(
Arg.Any<string>(), Arg.Any<string>(),
Arg.Is<IReadOnlyList<object>>(declarations =>
ToolNames(declarations).SequenceEqual(new[] { "assign_tags", "create_habit", "delete_habit" })),
ToolNames(declarations).SequenceEqual(ExpectedOrderedToolNames)),
Arg.Any<Guid>(),
Arg.Any<byte[]?>(), Arg.Any<string?>(),
Arg.Any<IReadOnlyList<ChatHistoryMessage>?>(), Arg.Any<Func<AiStreamEvent, Task>?>(), Arg.Any<CancellationToken>());
Expand Down Expand Up @@ -907,7 +910,7 @@ public async Task Handle_ReadOnlyToolWithRelatedSurfaces_SurfacesThemOnResponse(
.Returns(new ToolResult(true, Payload: new
{
key = "streaks",
related_surfaces = new[] { "gamification", "today" },
related_surfaces = GamificationTodaySurfaces,
markdown = "# Streaks"
}));

Expand Down Expand Up @@ -1697,7 +1700,7 @@ public async Task Handle_MultipleReadOnlyTools_PreserveDeterministicRelatedSurfa
.Returns(async _ =>
{
await Task.Delay(40);
return new ToolResult(true, Payload: new { related_surfaces = new[] { "gamification", "today" } });
return new ToolResult(true, Payload: new { related_surfaces = GamificationTodaySurfaces });
});

var fastSecond = Substitute.For<IAiTool>();
Expand All @@ -1706,7 +1709,7 @@ public async Task Handle_MultipleReadOnlyTools_PreserveDeterministicRelatedSurfa
fastSecond.IsReadOnly.Returns(true);
fastSecond.GetParameterSchema().Returns(new { type = "object" });
fastSecond.ExecuteAsync(Arg.Any<JsonElement>(), UserId, Arg.Any<CancellationToken>())
.Returns(new ToolResult(true, Payload: new { related_surfaces = new[] { "habits" } }));
.Returns(new ToolResult(true, Payload: new { related_surfaces = HabitsSurfaces }));

var handler = CreateHandler(slowFirst, fastSecond);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public class BulkCreateHabitsCommandHandlerTests
private static readonly Guid UserId = Guid.NewGuid();
private static readonly DateOnly Today = new(2026, 3, 20);

private static readonly string[] ExpectedTagNames = new[] { "Fitness", "Health" };

public BulkCreateHabitsCommandHandlerTests()
{
_handler = new BulkCreateHabitsCommandHandler(
Expand Down Expand Up @@ -281,7 +283,7 @@ public async Task Handle_WithTags_CreatesAndAttachesNewTagsWithDefaultColor()

result.IsSuccess.Should().BeTrue();
addedTags.Should().HaveCount(2);
addedTags.Select(t => t.Name).Should().BeEquivalentTo(new[] { "Fitness", "Health" });
addedTags.Select(t => t.Name).Should().BeEquivalentTo(ExpectedTagNames);
addedTags.Should().AllSatisfy(t => t.Color.Should().Be("#7c3aed"));
addedHabits.Should().ContainSingle();
addedHabits[0].Tags.Should().HaveCount(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,19 @@ public class SuggestHabitSetupCommandHandlerTests

private static readonly Guid UserId = Guid.NewGuid();

private static readonly DayOfWeek[] SuggestionDays = new[] { DayOfWeek.Monday };
private static readonly string[] SubHabits = new[] { "Warm up" };

public SuggestHabitSetupCommandHandlerTests()
{
_handler = new SuggestHabitSetupCommandHandler(
_payGate, _suggestionService, _userRepo, _unitOfWork, _cache, _logger);
}

private static HabitSetupSuggestion SampleSuggestion() =>
new("R", FrequencyUnit.Day, 1, new[] { DayOfWeek.Monday },
new("R", FrequencyUnit.Day, 1, SuggestionDays,
IsFlexible: false, FlexibleTarget: null, DueTime: null,
SubHabits: new[] { "Warm up" }, ChecklistItems: Array.Empty<string>());
SubHabits: SubHabits, ChecklistItems: Array.Empty<string>());

private void SetupTrackedUser()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public class GetUserCalendarsQueryHandlerTests
private readonly GetUserCalendarsQueryHandler _handler;

private static readonly Guid UserId = Guid.NewGuid();
private static readonly string[] SharedCalendarSelection = new[] { "shared" };

public GetUserCalendarsQueryHandlerTests()
{
Expand Down Expand Up @@ -81,7 +82,7 @@ public async Task Handle_NullSelection_IsSyncedReflectsDefaultOwned()
public async Task Handle_ExplicitSelection_IsSyncedReflectsSelectedSet()
{
var user = CreateUser();
user.SetSelectedCalendars(new[] { "shared" });
user.SetSelectedCalendars(SharedCalendarSelection);
_userRepo.GetByIdAsync(UserId, Arg.Any<CancellationToken>()).Returns(user);
_googleTokenService.GetValidAccessTokenAsync(user, Arg.Any<CancellationToken>()).Returns("token");
_eventFetcher.ListCalendarsAsync("token", Arg.Any<CancellationToken>()).Returns(SampleCalendars());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class GetDailySummaryQueryHandlerTests

private static readonly Guid UserId = Guid.NewGuid();
private static readonly DateOnly Today = new(2026, 4, 3);
private static readonly string[] ExpectedHabitTitles = new[] { "Read" };

public GetDailySummaryQueryHandlerTests()
{
Expand Down Expand Up @@ -136,7 +137,7 @@ public async Task Handle_ExcludesHabitsSkippedInRequestedRange()
result.IsSuccess.Should().BeTrue();
await _summaryService.Received(1).GenerateSummaryAsync(
Arg.Is<IEnumerable<Habit>>(habits =>
habits.Select(h => h.Title).SequenceEqual(new[] { "Read" })),
habits.Select(h => h.Title).SequenceEqual(ExpectedHabitTitles)),
Today, Today, Arg.Any<DateOnly>(), "en",
Arg.Any<TimeOnly?>(),
Arg.Any<int>(), Arg.Any<int>(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ public class GetPublicProfileQueryHandlerTests

private const string Slug = "ABCDEFGHJKLMNPQRSTUV12";

private static readonly string[] ExpectedAchievementKeys = new[] { "first_orbit", "week_warrior" };

public GetPublicProfileQueryHandlerTests()
{
_handler = new GetPublicProfileQueryHandler(_userRepo, _achievementRepo, _habitRepo);
Expand Down Expand Up @@ -88,7 +90,7 @@ public async Task Handle_AllStatFlagsOn_ReturnsPublicFieldsAndOwnerLanguage()
view.Level.Should().NotBeNull();
view.LevelTitle.Should().NotBeNullOrWhiteSpace();
view.Achievements.Should().NotBeNull();
view.Achievements!.Select(a => a.IconKey).Should().Contain(new[] { "first_orbit", "week_warrior" });
view.Achievements!.Select(a => a.IconKey).Should().Contain(ExpectedAchievementKeys);
view.TopHabits.Should().BeNull();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public class XpAwardLogBackfillServiceTests
private static readonly Guid UserId = Guid.NewGuid();
private static readonly DateOnly Today = new(2026, 3, 20);

private static readonly int[] ExpectedHabitXpAmounts = new[] { 11, 12, 13 };

public XpAwardLogBackfillServiceTests()
{
_sut = new XpAwardLogBackfillService(_userRepo, _habitRepo, _goalRepo, _achievementRepo, _xpRepo, _unitOfWork);
Expand Down Expand Up @@ -79,7 +81,7 @@ public async Task BackfillUser_ReplaysHabitXpWithRecomputedPerDateStreak()
processed.Should().BeTrue();
_added.Should().HaveCount(3);
_added.Should().OnlyContain(r => r.Source == XpAwardSource.HabitLog);
_added.Select(r => r.Amount).Should().BeEquivalentTo(new[] { 11, 12, 13 });
_added.Select(r => r.Amount).Should().BeEquivalentTo(ExpectedHabitXpAmounts);
await _unitOfWork.Received(1).SaveChangesAsync(Arg.Any<CancellationToken>());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ public class GetFriendProfileQueryHandlerTests

private static readonly DateOnly Today = new(2026, 6, 15);

private static readonly string[] ExpectedAchievementKeys = new[] { "first_orbit", "week_warrior" };

public GetFriendProfileQueryHandlerTests()
{
var guard = new SocialAccessGuard(_userRepository);
Expand Down Expand Up @@ -105,7 +107,7 @@ public async Task Handle_AcceptedFriend_ReturnsProfileStatsAndAchievements()
view.Handle.Should().NotBeNullOrWhiteSpace();
view.CurrentStreak.Should().Be(12);
view.Level.Should().Be(5);
view.Achievements.Select(a => a.IconKey).Should().Contain(new[] { "first_orbit", "week_warrior" });
view.Achievements.Select(a => a.IconKey).Should().Contain(ExpectedAchievementKeys);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ public class CreateHabitCommandValidatorTests
{
private readonly CreateHabitCommandValidator _validator = new();

private static readonly DayOfWeek[] MondayOnly = new[] { DayOfWeek.Monday };
private static readonly DayOfWeek[] MondayAndWednesday = new[] { DayOfWeek.Monday, DayOfWeek.Wednesday };
private static readonly int[] ValidReminderTimes = new[] { 0, 15, 60, 1440 };
private static readonly int[] DuplicateReminderTimes = new[] { 15, 15 };
private static readonly int[] NegativeReminderTimes = new[] { -1 };
private static readonly int[] OverMaxReminderTimes = new[] { AppConstants.MaxReminderMinutesBefore + 1 };

private static CreateHabitCommand ValidCommand() => new(
UserId: Guid.NewGuid(),
Title: "My Habit",
Expand Down Expand Up @@ -97,7 +104,7 @@ public void Validate_DaysWithQtyNot1_HasError()
var command = ValidCommand() with
{
FrequencyQuantity = 2,
Options = new HabitCommandOptions(Days: new[] { DayOfWeek.Monday })
Options = new HabitCommandOptions(Days: MondayOnly)
};

var result = _validator.TestValidate(command);
Expand All @@ -111,7 +118,7 @@ public void Validate_DaysWithQty1_NoError()
var command = ValidCommand() with
{
FrequencyQuantity = 1,
Options = new HabitCommandOptions(Days: new[] { DayOfWeek.Monday, DayOfWeek.Wednesday })
Options = new HabitCommandOptions(Days: MondayAndWednesday)
};

var result = _validator.TestValidate(command);
Expand All @@ -126,7 +133,7 @@ public void Validate_DaysWithNonDayUnit_HasError()
{
FrequencyUnit = FrequencyUnit.Week,
FrequencyQuantity = 1,
Options = new HabitCommandOptions(Days: new[] { DayOfWeek.Monday })
Options = new HabitCommandOptions(Days: MondayOnly)
};

var result = _validator.TestValidate(command);
Expand All @@ -141,7 +148,7 @@ public void Validate_DaysWhenFlexible_NoError()
{
FrequencyUnit = FrequencyUnit.Week,
FrequencyQuantity = 1,
Options = new HabitCommandOptions(Days: new[] { DayOfWeek.Monday }, IsFlexible: true)
Options = new HabitCommandOptions(Days: MondayOnly, IsFlexible: true)
};

var result = _validator.TestValidate(command);
Expand Down Expand Up @@ -303,7 +310,7 @@ public void Validate_ValidReminderTimes_NoError()
{
var command = ValidCommand() with
{
Options = new HabitCommandOptions(ReminderTimes: new[] { 0, 15, 60, 1440 })
Options = new HabitCommandOptions(ReminderTimes: ValidReminderTimes)
};

var result = _validator.TestValidate(command);
Expand All @@ -315,7 +322,7 @@ public void Validate_ReminderTimes_Duplicates_HasError()
{
var command = ValidCommand() with
{
Options = new HabitCommandOptions(ReminderTimes: new[] { 15, 15 })
Options = new HabitCommandOptions(ReminderTimes: DuplicateReminderTimes)
};

var result = _validator.TestValidate(command);
Expand All @@ -327,7 +334,7 @@ public void Validate_ReminderTimes_Negative_HasError()
{
var command = ValidCommand() with
{
Options = new HabitCommandOptions(ReminderTimes: new[] { -1 })
Options = new HabitCommandOptions(ReminderTimes: NegativeReminderTimes)
};

var result = _validator.TestValidate(command);
Expand All @@ -339,7 +346,7 @@ public void Validate_ReminderTimes_OverMax_HasError()
{
var command = ValidCommand() with
{
Options = new HabitCommandOptions(ReminderTimes: new[] { AppConstants.MaxReminderMinutesBefore + 1 })
Options = new HabitCommandOptions(ReminderTimes: OverMaxReminderTimes)
};

var result = _validator.TestValidate(command);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ public class UpdateHabitCommandValidatorTests
{
private readonly UpdateHabitCommandValidator _validator = new();

private static readonly DayOfWeek[] MondayOnly = new[] { DayOfWeek.Monday };
private static readonly int[] DuplicateReminderTimes = new[] { 15, 15 };
private static readonly int[] OutOfRangeReminderTimes = new[] { -5 };

private static UpdateHabitCommand ValidCommand() => new(
UserId: Guid.NewGuid(),
HabitId: Guid.NewGuid(),
Expand Down Expand Up @@ -83,7 +87,7 @@ public void Validate_DaysWithQtyNot1_HasError()
var command = ValidCommand() with
{
FrequencyQuantity = 2,
Options = new UpdateHabitCommandOptions(Days: new[] { DayOfWeek.Monday })
Options = new UpdateHabitCommandOptions(Days: MondayOnly)
};

var result = _validator.TestValidate(command);
Expand All @@ -98,7 +102,7 @@ public void Validate_DaysWithNonDayUnit_HasError()
{
FrequencyUnit = FrequencyUnit.Week,
FrequencyQuantity = 1,
Options = new UpdateHabitCommandOptions(Days: new[] { DayOfWeek.Monday })
Options = new UpdateHabitCommandOptions(Days: MondayOnly)
};

var result = _validator.TestValidate(command);
Expand All @@ -113,7 +117,7 @@ public void Validate_DaysWithDayUnitQty1_NoError()
{
FrequencyUnit = FrequencyUnit.Day,
FrequencyQuantity = 1,
Options = new UpdateHabitCommandOptions(Days: new[] { DayOfWeek.Monday })
Options = new UpdateHabitCommandOptions(Days: MondayOnly)
};

var result = _validator.TestValidate(command);
Expand Down Expand Up @@ -156,7 +160,7 @@ public void Validate_ReminderTimes_Duplicates_HasError()
{
var command = ValidCommand() with
{
Options = new UpdateHabitCommandOptions(ReminderTimes: new[] { 15, 15 })
Options = new UpdateHabitCommandOptions(ReminderTimes: DuplicateReminderTimes)
};

var result = _validator.TestValidate(command);
Expand All @@ -169,7 +173,7 @@ public void Validate_ReminderTimes_OutOfRange_HasError()
{
var command = ValidCommand() with
{
Options = new UpdateHabitCommandOptions(ReminderTimes: new[] { -5 })
Options = new UpdateHabitCommandOptions(ReminderTimes: OutOfRangeReminderTimes)
};

var result = _validator.TestValidate(command);
Expand Down
Loading
Loading