From 9158a59350ad98a626d3b88825ac0aa48fc9af91 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:11:40 +0000 Subject: [PATCH 1/7] Initial plan From 5419d3abe30f3d4fb2c8e5e5cdf37e8bbec9f6bd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:15:25 +0000 Subject: [PATCH 2/7] Clean up magic strings in Python, Java, C#, and TypeScript implementations Co-authored-by: nstubbe <20206435+nstubbe@users.noreply.github.com> --- csharp-ms/SupermarketReceipt/ShoppingCart.cs | 8 ++++++-- csharp/SupermarketReceipt/ShoppingCart.cs | 8 ++++++-- .../java/dojo/supermarket/model/ShoppingCart.java | 8 ++++++-- python/shopping_cart.py | 13 +++++++++---- python_pytest/src/shopping_cart.py | 13 +++++++++---- typescript/src/model/ShoppingCart.ts | 8 ++++++-- 6 files changed, 42 insertions(+), 16 deletions(-) diff --git a/csharp-ms/SupermarketReceipt/ShoppingCart.cs b/csharp-ms/SupermarketReceipt/ShoppingCart.cs index 28abbe7..111ea7f 100644 --- a/csharp-ms/SupermarketReceipt/ShoppingCart.cs +++ b/csharp-ms/SupermarketReceipt/ShoppingCart.cs @@ -4,6 +4,10 @@ namespace SupermarketReceipt { public class ShoppingCart { + // Discount description constants + private const string THREE_FOR_TWO_DESCRIPTION = "3 for 2"; + private const string PERCENT_OFF_SUFFIX = "% off"; + private readonly List _items = new List(); private readonly Dictionary _productQuantities = new Dictionary(); @@ -65,10 +69,10 @@ public void HandleOffers(Receipt receipt, Dictionary offers, Sup if (offer.OfferType == SpecialOfferType.ThreeForTwo && quantityAsInt > 2) { var discountAmount = quantity * unitPrice - (numberOfXs * 2 * unitPrice + quantityAsInt % 3 * unitPrice); - discount = new Discount(p, "3 for 2", -discountAmount); + discount = new Discount(p, THREE_FOR_TWO_DESCRIPTION, -discountAmount); } - if (offer.OfferType == SpecialOfferType.TenPercentDiscount) discount = new Discount(p, offer.Argument + "% off", -quantity * unitPrice * offer.Argument / 100.0); + if (offer.OfferType == SpecialOfferType.TenPercentDiscount) discount = new Discount(p, offer.Argument + PERCENT_OFF_SUFFIX, -quantity * unitPrice * offer.Argument / 100.0); if (offer.OfferType == SpecialOfferType.FiveForAmount && quantityAsInt >= 5) { var discountTotal = unitPrice * quantity - (offer.Argument * numberOfXs + quantityAsInt % 5 * unitPrice); diff --git a/csharp/SupermarketReceipt/ShoppingCart.cs b/csharp/SupermarketReceipt/ShoppingCart.cs index 72b6b4a..0e346af 100644 --- a/csharp/SupermarketReceipt/ShoppingCart.cs +++ b/csharp/SupermarketReceipt/ShoppingCart.cs @@ -5,6 +5,10 @@ namespace SupermarketReceipt { public class ShoppingCart { + // Discount description constants + private const string THREE_FOR_TWO_DESCRIPTION = "3 for 2"; + private const string PERCENT_OFF_SUFFIX = "% off"; + private readonly List _items = new List(); private readonly Dictionary _productQuantities = new Dictionary(); private static readonly CultureInfo Culture = CultureInfo.CreateSpecificCulture("en-GB"); @@ -67,10 +71,10 @@ public void HandleOffers(Receipt receipt, Dictionary offers, Sup if (offer.OfferType == SpecialOfferType.ThreeForTwo && quantityAsInt > 2) { var discountAmount = quantity * unitPrice - (numberOfXs * 2 * unitPrice + quantityAsInt % 3 * unitPrice); - discount = new Discount(p, "3 for 2", -discountAmount); + discount = new Discount(p, THREE_FOR_TWO_DESCRIPTION, -discountAmount); } - if (offer.OfferType == SpecialOfferType.TenPercentDiscount) discount = new Discount(p, offer.Argument + "% off", -quantity * unitPrice * offer.Argument / 100.0); + if (offer.OfferType == SpecialOfferType.TenPercentDiscount) discount = new Discount(p, offer.Argument + PERCENT_OFF_SUFFIX, -quantity * unitPrice * offer.Argument / 100.0); if (offer.OfferType == SpecialOfferType.FiveForAmount && quantityAsInt >= 5) { var discountTotal = unitPrice * quantity - (offer.Argument * numberOfXs + quantityAsInt % 5 * unitPrice); diff --git a/java/src/main/java/dojo/supermarket/model/ShoppingCart.java b/java/src/main/java/dojo/supermarket/model/ShoppingCart.java index 9293086..c988c91 100644 --- a/java/src/main/java/dojo/supermarket/model/ShoppingCart.java +++ b/java/src/main/java/dojo/supermarket/model/ShoppingCart.java @@ -8,6 +8,10 @@ public class ShoppingCart { + // Discount description constants + private static final String THREE_FOR_TWO_DESCRIPTION = "3 for 2"; + private static final String PERCENT_OFF_SUFFIX = "% off"; + private final List items = new ArrayList<>(); private final Map productQuantities = new HashMap<>(); @@ -58,10 +62,10 @@ void handleOffers(Receipt receipt, Map offers, SupermarketCatalo int numberOfXs = quantityAsInt / x; if (offer.offerType == SpecialOfferType.THREE_FOR_TWO && quantityAsInt > 2) { double discountAmount = quantity * unitPrice - ((numberOfXs * 2 * unitPrice) + quantityAsInt % 3 * unitPrice); - discount = new Discount(p, "3 for 2", -discountAmount); + discount = new Discount(p, THREE_FOR_TWO_DESCRIPTION, -discountAmount); } if (offer.offerType == SpecialOfferType.TEN_PERCENT_DISCOUNT) { - discount = new Discount(p, offer.argument + "% off", -quantity * unitPrice * offer.argument / 100.0); + discount = new Discount(p, offer.argument + PERCENT_OFF_SUFFIX, -quantity * unitPrice * offer.argument / 100.0); } if (offer.offerType == SpecialOfferType.FIVE_FOR_AMOUNT && quantityAsInt >= 5) { double discountTotal = unitPrice * quantity - (offer.argument * numberOfXs + quantityAsInt % 5 * unitPrice); diff --git a/python/shopping_cart.py b/python/shopping_cart.py index 4e36cc5..7572d3d 100644 --- a/python/shopping_cart.py +++ b/python/shopping_cart.py @@ -3,6 +3,11 @@ from model_objects import ProductQuantity, SpecialOfferType, Discount +# Discount description constants +THREE_FOR_TWO_DESCRIPTION = "3 for 2" +PERCENT_OFF_SUFFIX = "% off" + + class ShoppingCart: def __init__(self): @@ -44,7 +49,7 @@ def handle_offers(self, receipt, offers, catalog): if quantity_as_int >= 2: total = offer.argument * (quantity_as_int / x) + quantity_as_int % 2 * unit_price discount_n = unit_price * quantity - total - discount = Discount(p, "2 for " + str(offer.argument), -discount_n) + discount = Discount(p, f"2 for {offer.argument}", -discount_n) if offer.offer_type == SpecialOfferType.FIVE_FOR_AMOUNT: x = 5 @@ -53,16 +58,16 @@ def handle_offers(self, receipt, offers, catalog): if offer.offer_type == SpecialOfferType.THREE_FOR_TWO and quantity_as_int > 2: discount_amount = quantity * unit_price - ( (number_of_x * 2 * unit_price) + quantity_as_int % 3 * unit_price) - discount = Discount(p, "3 for 2", -discount_amount) + discount = Discount(p, THREE_FOR_TWO_DESCRIPTION, -discount_amount) if offer.offer_type == SpecialOfferType.TEN_PERCENT_DISCOUNT: - discount = Discount(p, str(offer.argument) + "% off", + discount = Discount(p, f"{offer.argument}{PERCENT_OFF_SUFFIX}", -quantity * unit_price * offer.argument / 100.0) if offer.offer_type == SpecialOfferType.FIVE_FOR_AMOUNT and quantity_as_int >= 5: discount_total = unit_price * quantity - ( offer.argument * number_of_x + quantity_as_int % 5 * unit_price) - discount = Discount(p, str(x) + " for " + str(offer.argument), -discount_total) + discount = Discount(p, f"{x} for {offer.argument}", -discount_total) if discount: receipt.add_discount(discount) diff --git a/python_pytest/src/shopping_cart.py b/python_pytest/src/shopping_cart.py index 4e36cc5..7572d3d 100644 --- a/python_pytest/src/shopping_cart.py +++ b/python_pytest/src/shopping_cart.py @@ -3,6 +3,11 @@ from model_objects import ProductQuantity, SpecialOfferType, Discount +# Discount description constants +THREE_FOR_TWO_DESCRIPTION = "3 for 2" +PERCENT_OFF_SUFFIX = "% off" + + class ShoppingCart: def __init__(self): @@ -44,7 +49,7 @@ def handle_offers(self, receipt, offers, catalog): if quantity_as_int >= 2: total = offer.argument * (quantity_as_int / x) + quantity_as_int % 2 * unit_price discount_n = unit_price * quantity - total - discount = Discount(p, "2 for " + str(offer.argument), -discount_n) + discount = Discount(p, f"2 for {offer.argument}", -discount_n) if offer.offer_type == SpecialOfferType.FIVE_FOR_AMOUNT: x = 5 @@ -53,16 +58,16 @@ def handle_offers(self, receipt, offers, catalog): if offer.offer_type == SpecialOfferType.THREE_FOR_TWO and quantity_as_int > 2: discount_amount = quantity * unit_price - ( (number_of_x * 2 * unit_price) + quantity_as_int % 3 * unit_price) - discount = Discount(p, "3 for 2", -discount_amount) + discount = Discount(p, THREE_FOR_TWO_DESCRIPTION, -discount_amount) if offer.offer_type == SpecialOfferType.TEN_PERCENT_DISCOUNT: - discount = Discount(p, str(offer.argument) + "% off", + discount = Discount(p, f"{offer.argument}{PERCENT_OFF_SUFFIX}", -quantity * unit_price * offer.argument / 100.0) if offer.offer_type == SpecialOfferType.FIVE_FOR_AMOUNT and quantity_as_int >= 5: discount_total = unit_price * quantity - ( offer.argument * number_of_x + quantity_as_int % 5 * unit_price) - discount = Discount(p, str(x) + " for " + str(offer.argument), -discount_total) + discount = Discount(p, f"{x} for {offer.argument}", -discount_total) if discount: receipt.add_discount(discount) diff --git a/typescript/src/model/ShoppingCart.ts b/typescript/src/model/ShoppingCart.ts index ac090cc..70edc78 100644 --- a/typescript/src/model/ShoppingCart.ts +++ b/typescript/src/model/ShoppingCart.ts @@ -7,6 +7,10 @@ import {Receipt} from "./Receipt" import {Offer} from "./Offer" import {SpecialOfferType} from "./SpecialOfferType" +// Discount description constants +const THREE_FOR_TWO_DESCRIPTION = "3 for 2"; +const PERCENT_OFF_SUFFIX = "% off"; + type ProductQuantities = { [productName: string]: ProductQuantity } export type OffersByProduct = {[productName: string]: Offer}; @@ -73,10 +77,10 @@ export class ShoppingCart { const numberOfXs = Math.floor(quantityAsInt / x); if (offer.offerType == SpecialOfferType.ThreeForTwo && quantityAsInt > 2) { const discountAmount = quantity * unitPrice - ((numberOfXs * 2 * unitPrice) + quantityAsInt % 3 * unitPrice); - discount = new Discount(product, "3 for 2", discountAmount); + discount = new Discount(product, THREE_FOR_TWO_DESCRIPTION, discountAmount); } if (offer.offerType == SpecialOfferType.TenPercentDiscount) { - discount = new Discount(product, offer.argument + "% off", quantity * unitPrice * offer.argument / 100.0); + discount = new Discount(product, offer.argument + PERCENT_OFF_SUFFIX, quantity * unitPrice * offer.argument / 100.0); } if (offer.offerType == SpecialOfferType.FiveForAmount && quantityAsInt >= 5) { const discountTotal = unitPrice * quantity - (offer.argument * numberOfXs + quantityAsInt % 5 * unitPrice); From cccbd171771a7e5e88324cead508aacffcaf4306 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:17:38 +0000 Subject: [PATCH 3/7] Clean up magic strings in Go, Ruby, Elixir, Lisp, Kotlin, PHP, Swift, and C++ implementations Co-authored-by: nstubbe <20206435+nstubbe@users.noreply.github.com> --- common-lisp/source/shopping-cart.lisp | 8 ++++++-- cpp/src/ShoppingCart.cpp | 8 ++++++-- elixir/lib/supermarket/model/shopping_cart.ex | 8 ++++++-- go/supermarket/shopping_cart.go | 10 ++++++++-- .../src/main/kotlin/supermarket/model/ShoppingCart.kt | 10 ++++++++-- php/src/Model/ShoppingCart.php | 8 ++++++-- ruby/lib/models/shopping_cart.rb | 8 ++++++-- swift/SupermarketReceipt/ShoppingCart.swift | 8 ++++++-- 8 files changed, 52 insertions(+), 16 deletions(-) diff --git a/common-lisp/source/shopping-cart.lisp b/common-lisp/source/shopping-cart.lisp index 51631a2..10eedde 100644 --- a/common-lisp/source/shopping-cart.lisp +++ b/common-lisp/source/shopping-cart.lisp @@ -2,6 +2,10 @@ (in-package :supermarket-receipt) +;; Discount description constants +(defconstant +three-for-two-description+ "3 for 2") +(defconstant +percent-off-suffix+ " % off") + (defclass shopping-cart () ((items :initform nil :type list @@ -56,12 +60,12 @@ (* (mod floored-quantity 3) a-unit-price))))) (setf a-discount (make-instance 'discount :product a-product - :description "3 for 2" + :description +three-for-two-description+ :amount (- discount-amount))))) (when (eq the-offer-type 'ten-percent-discount) (setf a-discount (make-instance 'discount :product a-product - :description (format nil "~S % off" (offer-argument offer-for-product)) + :description (format nil "~S~A" (offer-argument offer-for-product) +percent-off-suffix+) :amount (/ (* (- a-quantity) a-unit-price (offer-argument offer-for-product)) 100.0)))) (when (and (eq the-offer-type 'five-for-amount) (>= floored-quantity 5)) diff --git a/cpp/src/ShoppingCart.cpp b/cpp/src/ShoppingCart.cpp index 3c3a523..1871f44 100644 --- a/cpp/src/ShoppingCart.cpp +++ b/cpp/src/ShoppingCart.cpp @@ -1,5 +1,9 @@ #include "ShoppingCart.h" +// Discount description constants +static const std::string THREE_FOR_TWO_DESCRIPTION = "3 for 2"; +static const std::string PERCENT_OFF_SUFFIX = "% off"; + void addItemQuantity(const Product& product, double quantity); std::vector ShoppingCart::getItems() const { @@ -49,10 +53,10 @@ void ShoppingCart::handleOffers(Receipt& receipt, std::map offer int numberOfXs = quantityAsInt / x; if (offer.getOfferType() == SpecialOfferType::ThreeForTwo && quantityAsInt > 2) { double discountAmount = quantity * unitPrice - ((numberOfXs * 2 * unitPrice) + quantityAsInt % 3 * unitPrice); - discount = new Discount("3 for 2", -discountAmount, product); + discount = new Discount(THREE_FOR_TWO_DESCRIPTION, -discountAmount, product); } if (offer.getOfferType() == SpecialOfferType::TenPercentDiscount) { - discount = new Discount(std::to_string(offer.getArgument()) + "% off", -quantity * unitPrice * offer.getArgument() / 100.0, product); + discount = new Discount(std::to_string(offer.getArgument()) + PERCENT_OFF_SUFFIX, -quantity * unitPrice * offer.getArgument() / 100.0, product); } if (offer.getOfferType() == SpecialOfferType::FiveForAmount && quantityAsInt >= 5) { double discountTotal = unitPrice * quantity - (offer.getArgument() * numberOfXs + quantityAsInt % 5 * unitPrice); diff --git a/elixir/lib/supermarket/model/shopping_cart.ex b/elixir/lib/supermarket/model/shopping_cart.ex index b0fc089..8c55f55 100644 --- a/elixir/lib/supermarket/model/shopping_cart.ex +++ b/elixir/lib/supermarket/model/shopping_cart.ex @@ -5,6 +5,10 @@ defmodule Supermarket.Model.ShoppingCart do alias Supermarket.Model.Receipt alias Supermarket.Model.SupermarketCatalog + # Discount description constants + @three_for_two_description "3 for 2" + @percent_off_suffix "% off" + defstruct [:items, :product_quantities] def new, do: %__MODULE__{items: [], product_quantities: %{}} @@ -70,12 +74,12 @@ defmodule Supermarket.Model.ShoppingCart do quantity * unit_price - (number_of_xs * 2 * unit_price + Integer.mod(quantity_as_int, 3) * unit_price) - Discount.new(p, "3 for 2", -discount_amount) + Discount.new(p, @three_for_two_description, -discount_amount) offer.offer_type == :ten_percent_discount -> Discount.new( p, - "#{offer.argument}% off", + "#{offer.argument}#{@percent_off_suffix}", -quantity * unit_price * offer.argument / 100.0 ) diff --git a/go/supermarket/shopping_cart.go b/go/supermarket/shopping_cart.go index 3079f92..9ddf569 100644 --- a/go/supermarket/shopping_cart.go +++ b/go/supermarket/shopping_cart.go @@ -5,6 +5,12 @@ import ( "math" ) +// Discount description constants +const ( + threeForTwoDescription = "3 for 2" + percentOffSuffix = " %% off" +) + type ProductQuantity struct { product Product quantity float64 @@ -62,10 +68,10 @@ func (c *ShoppingCart) handleOffers(receipt *Receipt, offers map[Product]Special var numberOfXs int = quantityAsInt / x; if offer.offerType == ThreeForTwo && quantityAsInt > 2 { var discountAmount = quantity * unitPrice - (float64(numberOfXs * 2) * unitPrice + float64(quantityAsInt % 3) * unitPrice) - discount = &Discount{product: p, description: "3 for 2", discountAmount: -discountAmount} + discount = &Discount{product: p, description: threeForTwoDescription, discountAmount: -discountAmount} } if offer.offerType == TenPercentDiscount { - discount = &Discount{product: p, description: fmt.Sprintf("%.0f %% off", offer.argument), discountAmount: -quantity * unitPrice * offer.argument / 100.0} + discount = &Discount{product: p, description: fmt.Sprintf("%.0f", offer.argument) + percentOffSuffix, discountAmount: -quantity * unitPrice * offer.argument / 100.0} } if offer.offerType == FiveForAmount && quantityAsInt >= 5 { var discountTotal = unitPrice * quantity - (offer.argument * float64(numberOfXs) + float64(quantityAsInt % 5) * unitPrice) diff --git a/kotlin/src/main/kotlin/supermarket/model/ShoppingCart.kt b/kotlin/src/main/kotlin/supermarket/model/ShoppingCart.kt index 83e7f30..04a5781 100644 --- a/kotlin/src/main/kotlin/supermarket/model/ShoppingCart.kt +++ b/kotlin/src/main/kotlin/supermarket/model/ShoppingCart.kt @@ -5,6 +5,12 @@ import java.util.HashMap class ShoppingCart { + // Discount description constants + companion object { + private const val THREE_FOR_TWO_DESCRIPTION = "3 for 2" + private const val PERCENT_OFF_SUFFIX = "% off" + } + private val items = ArrayList() internal var productQuantities: MutableMap = HashMap() @@ -59,11 +65,11 @@ class ShoppingCart { if (offer.offerType === SpecialOfferType.ThreeForTwo && quantityAsInt > 2) { val discountAmount = quantity * unitPrice - (numberOfXs.toDouble() * 2.0 * unitPrice + quantityAsInt % 3 * unitPrice) - discount = Discount(p, "3 for 2", discountAmount) + discount = Discount(p, THREE_FOR_TWO_DESCRIPTION, discountAmount) } if (offer.offerType === SpecialOfferType.TenPercentDiscount) { discount = - Discount(p, offer.argument.toString() + "% off", quantity * unitPrice * offer.argument / 100.0) + Discount(p, offer.argument.toString() + PERCENT_OFF_SUFFIX, quantity * unitPrice * offer.argument / 100.0) } if (offer.offerType === SpecialOfferType.FiveForAmount && quantityAsInt >= 5) { val discountTotal = diff --git a/php/src/Model/ShoppingCart.php b/php/src/Model/ShoppingCart.php index d2f6c78..929f7aa 100644 --- a/php/src/Model/ShoppingCart.php +++ b/php/src/Model/ShoppingCart.php @@ -8,6 +8,10 @@ class ShoppingCart { + // Discount description constants + private const THREE_FOR_TWO_DESCRIPTION = '3 for 2'; + private const PERCENT_OFF_SUFFIX = '% off'; + /** * @var ProductQuantity[] */ @@ -81,13 +85,13 @@ public function handleOffers(Receipt $receipt, Map $offers, SupermarketCatalog $ $numberOfXs = intdiv($quantityAsInt, $x); if ($offer->getOfferType()->equals(SpecialOfferType::THREE_FOR_TWO()) && $quantityAsInt > 2) { $discountAmount = $quantity * $unitPrice - ($numberOfXs * 2 * $unitPrice + $quantityAsInt % 3 * $unitPrice); - $discount = new Discount($p, '3 for 2', -$discountAmount); + $discount = new Discount($p, self::THREE_FOR_TWO_DESCRIPTION, -$discountAmount); } if ($offer->getOfferType()->equals(SpecialOfferType::TEN_PERCENT_DISCOUNT())) { $discount = new Discount( $p, - "{$offer->getArgument()}% off", + "{$offer->getArgument()}" . self::PERCENT_OFF_SUFFIX, -$quantity * $unitPrice * $offer->getArgument() / 100.0 ); } diff --git a/ruby/lib/models/shopping_cart.rb b/ruby/lib/models/shopping_cart.rb index 6eea42e..e4d7f08 100644 --- a/ruby/lib/models/shopping_cart.rb +++ b/ruby/lib/models/shopping_cart.rb @@ -1,5 +1,9 @@ class ShoppingCart + # Discount description constants + THREE_FOR_TWO_DESCRIPTION = "3 for 2" + PERCENT_OFF_SUFFIX = "% off" + def initialize @items = [] @product_quantities = {} @@ -54,10 +58,10 @@ def handle_offers(receipt, offers, catalog) number_of_x = quantity_as_int / x if offer.offer_type == SpecialOfferType::THREE_FOR_TWO && quantity_as_int > 2 discount_amount = quantity * unit_price - ((number_of_x * 2 * unit_price) + quantity_as_int % 3 * unit_price) - discount = Discount.new(p, "3 for 2", discount_amount) + discount = Discount.new(p, THREE_FOR_TWO_DESCRIPTION, discount_amount) end if offer.offer_type == SpecialOfferType::TEN_PERCENT_DISCOUNT - discount = Discount.new(p, offer.argument.to_s + "% off", quantity * unit_price * offer.argument / 100.0) + discount = Discount.new(p, offer.argument.to_s + PERCENT_OFF_SUFFIX, quantity * unit_price * offer.argument / 100.0) end if offer.offer_type == SpecialOfferType::FIVE_FOR_AMOUNT && quantity_as_int >= 5 discount_total = unit_price * quantity - (offer.argument * number_of_x + quantity_as_int % 5 * unit_price) diff --git a/swift/SupermarketReceipt/ShoppingCart.swift b/swift/SupermarketReceipt/ShoppingCart.swift index d34c8bc..f2fa1ac 100644 --- a/swift/SupermarketReceipt/ShoppingCart.swift +++ b/swift/SupermarketReceipt/ShoppingCart.swift @@ -1,5 +1,9 @@ public class ShoppingCart { + // Discount description constants + private static let threeForTwoDescription = "3 for 2" + private static let percentOffSuffix = "% off" + public var items = [ProductQuantity]() public var productQuantities = [Product: Double]() @@ -52,10 +56,10 @@ public class ShoppingCart { var right = Double(quantityAsInt % 3) * unitPrice var lastPart = left + right var discountAmount = ((quantity ?? 1) * unitPrice) - lastPart - discount = Discount(description: "3 for 2", discountAmount: discountAmount, product: p) + discount = Discount(description: ShoppingCart.threeForTwoDescription, discountAmount: discountAmount, product: p) } if offer?.offerType == SpecialOfferType.TenPercentDiscount { - discount = Discount(description: "\(offer!.argument)% off", discountAmount: (quantity ?? 1) * unitPrice * (offer?.argument ?? 1) / 100.0, product: p) + discount = Discount(description: "\(offer!.argument)\(ShoppingCart.percentOffSuffix)", discountAmount: (quantity ?? 1) * unitPrice * (offer?.argument ?? 1) / 100.0, product: p) } if offer?.offerType == SpecialOfferType.FiveForAmount && quantityAsInt >= 5 { var left = (unitPrice * (quantity ?? 1)) From 1fa30ed32aea1e360e1fb4b9dd33310c9efa91c3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:19:55 +0000 Subject: [PATCH 4/7] Fix spacing consistency in Go and Common Lisp discount descriptions Co-authored-by: nstubbe <20206435+nstubbe@users.noreply.github.com> --- common-lisp/source/shopping-cart.lisp | 4 ++-- go/supermarket/shopping_cart.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/common-lisp/source/shopping-cart.lisp b/common-lisp/source/shopping-cart.lisp index 10eedde..dcc99db 100644 --- a/common-lisp/source/shopping-cart.lisp +++ b/common-lisp/source/shopping-cart.lisp @@ -4,7 +4,7 @@ ;; Discount description constants (defconstant +three-for-two-description+ "3 for 2") -(defconstant +percent-off-suffix+ " % off") +(defconstant +percent-off-suffix+ "% off") (defclass shopping-cart () ((items :initform nil @@ -65,7 +65,7 @@ (when (eq the-offer-type 'ten-percent-discount) (setf a-discount (make-instance 'discount :product a-product - :description (format nil "~S~A" (offer-argument offer-for-product) +percent-off-suffix+) + :description (format nil "~S ~A" (offer-argument offer-for-product) +percent-off-suffix+) :amount (/ (* (- a-quantity) a-unit-price (offer-argument offer-for-product)) 100.0)))) (when (and (eq the-offer-type 'five-for-amount) (>= floored-quantity 5)) diff --git a/go/supermarket/shopping_cart.go b/go/supermarket/shopping_cart.go index 9ddf569..2e7ddf4 100644 --- a/go/supermarket/shopping_cart.go +++ b/go/supermarket/shopping_cart.go @@ -8,7 +8,7 @@ import ( // Discount description constants const ( threeForTwoDescription = "3 for 2" - percentOffSuffix = " %% off" + percentOffSuffix = "%% off" ) type ProductQuantity struct { @@ -71,7 +71,7 @@ func (c *ShoppingCart) handleOffers(receipt *Receipt, offers map[Product]Special discount = &Discount{product: p, description: threeForTwoDescription, discountAmount: -discountAmount} } if offer.offerType == TenPercentDiscount { - discount = &Discount{product: p, description: fmt.Sprintf("%.0f", offer.argument) + percentOffSuffix, discountAmount: -quantity * unitPrice * offer.argument / 100.0} + discount = &Discount{product: p, description: fmt.Sprintf("%.0f", offer.argument) + " " + percentOffSuffix, discountAmount: -quantity * unitPrice * offer.argument / 100.0} } if offer.offerType == FiveForAmount && quantityAsInt >= 5 { var discountTotal = unitPrice * quantity - (offer.argument * float64(numberOfXs) + float64(quantityAsInt % 5) * unitPrice) From 4a7e2b82d309bf068c7efd21ff6a0e87cbeea3d6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:21:11 +0000 Subject: [PATCH 5/7] Fix Go and Common Lisp formatting for percent off suffix Co-authored-by: nstubbe <20206435+nstubbe@users.noreply.github.com> --- common-lisp/source/shopping-cart.lisp | 2 +- go/supermarket/shopping_cart.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common-lisp/source/shopping-cart.lisp b/common-lisp/source/shopping-cart.lisp index dcc99db..53c68b1 100644 --- a/common-lisp/source/shopping-cart.lisp +++ b/common-lisp/source/shopping-cart.lisp @@ -65,7 +65,7 @@ (when (eq the-offer-type 'ten-percent-discount) (setf a-discount (make-instance 'discount :product a-product - :description (format nil "~S ~A" (offer-argument offer-for-product) +percent-off-suffix+) + :description (format nil "~A ~A" (offer-argument offer-for-product) +percent-off-suffix+) :amount (/ (* (- a-quantity) a-unit-price (offer-argument offer-for-product)) 100.0)))) (when (and (eq the-offer-type 'five-for-amount) (>= floored-quantity 5)) diff --git a/go/supermarket/shopping_cart.go b/go/supermarket/shopping_cart.go index 2e7ddf4..7fbe8aa 100644 --- a/go/supermarket/shopping_cart.go +++ b/go/supermarket/shopping_cart.go @@ -8,7 +8,7 @@ import ( // Discount description constants const ( threeForTwoDescription = "3 for 2" - percentOffSuffix = "%% off" + percentOffSuffix = "% off" ) type ProductQuantity struct { @@ -71,7 +71,7 @@ func (c *ShoppingCart) handleOffers(receipt *Receipt, offers map[Product]Special discount = &Discount{product: p, description: threeForTwoDescription, discountAmount: -discountAmount} } if offer.offerType == TenPercentDiscount { - discount = &Discount{product: p, description: fmt.Sprintf("%.0f", offer.argument) + " " + percentOffSuffix, discountAmount: -quantity * unitPrice * offer.argument / 100.0} + discount = &Discount{product: p, description: fmt.Sprintf("%.0f %s", offer.argument, percentOffSuffix), discountAmount: -quantity * unitPrice * offer.argument / 100.0} } if offer.offerType == FiveForAmount && quantityAsInt >= 5 { var discountTotal = unitPrice * quantity - (offer.argument * float64(numberOfXs) + float64(quantityAsInt % 5) * unitPrice) From 93bc23df41673ae1c8ec97124dea107bcca7f9eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:23:29 +0000 Subject: [PATCH 6/7] Add leading space to percent off suffix constants for consistent formatting Co-authored-by: nstubbe <20206435+nstubbe@users.noreply.github.com> --- common-lisp/source/shopping-cart.lisp | 4 ++-- cpp/src/ShoppingCart.cpp | 2 +- csharp-ms/SupermarketReceipt/ShoppingCart.cs | 2 +- csharp/SupermarketReceipt/ShoppingCart.cs | 2 +- elixir/lib/supermarket/model/shopping_cart.ex | 2 +- go/supermarket/shopping_cart.go | 4 ++-- java/src/main/java/dojo/supermarket/model/ShoppingCart.java | 2 +- kotlin/src/main/kotlin/supermarket/model/ShoppingCart.kt | 2 +- php/src/Model/ShoppingCart.php | 2 +- python/shopping_cart.py | 2 +- python_pytest/src/shopping_cart.py | 2 +- ruby/lib/models/shopping_cart.rb | 2 +- swift/SupermarketReceipt/ShoppingCart.swift | 2 +- typescript/src/model/ShoppingCart.ts | 2 +- 14 files changed, 16 insertions(+), 16 deletions(-) diff --git a/common-lisp/source/shopping-cart.lisp b/common-lisp/source/shopping-cart.lisp index 53c68b1..1167c78 100644 --- a/common-lisp/source/shopping-cart.lisp +++ b/common-lisp/source/shopping-cart.lisp @@ -4,7 +4,7 @@ ;; Discount description constants (defconstant +three-for-two-description+ "3 for 2") -(defconstant +percent-off-suffix+ "% off") +(defconstant +percent-off-suffix+ " % off") (defclass shopping-cart () ((items :initform nil @@ -65,7 +65,7 @@ (when (eq the-offer-type 'ten-percent-discount) (setf a-discount (make-instance 'discount :product a-product - :description (format nil "~A ~A" (offer-argument offer-for-product) +percent-off-suffix+) + :description (format nil "~A~A" (offer-argument offer-for-product) +percent-off-suffix+) :amount (/ (* (- a-quantity) a-unit-price (offer-argument offer-for-product)) 100.0)))) (when (and (eq the-offer-type 'five-for-amount) (>= floored-quantity 5)) diff --git a/cpp/src/ShoppingCart.cpp b/cpp/src/ShoppingCart.cpp index 1871f44..5834f35 100644 --- a/cpp/src/ShoppingCart.cpp +++ b/cpp/src/ShoppingCart.cpp @@ -2,7 +2,7 @@ // Discount description constants static const std::string THREE_FOR_TWO_DESCRIPTION = "3 for 2"; -static const std::string PERCENT_OFF_SUFFIX = "% off"; +static const std::string PERCENT_OFF_SUFFIX = " % off"; void addItemQuantity(const Product& product, double quantity); diff --git a/csharp-ms/SupermarketReceipt/ShoppingCart.cs b/csharp-ms/SupermarketReceipt/ShoppingCart.cs index 111ea7f..05c7d88 100644 --- a/csharp-ms/SupermarketReceipt/ShoppingCart.cs +++ b/csharp-ms/SupermarketReceipt/ShoppingCart.cs @@ -6,7 +6,7 @@ public class ShoppingCart { // Discount description constants private const string THREE_FOR_TWO_DESCRIPTION = "3 for 2"; - private const string PERCENT_OFF_SUFFIX = "% off"; + private const string PERCENT_OFF_SUFFIX = " % off"; private readonly List _items = new List(); private readonly Dictionary _productQuantities = new Dictionary(); diff --git a/csharp/SupermarketReceipt/ShoppingCart.cs b/csharp/SupermarketReceipt/ShoppingCart.cs index 0e346af..ef032d3 100644 --- a/csharp/SupermarketReceipt/ShoppingCart.cs +++ b/csharp/SupermarketReceipt/ShoppingCart.cs @@ -7,7 +7,7 @@ public class ShoppingCart { // Discount description constants private const string THREE_FOR_TWO_DESCRIPTION = "3 for 2"; - private const string PERCENT_OFF_SUFFIX = "% off"; + private const string PERCENT_OFF_SUFFIX = " % off"; private readonly List _items = new List(); private readonly Dictionary _productQuantities = new Dictionary(); diff --git a/elixir/lib/supermarket/model/shopping_cart.ex b/elixir/lib/supermarket/model/shopping_cart.ex index 8c55f55..df03fd9 100644 --- a/elixir/lib/supermarket/model/shopping_cart.ex +++ b/elixir/lib/supermarket/model/shopping_cart.ex @@ -7,7 +7,7 @@ defmodule Supermarket.Model.ShoppingCart do # Discount description constants @three_for_two_description "3 for 2" - @percent_off_suffix "% off" + @percent_off_suffix " % off" defstruct [:items, :product_quantities] diff --git a/go/supermarket/shopping_cart.go b/go/supermarket/shopping_cart.go index 7fbe8aa..a676ecb 100644 --- a/go/supermarket/shopping_cart.go +++ b/go/supermarket/shopping_cart.go @@ -8,7 +8,7 @@ import ( // Discount description constants const ( threeForTwoDescription = "3 for 2" - percentOffSuffix = "% off" + percentOffSuffix = " % off" ) type ProductQuantity struct { @@ -71,7 +71,7 @@ func (c *ShoppingCart) handleOffers(receipt *Receipt, offers map[Product]Special discount = &Discount{product: p, description: threeForTwoDescription, discountAmount: -discountAmount} } if offer.offerType == TenPercentDiscount { - discount = &Discount{product: p, description: fmt.Sprintf("%.0f %s", offer.argument, percentOffSuffix), discountAmount: -quantity * unitPrice * offer.argument / 100.0} + discount = &Discount{product: p, description: fmt.Sprintf("%.0f%s", offer.argument, percentOffSuffix), discountAmount: -quantity * unitPrice * offer.argument / 100.0} } if offer.offerType == FiveForAmount && quantityAsInt >= 5 { var discountTotal = unitPrice * quantity - (offer.argument * float64(numberOfXs) + float64(quantityAsInt % 5) * unitPrice) diff --git a/java/src/main/java/dojo/supermarket/model/ShoppingCart.java b/java/src/main/java/dojo/supermarket/model/ShoppingCart.java index c988c91..1cbf26b 100644 --- a/java/src/main/java/dojo/supermarket/model/ShoppingCart.java +++ b/java/src/main/java/dojo/supermarket/model/ShoppingCart.java @@ -10,7 +10,7 @@ public class ShoppingCart { // Discount description constants private static final String THREE_FOR_TWO_DESCRIPTION = "3 for 2"; - private static final String PERCENT_OFF_SUFFIX = "% off"; + private static final String PERCENT_OFF_SUFFIX = " % off"; private final List items = new ArrayList<>(); private final Map productQuantities = new HashMap<>(); diff --git a/kotlin/src/main/kotlin/supermarket/model/ShoppingCart.kt b/kotlin/src/main/kotlin/supermarket/model/ShoppingCart.kt index 04a5781..92e2d3f 100644 --- a/kotlin/src/main/kotlin/supermarket/model/ShoppingCart.kt +++ b/kotlin/src/main/kotlin/supermarket/model/ShoppingCart.kt @@ -8,7 +8,7 @@ class ShoppingCart { // Discount description constants companion object { private const val THREE_FOR_TWO_DESCRIPTION = "3 for 2" - private const val PERCENT_OFF_SUFFIX = "% off" + private const val PERCENT_OFF_SUFFIX = " % off" } private val items = ArrayList() diff --git a/php/src/Model/ShoppingCart.php b/php/src/Model/ShoppingCart.php index 929f7aa..1130bf7 100644 --- a/php/src/Model/ShoppingCart.php +++ b/php/src/Model/ShoppingCart.php @@ -10,7 +10,7 @@ class ShoppingCart { // Discount description constants private const THREE_FOR_TWO_DESCRIPTION = '3 for 2'; - private const PERCENT_OFF_SUFFIX = '% off'; + private const PERCENT_OFF_SUFFIX = ' % off'; /** * @var ProductQuantity[] diff --git a/python/shopping_cart.py b/python/shopping_cart.py index 7572d3d..705a3dd 100644 --- a/python/shopping_cart.py +++ b/python/shopping_cart.py @@ -5,7 +5,7 @@ # Discount description constants THREE_FOR_TWO_DESCRIPTION = "3 for 2" -PERCENT_OFF_SUFFIX = "% off" +PERCENT_OFF_SUFFIX = " % off" class ShoppingCart: diff --git a/python_pytest/src/shopping_cart.py b/python_pytest/src/shopping_cart.py index 7572d3d..705a3dd 100644 --- a/python_pytest/src/shopping_cart.py +++ b/python_pytest/src/shopping_cart.py @@ -5,7 +5,7 @@ # Discount description constants THREE_FOR_TWO_DESCRIPTION = "3 for 2" -PERCENT_OFF_SUFFIX = "% off" +PERCENT_OFF_SUFFIX = " % off" class ShoppingCart: diff --git a/ruby/lib/models/shopping_cart.rb b/ruby/lib/models/shopping_cart.rb index e4d7f08..fbaf734 100644 --- a/ruby/lib/models/shopping_cart.rb +++ b/ruby/lib/models/shopping_cart.rb @@ -2,7 +2,7 @@ class ShoppingCart # Discount description constants THREE_FOR_TWO_DESCRIPTION = "3 for 2" - PERCENT_OFF_SUFFIX = "% off" + PERCENT_OFF_SUFFIX = " % off" def initialize @items = [] diff --git a/swift/SupermarketReceipt/ShoppingCart.swift b/swift/SupermarketReceipt/ShoppingCart.swift index f2fa1ac..18a472d 100644 --- a/swift/SupermarketReceipt/ShoppingCart.swift +++ b/swift/SupermarketReceipt/ShoppingCart.swift @@ -2,7 +2,7 @@ public class ShoppingCart { // Discount description constants private static let threeForTwoDescription = "3 for 2" - private static let percentOffSuffix = "% off" + private static let percentOffSuffix = " % off" public var items = [ProductQuantity]() public var productQuantities = [Product: Double]() diff --git a/typescript/src/model/ShoppingCart.ts b/typescript/src/model/ShoppingCart.ts index 70edc78..fedb23c 100644 --- a/typescript/src/model/ShoppingCart.ts +++ b/typescript/src/model/ShoppingCart.ts @@ -9,7 +9,7 @@ import {SpecialOfferType} from "./SpecialOfferType" // Discount description constants const THREE_FOR_TWO_DESCRIPTION = "3 for 2"; -const PERCENT_OFF_SUFFIX = "% off"; +const PERCENT_OFF_SUFFIX = " % off"; type ProductQuantities = { [productName: string]: ProductQuantity } export type OffersByProduct = {[productName: string]: Offer}; From af4499cc3dd9164cb6b756f54b8f6bf0c4f6bc19 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Feb 2026 12:27:33 +0000 Subject: [PATCH 7/7] Finalize magic string cleanup across all implementations Co-authored-by: nstubbe <20206435+nstubbe@users.noreply.github.com> --- _codeql_detected_source_root | 1 + 1 file changed, 1 insertion(+) create mode 120000 _codeql_detected_source_root diff --git a/_codeql_detected_source_root b/_codeql_detected_source_root new file mode 120000 index 0000000..945c9b4 --- /dev/null +++ b/_codeql_detected_source_root @@ -0,0 +1 @@ +. \ No newline at end of file