Skip to content

Commit

Permalink
Slimmed down immutable exercise even more to follow Decider pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
oskardudycz committed May 3, 2024
1 parent 2331165 commit 3aa28e2
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 122 deletions.
Expand Up @@ -5,8 +5,7 @@
namespace IntroductionToEventSourcing.BusinessLogic.Slimmed.Immutable;

using static ShoppingCart.Event;
using static ShoppingCartCommand;
using static ShoppingCartService;
using static ShoppingCart.Command;
using static ShoppingCart;

public class BusinessLogicTests
Expand All @@ -15,20 +14,15 @@ public class BusinessLogicTests
[Fact]
public void OpensShoppingCart() =>
Spec.Given([])
.When(() => Decide(new Open(clientId, now), new Initial()))
.When(new Open(clientId, now))
.Then(new Opened(clientId, now));

// Add
[Fact]
public void CantAddProductItemToNotExistingShoppingCart() =>
Spec.Given([])
.When(state =>
Decide(
new AddProductItem(FakeProductPriceCalculator.Returning(Price).Calculate(ProductItem),
now
),
state
)
.When(
new AddProductItem(FakeProductPriceCalculator.Returning(Price).Calculate(ProductItem), now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -37,14 +31,7 @@ public class BusinessLogicTests
Spec.Given([
new Opened(clientId, now)
])
.When(state =>
Decide(
new AddProductItem(FakeProductPriceCalculator.Returning(Price).Calculate(ProductItem),
now
),
state
)
)
.When(new AddProductItem(FakeProductPriceCalculator.Returning(Price).Calculate(ProductItem), now))
.Then(
new ProductItemAdded(
new PricedProductItem(ProductItem.ProductId, ProductItem.Quantity, Price),
Expand All @@ -59,13 +46,8 @@ public class BusinessLogicTests
new Opened(clientId, now),
new ProductItemAdded(pricedProductItem, now),
])
.When(state =>
Decide(
new AddProductItem(FakeProductPriceCalculator.Returning(OtherPrice).Calculate(OtherProductItem),
now
),
state
)
.When(
new AddProductItem(FakeProductPriceCalculator.Returning(OtherPrice).Calculate(OtherProductItem), now)
)
.Then(
new ProductItemAdded(
Expand All @@ -81,13 +63,8 @@ public class BusinessLogicTests
new ProductItemAdded(pricedProductItem, now),
new Confirmed(now)
])
.When(state =>
Decide(
new AddProductItem(FakeProductPriceCalculator.Returning(Price).Calculate(ProductItem),
now
),
state
)
.When(
new AddProductItem(FakeProductPriceCalculator.Returning(Price).Calculate(ProductItem), now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -98,25 +75,17 @@ public class BusinessLogicTests
new ProductItemAdded(pricedProductItem, now),
new Canceled(now)
])
.When(state =>
Decide(
new AddProductItem(FakeProductPriceCalculator.Returning(Price).Calculate(ProductItem),
now
),
state
)
.When(
new AddProductItem(FakeProductPriceCalculator.Returning(Price).Calculate(ProductItem), now)
)
.ThenThrows<InvalidOperationException>();

// Remove
[Fact]
public void CantRemoveProductItemFromNotExistingShoppingCart() =>
Spec.Given([])
.When(state =>
Decide(
new RemoveProductItem(pricedProductItem, now),
state
)
.When(
new RemoveProductItem(pricedProductItem, now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -126,11 +95,8 @@ public class BusinessLogicTests
new Opened(clientId, now),
new ProductItemAdded(pricedProductItem, now),
])
.When(state =>
Decide(
new RemoveProductItem(pricedProductItem with { Quantity = 1 }, now),
state
)
.When(
new RemoveProductItem(pricedProductItem with { Quantity = 1 }, now)
)
.Then(
new ProductItemRemoved(
Expand All @@ -145,12 +111,8 @@ public class BusinessLogicTests
new Opened(clientId, now),
new ProductItemAdded(pricedProductItem, now),
])
.When(state =>
Decide(
new RemoveProductItem(otherPricedProductItem with { Quantity = 1 },
now),
state
)
.When(
new RemoveProductItem(otherPricedProductItem with { Quantity = 1 }, now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -161,11 +123,8 @@ public class BusinessLogicTests
new ProductItemAdded(pricedProductItem, now),
new Confirmed(now)
])
.When(state =>
Decide(
new RemoveProductItem(pricedProductItem with { Quantity = 1 }, now),
state
)
.When(
new RemoveProductItem(pricedProductItem with { Quantity = 1 }, now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -176,11 +135,8 @@ public class BusinessLogicTests
new ProductItemAdded(pricedProductItem, now),
new Canceled(now)
])
.When(state =>
Decide(
new RemoveProductItem(pricedProductItem with { Quantity = 1 }, now),
state
)
.When(
new RemoveProductItem(pricedProductItem with { Quantity = 1 }, now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -189,8 +145,8 @@ public class BusinessLogicTests
[Fact]
public void CantConfirmNotExistingShoppingCart() =>
Spec.Given([])
.When(state =>
Decide(new Confirm(now), state)
.When(
new Confirm(now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -200,8 +156,8 @@ public class BusinessLogicTests
Spec.Given([
new Opened(clientId, now),
])
.When(state =>
Decide(new Confirm(now), state)
.When(
new Confirm(now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -211,8 +167,8 @@ public class BusinessLogicTests
new Opened(clientId, now),
new ProductItemAdded(pricedProductItem, now),
])
.When(state =>
Decide(new Confirm(now), state)
.When(
new Confirm(now)
)
.Then(
new Confirmed(now)
Expand All @@ -225,8 +181,8 @@ public class BusinessLogicTests
new ProductItemAdded(pricedProductItem, now),
new Confirmed(now)
])
.When(state =>
Decide(new Confirm(now), state)
.When(
new Confirm(now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -237,8 +193,8 @@ public class BusinessLogicTests
new ProductItemAdded(pricedProductItem, now),
new Canceled(now)
])
.When(state =>
Decide(new Confirm(now), state)
.When(
new Confirm(now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -247,8 +203,8 @@ public class BusinessLogicTests
[Trait("Category", "SkipCI")]
public void CantCancelNotExistingShoppingCart() =>
Spec.Given([])
.When(state =>
Decide(new Cancel(now), state)
.When(
new Cancel(now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -257,8 +213,8 @@ public class BusinessLogicTests
Spec.Given([
new Opened(clientId, now),
])
.When(state =>
Decide(new Cancel(now), state)
.When(
new Cancel(now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -268,8 +224,8 @@ public class BusinessLogicTests
new Opened(clientId, now),
new ProductItemAdded(pricedProductItem, now),
])
.When(state =>
Decide(new Cancel(now), state)
.When(
new Cancel(now)
)
.Then(
new Canceled(now)
Expand All @@ -282,8 +238,8 @@ public class BusinessLogicTests
new ProductItemAdded(pricedProductItem, now),
new Canceled(now)
])
.When(state =>
Decide(new Cancel(now), state)
.When(
new Cancel(now)
)
.ThenThrows<InvalidOperationException>();

Expand All @@ -294,14 +250,13 @@ public class BusinessLogicTests
new ProductItemAdded(pricedProductItem, now),
new Confirmed(now)
])
.When(state =>
Decide(new Cancel(now), state)
.When(
new Cancel(now)
)
.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);
Expand All @@ -314,6 +269,6 @@ public class BusinessLogicTests
new(OtherProductItem.ProductId, OtherProductItem.Quantity, Price);


private readonly HandlerSpecification<Event, ShoppingCart> Spec =
Specification.For<ShoppingCart.Event, ShoppingCart>(Evolve, () => new Initial());
private readonly DeciderSpecification<Command, Event, ShoppingCart> Spec =
Specification.For<Command, Event, ShoppingCart>(Decide, Evolve, () => new Initial());
}
Expand Up @@ -6,7 +6,7 @@ namespace IntroductionToEventSourcing.BusinessLogic.Slimmed.Immutable;

// EVENTS

public abstract record ShoppingCart
public abstract partial record ShoppingCart
{
public abstract record Event
{
Expand Down
Expand Up @@ -3,40 +3,39 @@
namespace IntroductionToEventSourcing.BusinessLogic.Slimmed.Immutable;

using static ShoppingCart.Event;
using static ShoppingCartCommand;
using static ShoppingCart;
using static ShoppingCart.Command;

public abstract record ShoppingCartCommand
public partial record ShoppingCart
{
public record Open(
Guid ClientId,
DateTimeOffset Now
): ShoppingCartCommand;

public record AddProductItem(
PricedProductItem ProductItem,
DateTimeOffset Now
): ShoppingCartCommand;

public record RemoveProductItem(
PricedProductItem ProductItem,
DateTimeOffset Now
): ShoppingCartCommand;

public record Confirm(
DateTimeOffset Now
): ShoppingCartCommand;

public record Cancel(
DateTimeOffset Now
): ShoppingCartCommand;

private ShoppingCartCommand() { }
}

public static class ShoppingCartService
{
public static Event Decide(ShoppingCartCommand command, ShoppingCart state) =>
public abstract record Command
{
public record Open(
Guid ClientId,
DateTimeOffset Now
): Command;

public record AddProductItem(
PricedProductItem ProductItem,
DateTimeOffset Now
): Command;

public record RemoveProductItem(
PricedProductItem ProductItem,
DateTimeOffset Now
): Command;

public record Confirm(
DateTimeOffset Now
): Command;

public record Cancel(
DateTimeOffset Now
): Command;

private Command() { }
}

public static Event Decide(Command command, ShoppingCart state) =>
(state, command) switch
{
(Initial, Open(var clientId, var now)) =>
Expand All @@ -56,6 +55,7 @@ public static class ShoppingCartService
(Pending, Cancel(var now)) =>
new Canceled(now),

_ => throw new InvalidOperationException($"Cannot {command.GetType().Name} for {state.GetType().Name} shopping cart")
_ => throw new InvalidOperationException(
$"Cannot {command.GetType().Name} for {state.GetType().Name} shopping cart")
};
}

0 comments on commit 3aa28e2

Please sign in to comment.