public async Task VoteWithCountdownIdThatDoesntExist_VoteIsAdded() { var voteService = TestableVoteService.Create(); voteService.MockCountdownRepository .Setup(x => x.GetByIdAsync(TestableVoteService.CountdownId)) .Returns(Task.FromResult(new Countdown { Description = "Test description", Id = TestableVoteService.CountdownId })); var vote = new Vote { CountdownId = TestableVoteService.CountdownId, CastedById = TestableVoteService.AccountId, CastedOn = DateTime.UtcNow, Value = 1 }; await voteService.CastAsync(vote); Vote storedVote = await voteService.FakeVoteRepository.GetCountdownVoteAsync(TestableVoteService.CountdownId, TestableVoteService.AccountId); Assert.IsNotNull(storedVote); Assert.AreEqual(1, storedVote.Value); }
private Task UpateOwnerReputationAsync(Vote vote, Vote existingVote, Account owner) { if (existingVote != null) { owner.Reputation -= CalculateRepScore(existingVote); } owner.Reputation += CalculateRepScore(vote); return _accountRepository.UpdateAsync(owner); }
public Task UpdateAsync(Vote vote) { return Task.Run(() => { Vote v = _votes.FirstOrDefault(x => x.CountdownId == vote.CountdownId && x.CastedById == vote.CastedById); if (v != null) { v.Value = vote.Value; } }); }
public async Task CreateAsync(Vote vote) { using (SqlConnection connection = Connection) { const string sql = "INSERT INTO Votes (CountdownId, CommentId, Value, CastedById, CastedOn) " + "OUTPUT INSERTED.Id " + "VALUES (@CountdownId, @CommentId, @Value, @CastedById, @CastedOn)"; vote.Id = (await connection.QueryAsync<Guid>(sql, vote)).Single(); } }
private async Task CreateNotification(Vote vote, Account owner) { var notification = new Notification { AccountId = owner.Id, Read = false, CreatedOn = DateTime.UtcNow, Type = NotificationType.Vote, Content = await GenerateNotificationContentAsync(vote) }; _notificationDispatcher.Dispatch(notification); }
private async Task<string> GenerateNotificationContentAsync(Vote vote) { if (vote.CountdownId != null) { Countdown countdown = await _countdownRepository.GetByIdAsync((int) vote.CountdownId); return string.Format("Upvoted on a Countdown - <a href=\"/Countdown/{0}\">{1}</a>", countdown.Id, countdown.Description); } else { Countdown countdown = await _countdownRepository.GetByCommentIdAsync((int) vote.CommentId); return string.Format("Upvoted on a Comment - <a href=\"/Countdown/{0}#{1}\">{2}</a>", countdown.Id, vote.CommentId, countdown.Description); } }
public async Task CastAsync(Vote vote) { Task<Vote> existingVoteTask = GetExistingVoteAsync(vote); Task<Account> contentOwnerTask = GetContentOwnerAsync(vote); await Task.WhenAll(existingVoteTask, contentOwnerTask); Vote existingVote = await existingVoteTask; Account owner = await contentOwnerTask; if (existingVote == null) { await CreateVoteAsync(vote, owner); } else { await UpdateVoteAsync(vote, existingVote); } await UpateOwnerReputationAsync(vote, existingVote, owner); }
public async Task VoteWithCommentIdThatDoesntExist_ReputationOfTheOwnerIsUpdated(short voteValue, int reputationScore) { var voteService = TestableVoteService.Create(); voteService.MockCountdownRepository .Setup(x => x.GetByCommentIdAsync(TestableVoteService.CommentId)) .Returns(Task.FromResult(new Countdown { Description = "Test description", Id = TestableVoteService.CountdownId })); var vote = new Vote { CommentId = TestableVoteService.CommentId, CastedById = TestableVoteService.AccountId, CastedOn = DateTime.UtcNow, Value = voteValue }; await voteService.CastAsync(vote); voteService.MockAccountRepository .Verify(x => x.UpdateAsync(It.Is<Account>(a => a.Reputation == reputationScore)), Times.Once()); }
public Task CreateAsync(Vote vote) { return Task.Run(() => _votes.Add(vote)); }
private async Task CreateVoteAsync(Vote vote, Account owner) { await _voteRepository.CreateAsync(vote); await CreateNotification(vote, owner); }
private Task UpdateVoteAsync(Vote vote, Vote existingVote) { if (existingVote.Value == vote.Value) { throw new Exception("Can't cast the same vote twice"); } vote.Id = existingVote.Id; return _voteRepository.UpdateAsync(vote); }
private Task<Vote> GetExistingVoteAsync(Vote vote) { bool hasCommentId = vote.CommentId != null; bool hasCountdownId = vote.CountdownId != null; if (hasCommentId ^ hasCountdownId) { return hasCountdownId ? _voteRepository.GetCountdownVoteAsync((int) vote.CountdownId, vote.CastedById) : _voteRepository.GetCommentVoteAsync((int) vote.CommentId, vote.CastedById); } throw new ArgumentException("Can't determine the type of vote", "vote"); }
public void Delete(Vote vote) { _votes.Remove(vote); }
private static int CalculateRepScore(Vote vote) { return vote.CountdownId != null ? CalculateCountdownRepScore(vote) : CalculateCommentRepScore(vote); }
public async Task VoteWithCountdownId_CreatesANotificationForTheOwner() { var voteService = TestableVoteService.Create(); var countdownVote = new Vote { CountdownId = TestableVoteService.CountdownId, CastedById = TestableVoteService.AccountId, Value = 1 }; var countdown = new Countdown { Description = "Test description", Id = TestableVoteService.CountdownId }; voteService.MockCountdownRepository .Setup(x => x.GetByIdAsync(TestableVoteService.CountdownId)) .Returns(Task.FromResult(countdown)); await voteService.CastAsync(countdownVote); string expectedContent = string.Format("Upvoted on a Countdown - <a href=\"/Countdown/{0}\">{1}</a>", countdown.Id, countdown.Description); voteService.MockNotificationDispatcher .Verify(x => x.Dispatch( It.Is<Notification>( n => n.AccountId == TestableVoteService.OwnerId && n.Content == expectedContent && n.Read == false && // TODO - Refactor this DateTime bit -> Possibly Inject an IClock and mock it (n.CreatedOn.Date == DateTime.UtcNow.Date && n.CreatedOn.Hour == DateTime.UtcNow.Hour && n.CreatedOn.Minute == DateTime.UtcNow.Minute) && n.ReadOn == null && n.Type == NotificationType.Vote )), Times.Once()); }
public void VoteWithCommentIdAndCountdownId_ThrowsAnException() { var voteService = TestableVoteService.Create(); var vote = new Vote { CommentId = TestableVoteService.CommentId, CountdownId = TestableVoteService.CountdownId, Value = 0 }; var ex = Assert.Throws<ArgumentException>(async () => await voteService.CastAsync(vote)); Assert.AreEqual("Can't determine the type of vote\r\nParameter name: vote", ex.Message); }
public async Task VoteWithCommentIdThatAlreadyHasTheSameVoteByTheAccountId_ThrowsAnException() { var voteService = TestableVoteService.Create(); var vote = new Vote { CommentId = TestableVoteService.CommentId, CastedById = TestableVoteService.AccountId, Value = 1 }; await voteService.FakeVoteRepository.CreateAsync(vote); var ex = Assert.Throws<Exception>(async () => await voteService.CastAsync(vote)); Assert.AreEqual("Can't cast the same vote twice", ex.Message); }
public async Task VoteWithCommentIdThatAlreadyHasADifferentVoteByTheAccountId_UpdatesTheVote(short existingVoteValue, short newVoteValue) { var voteService = TestableVoteService.Create(); var vote = new Vote { CommentId = TestableVoteService.CommentId, CastedById = TestableVoteService.AccountId, CastedOn = DateTime.UtcNow, Value = newVoteValue }; await voteService.FakeVoteRepository.CreateAsync(new Vote { CommentId = TestableVoteService.CommentId, CastedById = TestableVoteService.AccountId, Value = existingVoteValue }); await voteService.CastAsync(vote); Vote updatedVote = await voteService.FakeVoteRepository.GetCommentVoteAsync(TestableVoteService.CommentId, TestableVoteService.AccountId); Assert.AreEqual(newVoteValue, updatedVote.Value); }
public async Task VoteWithCommentIdThatAlreadyHasADifferentVoteByTheAccountId_ReputationOfTheOwnerRolledbackAndUpdated(short existingVoteValue, short newVoteValue, int reputationScore) { var mockAccountRepository = new Mock<IAccountRepository>(); mockAccountRepository .Setup(x => x.GetByCommentIdAsync(TestableVoteService.CommentId)) .Returns(Task.FromResult(new Account {Id = TestableVoteService.OwnerId, Reputation = 10})); var mockVoteRepository = new Mock<IVoteRepository>(); mockVoteRepository .Setup(x => x.GetCommentVoteAsync(It.IsAny<long>(), It.IsAny<int>())) .Returns(Task.FromResult(new Vote { CommentId = TestableVoteService.CommentId, CastedById = TestableVoteService.AccountId, Value = existingVoteValue })); var voteService = new VoteService( mockVoteRepository.Object, new Mock<INotificationDispatcher>().Object, mockAccountRepository.Object, new Mock<ICountdownRepository>().Object); var vote = new Vote { CommentId = TestableVoteService.CommentId, CastedById = TestableVoteService.AccountId, CastedOn = DateTime.UtcNow, Value = newVoteValue }; await voteService.CastAsync(vote); mockAccountRepository .Verify(x => x.UpdateAsync(It.Is<Account>(a => a.Reputation == reputationScore)), Times.Once()); }
private static short CalculateCountdownRepScore(Vote vote) { return vote.Value > 0 ? CountdownUpVoteScore : CountdownDownVoteScore; }
private static short CalculateCommentRepScore(Vote vote) { return vote.Value > 0 ? CommentUpVoteScore : CommentDownVoteScore; }
public async Task UpdateAsync(Vote vote) { using (SqlConnection connection = Connection) { await connection.ExecuteAsync("UPDATE Votes SET Value = @Value, CastedOn = @CastedOn WHERE Id = @Id", vote); } }
public void VoteWithCountdownIdThatHasAnInvalidOwner_ThrowsAnException() { var voteService = TestableVoteService.Create(); voteService.MockAccountRepository .Setup(x => x.GetByCountdownIdAsync(TestableVoteService.CountdownId)) .Returns(Task.FromResult<Account>(null)); var commentVote = new Vote { CountdownId = TestableVoteService.CountdownId, CastedById = TestableVoteService.AccountId, Value = 1 }; var ex = Assert.Throws<Exception>(async () => await voteService.CastAsync(commentVote)); Assert.AreEqual("Can't find the content owner", ex.Message); }
private async Task CastVoteAsync(int commentId, short value) { Account account = await _contextService.GetCurrentAccountAsync(); var vote = new Vote { CommentId = commentId, Value = value, CastedById = account.Id, CastedOn = DateTime.UtcNow }; _voteService.CastAsync(vote); }
private async Task<Account> GetContentOwnerAsync(Vote vote) { Account owner = vote.CommentId != null ? await _accountRepository.GetByCommentIdAsync((int) vote.CommentId) : await _accountRepository.GetByCountdownIdAsync((int) vote.CountdownId); if (owner == null) { throw new Exception("Can't find the content owner"); } return owner; }
public async Task VoteWithCountdownIdThatAlreadyHasAnOppositeVoteByTheAccountId_DoesntCreateANotificationForTheOwner() { var voteService = TestableVoteService.Create(); var vote = new Vote { CountdownId = TestableVoteService.CountdownId, CastedById = TestableVoteService.AccountId, Value = -1 }; await voteService.FakeVoteRepository.CreateAsync(new Vote { CountdownId = TestableVoteService.CountdownId, CastedById = TestableVoteService.AccountId, Value = 1 }); await voteService.CastAsync(vote); voteService.MockNotificationDispatcher .Verify(x => x.Dispatch(It.IsAny<Notification>()), Times.Never); }