diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..10f9606
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+bin/
+obj/
+*.user
+.vs/
diff --git a/livetest.slnx b/livetest.slnx
new file mode 100644
index 0000000..a4fc33f
--- /dev/null
+++ b/livetest.slnx
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/Prices/PriceCalculator.cs b/src/Prices/PriceCalculator.cs
new file mode 100644
index 0000000..c2b9cb3
--- /dev/null
+++ b/src/Prices/PriceCalculator.cs
@@ -0,0 +1,21 @@
+namespace Prices;
+
+/// Turns a list price into what the customer actually pays.
+public static class PriceCalculator
+{
+ /// Applies a percentage discount to a price, e.g. 25 for a quarter off.
+ public static decimal ApplyDiscount(decimal price, decimal discountPercent)
+ {
+ if (price < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(price), "A price cannot be negative.");
+ }
+
+ if (discountPercent is < 0 or > 100)
+ {
+ throw new ArgumentOutOfRangeException(nameof(discountPercent), "A discount is between 0 and 100 percent.");
+ }
+
+ return price - discountPercent;
+ }
+}
diff --git a/src/Prices/Prices.csproj b/src/Prices/Prices.csproj
new file mode 100644
index 0000000..93f5ab4
--- /dev/null
+++ b/src/Prices/Prices.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net10.0
+ enable
+ enable
+
+
+
diff --git a/tests/Prices.Tests/PriceCalculatorTests.cs b/tests/Prices.Tests/PriceCalculatorTests.cs
new file mode 100644
index 0000000..c49c29a
--- /dev/null
+++ b/tests/Prices.Tests/PriceCalculatorTests.cs
@@ -0,0 +1,36 @@
+using Xunit;
+
+namespace Prices.Tests;
+
+public sealed class PriceCalculatorTests
+{
+ [Fact]
+ public void No_discount_keeps_the_price()
+ {
+ Assert.Equal(100m, PriceCalculator.ApplyDiscount(100m, 0m));
+ }
+
+ [Fact]
+ public void A_full_discount_makes_it_free()
+ {
+ Assert.Equal(0m, PriceCalculator.ApplyDiscount(200m, 100m));
+ }
+
+ [Fact]
+ public void A_quarter_off_200_is_150()
+ {
+ Assert.Equal(150m, PriceCalculator.ApplyDiscount(200m, 25m));
+ }
+
+ [Fact]
+ public void Half_off_80_is_40()
+ {
+ Assert.Equal(40m, PriceCalculator.ApplyDiscount(80m, 50m));
+ }
+
+ [Fact]
+ public void A_discount_above_100_percent_is_refused()
+ {
+ Assert.Throws(() => PriceCalculator.ApplyDiscount(100m, 101m));
+ }
+}
diff --git a/tests/Prices.Tests/Prices.Tests.csproj b/tests/Prices.Tests/Prices.Tests.csproj
new file mode 100644
index 0000000..8525df0
--- /dev/null
+++ b/tests/Prices.Tests/Prices.Tests.csproj
@@ -0,0 +1,20 @@
+
+
+
+ net10.0
+ enable
+ enable
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+