1 package org.davidmoten.text.utils;
2
3 import static org.junit.Assert.assertEquals;
4 import static org.junit.Assert.assertTrue;
5
6 import java.io.ByteArrayInputStream;
7 import java.io.ByteArrayOutputStream;
8 import java.io.File;
9 import java.io.FileWriter;
10 import java.io.IOException;
11 import java.io.OutputStreamWriter;
12 import java.io.Reader;
13 import java.io.StringReader;
14 import java.io.Writer;
15 import java.nio.charset.StandardCharsets;
16 import java.nio.file.Files;
17 import java.util.ArrayList;
18 import java.util.Arrays;
19 import java.util.List;
20
21 import org.junit.FixMethodOrder;
22 import org.junit.Test;
23 import org.junit.runners.MethodSorters;
24
25 import com.github.davidmoten.junit.Asserts;
26
27 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
28 public class WordWrapTest {
29
30
31
32
33
34 @Test
35 public void longLineSplitsOnWhiteSpace() {
36 check("hello there", "hello\nthere");
37 }
38
39 @Test
40 public void longLineWithTwoSpacesInMiddle() {
41 check("hello there", "hello\nthere");
42 }
43
44 @Test
45 public void longLineALotOfWhiteSpaceInMiddle() {
46 check("hello there", "hello\nthere");
47 }
48
49 @Test
50 public void precedingWhitespaceConserved() {
51 check(" he", " he");
52 }
53
54 @Test
55 public void precedingWhitespaceLongWord() {
56 check(" helloyou", " hel-\nloyou");
57 }
58
59 @Test
60 public void whitespacePreservedAfterNewLine() {
61 check("hello\n the", "hello\n the");
62 }
63
64 @Test
65 public void shortLineNoWhitespace() {
66 check("hello", "hello");
67 }
68
69 @Test
70 public void shortLineHasWhitespace() {
71 check("hi bo", "hi bo");
72 }
73
74 @Test
75 public void emptyText() {
76 check("", "");
77 }
78
79 @Test
80 public void oneLetter() {
81 check("a", "a");
82 }
83
84 @Test
85 public void spaceThenOneLetter() {
86 check(" a", " a");
87 }
88
89 @Test
90 public void newLineCharacterPreserved() {
91 check("hello\nthere", "hello\nthere");
92 }
93
94 @Test
95 public void carriageReturnRemoved() {
96 check("hello\r\nthere", "hello\nthere");
97 }
98
99 @Test
100 public void whitespaceConservedAfterNewLine() {
101 check("hello\n there", "hello\n there");
102 }
103
104 @Test
105 public void wrapRightTrimsWhitespaceBeforeNewLine() {
106 check("abc \ncde ", "abc\ncde ");
107 }
108
109 @Test
110 public void longWordForcesBreak() {
111 check("hellothere", "hello-\nthere");
112 }
113
114 @Test
115 public void longWordForcesBreakNoHyphens() {
116 assertEquals("hellot\nhere",
117 WordWrap.from("hellothere").maxWidth(6).insertHyphens(false).wrap());
118 }
119
120 @Test
121 public void breakOnCommaDoesNotHappenWithoutSpaceAfter() {
122 check("hi,there", "hi,th-\nere");
123 }
124
125 @Test
126 public void noHyphenAfterDigits() {
127 check("1234567890", "123456\n7890");
128 }
129
130 @Test
131 public void breakOnCommasWithDigits() {
132 check("1,2,3,4,5,6,7,8,9", "1,2,3,\n4,5,6,\n7,8,9");
133 }
134
135 @Test
136 public void longThenShort() {
137 check("hellothere\n boo", "hello-\nthere\n boo");
138 }
139
140 @Test
141 public void longThenShortWithMoreLines() {
142 check("hellothere\n boo\n hi", "hello-\nthere\n boo\n hi");
143 }
144
145 @Test
146 public void endWithNewLine() {
147 check("a\n", "a\n");
148 }
149
150 @Test
151 public void spaceAndQuestionMark() {
152 check(" ?", " ?");
153 }
154
155 @Test
156 public void dontBreakOnQuestionMark() {
157 check("ab cde?", "ab\ncde?");
158 }
159
160 @Test
161 public void breakOnQuote() {
162 check("says 'helo'", "says\n'helo'");
163 }
164
165 @Test
166 public void breakQuoteInMiddle() {
167 check("why he's nasty", "why\nhe's\nnasty");
168 }
169
170 @Test
171 public void shortThenLong() {
172 check("hi mygoodnessme", "hi\nmygoo-\ndness-\nme");
173 }
174
175 @Test
176 public void longWhitespaceThenWord() {
177 check(" a", "\na");
178 }
179
180 @Test
181 public void longWhitespaceLastLine() {
182 check(" ", "");
183 }
184
185 @Test
186 public void longWhitespaceThenNewLine() {
187 check(" \n", "\n");
188 }
189
190 @Test
191 public void conserveWhitespace() {
192 check(" ab\n cd\n ef\n\nhi", " ab\n cd\n ef\n\nhi");
193 }
194
195
196
197
198
199 @Test
200 public void testLeftTrimLeadingEmpty() {
201 StringBuilder2 s = new StringBuilder2("");
202 WordWrap.leftTrim(s);
203 assertEquals("", s.toString());
204 }
205
206 @Test
207 public void testLeftTrimLeadingSpaces0() {
208 StringBuilder2 s = new StringBuilder2("abc");
209 WordWrap.leftTrim(s);
210 assertEquals("abc", s.toString());
211 }
212
213 @Test
214 public void testLeftTrimLeadingSpaces1() {
215 StringBuilder2 s = new StringBuilder2(" abc");
216 WordWrap.leftTrim(s);
217 assertEquals("abc", s.toString());
218 }
219
220 @Test
221 public void testLeftTrimLeadingSpaces3() {
222 StringBuilder2 s = new StringBuilder2(" abc");
223 WordWrap.leftTrim(s);
224 assertEquals("abc", s.toString());
225 }
226
227
228
229
230
231 @Test
232 public void testRightTrimAtEnd() {
233 assertEquals("abc", WordWrap.rightTrim("abc "));
234 }
235
236 @Test
237 public void testRightTrimNoSpace() {
238 assertEquals("abc", WordWrap.rightTrim("abc"));
239 }
240
241 @Test
242 public void testRightTrimEmpty() {
243 assertEquals("", WordWrap.rightTrim(""));
244 }
245
246 @Test
247 public void testRightTrimOnlySpace() {
248 assertEquals("", WordWrap.rightTrim(" "));
249 }
250
251
252
253
254
255 @Test
256 public void testStringWidth() {
257 String text = WordWrap.from("abc").maxWidth(4).stringWidth(s -> s.length() * 2).wrap();
258 assertEquals("a-\nbc", text);
259 }
260
261 @Test
262 public void testNewLineOverride() {
263 String text = WordWrap.from("abc").maxWidth(2).newLine("\r\n").wrap();
264 assertEquals("a-\r\nbc", text);
265 }
266
267 @Test
268 public void testSetWordChars() {
269 String text = WordWrap.from("abc").maxWidth(2).extraWordChars("abc").wrap();
270 assertEquals("a-\nbc", text);
271 }
272
273 @Test
274 public void testIncludeWordChars() {
275 String text = WordWrap.from("abc").maxWidth(2).extraWordChars("")
276 .includeExtraWordChars("abc").wrap();
277 assertEquals("a-\nbc", text);
278 }
279
280 @Test
281 public void testExcludeWordChars() {
282 String text = WordWrap.from("abc").maxWidth(2).extraWordChars("abc")
283 .excludeExtraWordChars("abc").wrap();
284 assertEquals("a-\nbc", text);
285 }
286
287 @Test
288 public void testDontBreakLongWords() {
289 String s = WordWrap.from("hello jonathon").maxWidth(6).breakWords(false).wrap();
290 assertEquals("hello\njonathon", s);
291 }
292
293 @Test
294 public void testDontBreakLongWords2() {
295 String s = WordWrap.from("hell jonathon").maxWidth(6).breakWords(false).wrap();
296 assertEquals("hell\njonathon", s);
297 }
298
299 @Test
300 public void testFromInputStream() {
301 ByteArrayInputStream bytes = new ByteArrayInputStream(
302 "hi".getBytes(StandardCharsets.UTF_8));
303 assertEquals("hi", WordWrap.fromUtf8(bytes).maxWidth(6).wrap());
304 }
305
306 @Test
307 public void testFromFile() throws IOException {
308 Files.write(new File("target/test1.txt").toPath(), "hi".getBytes(StandardCharsets.UTF_8));
309 assertEquals("hi", WordWrap.from(new File("target/test1.txt"), StandardCharsets.UTF_8)
310 .maxWidth(6).wrap());
311 }
312
313 @Test(expected = IORuntimeException.class)
314 public void testWriterThrows() {
315 WordWrap.from("abc").wrap(new Writer() {
316
317 @Override
318 public void write(char[] cbuf, int off, int len) throws IOException {
319 throw new IOException("boo");
320 }
321
322 @Override
323 public void flush() throws IOException {
324
325 }
326
327 @Override
328 public void close() throws IOException {
329
330 }
331 });
332 }
333
334 @Test(expected = IORuntimeException.class)
335 public void testWrapToFileThrows() {
336 WordWrap.from("abc").wrap(new File("target/doesNoExist/temp.txt"), StandardCharsets.UTF_8);
337 }
338
339 @Test(expected = IORuntimeException.class)
340 public void testCloseReaderThrows() {
341 WordWrap.close(new Reader() {
342
343 @Override
344 public int read(char[] cbuf, int off, int len) throws IOException {
345 return 0;
346 }
347
348 @Override
349 public void close() throws IOException {
350 throw new IOException("boo");
351 }
352 });
353 }
354
355 @Test(expected = IORuntimeException.class)
356 public void testFromFileDoesNotExist() throws IOException {
357 WordWrap.from(new File("target/doesNotExist"), StandardCharsets.UTF_8).maxWidth(6).wrap();
358 }
359
360 @Test
361 public void testToList() {
362 List<String> list = WordWrap.from("hello there how are you").maxWidth(10).wrapToList();
363 assertEquals(Arrays.asList("hello", "there how", "are you"), list);
364 }
365
366 @Test
367 public void testToListWithNewLines() {
368 List<String> list = WordWrap.from("hello\n\n\n\nhow how\n").maxWidth(10).wrapToList();
369 assertEquals(Arrays.asList("hello", "", "","", "how how"), list);
370 }
371
372 @Test
373 public void testToListFinishWithNewLines() {
374 List<String> list = WordWrap.from("hello\n\n\n\n").maxWidth(10).wrapToList();
375 assertEquals(Arrays.asList("hello", "", "",""), list);
376 }
377
378 @Test(expected=IORuntimeException.class)
379 public void testLineConsumerThrows() {
380 WordWrap.from("hello there how are you").maxWidth(10).wrap(new LineConsumer() {
381
382 @Override
383 public void write(char[] chars, int offset, int length) throws IOException {
384 throw new IOException("problem");
385 }
386
387 @Override
388 public void writeNewLine() throws IOException {
389 throw new IOException("problem");
390 }});
391 }
392
393 @Test(expected=IORuntimeException.class)
394 public void testLineConsumerThrowsDontCloseReader() {
395 StringReader reader = new StringReader("hello there how are you");
396 WordWrap.from(reader, false).maxWidth(10).wrap(new LineConsumer() {
397
398 @Override
399 public void write(char[] chars, int offset, int length) throws IOException {
400 throw new IOException("problem");
401 }
402
403 @Override
404 public void writeNewLine() throws IOException {
405 throw new IOException("problem");
406 }});
407 }
408
409 @Test(expected = IllegalArgumentException.class)
410 public void testMaxWidthZero() {
411 WordWrap.from("abc").maxWidth(0);
412 }
413
414 @Test
415 public void testWrapToFile() {
416 File file = new File("target/testWrap.txt");
417 WordWrap.from("abc").wrap(file.getAbsolutePath(), StandardCharsets.UTF_8);
418 assertTrue(file.exists());
419 }
420
421 @Test
422 public void testDontWrapNumbers() {
423 assertEquals("hello\n123", WordWrap.from("hello 123").extraWordChars("0123456789").breakWords(false).maxWidth(8).wrap());
424 }
425
426 @Test
427 public void testNumbersWrapByDefault() {
428 assertEquals("hello 12\n3", WordWrap.from("hello 123").breakWords(false).maxWidth(8).wrap());
429 }
430
431 @Test
432 public void testStatelessness() {
433 assertEquals("hello super-\ncool", WordWrap.from("hello super-cool").breakWords(false).maxWidth(12).wrap());
434 assertEquals("hello\nsuper-cool", WordWrap.from("hello super-cool").breakWords(false).maxWidth(12).includeExtraWordChars("-").wrap());
435 assertEquals("hello super-\ncool", WordWrap.from("hello super-cool").breakWords(false).maxWidth(12).wrap());
436 }
437
438 @Test
439 public void testIssue49() {
440 assertEquals("CELESTAN Depot\n2,7mg/ml",
441 WordWrap
442 .from("CELESTAN Depot 2,7mg/ml")
443 .includeExtraWordChars("0123456789")
444 .breakWords(false)
445 .maxWidth(17)
446 .wrap());
447 }
448
449
450
451
452
453 @Test
454 public void testImportanceOfBeingEarnest() throws IOException {
455 WordWrap.fromClasspathUtf8("/the-importance-of-being-earnest.txt")
456 .maxWidth(20)
457 .wrapUtf8("target/the-importance-of-being-earnest.txt");
458 }
459
460 @Test
461 public void testTheBlackGang() throws IOException {
462 WordWrap.fromClasspathUtf8("/the-black-gang.txt")
463 .maxWidth(20)
464 .wrapUtf8("target/the-black-gang.txt");
465 }
466
467 @Test
468 public void testTreasureIsland() throws IOException {
469 WordWrap.fromClasspathUtf8("/treasure-island-fragment.txt")
470 .maxWidth(80)
471 .wrapUtf8("target/treasure-island-fragment.txt");
472 }
473
474 @Test
475 public void testWrapWithAtLeastLineLongWhitespaceFollowedByParenthesis() {
476 int maxWidth = 25;
477 assertEquals("(abc", WordWrap.from(repeat(" ", maxWidth) + "(abc")
478 .maxWidth(maxWidth).wrap());
479 }
480
481 private static String repeat(String s, int n) {
482 StringBuilder b = new StringBuilder();
483 for (int i = 0; i < n; i++) {
484 b.append(s);
485 }
486 return b.toString();
487 }
488
489 @Test
490 public void testIsUtilityClass() {
491 Asserts.assertIsUtilityClass(WordWrap.class);
492 }
493
494 private static final class Check {
495 final String input;
496 final String output;
497 final String name;
498
499 Check(String input, String output, String name) {
500 this.input = input;
501 this.output = output;
502 this.name = name;
503 }
504
505 }
506
507 private static List<Check> checks = new ArrayList<>();
508
509 private static void check(String text, String expected) {
510 String s = WordWrap.from(text).maxWidth(6).wrap();
511
512 assertEquals(expected, s);
513 String name = Thread.currentThread().getStackTrace()[2].getMethodName();
514 checks.add(new Check(text, expected, name));
515 int i = 0;
516 try (FileWriter out = new FileWriter("src/docs/rules.md")) {
517 out.append("## Wrapping rules\n");
518 out.append(
519 "The rules below are generated from the unit tests in `WordWrapTest.java`. The default wrapping configuration used is a line length of 6 characters. The $ symbol is used to represent a new line character.\n\n");
520 for (Check check : checks) {
521 i++;
522 out.append(i + ". **" + check.name + "**\n\n");
523 out.append("Input:\n");
524 out.append("```\n");
525 out.append(prettify(check.input));
526 out.append("\n```\n");
527 out.append("Output:\n");
528 out.append("```\n");
529 out.append(prettify(check.output));
530 out.append("\n```\n\n");
531 }
532 } catch (IOException e) {
533 throw new RuntimeException(e);
534 }
535 }
536
537 private static String prettify(String s) {
538 return s.replace(" ", "\u2423").replace("\n", "$\n");
539 }
540
541 public static void main(String[] args) throws IOException {
542 int i = 0;
543 long t = 0;
544 ByteArrayOutputStream b = new ByteArrayOutputStream(128 * 1024);
545 byte[] bytes = Files
546 .readAllBytes(new File("src/test/resources/treasure-island-fragment.txt").toPath());
547 String text = new String(bytes, StandardCharsets.UTF_8);
548 while (true) {
549 b.reset();
550 Writer out = new OutputStreamWriter(b, StandardCharsets.UTF_8);
551 WordWrap.from(text)
552 .maxWidth(80)
553 .wrap(out);
554 i++;
555 if (i % 100 == 0) {
556 if (i > 1000 && t == 0) {
557 t = System.currentTimeMillis();
558 i = 0;
559 }
560 long dt = System.currentTimeMillis() - t;
561 if (dt != 0) {
562 System.out.println("avgPerSecond=" + (i * 1000 / dt));
563 }
564 }
565 }
566 }
567
568 }