Skip to content

Commit

Permalink
Added solutions (not yet refactored) for Slimmed Business logic
Browse files Browse the repository at this point in the history
  • Loading branch information
oskardudycz committed May 3, 2024
1 parent b12f3c2 commit f2dca14
Show file tree
Hide file tree
Showing 17 changed files with 1,942 additions and 0 deletions.
7 changes: 7 additions & 0 deletions EventSourcing.NetCore.sln
Expand Up @@ -467,6 +467,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "11-OptimisticConcurrency.Ev
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "07-BusinessLogic.Slimmed", "Workshops\IntroductionToEventSourcing\07-BusinessLogic.Slimmed\07-BusinessLogic.Slimmed.csproj", "{B7DBA2CE-DAA9-42C0-A967-E4B62297EC1D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "07-BusinessLogic.Slimmed", "Workshops\IntroductionToEventSourcing\Solved\07-BusinessLogic.Slimmed\07-BusinessLogic.Slimmed.csproj", "{6E19670C-0723-4458-B4E8-01E5C51DAD2C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1049,6 +1051,10 @@ Global
{B7DBA2CE-DAA9-42C0-A967-E4B62297EC1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7DBA2CE-DAA9-42C0-A967-E4B62297EC1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B7DBA2CE-DAA9-42C0-A967-E4B62297EC1D}.Release|Any CPU.Build.0 = Release|Any CPU
{6E19670C-0723-4458-B4E8-01E5C51DAD2C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6E19670C-0723-4458-B4E8-01E5C51DAD2C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E19670C-0723-4458-B4E8-01E5C51DAD2C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E19670C-0723-4458-B4E8-01E5C51DAD2C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1241,6 +1247,7 @@ Global
{7829C11A-59AF-4C10-A679-312B8940A68D} = {14C7B928-9D6C-441A-8A1F-0C49173E73EB}
{37E05147-F579-458D-9B4F-25B54AC078DE} = {14C7B928-9D6C-441A-8A1F-0C49173E73EB}
{B7DBA2CE-DAA9-42C0-A967-E4B62297EC1D} = {14C7B928-9D6C-441A-8A1F-0C49173E73EB}
{6E19670C-0723-4458-B4E8-01E5C51DAD2C} = {65F6E2BE-B2D4-4E56-B0CB-3062C4882B9E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A5F55604-2FF3-43B7-B657-4F18E6E95D3B}
Expand Down
@@ -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>
@@ -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);
}
@@ -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);
}
}

0 comments on commit f2dca14

Please sign in to comment.