-
-
Notifications
You must be signed in to change notification settings - Fork 517
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added solutions (not yet refactored) for Slimmed Business logic
- Loading branch information
1 parent
b12f3c2
commit f2dca14
Showing
17 changed files
with
1,942 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
29 changes: 29 additions & 0 deletions
29
...troductionToEventSourcing/Solved/07-BusinessLogic.Slimmed/07-BusinessLogic.Slimmed.csproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net8.0</TargetFramework> | ||
<RootNamespace>IntroductionToEventSourcing.BusinessLogic.Slimmed</RootNamespace> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="FluentAssertions" Version="6.12.0" /> | ||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> | ||
<PackageReference Include="GitHubActionsTestLogger" Version="2.3.3"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
</PackageReference> | ||
<PackageReference Include="Ogooreck" Version="0.8.1" /> | ||
<PackageReference Include="xunit" Version="2.8.0" /> | ||
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0"> | ||
<PrivateAssets>all</PrivateAssets> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> | ||
</PackageReference> | ||
<PackageReference Include="coverlet.collector" Version="6.0.2"> | ||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | ||
<PrivateAssets>all</PrivateAssets> | ||
</PackageReference> | ||
</ItemGroup> | ||
|
||
|
||
|
||
</Project> |
313 changes: 313 additions & 0 deletions
313
...troductionToEventSourcing/Solved/07-BusinessLogic.Slimmed/Immutable/BusinessLogicTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,313 @@ | ||
using Ogooreck.BusinessLogic; | ||
using Xunit; | ||
|
||
namespace IntroductionToEventSourcing.BusinessLogic.Slimmed.Immutable; | ||
|
||
using static ShoppingCartEvent; | ||
using static ShoppingCartCommand; | ||
using static ShoppingCartService; | ||
|
||
public class BusinessLogicTests | ||
{ | ||
// Open | ||
[Fact] | ||
public void OpensShoppingCart() => | ||
Spec.Given([]) | ||
.When(() => Handle(new OpenShoppingCart(shoppingCartId, clientId, now))) | ||
.Then(new ShoppingCartOpened(shoppingCartId, clientId, now)); | ||
|
||
// Add | ||
[Fact] | ||
public void CantAddProductItemToNotExistingShoppingCart() => | ||
Spec.Given([]) | ||
.When(state => | ||
Handle( | ||
FakeProductPriceCalculator.Returning(Price), | ||
new AddProductItemToShoppingCart(shoppingCartId, ProductItem, now), | ||
state | ||
) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void AddsProductItemToEmptyShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now) | ||
]) | ||
.When(state => | ||
Handle( | ||
FakeProductPriceCalculator.Returning(Price), | ||
new AddProductItemToShoppingCart(shoppingCartId, ProductItem, now), | ||
state | ||
) | ||
) | ||
.Then( | ||
new ProductItemAddedToShoppingCart( | ||
shoppingCartId, | ||
new PricedProductItem(ProductItem.ProductId, ProductItem.Quantity, Price), | ||
now | ||
) | ||
); | ||
|
||
|
||
[Fact] | ||
public void AddsProductItemToNonEmptyShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
]) | ||
.When(state => | ||
Handle( | ||
FakeProductPriceCalculator.Returning(OtherPrice), | ||
new AddProductItemToShoppingCart(shoppingCartId, OtherProductItem, now), | ||
state | ||
) | ||
) | ||
.Then( | ||
new ProductItemAddedToShoppingCart( | ||
shoppingCartId, | ||
new PricedProductItem(OtherProductItem.ProductId, OtherProductItem.Quantity, OtherPrice), | ||
now | ||
) | ||
); | ||
|
||
[Fact] | ||
public void CantAddProductItemToConfirmedShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
new ShoppingCartConfirmed(shoppingCartId, now) | ||
]) | ||
.When(state => | ||
Handle( | ||
FakeProductPriceCalculator.Returning(Price), | ||
new AddProductItemToShoppingCart(shoppingCartId, ProductItem, now), | ||
state | ||
) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void CantAddProductItemToCanceledShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
new ShoppingCartCanceled(shoppingCartId, now) | ||
]) | ||
.When(state => | ||
Handle( | ||
FakeProductPriceCalculator.Returning(Price), | ||
new AddProductItemToShoppingCart(shoppingCartId, ProductItem, now), | ||
state | ||
) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
// Remove | ||
[Fact] | ||
public void CantRemoveProductItemFromNotExistingShoppingCart() => | ||
Spec.Given([]) | ||
.When(state => | ||
Handle( | ||
new RemoveProductItemFromShoppingCart(shoppingCartId, pricedProductItem, now), | ||
state | ||
) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void RemovesExistingProductItemFromShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
]) | ||
.When(state => | ||
Handle( | ||
new RemoveProductItemFromShoppingCart(shoppingCartId, pricedProductItem with { Quantity = 1 }, now), | ||
state | ||
) | ||
) | ||
.Then( | ||
new ProductItemRemovedFromShoppingCart( | ||
shoppingCartId, | ||
pricedProductItem with { Quantity = 1 }, | ||
now | ||
) | ||
); | ||
|
||
[Fact] | ||
public void CantRemoveNonExistingProductItemFromNonEmptyShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
]) | ||
.When(state => | ||
Handle( | ||
new RemoveProductItemFromShoppingCart(shoppingCartId, otherPricedProductItem with { Quantity = 1 }, | ||
now), | ||
state | ||
) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void CantRemoveExistingProductItemFromCanceledShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
new ShoppingCartConfirmed(shoppingCartId, now) | ||
]) | ||
.When(state => | ||
Handle( | ||
new RemoveProductItemFromShoppingCart(shoppingCartId, pricedProductItem with { Quantity = 1 }, now), | ||
state | ||
) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void CantRemoveExistingProductItemFromConfirmedShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
new ShoppingCartCanceled(shoppingCartId, now) | ||
]) | ||
.When(state => | ||
Handle( | ||
new RemoveProductItemFromShoppingCart(shoppingCartId, pricedProductItem with { Quantity = 1 }, now), | ||
state | ||
) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
// Confirm | ||
|
||
[Fact] | ||
public void CantConfirmNotExistingShoppingCart() => | ||
Spec.Given([]) | ||
.When(state => | ||
Handle(new ConfirmShoppingCart(shoppingCartId, now), state) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
[Trait("Category", "SkipCI")] | ||
public void CantConfirmEmptyShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
]) | ||
.When(state => | ||
Handle(new ConfirmShoppingCart(shoppingCartId, now), state) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void ConfirmsNonEmptyShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
]) | ||
.When(state => | ||
Handle(new ConfirmShoppingCart(shoppingCartId, now), state) | ||
) | ||
.Then( | ||
new ShoppingCartConfirmed(shoppingCartId, now) | ||
); | ||
|
||
[Fact] | ||
public void CantConfirmAlreadyConfirmedShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
new ShoppingCartConfirmed(shoppingCartId, now) | ||
]) | ||
.When(state => | ||
Handle(new ConfirmShoppingCart(shoppingCartId, now), state) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void CantConfirmCanceledShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
new ShoppingCartCanceled(shoppingCartId, now) | ||
]) | ||
.When(state => | ||
Handle(new ConfirmShoppingCart(shoppingCartId, now), state) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
// Cancel | ||
[Fact] | ||
[Trait("Category", "SkipCI")] | ||
public void CantCancelNotExistingShoppingCart() => | ||
Spec.Given([]) | ||
.When(state => | ||
Handle(new CancelShoppingCart(shoppingCartId, now), state) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void CancelsEmptyShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
]) | ||
.When(state => | ||
Handle(new CancelShoppingCart(shoppingCartId, now), state) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void CancelsNonEmptyShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
]) | ||
.When(state => | ||
Handle(new CancelShoppingCart(shoppingCartId, now), state) | ||
) | ||
.Then( | ||
new ShoppingCartCanceled(shoppingCartId, now) | ||
); | ||
|
||
[Fact] | ||
public void CantCancelAlreadyCanceledShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
new ShoppingCartCanceled(shoppingCartId, now) | ||
]) | ||
.When(state => | ||
Handle(new CancelShoppingCart(shoppingCartId, now), state) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
[Fact] | ||
public void CantCancelConfirmedShoppingCart() => | ||
Spec.Given([ | ||
new ShoppingCartOpened(shoppingCartId, clientId, now), | ||
new ProductItemAddedToShoppingCart(shoppingCartId, pricedProductItem, now), | ||
new ShoppingCartConfirmed(shoppingCartId, now) | ||
]) | ||
.When(state => | ||
Handle(new CancelShoppingCart(shoppingCartId, now), state) | ||
) | ||
.ThenThrows<InvalidOperationException>(); | ||
|
||
private readonly DateTimeOffset now = DateTimeOffset.Now; | ||
private readonly Guid clientId = Guid.NewGuid(); | ||
private readonly Guid shoppingCartId = Guid.NewGuid(); | ||
private static readonly ProductItem ProductItem = new(Guid.NewGuid(), Random.Shared.Next(1, 200)); | ||
private static readonly ProductItem OtherProductItem = new(Guid.NewGuid(), Random.Shared.Next(1, 200)); | ||
private static readonly int Price = Random.Shared.Next(1, 1000); | ||
private static readonly int OtherPrice = Random.Shared.Next(1, 1000); | ||
private readonly PricedProductItem pricedProductItem = | ||
new(ProductItem.ProductId, ProductItem.Quantity, Price); | ||
private readonly PricedProductItem otherPricedProductItem = | ||
new(OtherProductItem.ProductId, OtherProductItem.Quantity, Price); | ||
|
||
|
||
private readonly HandlerSpecification<ShoppingCartEvent, ShoppingCart> Spec = | ||
Specification.For<ShoppingCartEvent, ShoppingCart>(ShoppingCart.Evolve, ShoppingCart.Initial); | ||
} |
24 changes: 24 additions & 0 deletions
24
...ntroductionToEventSourcing/Solved/07-BusinessLogic.Slimmed/Immutable/PricingCalculator.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
namespace IntroductionToEventSourcing.BusinessLogic.Slimmed.Immutable; | ||
|
||
public interface IProductPriceCalculator | ||
{ | ||
PricedProductItem Calculate(ProductItem productItems); | ||
} | ||
|
||
public class FakeProductPriceCalculator: IProductPriceCalculator | ||
{ | ||
private readonly int value; | ||
|
||
private FakeProductPriceCalculator(int value) | ||
{ | ||
this.value = value; | ||
} | ||
|
||
public static FakeProductPriceCalculator Returning(int value) => new(value); | ||
|
||
public PricedProductItem Calculate(ProductItem productItem) | ||
{ | ||
var (productId, quantity) = productItem; | ||
return new PricedProductItem(productId, quantity, value); | ||
} | ||
} |
Oops, something went wrong.