Skip to content

Commit c57c43d

Browse files
committed
Add background story to README.md
1 parent 778d9cb commit c57c43d

File tree

1 file changed

+72
-36
lines changed

1 file changed

+72
-36
lines changed

README.md

Lines changed: 72 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,111 @@
1+
🕵️‍♂️ The Case of the Vanishing Code
2+
3+
Once upon a time in the bustling digital halls of the ITHS Java Lab, a brilliant team of developers built a sleek,
4+
elegant application. It was fast. It was flawless. It was... undocumented.
5+
6+
But then—disaster struck. During a routine migration to a new version control system, someone (we won’t name names, but
7+
let’s just say their coffee-to-commit ratio was dangerously high ☕💻) accidentally triggered the mythical git nuke
8+
--force command. The source code vanished into the void.
9+
10+
Gone. Poof. Like it never existed.
11+
12+
All that remained were the sacred test files—meticulously crafted, oddly untouched by the chaos. These tests, like
13+
ancient scrolls, held the secrets of what the application was supposed to do. They whispered of methods, behaviors, and
14+
edge cases. They were our only clue.
15+
16+
Now, the mission falls to you: the brave code archaeologists of Java25. Your task is to reconstruct the lost
17+
application, piece by piece, using only the tests as your guide. Think of it as reverse-engineering a fossilized
18+
dinosaur from its footprints... except the dinosaur is a Java program, and the footprints are JUnit assertions.
19+
20+
Luckily, a few fragments of implementation survived—like half-buried ruins in the sand. Use them wisely. Interpret the
21+
tests. Rebuild the logic. And maybe, just maybe, restore the glory of the lost codebase.
22+
123
# Warehouse Kata – Instructions
224

325
Welcome! In this exercise you will implement a small domain around a Warehouse with products. Your goal is to:
4-
- Create and complete several classes/interfaces under src/main/java that are currently missing or partially implemented.
26+
27+
- Create and complete several classes/interfaces under src/main/java that are currently missing or partially
28+
implemented.
529
- Pick correct data types for parameters and return values so the project compiles and tests can run.
630
- Make all tests in BasicTest green first.
731
- Commit after major steps. When all BasicTest tests are green, push your commits.
832
- Extra credit: implement the advanced features so that EdgeCaseTest is also green.
933

1034
## 1) Getting started
35+
1136
1. Open this project in your IDE (IntelliJ IDEA recommended).
1237
2. Ensure you have JDK 25.
1338
3. Build once to see current state:
14-
- ./mvnw compile
39+
- ./mvnw compile
1540

1641
## 2) What you will need to create/finish
17-
You will work primarily in src/main/java/com/example. Some files already exist but contain TODOs or empty methods. Implement the following:
42+
43+
You will work primarily in src/main/java/com/example. Some files already exist but contain TODOs or empty methods.
44+
Implement the following:
1845

1946
- Category (value object)
20-
- Use a private constructor and a public static factory Category.of(String name).
21-
- Validate input: null => "Category name can't be null"; empty/blank => "Category name can't be blank".
22-
- Normalize name with initial capital letter (e.g., "fruit" -> "Fruit").
23-
- Cache/flyweight: return the same instance for the same normalized name.
47+
- Use a private constructor and a public static factory Category.of(String name).
48+
- Validate input: null => "Category name can't be null"; empty/blank => "Category name can't be blank".
49+
- Normalize name with initial capital letter (e.g., "fruit" -> "Fruit").
50+
- Cache/flyweight: return the same instance for the same normalized name.
2451

2552
- Product (abstract base class)
26-
- Keep UUID id, String name, Category category, BigDecimal price.
27-
- Provide getters named uuid(), name(), category(), price() and a setter price(BigDecimal).
28-
- Provide an abstract String productDetails() for polymorphism.
53+
- Keep UUID id, String name, Category category, BigDecimal price.
54+
- Provide getters named uuid(), name(), category(), price() and a setter price(BigDecimal).
55+
- Provide an abstract String productDetails() for polymorphism.
2956

3057
- FoodProduct (extends Product)
31-
- Implements Perishable and Shippable.
32-
- Fields: LocalDate expirationDate, BigDecimal weight (kg).
33-
- Validations: negative price -> IllegalArgumentException("Price cannot be negative."); negative weight -> IllegalArgumentException("Weight cannot be negative.").
34-
- productDetails() should look like: "Food: Milk, Expires: 2025-12-24".
35-
- Shipping rule: cost = weight * 50.
58+
- Implements Perishable and Shippable.
59+
- Fields: LocalDate expirationDate, BigDecimal weight (kg).
60+
- Validations: negative price -> IllegalArgumentException("Price cannot be negative."); negative weight ->
61+
IllegalArgumentException("Weight cannot be negative.").
62+
- productDetails() should look like: "Food: Milk, Expires: 2025-12-24".
63+
- Shipping rule: cost = weight * 50.
3664

