Word Wrap
Level: Intermediate 30–60 minConcepts: Strings
Solutions: C# | TypeScript | Python
Create a program that wraps text at a specified column width.
Requirements
- Implement text wrapping rules:
- Break text at word boundaries when possible
- Break words only if they exceed the column width
- Preserve whitespace between words
- Handle multiple spaces and tabs
- Handle edge cases:
- Empty input
- Input shorter than column width
- Words longer than column width
- Multiple consecutive spaces
- Return appropriate results:
- Wrapped text as a string
- Error message for invalid inputs
Test Cases
| Input | Column Width | Expected Output | Notes |
|---|---|---|---|
| ”Hello” | 5 | ”Hello” | No wrapping needed |
| ”Hello World” | 5 | ”Hello\nWorld” | Break at word boundary |
| ”Hello World” | 7 | ”Hello\nWorld” | Break at word boundary |
| ”Hello World” | 20 | ”Hello World” | No wrapping needed |
| ”Supercalifragilisticexpialidocious” | 10 | ”Supercalif\nragilisti\ncexpiali\ndocious” | Break long word |
| ”Hello World” | 5 | ”Hello\nWorld” | Handle multiple spaces |
Edge Cases to Consider
- Empty string
- Null input
- Zero or negative column width
- Very long words
- Multiple consecutive spaces or tabs
- Text with line breaks
Tips
- Start with simple cases (no wrapping needed)
- Add word boundary breaking next
- Then handle long words
- Finally add whitespace handling
- Consider using regular expressions for word boundaries
Reference Walkthrough
Reference implementations in C#, TypeScript, and Python live at tddbuddy-reference-katas/word-wrap. This is an F1 kata — twelve scenarios covering empty and whitespace-only input, single-word lines, greedy word-boundary packing, oversize-word hard splitting, oversize-remainder joining with the next word, and whitespace collapsing — shared across all three languages, each a single pure function wrap(text, width) returning a \n-joined string.
- C# (.NET 8, xUnit, FluentAssertions 6.12.0) — walkthrough
- TypeScript (Node 20, Vitest 1.6, TS 5 strict) — walkthrough
- Python (3.11, pytest) — walkthrough
This kata ships in Agent Full-Bake mode at high gear: the rules land as one commit per language, with a brief walkthrough noting there are no builders because the inputs and outputs are the domain. A greedy line-packer tokenizes on runs of whitespace, accumulates words until the next word would push the line past width, splits any oversize word hard at the width-th character before letting its remainder begin the next line (where following words may still join it if they fit), and joins the resulting lines with \n — matching the classic Kent Beck kata shape that returns a single string rather than a list. See the repo’s Gears section for when high gear is the right call.
Related reading
- Katas Are Rehearsal, Not Performance
You don't practice TDD on production code. You practice on katas and bring the muscle memory to production. The gap between knowing TDD and doing TDD is reps. - Test Deletion Is a Privileged Operation
The cheapest way for an agent to make a failing test pass is to delete it. That is logical for the agent and catastrophic for the codebase. Tests are append-only by default. Deletion needs a human author, a separate commit, and a separate review. - Refactor Was Always Where Compounding Lived
Red and green were the visible two thirds of TDD. Refactor was the optional polish. Codebases that compound did the refactor pass; codebases that accrete did not. Agents skip refactor by default because it has no green-bar reward, and a year of skipped refactors is how a codebase loses its shape.