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\nr\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 *\nfoo\n *\nbar\n\n\n *\nbaz\nBAM\n",
90 6,
91 },
92 // Handle chinese (wide characters)
93 {
94 "一只敏捷的狐狸跳过了一只懒狗。",
95 "一只敏捷的狐\n狸跳过了一只\n懒狗。",
96 12,
97 },
98 // Handle chinese with colors
99 {
100 "一只敏捷的\x1b[31m狐狸跳过\x1b[0m了一只懒狗。",
101 "一只敏捷的\x1b[31m狐\n狸跳过\x1b[0m了一只\n懒狗。",
102 12,
103 },
104 // Handle mixed wide and short characters
105 {
106 "敏捷 A quick 的狐狸 fox 跳过 jumps over a lazy 了一只懒狗 dog。",
107 "敏捷 A quick\n的狐狸 fox\n跳过 jumps\nover a lazy\n了一只懒狗\ndog。",
108 12,
109 },
110 // Handle mixed wide and short characters with color
111 {
112 "敏捷 A \x1b31mquick 的狐狸 fox 跳\x1b0m过 jumps over a lazy 了一只懒狗 dog。",
113 "敏捷 A \x1b31mquick\n的狐狸 fox\n跳\x1b0m过 jumps\nover a lazy\n了一只懒狗\ndog。",
114 12,
115 },
116 }
117
118 for i, tc := range cases {
119 actual, lines := Wrap(tc.Input, tc.Lim)
120 if actual != tc.Output {
121 t.Fatalf("Case %d Input:\n\n`%s`\n\nExpected Output:\n\n`%s`\n\nActual Output:\n\n`%s`",
122 i, tc.Input, tc.Output, actual)
123 }
124
125 expected := len(strings.Split(tc.Output, "\n"))
126 if expected != lines {
127 t.Fatalf("Case %d Nb lines mismatch\nExpected:%d\nActual:%d",
128 i, expected, lines)
129 }
130 }
131}
132
133func TestWrapLeftPadded(t *testing.T) {
134 cases := []struct {
135 input, output string
136 lim, pad int
137 }{
138 {
139 "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.",
140 ` The Lorem ipsum text is typically composed of
141 pseudo-Latin words. It is commonly used as placeholder
142 text to examine or demonstrate the visual effects of
143 various graphic design.`,
144 59, 4,
145 },
146 // Handle Chinese
147 {
148 "婞一枳郲逴靲屮蜧曀殳,掫乇峔掮傎溒兀緉冘仜。郼牪艽螗媷錵朸一詅掜豗怙刉笀丌,楀棶乇矹迡搦囷圣亍昄漚粁仈祂。覂一洳袶揙楱亍滻瘯毌,掗屮柅軡菵腩乜榵毌夯。勼哻怌婇怤灟葠雺奷朾恦扰衪岨坋誁乇芚誙腞。冇笉妺悆浂鱦賌廌灱灱觓坋佫呬耴跣兀枔蓔輈。嵅咍犴膰痭瘰机一靬涽捊矷尒玶乇,煚塈丌岰陊鉖怞戉兀甿跾觓夬侄。棩岧汌橩僁螗玎一逭舴圂衪扐衲兀,嵲媕亍衩衿溽昃夯丌侄蒰扂丱呤。毰侘妅錣廇螉仴一暀淖蚗佶庂咺丌,輀鈁乇彽洢溦洰氶乇构碨洐巿阹。",
149 ` 婞一枳郲逴靲屮蜧曀殳,掫乇峔掮傎溒兀緉冘仜。郼牪艽螗媷
150 錵朸一詅掜豗怙刉笀丌,楀棶乇矹迡搦囷圣亍昄漚粁仈祂。覂
151 一洳袶揙楱亍滻瘯毌,掗屮柅軡菵腩乜榵毌夯。勼哻怌婇怤灟
152 葠雺奷朾恦扰衪岨坋誁乇芚誙腞。冇笉妺悆浂鱦賌廌灱灱觓坋
153 佫呬耴跣兀枔蓔輈。嵅咍犴膰痭瘰机一靬涽捊矷尒玶乇,煚塈
154 丌岰陊鉖怞戉兀甿跾觓夬侄。棩岧汌橩僁螗玎一逭舴圂衪扐衲
155 兀,嵲媕亍衩衿溽昃夯丌侄蒰扂丱呤。毰侘妅錣廇螉仴一暀淖
156 蚗佶庂咺丌,輀鈁乇彽洢溦洰氶乇构碨洐巿阹。`,
157 59, 4,
158 },
159 }
160
161 for i, tc := range cases {
162 actual, lines := WrapLeftPadded(tc.input, tc.lim, tc.pad)
163 if actual != tc.output {
164 t.Fatalf("Case %d Input:\n\n`%s`\n\nExpected Output:\n`\n%s`\n\nActual Output:\n`\n%s\n%s`",
165 i, tc.input, tc.output,
166 "|"+strings.Repeat("-", tc.lim-2)+"|",
167 actual)
168 }
169
170 expected := len(strings.Split(tc.output, "\n"))
171 if expected != lines {
172 t.Fatalf("Case %d Nb lines mismatch\nExpected:%d\nActual:%d",
173 i, expected, lines)
174 }
175 }
176}
177
178func TestWordLen(t *testing.T) {
179 cases := []struct {
180 Input string
181 Length int
182 }{
183 // A simple word
184 {
185 "foo",
186 3,
187 },
188 // A simple word with colors
189 {
190 "\x1b[31mbar\x1b[0m",
191 3,
192 },
193 // Handle prefix and suffix properly
194 {
195 "foo\x1b[31mfoobarHoy\x1b[0mbaaar",
196 17,
197 },
198 // Handle chinese
199 {
200 "快檢什麼望對",
201 12,
202 },
203 // Handle chinese with colors
204 {
205 "快\x1b[31m檢什麼\x1b[0m望對",
206 12,
207 },
208 }
209
210 for i, tc := range cases {
211 l := wordLen(tc.Input)
212 if l != tc.Length {
213 t.Fatalf("Case %d Input:\n\n`%s`\n\nExpected Output:\n\n`%d`\n\nActual Output:\n\n`%d`",
214 i, tc.Input, tc.Length, l)
215 }
216 }
217}
218
219func TestSplitWord(t *testing.T) {
220 cases := []struct {
221 Input string
222 Length int
223 Result, Leftover string
224 }{
225 // A simple word passes through.
226 {
227 "foo",
228 4,
229 "foo", "",
230 },
231 // Cut at the right place
232 {
233 "foobarHoy",
234 4,
235 "foob", "arHoy",
236 },
237 // A simple word passes through with colors
238 {
239 "\x1b[31mbar\x1b[0m",
240 4,
241 "\x1b[31mbar\x1b[0m", "",
242 },
243 // Cut at the right place with colors
244 {
245 "\x1b[31mfoobarHoy\x1b[0m",
246 4,
247 "\x1b[31mfoob", "arHoy\x1b[0m",
248 },
249 // Handle prefix and suffix properly
250 {
251 "foo\x1b[31mfoobarHoy\x1b[0mbaaar",
252 4,
253 "foo\x1b[31mf", "oobarHoy\x1b[0mbaaar",
254 },
255 // Cut properly with length = 0
256 {
257 "foo",
258 0,
259 "", "foo",
260 },
261 // Handle chinese
262 {
263 "快檢什麼望對",
264 4,
265 "快檢", "什麼望對",
266 },
267 {
268 "快檢什麼望對",
269 5,
270 "快檢", "什麼望對",
271 },
272 // Handle chinese with colors
273 {
274 "快\x1b[31m檢什麼\x1b[0m望對",
275 4,
276 "快\x1b[31m檢", "什麼\x1b[0m望對",
277 },
278 }
279
280 for i, tc := range cases {
281 result, leftover := splitWord(tc.Input, tc.Length)
282 if result != tc.Result || leftover != tc.Leftover {
283 t.Fatalf("Case %d Input:\n\n`%s`\n\nExpected Output:\n\n`%s` - `%s`\n\nActual Output:\n\n`%s` - `%s`",
284 i, tc.Input, tc.Result, tc.Leftover, result, leftover)
285 }
286 }
287}