From 34ace01fbefdd8593c8873fba5c183149ad67bdf Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 6 Sep 2026 07:16:04 +0000 Subject: [PATCH 1/2] Validate menu item prices and ids on restaurant creation Co-Authored-By: Wes Convery <2wconvery@gmail.com> --- .../chrisrichardson/ftgo/common/Money.java | 4 ++ .../chrisrichardson/ftgo/domain/MenuItem.java | 14 +++++++ .../ftgo/domain/MenuItemPriceTest.java | 40 +++++++++++++++++++ .../domain/RestaurantService.java | 3 ++ 4 files changed, 61 insertions(+) create mode 100644 ftgo-domain/src/test/java/net/chrisrichardson/ftgo/domain/MenuItemPriceTest.java diff --git a/ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/Money.java b/ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/Money.java index 489bd4c63..e022129f4 100644 --- a/ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/Money.java +++ b/ftgo-common/src/main/java/net/chrisrichardson/ftgo/common/Money.java @@ -68,6 +68,10 @@ public boolean isGreaterThanOrEqual(Money other) { return amount.compareTo(other.amount) >= 0; } + public boolean isPositive() { + return amount.signum() > 0; + } + public String asString() { return amount.toPlainString(); } diff --git a/ftgo-domain/src/main/java/net/chrisrichardson/ftgo/domain/MenuItem.java b/ftgo-domain/src/main/java/net/chrisrichardson/ftgo/domain/MenuItem.java index 5186f0900..28dd22ec6 100644 --- a/ftgo-domain/src/main/java/net/chrisrichardson/ftgo/domain/MenuItem.java +++ b/ftgo-domain/src/main/java/net/chrisrichardson/ftgo/domain/MenuItem.java @@ -23,11 +23,24 @@ private MenuItem() { } public MenuItem(String id, String name, Money price) { + if (id == null || id.trim().isEmpty()) { + throw new IllegalArgumentException("Menu item id must not be blank"); + } + if (name == null || name.trim().isEmpty()) { + throw new IllegalArgumentException("Menu item name must not be blank: " + id); + } + requirePositivePrice(id, price); this.id = id; this.name = name; this.price = price; } + static void requirePositivePrice(String id, Money price) { + if (price == null || !price.isPositive()) { + throw new IllegalArgumentException("Menu item price must be greater than zero: " + id); + } + } + @Override public boolean equals(Object o) { return EqualsBuilder.reflectionEquals(this, o); @@ -64,6 +77,7 @@ public Money getPrice() { } public void setPrice(Money price) { + requirePositivePrice(id, price); this.price = price; } } diff --git a/ftgo-domain/src/test/java/net/chrisrichardson/ftgo/domain/MenuItemPriceTest.java b/ftgo-domain/src/test/java/net/chrisrichardson/ftgo/domain/MenuItemPriceTest.java new file mode 100644 index 000000000..286ce2ced --- /dev/null +++ b/ftgo-domain/src/test/java/net/chrisrichardson/ftgo/domain/MenuItemPriceTest.java @@ -0,0 +1,40 @@ +package net.chrisrichardson.ftgo.domain; + +import net.chrisrichardson.ftgo.common.Money; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class MenuItemPriceTest { + + @Test + public void shouldAcceptPositivePrice() { + MenuItem item = new MenuItem("1", "Chicken Vindaloo", new Money("12.34")); + assertEquals(new Money("12.34"), item.getPrice()); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldRejectNegativePrice() { + new MenuItem("1", "Refund", new Money("-500.00")); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldRejectZeroPrice() { + new MenuItem("1", "Free", Money.ZERO); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldRejectNullPrice() { + new MenuItem("1", "Missing", null); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldRejectBlankId() { + new MenuItem(" ", "Chicken Vindaloo", new Money("12.34")); + } + + @Test(expected = IllegalArgumentException.class) + public void shouldRejectNegativePriceOnUpdate() { + new MenuItem("1", "Chicken Vindaloo", new Money("12.34")).setPrice(new Money("-1")); + } +} diff --git a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java index 960050407..414426c34 100644 --- a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java +++ b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java @@ -25,6 +25,9 @@ public Restaurant create(CreateRestaurantRequest request) { } private RestaurantMenu makeRestaurantMenu(RestaurantMenuDTO menu) { + if (menu == null || menu.getMenuItemDTOs() == null || menu.getMenuItemDTOs().isEmpty()) { + throw new IllegalArgumentException("Restaurant menu must contain at least one item"); + } return new RestaurantMenu(menu.getMenuItemDTOs().stream().map(mi -> new MenuItem(mi.getId(), mi.getName(), mi.getPrice())).collect(Collectors.toList())); } From 49116c54de0c0c6a5250e466b49e38f176009c08 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 6 Sep 2026 07:18:33 +0000 Subject: [PATCH 2/2] Reject null menu entries on restaurant creation Co-Authored-By: Wes Convery <2wconvery@gmail.com> --- .../ftgo/restaurantservice/domain/RestaurantService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java index 414426c34..945c7a47f 100644 --- a/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java +++ b/ftgo-restaurant-service/src/main/java/net/chrisrichardson/ftgo/restaurantservice/domain/RestaurantService.java @@ -25,8 +25,9 @@ public Restaurant create(CreateRestaurantRequest request) { } private RestaurantMenu makeRestaurantMenu(RestaurantMenuDTO menu) { - if (menu == null || menu.getMenuItemDTOs() == null || menu.getMenuItemDTOs().isEmpty()) { - throw new IllegalArgumentException("Restaurant menu must contain at least one item"); + if (menu == null || menu.getMenuItemDTOs() == null || menu.getMenuItemDTOs().isEmpty() + || menu.getMenuItemDTOs().stream().anyMatch(mi -> mi == null)) { + throw new IllegalArgumentException("Restaurant menu must contain at least one valid item"); } return new RestaurantMenu(menu.getMenuItemDTOs().stream().map(mi -> new MenuItem(mi.getId(), mi.getName(), mi.getPrice())).collect(Collectors.toList())); }