3765
- ElectronicsProduct (extends Product)
38-
- Implements Shippable.
39-
- Fields: int warrantyMonths, BigDecimal weight (kg).
40-
- Validation: negative warranty -> IllegalArgumentException("Warranty months cannot be negative.").
41-
- productDetails() should look like: "Electronics: Laptop, Warranty: 24 months".
42-
- Shipping rule: base 79, add 49 if weight > 5.0 kg.
66+
- Implements Shippable.
67+
- Fields: int warrantyMonths, BigDecimal weight (kg).
68+
- Validation: negative warranty -> IllegalArgumentException("Warranty months cannot be negative.").
69+
- productDetails() should look like: "Electronics: Laptop, Warranty: 24 months".
70+
- Shipping rule: base 79, add 49 if weight > 5.0 kg.
4371

4472
- Interfaces
45-
- Perishable: expose expirationDate() and a default isExpired() based on LocalDate.now().
46-
- Shippable: expose calculateShippingCost() and weight() (used by shipping optimizer in extra tests).
73+
- Perishable: expose expirationDate() and a default isExpired() based on LocalDate.now().
74+
- Shippable: expose calculateShippingCost() and weight() (used by shipping optimizer in extra tests).
4775

4876
- Warehouse (singleton per name)
49-
- getInstance(String name) returns the same instance per unique name.
50-
- addProduct(Product): throw IllegalArgumentException("Product cannot be null.") if null.
51-
- getProducts(): return an unmodifiable copy.
52-
- getProductById(UUID): return Optional.
53-
- updateProductPrice(UUID, BigDecimal): when not found, throw NoSuchElementException("Product not found with id: <uuid>"). Also track changed products in getChangedProducts().
54-
- expiredProducts(): return List<Perishable> that are expired.
55-
- shippableProducts(): return List<Shippable> from stored products.
56-
- remove(UUID): remove the matching product if present.
77+
- getInstance(String name) returns the same instance per unique name.
78+
- addProduct(Product): throw IllegalArgumentException("Product cannot be null.") if null.
79+
- getProducts(): return an unmodifiable copy.
80+
- getProductById(UUID): return Optional.
81+
- updateProductPrice(UUID, BigDecimal): when not found, throw NoSuchElementException("Product not found with
82+
id: <uuid>"). Also track changed products in getChangedProducts().
83+
- expiredProducts(): return List<Perishable> that are expired.
84+
- shippableProducts(): return List<Shippable> from stored products.
85+
- remove(UUID): remove the matching product if present.
5786

5887
- WarehouseAnalyzer (extra credit)
59-
- Implement the advanced methods used by EdgeCaseTest: price-range search (inclusive), expiring-within-days, case-insensitive name search, above-price search, weighted average per category (round to 2 decimals), price outliers (population stddev), shipping group optimization (first‑fit decreasing by weight), expiration-based discounts, inventory validation summary, and inventory statistics.
88+
- Implement the advanced methods used by EdgeCaseTest: price-range search (inclusive), expiring-within-days,
89+
case-insensitive name search, above-price search, weighted average per category (round to 2 decimals), price
90+
outliers (population stddev), shipping group optimization (first‑fit decreasing by weight), expiration-based
91+
discounts, inventory validation summary, and inventory statistics.
6092

6193
## 3) Workflow to follow
94+
6295
1. Implement the missing classes/interfaces and methods so the project compiles.
6396
2. Run tests:
64-
- Basic first: ./mvnw -Dtest=BasicTest test
65-
- When green, commit with a clear message.
97+
- Basic first: ./mvnw -Dtest=BasicTest test
98+
- When green, commit with a clear message.
6699
3. Extra credit: make EdgeCaseTest green:
67-
- ./mvnw -Dtest=EdgeCaseTest test
68-
4. Commit after each major milestone (e.g., "Implement Product & FoodProduct", "Warehouse behaviors", "Analyzer advanced features").
100+
- ./mvnw -Dtest=EdgeCaseTest test
101+
4. Commit after each major milestone (e.g., "Implement Product & FoodProduct", "Warehouse behaviors", "Analyzer advanced
102+
features").
69103
5. Push when BasicTest is fully green (and EdgeCaseTest too if you do the extra credit).
70104

71105
## 4) Tips
72-
- Prefer BigDecimal for prices and weights (exact values in tests). Where an interface requires Double (e.g., weight()), convert BigDecimal to double on return.
106+
107+
- Prefer BigDecimal for prices and weights (exact values in tests). Where an interface requires Double (e.g., weight()),
108+
convert BigDecimal to double on return.
73109
- Always round monetary results to 2 decimals using HALF_UP when tests assert exact values.
74110
- Keep public APIs exactly as tests expect (method names, exception messages).
75111
- Ensure Warehouse.clearProducts() is called in tests; do not share state between tests.

0 commit comments

Comments
 (0)