diff --git a/src/ApplicationCore/ApplicationCore.csproj b/src/ApplicationCore/ApplicationCore.csproj
index e0c49c1..f8d7d9a 100644
--- a/src/ApplicationCore/ApplicationCore.csproj
+++ b/src/ApplicationCore/ApplicationCore.csproj
@@ -5,6 +5,7 @@
+
diff --git a/src/ApplicationCore/Exceptions/BasketNotFoundException.cs b/src/ApplicationCore/Exceptions/BasketNotFoundException.cs
new file mode 100644
index 0000000..7a3f804
--- /dev/null
+++ b/src/ApplicationCore/Exceptions/BasketNotFoundException.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace ApplicationCore.Exceptions
+{
+ public class BasketNotFoundException : Exception
+ {
+ public BasketNotFoundException(int basketId) : base($"No basket found with id {basketId}")
+ {
+ }
+
+ protected BasketNotFoundException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context)
+ {
+ }
+
+ public BasketNotFoundException(string message) : base(message)
+ {
+ }
+
+ public BasketNotFoundException(string message, Exception innerException) : base(message, innerException)
+ {
+ }
+ }
+}
diff --git a/src/ApplicationCore/Exceptions/GuardExtensions.cs b/src/ApplicationCore/Exceptions/GuardExtensions.cs
new file mode 100644
index 0000000..0c840a0
--- /dev/null
+++ b/src/ApplicationCore/Exceptions/GuardExtensions.cs
@@ -0,0 +1,14 @@
+using ApplicationCore.Exceptions;
+using Microsoft.eShopWeb.ApplicationCore.Entities;
+
+namespace Ardalis.GuardClauses
+{
+ public static class FooGuard
+ {
+ public static void NullBasket(this IGuardClause guardClause, int basketId, Basket basket)
+ {
+ if (basket == null)
+ throw new BasketNotFoundException(basketId);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ApplicationCore/Interfaces/IRepository.cs b/src/ApplicationCore/Interfaces/IRepository.cs
index a448152..9099188 100644
--- a/src/ApplicationCore/Interfaces/IRepository.cs
+++ b/src/ApplicationCore/Interfaces/IRepository.cs
@@ -1,12 +1,12 @@
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System.Collections.Generic;
-using System.Threading.Tasks;
namespace ApplicationCore.Interfaces
{
public interface IRepository where T : BaseEntity
{
T GetById(int id);
+ T GetSingleBySpec(ISpecification spec);
IEnumerable ListAll();
IEnumerable List(ISpecification spec);
T Add(T entity);
diff --git a/src/ApplicationCore/Services/BasketService.cs b/src/ApplicationCore/Services/BasketService.cs
index 209886d..f189812 100644
--- a/src/ApplicationCore/Services/BasketService.cs
+++ b/src/ApplicationCore/Services/BasketService.cs
@@ -4,6 +4,7 @@ using System.Collections.Generic;
using ApplicationCore.Specifications;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System.Linq;
+using Ardalis.GuardClauses;
namespace ApplicationCore.Services
{
@@ -43,6 +44,7 @@ namespace ApplicationCore.Services
public async Task GetBasketItemCountAsync(string userName)
{
+ Guard.Against.NullOrEmpty(userName, nameof(userName));
var basketSpec = new BasketWithItemsSpecification(userName);
var basket = (await _basketRepository.ListAsync(basketSpec)).FirstOrDefault();
if (basket == null)
@@ -57,7 +59,9 @@ namespace ApplicationCore.Services
public async Task SetQuantities(int basketId, Dictionary quantities)
{
+ Guard.Against.Null(quantities, nameof(quantities));
var basket = await _basketRepository.GetByIdAsync(basketId);
+ Guard.Against.NullBasket(basketId, basket);
foreach (var item in basket.Items)
{
if (quantities.TryGetValue(item.Id.ToString(), out var quantity))
@@ -71,6 +75,8 @@ namespace ApplicationCore.Services
public async Task TransferBasketAsync(string anonymousId, string userName)
{
+ Guard.Against.NullOrEmpty(anonymousId, nameof(anonymousId));
+ Guard.Against.NullOrEmpty(userName, nameof(userName));
var basketSpec = new BasketWithItemsSpecification(anonymousId);
var basket = (await _basketRepository.ListAsync(basketSpec)).FirstOrDefault();
if (basket == null) return;
diff --git a/src/ApplicationCore/Services/OrderService.cs b/src/ApplicationCore/Services/OrderService.cs
index e666182..162e289 100644
--- a/src/ApplicationCore/Services/OrderService.cs
+++ b/src/ApplicationCore/Services/OrderService.cs
@@ -3,6 +3,7 @@ using ApplicationCore.Entities.OrderAggregate;
using System.Threading.Tasks;
using Microsoft.eShopWeb.ApplicationCore.Entities;
using System.Collections.Generic;
+using Ardalis.GuardClauses;
namespace ApplicationCore.Services
{
@@ -24,6 +25,7 @@ namespace ApplicationCore.Services
public async Task CreateOrderAsync(int basketId, Address shippingAddress)
{
var basket = await _basketRepository.GetByIdAsync(basketId);
+ Guard.Against.NullBasket(basketId, basket);
var items = new List();
foreach (var item in basket.Items)
{
diff --git a/src/Infrastructure/Data/EfRepository.cs b/src/Infrastructure/Data/EfRepository.cs
index b0cecfa..47fe8a2 100644
--- a/src/Infrastructure/Data/EfRepository.cs
+++ b/src/Infrastructure/Data/EfRepository.cs
@@ -26,6 +26,12 @@ namespace Infrastructure.Data
return _dbContext.Set().Find(id);
}
+ public T GetSingleBySpec(ISpecification spec)
+ {
+ return List(spec).FirstOrDefault();
+ }
+
+
public virtual async Task GetByIdAsync(int id)
{
return await _dbContext.Set().FindAsync(id);
diff --git a/src/Infrastructure/Logging/LoggerAdapter.cs b/src/Infrastructure/Logging/LoggerAdapter.cs
index 93b5447..240c5b1 100644
--- a/src/Infrastructure/Logging/LoggerAdapter.cs
+++ b/src/Infrastructure/Logging/LoggerAdapter.cs
@@ -15,6 +15,7 @@ namespace Infrastructure.Logging
{
_logger.LogWarning(message, args);
}
+
public void LogInformation(string message, params object[] args)
{
_logger.LogInformation(message, args);
diff --git a/tests/UnitTests/ApplicationCore/Services/BasketServiceTests/SetQuantities.cs b/tests/UnitTests/ApplicationCore/Services/BasketServiceTests/SetQuantities.cs
new file mode 100644
index 0000000..8e98009
--- /dev/null
+++ b/tests/UnitTests/ApplicationCore/Services/BasketServiceTests/SetQuantities.cs
@@ -0,0 +1,40 @@
+using ApplicationCore.Exceptions;
+using ApplicationCore.Interfaces;
+using ApplicationCore.Services;
+using Microsoft.eShopWeb.ApplicationCore.Entities;
+using Moq;
+using System;
+using Xunit;
+
+namespace UnitTests.ApplicationCore.Services.BasketServiceTests
+{
+ public class SetQuantities
+ {
+ private int _invalidId = -1;
+ private Mock> _mockBasketRepo;
+
+ public SetQuantities()
+ {
+ _mockBasketRepo = new Mock>();
+ }
+
+ [Fact]
+ public async void ThrowsGivenInvalidBasketId()
+ {
+ var basketService = new BasketService(_mockBasketRepo.Object, null, null, null);
+
+ await Assert.ThrowsAsync(async () =>
+ await basketService.SetQuantities(_invalidId, new System.Collections.Generic.Dictionary()));
+ }
+
+ [Fact]
+ public async void ThrowsGivenNullQuantities()
+ {
+ var basketService = new BasketService(null, null, null, null);
+
+ await Assert.ThrowsAsync(async () =>
+ await basketService.SetQuantities(123, null));
+ }
+
+ }
+}
diff --git a/tests/UnitTests/ApplicationCore/Services/BasketServiceTests/TransferBasket.cs b/tests/UnitTests/ApplicationCore/Services/BasketServiceTests/TransferBasket.cs
new file mode 100644
index 0000000..f284f56
--- /dev/null
+++ b/tests/UnitTests/ApplicationCore/Services/BasketServiceTests/TransferBasket.cs
@@ -0,0 +1,25 @@
+using ApplicationCore.Services;
+using System;
+using Xunit;
+
+namespace UnitTests.ApplicationCore.Services.BasketServiceTests
+{
+ public class TransferBasket
+ {
+ [Fact]
+ public async void ThrowsGivenNullAnonymousId()
+ {
+ var basketService = new BasketService(null, null, null, null);
+
+ await Assert.ThrowsAsync(async () => await basketService.TransferBasketAsync(null, "steve"));
+ }
+
+ [Fact]
+ public async void ThrowsGivenNullUserId()
+ {
+ var basketService = new BasketService(null, null, null, null);
+
+ await Assert.ThrowsAsync(async () => await basketService.TransferBasketAsync("abcdefg", null));
+ }
+ }
+}