diff --git a/.mvn/jvm.config b/.mvn/jvm.config
index 1d210e8..3e3059a 100644
--- a/.mvn/jvm.config
+++ b/.mvn/jvm.config
@@ -1,4 +1,8 @@
--Xss16m -Xms256m -Xmx1024m -Djava.awt.headless=true
+-Xss16m
+-XX:+EnableDynamicAgentLoading
+-Xms256m
+-Xmx1024m
+-Djava.awt.headless=true
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
diff --git a/README.md b/README.md
index ceaef88..83cd1d9 100644
--- a/README.md
+++ b/README.md
@@ -35,6 +35,11 @@ PrimeKit Coding Challenges
+
+
+
+
+ |
@@ -56,6 +61,11 @@ PrimeKit Coding Challenges
+
+
+
+
+ |
diff --git a/pom.xml b/pom.xml
index b631601..1161fa8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,6 +35,7 @@
true
1.18.32
+ 5.20.0
5.10.2
1.10.2
3.14.0
@@ -140,17 +141,23 @@
${instancio.version}
test
-
- org.junit.jupiter
- junit-jupiter
- test
-
-
- org.mockito
- mockito-core
- ${mockito.version}
- test
-
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.mockito
+ mockito-core
+ ${mockito.version}
+ test
+
+
+ org.mockito
+ mockito-junit-jupiter
+ ${mockito.version}
+ test
+
@@ -250,6 +257,7 @@
true
*com.shortthirdman.primekit.common.*
+ *com.shortthirdman.primekit.core.*
@@ -280,6 +288,7 @@
${project.build.sourceEncoding}
com/shortthirdman/primekit/common/**/*.java
+ com/shortthirdman/primekit/core/**/*.java
${project.build.sourceEncoding}
diff --git a/src/main/java/com/shortthirdman/primekit/coderbyte/PatternAnalyzer.java b/src/main/java/com/shortthirdman/primekit/coderbyte/PatternAnalyzer.java
new file mode 100644
index 0000000..ccd7f47
--- /dev/null
+++ b/src/main/java/com/shortthirdman/primekit/coderbyte/PatternAnalyzer.java
@@ -0,0 +1,61 @@
+package com.shortthirdman.primekit.coderbyte;
+
+import com.shortthirdman.primekit.core.domain.ProductCategory;
+import com.shortthirdman.primekit.core.funcinterface.TaxCalculator;
+import com.shortthirdman.primekit.core.strategy.LuxuryTaxCalculation;
+import com.shortthirdman.primekit.core.strategy.PremiumTaxCalculation;
+import com.shortthirdman.primekit.core.strategy.StandardTaxCalculation;
+import com.shortthirdman.primekit.core.strategy.TaxCalculationStrategy;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Objects;
+
+/**
+ * Calculates tax by category and strategy
+ * @since 1.1.1
+ * @author ShortThirdMan
+ */
+public class PatternAnalyzer {
+
+ private static final Boolean DEBUG = System.getenv("DEBUG") != null || System.getProperty("DEBUG") != null;
+
+ public double calculateTaxByStrategy(double baseAmount, ProductCategory category) {
+ if (Objects.isNull(category)) {
+ throw new IllegalArgumentException("Category is null");
+ }
+
+ TaxCalculationStrategy strategy = switch (category) {
+ case STANDARD -> new StandardTaxCalculation();
+ case PREMIUM -> new PremiumTaxCalculation();
+ case LUXURY -> new LuxuryTaxCalculation();
+ default -> throw new IllegalArgumentException("Unsupported product category");
+ };
+
+ double taxAmount = strategy.calculateTax(baseAmount);
+ if (DEBUG) {
+ System.out.println("[CalculateTaxByStrategy] Tax for $" + baseAmount + " (" + category + "): $" + taxAmount);
+ }
+
+ return taxAmount;
+ }
+
+ public double calculateTaxByCategory(double baseAmount, ProductCategory category) {
+ if (Objects.isNull(category)) {
+ throw new IllegalArgumentException("Category is null");
+ }
+
+ TaxCalculator calculator = switch (category) {
+ case STANDARD -> amount1 -> amount1 * 0.10; // 10% tax
+ case PREMIUM -> amount1 -> amount1 * 0.20; // 20% tax
+ case LUXURY -> amount1 -> amount1 * 0.30; // 30% tax
+ default -> throw new IllegalArgumentException("Unsupported product category");
+ };
+
+ double taxAmount = calculator.calculate(baseAmount);
+ if (DEBUG) {
+ System.out.println("[CalculateTaxByCategory] Tax for $" + baseAmount + " (" + category + "): $" + taxAmount);
+ }
+
+ return taxAmount;
+ }
+}
diff --git a/src/main/java/com/shortthirdman/primekit/core/domain/ProductCategory.java b/src/main/java/com/shortthirdman/primekit/core/domain/ProductCategory.java
new file mode 100644
index 0000000..a0d1d0f
--- /dev/null
+++ b/src/main/java/com/shortthirdman/primekit/core/domain/ProductCategory.java
@@ -0,0 +1,6 @@
+package com.shortthirdman.primekit.core.domain;
+
+public enum ProductCategory {
+
+ STANDARD, PREMIUM, LUXURY
+}
diff --git a/src/main/java/com/shortthirdman/primekit/core/funcinterface/TaxCalculator.java b/src/main/java/com/shortthirdman/primekit/core/funcinterface/TaxCalculator.java
new file mode 100644
index 0000000..11cffc1
--- /dev/null
+++ b/src/main/java/com/shortthirdman/primekit/core/funcinterface/TaxCalculator.java
@@ -0,0 +1,7 @@
+package com.shortthirdman.primekit.core.funcinterface;
+
+@FunctionalInterface
+public interface TaxCalculator {
+
+ double calculate(double amount);
+}
diff --git a/src/main/java/com/shortthirdman/primekit/core/strategy/LuxuryTaxCalculation.java b/src/main/java/com/shortthirdman/primekit/core/strategy/LuxuryTaxCalculation.java
new file mode 100644
index 0000000..dba914c
--- /dev/null
+++ b/src/main/java/com/shortthirdman/primekit/core/strategy/LuxuryTaxCalculation.java
@@ -0,0 +1,9 @@
+package com.shortthirdman.primekit.core.strategy;
+
+public final class LuxuryTaxCalculation implements TaxCalculationStrategy {
+
+ @Override
+ public double calculateTax(double amount) {
+ return amount * 0.30; // 30% tax
+ }
+}
diff --git a/src/main/java/com/shortthirdman/primekit/core/strategy/PremiumTaxCalculation.java b/src/main/java/com/shortthirdman/primekit/core/strategy/PremiumTaxCalculation.java
new file mode 100644
index 0000000..f60466d
--- /dev/null
+++ b/src/main/java/com/shortthirdman/primekit/core/strategy/PremiumTaxCalculation.java
@@ -0,0 +1,9 @@
+package com.shortthirdman.primekit.core.strategy;
+
+public final class PremiumTaxCalculation implements TaxCalculationStrategy {
+
+ @Override
+ public double calculateTax(double amount) {
+ return amount * 0.20; // 20% tax
+ }
+}
diff --git a/src/main/java/com/shortthirdman/primekit/core/strategy/StandardTaxCalculation.java b/src/main/java/com/shortthirdman/primekit/core/strategy/StandardTaxCalculation.java
new file mode 100644
index 0000000..c5ef91b
--- /dev/null
+++ b/src/main/java/com/shortthirdman/primekit/core/strategy/StandardTaxCalculation.java
@@ -0,0 +1,9 @@
+package com.shortthirdman.primekit.core.strategy;
+
+public final class StandardTaxCalculation implements TaxCalculationStrategy {
+
+ @Override
+ public double calculateTax(double amount) {
+ return amount * 0.10; // 10% tax
+ }
+}
diff --git a/src/main/java/com/shortthirdman/primekit/core/strategy/TaxCalculationStrategy.java b/src/main/java/com/shortthirdman/primekit/core/strategy/TaxCalculationStrategy.java
new file mode 100644
index 0000000..1b2f075
--- /dev/null
+++ b/src/main/java/com/shortthirdman/primekit/core/strategy/TaxCalculationStrategy.java
@@ -0,0 +1,6 @@
+package com.shortthirdman.primekit.core.strategy;
+
+public sealed interface TaxCalculationStrategy permits StandardTaxCalculation, PremiumTaxCalculation, LuxuryTaxCalculation {
+
+ double calculateTax(double amount);
+}
diff --git a/src/test/java/com/shortthirdman/primekit/coderbyte/PatternAnalyzerTest.java b/src/test/java/com/shortthirdman/primekit/coderbyte/PatternAnalyzerTest.java
new file mode 100644
index 0000000..ada42a1
--- /dev/null
+++ b/src/test/java/com/shortthirdman/primekit/coderbyte/PatternAnalyzerTest.java
@@ -0,0 +1,187 @@
+package com.shortthirdman.primekit.coderbyte;
+
+import com.shortthirdman.primekit.core.domain.ProductCategory;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class PatternAnalyzerTest {
+
+ private static PatternAnalyzer analyzer;
+
+ @BeforeAll
+ static void setUp() {
+ analyzer = new PatternAnalyzer();
+ }
+
+ // ==============================================================
+ // calculateTaxByStrategy() POSITIVE TESTS
+ // ==============================================================
+
+ @Test
+ @DisplayName("calculateTaxByStrategy - STANDARD tax should be 10%")
+ void testStrategyStandardTax() {
+ double tax = analyzer.calculateTaxByStrategy(100.00, ProductCategory.STANDARD);
+ assertEquals(10.00, tax, 0.001);
+ }
+
+ @Test
+ @DisplayName("calculateTaxByStrategy - PREMIUM tax should be 20%")
+ void testStrategyPremiumTax() {
+ double tax = analyzer.calculateTaxByStrategy(200.00, ProductCategory.PREMIUM);
+ assertEquals(40.00, tax, 0.001);
+ }
+
+ @Test
+ @DisplayName("calculateTaxByStrategy - LUXURY tax should be 30%")
+ void testStrategyLuxuryTax() {
+ double tax = analyzer.calculateTaxByStrategy(300.00, ProductCategory.LUXURY);
+ assertEquals(90.00, tax, 0.001);
+ }
+
+ // ==============================================================
+ // calculateTaxByCategory() POSITIVE TESTS
+ // ==============================================================
+
+ @Test
+ @DisplayName("calculateTaxByCategory - STANDARD tax should be 10%")
+ void testCategoryStandardTax() {
+ double tax = analyzer.calculateTaxByCategory(100.00, ProductCategory.STANDARD);
+ assertEquals(10.00, tax, 0.001);
+ }
+
+ @Test
+ @DisplayName("calculateTaxByCategory - PREMIUM tax should be 20%")
+ void testCategoryPremiumTax() {
+ double tax = analyzer.calculateTaxByCategory(200.00, ProductCategory.PREMIUM);
+ assertEquals(40.00, tax, 0.001);
+ }
+
+ @Test
+ @DisplayName("calculateTaxByCategory - LUXURY tax should be 30%")
+ void testCategoryLuxuryTax() {
+ double tax = analyzer.calculateTaxByCategory(300.00, ProductCategory.LUXURY);
+ assertEquals(90.00, tax, 0.001);
+ }
+
+
+
+ // ==============================================================
+ // NEGATIVE INPUT TESTS (invalid numbers)
+ // ==============================================================
+
+ @Test
+ @DisplayName("calculateTaxByStrategy - negative amount allowed but calculation valid")
+ void testStrategyNegativeAmount() {
+ double tax = analyzer.calculateTaxByStrategy(-100.00, ProductCategory.STANDARD);
+ assertEquals(-10.00, tax, 0.001);
+ }
+
+ @Test
+ @DisplayName("calculateTaxByCategory - negative amount allowed but calculation valid")
+ void testCategoryNegativeAmount() {
+ double tax = analyzer.calculateTaxByCategory(-100.00, ProductCategory.LUXURY);
+ assertEquals(-30.00, tax, 0.001);
+ }
+
+ // ==============================================================
+ // EDGE CASES
+ // ==============================================================
+
+ @Test
+ @DisplayName("calculateTaxByStrategy - zero amount should return zero")
+ void testStrategyZeroAmount() {
+ double tax = analyzer.calculateTaxByStrategy(0.0, ProductCategory.PREMIUM);
+ assertEquals(0.0, tax);
+ }
+
+ @Test
+ @DisplayName("calculateTaxByCategory - zero amount should return zero")
+ void testCategoryZeroAmount() {
+ double tax = analyzer.calculateTaxByCategory(0.0, ProductCategory.LUXURY);
+ assertEquals(0.0, tax);
+ }
+
+ @Test
+ @DisplayName("calculateTaxByStrategy - very large amount precision test")
+ void testStrategyLargeAmount() {
+ double tax = analyzer.calculateTaxByStrategy(1_000_000.0, ProductCategory.LUXURY);
+ assertEquals(300_000.0, tax);
+ }
+
+ @Test
+ @DisplayName("calculateTaxByCategory - very large amount precision test")
+ void testCategoryLargeAmount() {
+ double tax = analyzer.calculateTaxByCategory(1_000_000.0, ProductCategory.STANDARD);
+ assertEquals(100_000.0, tax);
+ }
+
+ // ==============================================================
+ // NULL CATEGORY (EXCEPTION TESTS)
+ // ==============================================================
+
+ @Test
+ @DisplayName("calculateTaxByStrategy - null category throws IllegalArgumentException")
+ void testStrategyNullCategory() {
+ Assertions.assertThrows(IllegalArgumentException.class,
+ () -> analyzer.calculateTaxByStrategy(50.0, null));
+ }
+
+ @Test
+ @DisplayName("calculateTaxByCategory - null category throws IllegalArgumentException")
+ void testCategoryNullCategory() {
+ Assertions.assertThrows(IllegalArgumentException.class,
+ () -> analyzer.calculateTaxByCategory(50.0, null));
+ }
+
+ // ==============================================================
+ // UNSUPPORTED CATEGORY (just in case enum grows)
+ // ==============================================================
+
+ @Test
+ @DisplayName("calculateTaxByStrategy - unsupported category throws IllegalArgumentException")
+ void testStrategyUnsupportedCategory() {
+ Assertions.assertThrows(IllegalArgumentException.class,
+ () -> analyzer.calculateTaxByStrategy(100.0, ProductCategory.valueOf("UNKNOWN")));
+ }
+
+ @Test
+ @DisplayName("calculateTaxByCategory - unsupported category throws IllegalArgumentException")
+ void testCategoryUnsupportedCategory() {
+ Assertions.assertThrows(IllegalArgumentException.class,
+ () -> analyzer.calculateTaxByCategory(100.0, ProductCategory.valueOf("UNKNOWN")));
+ }
+
+ @Test
+ @DisplayName("Standard category applies 10% tax")
+ void standardCategoryApplies10PercentTax() {
+ PatternAnalyzer analyzer = new PatternAnalyzer();
+
+ double result = analyzer.calculateTaxByStrategy(100, ProductCategory.STANDARD);
+
+ assertEquals(10.0, result);
+ }
+
+ @Test
+ @DisplayName("Premium category applies 20% tax")
+ void premiumCategoryApplies20PercentTax() {
+ PatternAnalyzer analyzer = new PatternAnalyzer();
+
+ double result = analyzer.calculateTaxByStrategy(100, ProductCategory.PREMIUM);
+
+ assertEquals(20.0, result);
+ }
+
+ @Test
+ @DisplayName("Luxury category applies 30% tax")
+ void luxuryCategoryApplies30PercentTax() {
+ PatternAnalyzer analyzer = new PatternAnalyzer();
+
+ double result = analyzer.calculateTaxByStrategy(100, ProductCategory.LUXURY);
+
+ assertEquals(30.0, result);
+ }
+}
\ No newline at end of file
|