using FluentAssertions; using Marathon.Application.Abstractions; using Marathon.Application.UseCases; using Marathon.Domain.Entities; using Marathon.Domain.Enums; using Marathon.Domain.ValueObjects; using Microsoft.Extensions.Logging.Abstractions; using NSubstitute; namespace Marathon.Application.Tests.UseCases; public sealed class RecordPlacedBetUseCaseTests { private static readonly TimeSpan MoscowOffset = TimeSpan.FromHours(3); private readonly IPlacedBetRepository _bets = Substitute.For(); private readonly IEventRepository _events = Substitute.For(); private readonly IResultRepository _results = Substitute.For(); private RecordPlacedBetUseCase CreateSut() => new(_bets, _events, _results, NullLogger.Instance); private static PlacedBet MakePending(EventId id, Side side = Side.Side1) => new( Id: Guid.NewGuid(), EventId: id, Selection: new Bet(MatchScope.Instance, BetType.Win, side, null, new OddsRate(2.10m)), Stake: 100m, PlacedAt: new DateTimeOffset(2026, 5, 16, 12, 0, 0, MoscowOffset), Outcome: BetOutcome.Pending, Notes: null); [Fact] public async Task Should_Throw_When_EventDoesNotExist() { var id = new EventId("missing"); _events.GetAsync(id, Arg.Any()).Returns((Event?)null); var act = async () => await CreateSut().ExecuteAsync(MakePending(id), CancellationToken.None); await act.Should().ThrowAsync().WithMessage("*unknown event*"); await _bets.DidNotReceive().AddAsync(Arg.Any(), Arg.Any()); } [Fact] public async Task Should_PersistPending_When_NoResultYet() { var id = new EventId("event001"); _events.GetAsync(id, Arg.Any()).Returns(TestFixtures.MakeEvent(id.Value)); _results.GetAsync(id, Arg.Any()).Returns((EventResult?)null); var bet = MakePending(id); var stored = await CreateSut().ExecuteAsync(bet, CancellationToken.None); stored.Outcome.Should().Be(BetOutcome.Pending, "no result yet — should remain pending"); await _bets.Received(1).AddAsync(Arg.Any(), Arg.Any()); await _bets.Received(1).SaveChangesAsync(Arg.Any()); } [Fact] public async Task Should_AutoGrade_When_ResultAlreadyAvailable() { var id = new EventId("event002"); _events.GetAsync(id, Arg.Any()).Returns(TestFixtures.MakeEvent(id.Value)); _results.GetAsync(id, Arg.Any()) .Returns(new EventResult(id, 2, 1, Side.Side1, DateTimeOffset.UtcNow)); var bet = MakePending(id, side: Side.Side1); var stored = await CreateSut().ExecuteAsync(bet, CancellationToken.None); stored.Outcome.Should().Be(BetOutcome.Won, "Side1 was selected and Side1 won"); } }