From ad774b89c881d897ec7df9f848da38098df53240 Mon Sep 17 00:00:00 2001 From: fiatcode Date: Wed, 18 Feb 2026 13:00:26 +0700 Subject: [PATCH] docs: Document String Calculator Bug Hunt Kata - Add comprehensive String Calculator section to README - Document Bug Hunt approach: test-driven bug finding - List all 5 bugs found and fixed with RED-GREEN commits - Include code examples and usage - Update comparison table to include all 4 katas - Add 'What Each Kata Teaches' for String Calculator - Update progressive learning path to include fourth kata --- README.md | 134 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 118 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e7c506b..803531d 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,99 @@ gildedRose.updateQuality(); // Updates all items per domain rules --- +### 4. String Calculator ✅ + +**Implementation:** [`lib/string_calculator.dart`](lib/string_calculator.dart) +**Tests:** [`test/string_calculator_test.dart`](test/string_calculator_test.dart) + +A Bug Hunt Kata demonstrating how to use TDD to discover and fix bugs in existing code. Each bug is exposed with a RED test, then fixed with GREEN implementation. + +#### Domain Context + +A simple calculator that sums numbers from a string input with various delimiter support: + +**Features:** + +1. **Empty String:** Returns 0 +2. **Single Number:** Returns that number (`"5"` → 5) +3. **Comma Delimiter:** Sums comma-separated numbers (`"1,2,3"` → 6) +4. **Custom Delimiters:** Supports format `"//[delimiter]\n[numbers]"` (`"//;\n1;2"` → 3) +5. **Ignore Large Numbers:** Numbers > 1000 are ignored (`"2,1001"` → 2) + +#### The Bug Hunt Approach + +**Different from Previous Katas:** This wasn't built test-first. Instead, we started with **buggy working code** and used tests to expose and fix bugs one by one. + +**Bug Hunt Process:** +1. **RED:** Write test exposing a specific bug +2. **GREEN:** Fix only that bug +3. **Commit:** Document the bug found and fixed +4. **Repeat:** Move to next bug + +#### Bugs Found & Fixed + +**Bug #1: Empty String Returns Wrong Value** +- **Bug:** Returned 1 instead of 0 +- **Test:** `expect(calculator.add(''), equals(0))` +- **Fix:** Changed return value from 1 to 0 +- **Commits:** RED → GREEN + +**Bug #2: Single Number Off-By-One** +- **Bug:** Added +1 to parsed number +- **Test:** `expect(calculator.add('5'), equals(5))` +- **Expected:** 5, **Actual:** 6 +- **Fix:** Removed `+ 1` from parsing +- **Commits:** RED → GREEN + +**Bug #3: Summation Loop Misses Last Element** +- **Bug:** Loop condition `i < length - 1` skipped last item +- **Test:** `expect(calculator.add('1,2'), equals(3))` +- **Expected:** 3, **Actual:** 1 +- **Fix:** Changed to `i < length` +- **Commits:** RED → GREEN + +**Bug #4: Custom Delimiter Not Extracted** +- **Bug:** Delimiter extraction line was commented out +- **Test:** `expect(calculator.add('//;\n1;2'), equals(3))` +- **Error:** FormatException trying to parse '1;2' +- **Fix:** Uncommented `delimiter = parts[0].substring(2)` +- **Commits:** RED → GREEN + +**Bug #5: Missing Feature - Ignore Numbers > 1000** +- **Bug:** All numbers included in sum +- **Test:** `expect(calculator.add('2,1001'), equals(2))` +- **Expected:** 2, **Actual:** 1003 +- **Fix:** Added `.where((n) => n <= 1000)` filter +- **Commits:** RED → GREEN + +#### Usage + +```dart +import 'package:tdd_katas/string_calculator.dart'; + +final calculator = StringCalculator(); + +calculator.add(''); // Returns: 0 +calculator.add('5'); // Returns: 5 +calculator.add('1,2,3'); // Returns: 6 +calculator.add('//;\n1;2'); // Returns: 3 +calculator.add('2,1001'); // Returns: 2 (1001 ignored) +``` + +#### The "Aha!" Moments + +1. **Tests as Bug Detectors:** Each test acted like a spotlight, illuminating exactly ONE bug at a time. No guessing—the test tells you what's broken. + +2. **RED-GREEN Still Works:** Even when fixing bugs (not adding features), the RED-GREEN rhythm provides safety. You're never fixing blind. + +3. **Regression Prevention:** After fixing each bug, ALL previous tests stay green. This proves you didn't break something while fixing something else. + +4. **Incremental Debugging:** Fixing one bug at a time with commits creates a clear audit trail. You can see exactly what each bug was and how it was fixed. + +5. **Real-World Skill:** This mirrors production work—most code you touch is existing code with bugs, not greenfield TDD. + +--- + ## Running Tests ```bash @@ -229,6 +322,7 @@ dart test dart test test/roman_numerals_test.dart dart test test/bowling_game_test.dart dart test test/gilded_rose_test.dart +dart test test/string_calculator_test.dart # Run with coverage dart test --coverage @@ -536,22 +630,23 @@ Decision: Skip refactor commit—code is already excellent. ## Comparing the Katas -### All Three Katas at a Glance +### All Four Katas at a Glance -| Aspect | Roman Numerals | Bowling Game | Gilded Rose | -|--------|----------------|--------------|-------------| -| **Complexity** | Beginner | Intermediate | Advanced | -| **Approach** | Greenfield TDD | Greenfield TDD | Legacy refactoring | -| **State** | Stateless | Stateful | Stateful | -| **Algorithm** | Table-driven lookup | Frame iteration | Strategy pattern | -| **Key Challenge** | Pattern recognition | State & bonuses | Refactoring safely | -| **Design Pattern** | Value Object | Implicit strategy | Explicit strategy | -| **Lines of Code** | ~45 production | ~30 production | ~120 production | -| **Test Count** | ~15 tests | ~10 tests | ~17 tests | -| **Aha! Moment** | Table = data structure | Simple → complex works | Refactoring = safety | +| Aspect | Roman Numerals | Bowling Game | Gilded Rose | String Calculator | +|--------|----------------|--------------|-------------|-------------------| +| **Complexity** | Beginner | Intermediate | Advanced | Beginner | +| **Approach** | Greenfield TDD | Greenfield TDD | Legacy refactoring | Bug hunting | +| **State** | Stateless | Stateful | Stateful | Stateless | +| **Algorithm** | Table-driven | Frame iteration | Strategy pattern | String parsing | +| **Key Challenge** | Pattern recognition | State & bonuses | Refactoring safely | Finding bugs | +| **Design Pattern** | Value Object | Implicit strategy | Explicit strategy | Filters & pipes | +| **Lines of Code** | ~45 production | ~30 production | ~120 production | ~25 production | +| **Test Count** | ~15 tests | ~10 tests | ~17 tests | 6 tests | +| **Aha! Moment** | Table = data | Simple → complex | Refactor = safe | Tests find bugs | ### What Each Kata Teaches +**Roman Numerals:** **Roman Numerals:** - Converting domain rules into data structures - Value Objects for enforcing constraints @@ -561,22 +656,29 @@ Decision: Skip refactor commit—code is already excellent. - State management without over-engineering - Look-ahead logic in sequential data - How correct abstractions scale beyond test cases + **Gilded Rose:** - Safely refactoring legacy code with characterization tests - Strategy pattern for eliminating conditional complexity - Open-Closed Principle for extensibility - Working effectively with code you didn't write +**String Calculator:** +- Using tests to expose bugs in existing code +- Bug hunting with RED-GREEN discipline +- Incremental debugging with clear commits +- Regression prevention through test accumulation + ### Progressive Learning Path 1. **Roman Numerals first:** Learn TDD fundamentals without state complexity 2. **Bowling Game second:** Apply TDD to stateful problems 3. **Gilded Rose third:** Master refactoring legacy code with tests as safety net -4. **Next kata:** Choose based on what you want to practice: - - **String Calculator:** Parsing, validation, error handling - - **Mars Rover:** Command pattern, multiple behaviors - - **Prime Factors:** Mathematical decomposition, algorithmic thinkingsts +4. **String Calculator fourth:** Practice bug hunting and fixing with TDD +5. **Next kata:** Choose based on what you want to practice: - **Mars Rover:** Command pattern, multiple behaviors + - **Prime Factors:** Mathematical decomposition, algorithmic thinking + - **Tennis Scoring:** State machines, domain language ---