1package text
2
3import (
4 "strings"
5 "testing"
6)
7
8func TestWrap(t *testing.T) {
9 cases := []struct {
10 Input, Output string
11 Lim int
12 }{
13 // A simple word passes through.
14 {
15 "foo",
16 "foo",
17 4,
18 },
19 // Word breaking
20 {
21 "foobarbaz",
22 "foob\narba\nz",
23 4,
24 },
25 // Lines are broken at whitespace.
26 {
27 "foo bar baz",
28 "foo\nbar\nbaz",
29 4,
30 },
31 // Word breaking
32 {
33 "foo bars bazzes",
34 "foo\nbars\nbazz\nes",
35 4,
36 },
37 // A word that would run beyond the width is wrapped.
38 {
39 "fo sop",
40 "fo\nsop",
41 4,
42 },
43 // A tab counts as 4 characters.
44 {
45 "foo\nb\t r\n baz",
46 "foo\nb\n r\n baz",
47 4,
48 },
49 // Trailing whitespace is removed after used for wrapping.
50 // Runs of whitespace on which a line is broken are removed.
51 {
52 "foo \nb ar ",
53 "foo\n\nb\nar\n",
54 4,
55 },
56 // An explicit line break at the end of the input is preserved.
57 {
58 "foo bar baz\n",
59 "foo\nbar\nbaz\n",
60 4,
61 },
62 // Explicit break are always preserved.
63 {
64 "\nfoo bar\n\n\nbaz\n",
65 "\nfoo\nbar\n\n\nbaz\n",
66 4,
67 },
68 // Ignore complete words with terminal color sequence
69 {
70 "foo \x1b[31mbar\x1b[0m baz",
71 "foo\n\x1b[31mbar\x1b[0m\nbaz",
72 4,
73 },
74 // Handle words with colors sequence inside the word
75 {
76 "foo b\x1b[31mbar\x1b[0mr baz",
77 "foo\nb\x1b[31mbar\n\x1b[0mr\nbaz",
78 4,
79 },
80 // Break words with colors sequence inside the word
81 {
82 "foo bb\x1b[31mbar\x1b[0mr baz",
83 "foo\nbb\x1b[31mba\nr\x1b[0mr\nbaz",
84 4,
85 },
86 // Complete example:
87 {
88 " This is a list: \n\n\t* foo\n\t* bar\n\n\n\t* baz \nBAM ",
89 " This\nis a\nlist:\n\n\n *\nfoo\n *\nbar\n\n\n *\nbaz\nBAM\n",
90 6,
91 },
92 // Handle chinese
93 {
94 "婞一枳郲逴靲屮蜧曀殳,掫乇峔掮傎溒兀緉冘仜。",
95 "婞一枳郲逴靲屮蜧曀殳,掫\n乇峔掮傎溒兀緉冘仜。",
96 12,
97 },
98 // Handle chinese with colors
99 {
100 "婞一枳郲逴\x1b[31m靲屮蜧曀殳,掫乇峔掮傎溒\x1b[0m兀緉冘仜。",
101 "婞一枳郲逴\x1b[31m靲屮蜧曀殳,掫\n乇峔掮傎溒\x1b[0m兀緉冘仜。",
102 12,
103 },
104 }
105
106 for i, tc := range cases {
107 actual, lines := Wrap(tc.Input, tc.Lim)
108 if actual != tc.Output {
109 t.Fatalf("Case %d Input:\n\n`%s`\n\nExpected Output:\n\n`%s`\n\nActual Output:\n`\n%s`",
110 i, tc.Input, tc.Output, actual)
111 }
112
113 expected := len(strings.Split(tc.Output, "\n"))
114 if expected != lines {
115 t.Fatalf("Case %d Nb lines mismatch\nExpected:%d\nActual:%d",
116 i, expected, lines)
117 }
118 }
119}
120
121func TestWrapLeftPadded(t *testing.T) {
122 cases := []struct {
123 input, output string
124 lim, pad int
125 }{
126 {
127 "The Lorem ipsum text is typically composed of pseudo-Latin words. It is commonly used as placeholder text to examine or demonstrate the visual effects of various graphic design.",
128 ` The Lorem ipsum text is typically composed of
129 pseudo-Latin words. It is commonly used as placeholder
130 text to examine or demonstrate the visual effects of
131 various graphic design.`,
132 59, 4,
133 },
134 }
135
136 for i, tc := range cases {
137 actual, lines := WrapLeftPadded(tc.input, tc.lim, tc.pad)
138 if actual != tc.output {
139 t.Fatalf("Case %d Input:\n\n`%s`\n\nExpected Output:\n`\n%s`\n\nActual Output:\n`\n%s\n%s`",
140 i, tc.input, tc.output,
141 "|"+strings.Repeat("-", tc.lim-2)+"|",
142 actual)
143 }
144
145 expected := len(strings.Split(tc.output, "\n"))
146 if expected != lines {
147 t.Fatalf("Case %d Nb lines mismatch\nExpected:%d\nActual:%d",
148 i, expected, lines)
149 }
150 }
151}
152
153func TestWordLen(t *testing.T) {
154 cases := []struct {
155 Input string
156 Length int
157 }{
158 // A simple word
159 {
160 "foo",
161 3,
162 },
163 // A simple word with colors
164 {
165 "\x1b[31mbar\x1b[0m",
166 3,
167 },
168 // Handle prefix and suffix properly
169 {
170 "foo\x1b[31mfoobarHoy\x1b[0mbaaar",
171 17,
172 },
173 // Handle chinese
174 {
175 "快檢什麼望對",
176 6,
177 },
178 // Handle chinese with colors
179 {
180 "快\x1b[31m檢什麼\x1b[0m望對",
181 6,
182 },
183 }
184
185 for i, tc := range cases {
186 l := wordLen(tc.Input)
187 if l != tc.Length {
188 t.Fatalf("Case %d Input:\n\n`%s`\n\nExpected Output:\n\n`%d`\n\nActual Output:\n\n`%d`",
189 i, tc.Input, tc.Length, l)
190 }
191 }
192}
193
194func TestSplitWord(t *testing.T) {
195 cases := []struct {
196 Input string
197 Length int
198 Result, Leftover string
199 }{
200 // A simple word passes through.
201 {
202 "foo",
203 4,
204 "foo", "",
205 },
206 // Cut at the right place
207 {
208 "foobarHoy",
209 4,
210 "foob", "arHoy",
211 },
212 // A simple word passes through with colors
213 {
214 "\x1b[31mbar\x1b[0m",
215 4,
216 "\x1b[31mbar\x1b[0m", "",
217 },
218 // Cut at the right place with colors
219 {
220 "\x1b[31mfoobarHoy\x1b[0m",
221 4,
222 "\x1b[31mfoob", "arHoy\x1b[0m",
223 },
224 // Handle prefix and suffix properly
225 {
226 "foo\x1b[31mfoobarHoy\x1b[0mbaaar",
227 4,
228 "foo\x1b[31mf", "oobarHoy\x1b[0mbaaar",
229 },
230 // Cut properly with length = 0
231 {
232 "foo",
233 0,
234 "", "foo",
235 },
236 // Handle chinese
237 {
238 "快檢什麼望對",
239 2,
240 "快檢", "什麼望對",
241 },
242 // Handle chinese with colors
243 {
244 "快\x1b[31m檢什麼\x1b[0m望對",
245 2,
246 "快\x1b[31m檢", "什麼\x1b[0m望對",
247 },
248 }
249
250 for i, tc := range cases {
251 result, leftover := splitWord(tc.Input, tc.Length)
252 if result != tc.Result || leftover != tc.Leftover {
253 t.Fatalf("Case %d Input:\n\n`%s`\n\nExpected Output:\n\n`%s` - `%s`\n\nActual Output:\n\n`%s` - `%s`",
254 i, tc.Input, tc.Result, tc.Leftover, result, leftover)
255 }
256 }
257}