Implement Text to ASCII Art Generator with Standard and Block Fonts#139
Implement Text to ASCII Art Generator with Standard and Block Fonts#139MudasirStanikzay wants to merge 1 commit intomainfrom
Conversation
WalkthroughAdds a new ASCII art generation feature under org.fungover.breeze.ascii2: an AsciiFont interface, two font implementations (StandardFont, BlockFont), an AsciiArtGenerator orchestrator with input validation and length check, and unit tests validating rendering and error conditions. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Client
participant G as AsciiArtGenerator
participant F as AsciiFont<br/>(StandardFont/BlockFont)
C->>G: generate(text)
alt text null/blank
G-->>C: throw IllegalArgumentException("Text cannot be null or empty")
else text length > 50
G-->>C: throw IllegalArgumentException("Text too long. Max 50 characters.")
else valid
G->>F: render(text)
alt unsupported character in font
F-->>G: throw IllegalArgumentException("Unsupported character: X")
G-->>C: propagate exception
else supported
F-->>G: asciiArt
G-->>C: asciiArt
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (12)
src/main/java/org/fungover/breeze/ascii2/AsciiFont.java (1)
3-6: Document the contract (rows, newlines, unsupported chars) in the interface.Clarify that implementations should return exactly N rows separated by '\n' (and whether a trailing '\n' is expected), and how unsupported characters are handled. This keeps fonts consistent and testing simpler.
Apply Javadoc (non-breaking):
public interface AsciiFont { - String render(String text); - String getName(); + /** + * Renders the given text as multi-line ASCII art. + * Implementations should: + * - Use a fixed row height per font. + * - Return rows separated by '\n'. Trailing '\n' is allowed. + * - Throw IllegalArgumentException for unsupported characters. + */ + String render(String text); + /** Human-friendly font name (e.g., "Standard", "Block"). */ + String getName(); }src/test/java/org/fungover/breeze/ascii2/AsciiArtGeneratorTest.java (3)
9-13: These assertions are very loose; add structure checks.Add a test that verifies the output has exactly 3 rows (after stripTrailing) to catch formatting regressions.
void testStandardFontHello() { AsciiArtGenerator gen = new AsciiArtGenerator(new StandardFont()); String output = gen.generate("HELLO"); assertTrue(output.contains("H H")); + assertEquals(3, output.stripTrailing().split("\n").length); }
34-39: Add boundary tests for max length.Verify exactly 50 chars passes and 51 fails to lock the contract.
void testTooLongInputThrowsException() { AsciiArtGenerator gen = new AsciiArtGenerator(new StandardFont()); String longText = "A".repeat(60); assertThrows(IllegalArgumentException.class, () -> gen.generate(longText)); } + + @Test + void testMaxLengthAccepted() { + AsciiArtGenerator gen = new AsciiArtGenerator(new StandardFont()); + String exact = "A".repeat(50); + String out = gen.generate(exact); + assertFalse(out.isBlank()); + } + + @Test + void testOverMaxLengthRejected() { + AsciiArtGenerator gen = new AsciiArtGenerator(new StandardFont()); + String over = "A".repeat(51); + assertThrows(IllegalArgumentException.class, () -> gen.generate(over)); + }
15-20: Decide on space handling and add tests accordingly.Currently, fonts do not map ' ' and will throw. If you want “HELLO WORLD” to work, add a space glyph and test it; otherwise, add a test asserting it throws to make the behavior explicit.
src/main/java/org/fungover/breeze/ascii2/AsciiArtGenerator.java (1)
11-15: LGTM; consider extracting constants.Minor: Extract the 50 limit and error messages to named constants for reuse and clarity.
public class AsciiArtGenerator { private final AsciiFont font; + private static final int MAX_LENGTH = 50; + private static final String ERR_EMPTY = "Text cannot be null or empty"; + private static final String ERR_TOO_LONG = "Text too long. Max 50 characters."; public AsciiArtGenerator(AsciiFont font) { this.font = font; } public String generate(String text) { - if (text == null || text.isBlank()) throw new IllegalArgumentException("Text cannot be null or empty"); - if (text.length() > 50) throw new IllegalArgumentException("Text too long. Max 50 characters."); + if (text == null || text.isBlank()) throw new IllegalArgumentException(ERR_EMPTY); + if (text.length() > MAX_LENGTH) throw new IllegalArgumentException(ERR_TOO_LONG); return font.render(text); } }src/main/java/org/fungover/breeze/ascii2/BlockFont.java (3)
14-35: Support spaces for usability.Map ' ' to a blank glyph so phrases work (e.g., “HELLO WORLD”) instead of throwing.
private void loadFont() { + // space (width matches other glyphs) + fontMap.put(' ', new String[]{ + " ", + " ", + " " + }); fontMap.put('H', new String[]{ "██ ██", "██████", "██ ██" });
38-53: Minor perf/readability: avoid toCharArray() per row and cache glyph lookups.This reduces allocations and map hits in the inner loop.
@Override public String render(String text) { if (text == null || text.isBlank()) throw new IllegalArgumentException("Text cannot be null or empty"); text = text.toUpperCase(); - StringBuilder sb = new StringBuilder(); - int height = 3; - for (int row = 0; row < height; row++) { - for (char c : text.toCharArray()) { - if (!fontMap.containsKey(c)) { - throw new IllegalArgumentException("Unsupported character: " + c); - } - sb.append(fontMap.get(c)[row]).append(" "); - } - sb.append("\n"); - } + final int height = 3; + final char[] chars = text.toCharArray(); + StringBuilder sb = new StringBuilder(text.length() * (height * 8)); // rough capacity + for (int row = 0; row < height; row++) { + for (char c : chars) { + String[] glyph = fontMap.get(c); + if (glyph == null) throw new IllegalArgumentException("Unsupported character: " + c); + sb.append(glyph[row]).append(" "); + } + sb.append('\n'); + } return sb.toString(); }
6-12: Immutable font map (optional).After load, wrap with Collections.unmodifiableMap to prevent accidental mutation.
src/main/java/org/fungover/breeze/ascii2/StandardFont.java (4)
15-16: Use English for inline comments.Keep code comments consistent with the codebase language.
- // Förenklad version, fler kan läggas till + // Simplified version; more glyphs can be added
14-46: Support spaces for phrases.Add a space glyph so multi-word inputs don’t error.
private void loadFont() { + fontMap.put(' ', new String[]{ + " ", + " ", + " " + }); fontMap.put('A', new String[]{ " A ", " A A ", "AAAAA" });
48-64: Minor perf/readability: cache chars and glyphs inside loops.Same micro-optimization as in BlockFont.
@Override public String render(String text) { if (text == null || text.isBlank()) throw new IllegalArgumentException("Text cannot be null or empty"); text = text.toUpperCase(); - StringBuilder sb = new StringBuilder(); - int height = 3; - for (int row = 0; row < height; row++) { - for (char c : text.toCharArray()) { - if (!fontMap.containsKey(c)) { - throw new IllegalArgumentException("Unsupported character: " + c); - } - sb.append(fontMap.get(c)[row]).append(" "); - } - sb.append("\n"); - } + final int height = 3; + final char[] chars = text.toCharArray(); + StringBuilder sb = new StringBuilder(text.length() * (height * 6)); // rough capacity + for (int row = 0; row < height; row++) { + for (char c : chars) { + String[] glyph = fontMap.get(c); + if (glyph == null) throw new IllegalArgumentException("Unsupported character: " + c); + sb.append(glyph[row]).append(" "); + } + sb.append('\n'); + } return sb.toString(); }
6-12: Consider sharing common rendering logic.Both fonts duplicate rendering/validation. An abstract base (e.g., AbstractAsciiFont with height, render loop, and a protected glyph lookup) would reduce duplication and centralize behavior.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (5)
src/main/java/org/fungover/breeze/ascii2/AsciiArtGenerator.java(1 hunks)src/main/java/org/fungover/breeze/ascii2/AsciiFont.java(1 hunks)src/main/java/org/fungover/breeze/ascii2/BlockFont.java(1 hunks)src/main/java/org/fungover/breeze/ascii2/StandardFont.java(1 hunks)src/test/java/org/fungover/breeze/ascii2/AsciiArtGeneratorTest.java(1 hunks)
There was a problem hiding this comment.
Simple, clear responsibility: delegates rendering to AsciiFont.
Good input validation (null, blank, max length).
There was a problem hiding this comment.
Clean interface with only necessary methods (render, getName).
Encourages different font implementations.
There was a problem hiding this comment.
Good encapsulation with fontMap and loadFont().
Provides clear error when encountering unsupported characters.
There was a problem hiding this comment.
Similar consistent structure as BlockFont.
Easy to extend with more characters.
There was a problem hiding this comment.
Tests cover valid rendering, invalid inputs (null, empty, too long).
Checks that different fonts produce expected output.
Clear use of JUnit assertions.
This PR implements a utility for converting plain text into ASCII art.
Supports Standard and Block font styles.
Summary by CodeRabbit