1 package text
2
3 import (
4 "testing"
5 "time"
6
7 "github.com/stretchr/testify/assert"
8 )
9
10 func TestRelativeTimeAgo(t *testing.T) {
11 const form = "2006-Jan-02 15:04:05"
12 now, _ := time.Parse(form, "2020-Nov-22 14:00:00")
13 cases := map[string]string{
14 "2020-Nov-22 14:00:00": "less than a minute ago",
15 "2020-Nov-22 13:59:30": "less than a minute ago",
16 "2020-Nov-22 13:59:00": "about 1 minute ago",
17 "2020-Nov-22 13:30:00": "about 30 minutes ago",
18 "2020-Nov-22 13:00:00": "about 1 hour ago",
19 "2020-Nov-22 02:00:00": "about 12 hours ago",
20 "2020-Nov-21 14:00:00": "about 1 day ago",
21 "2020-Nov-07 14:00:00": "about 15 days ago",
22 "2020-Oct-24 14:00:00": "about 29 days ago",
23 "2020-Oct-23 14:00:00": "about 1 month ago",
24 "2020-Sep-23 14:00:00": "about 2 months ago",
25 "2019-Nov-22 14:00:00": "about 1 year ago",
26 "2018-Nov-22 14:00:00": "about 2 years ago",
27 }
28 for createdAt, expected := range cases {
29 d, err := time.Parse(form, createdAt)
30 assert.NoError(t, err)
31 relative := RelativeTimeAgo(now, d)
32 assert.Equal(t, expected, relative)
33 }
34 }
35
36 func TestTruncate(t *testing.T) {
37 type args struct {
38 max int
39 s string
40 }
41 tests := []struct {
42 name string
43 args args
44 want string
45 }{
46 {
47 name: "empty",
48 args: args{
49 s: "",
50 max: 10,
51 },
52 want: "",
53 },
54 {
55 name: "short",
56 args: args{
57 s: "hello",
58 max: 3,
59 },
60 want: "hel",
61 },
62 {
63 name: "long",
64 args: args{
65 s: "hello world",
66 max: 5,
67 },
68 want: "he...",
69 },
70 {
71 name: "no truncate",
72 args: args{
73 s: "hello world",
74 max: 11,
75 },
76 want: "hello world",
77 },
78 {
79 name: "Short enough",
80 args: args{
81 max: 5,
82 s: "short",
83 },
84 want: "short",
85 },
86 {
87 name: "Too short",
88 args: args{
89 max: 4,
90 s: "short",
91 },
92 want: "shor",
93 },
94 {
95 name: "Japanese",
96 args: args{
97 max: 11,
98 s: "テストテストテストテスト",
99 },
100 want: "テストテ...",
101 },
102 {
103 name: "Japanese filled",
104 args: args{
105 max: 11,
106 s: "aテストテストテストテスト",
107 },
108 want: "aテスト... ",
109 },
110 {
111 name: "Chinese",
112 args: args{
113 max: 11,
114 s: "幫新舉報違章工廠新增編號",
115 },
116 want: "幫新舉報...",
117 },
118 {
119 name: "Chinese filled",
120 args: args{
121 max: 11,
122 s: "a幫新舉報違章工廠新增編號",
123 },
124 want: "a幫新舉... ",
125 },
126 {
127 name: "Korean",
128 args: args{
129 max: 11,
130 s: "프로젝트 내의",
131 },
132 want: "프로젝트...",
133 },
134 {
135 name: "Korean filled",
136 args: args{
137 max: 11,
138 s: "a프로젝트 내의",
139 },
140 want: "a프로젝... ",
141 },
142 {
143 name: "Emoji",
144 args: args{
145 max: 11,
146 s: "💡💡💡💡💡💡💡💡💡💡💡💡",
147 },
148 want: "💡💡💡💡...",
149 },
150 {
151 name: "Accented characters",
152 args: args{
153 max: 11,
154 s: "é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́",
155 },
156 want: "é́́é́́é́́é́́é́́é́́é́́é́́...",
157 },
158 {
159 name: "Red accented characters",
160 args: args{
161 max: 11,
162 s: "\x1b[0;31mé́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́é́́\x1b[0m",
163 },
164 want: "\x1b[0;31mé́́é́́é́́é́́é́́é́́é́́é́́...\x1b[0m",
165 },
166 }
167 for _, tt := range tests {
168 t.Run(tt.name, func(t *testing.T) {
169 got := Truncate(tt.args.max, tt.args.s)
170 assert.Equal(t, tt.want, got)
171 })
172 }
173 }
174
175 func TestPadRight(t *testing.T) {
176 type args struct {
177 max int
178 s string
179 }
180 tests := []struct {
181 name string
182 args args
183 want string
184 }{
185 {
186 name: "empty",
187 args: args{
188 s: "",
189 max: 5,
190 },
191 want: " ",
192 },
193 {
194 name: "short",
195 args: args{
196 s: "hello",
197 max: 7,
198 },
199 want: "hello ",
200 },
201 {
202 name: "long",
203 args: args{
204 s: "hello world",
205 max: 5,
206 },
207 want: "hello world",
208 },
209 {
210 name: "exact",
211 args: args{
212 s: "hello world",
213 max: 11,
214 },
215 want: "hello world",
216 },
217 {
218 name: "Japanese",
219 args: args{
220 s: "テストテスト",
221 max: 13,
222 },
223 want: "テストテスト ",
224 },
225 {
226 name: "Japanese filled",
227 args: args{
228 s: "aテスト",
229 max: 9,
230 },
231 want: "aテスト ",
232 },
233 {
234 name: "Chinese",
235 args: args{
236 s: "幫新舉報違章工廠新增編號",
237 max: 26,
238 },
239 want: "幫新舉報違章工廠新增編號 ",
240 },
241 {
242 name: "Chinese filled",
243 args: args{
244 s: "a幫新舉報違章工廠新增編號",
245 max: 26,
246 },
247 want: "a幫新舉報違章工廠新增編號 ",
248 },
249 {
250 name: "Korean",
251 args: args{
252 s: "프로젝트 내의",
253 max: 15,
254 },
255 want: "프로젝트 내의 ",
256 },
257 {
258 name: "Korean filled",
259 args: args{
260 s: "a프로젝트 내의",
261 max: 15,
262 },
263 want: "a프로젝트 내의 ",
264 },
265 {
266 name: "Emoji",
267 args: args{
268 s: "💡💡💡💡",
269 max: 10,
270 },
271 want: "💡💡💡💡 ",
272 },
273 {
274 name: "Accented characters",
275 args: args{
276 s: "é́́é́́é́́é́́é́́",
277 max: 7,
278 },
279 want: "é́́é́́é́́é́́é́́ ",
280 },
281 {
282 name: "Red accented characters",
283 args: args{
284 s: "\x1b[0;31mé́́é́́é́́é́́é́́\x1b[0m",
285 max: 7,
286 },
287 want: "\x1b[0;31mé́́é́́é́́é́́é́́\x1b[0m ",
288 },
289 }
290 for _, tt := range tests {
291 t.Run(tt.name, func(t *testing.T) {
292 got := PadRight(tt.args.max, tt.args.s)
293 assert.Equal(t, tt.want, got)
294 })
295 }
296 }
297
298 func TestDisplayWidth(t *testing.T) {
299 tests := []struct {
300 name string
301 text string
302 want int
303 }{
304 {
305 name: "check mark",
306 text: `✓`,
307 want: 1,
308 },
309 {
310 name: "bullet icon",
311 text: `•`,
312 want: 1,
313 },
314 {
315 name: "middle dot",
316 text: `·`,
317 want: 1,
318 },
319 {
320 name: "ellipsis",
321 text: `…`,
322 want: 1,
323 },
324 {
325 name: "right arrow",
326 text: `→`,
327 want: 1,
328 },
329 {
330 name: "smart double quotes",
331 text: `“”`,
332 want: 2,
333 },
334 {
335 name: "smart single quotes",
336 text: `‘’`,
337 want: 2,
338 },
339 {
340 name: "em dash",
341 text: `—`,
342 want: 1,
343 },
344 {
345 name: "en dash",
346 text: `–`,
347 want: 1,
348 },
349 {
350 name: "emoji",
351 text: `👍`,
352 want: 2,
353 },
354 {
355 name: "multi-byte emoji",
356 text: `👨💻`,
357 want: 2,
358 },
359 {
360 name: "accent character",
361 text: `é́́`,
362 want: 1,
363 },
364 {
365 name: "color codes",
366 text: "\x1b[0;31mred\x1b[0m",
367 want: 3,
368 },
369 {
370 name: "empty",
371 text: "",
372 want: 0,
373 },
374 {
375 name: "Latin",
376 text: "hello world 123$#!",
377 want: 18,
378 },
379 {
380 name: "Asian",
381 text: "つのだ☆HIRO",
382 want: 11,
383 },
384 }
385 for _, tt := range tests {
386 t.Run(tt.name, func(t *testing.T) {
387 got := DisplayWidth(tt.text)
388 assert.Equal(t, tt.want, got)
389 })
390 }
391 }
392
393 func TestIndent(t *testing.T) {
394 type args struct {
395 s string
396 indent string
397 }
398 tests := []struct {
399 name string
400 args args
401 want string
402 }{
403 {
404 name: "empty",
405 args: args{
406 s: "",
407 indent: "--",
408 },
409 want: "",
410 },
411 {
412 name: "blank",
413 args: args{
414 s: "\n",
415 indent: "--",
416 },
417 want: "\n",
418 },
419 {
420 name: "indent",
421 args: args{
422 s: "one\ntwo\nthree",
423 indent: "--",
424 },
425 want: "--one\n--two\n--three",
426 },
427 }
428 for _, tt := range tests {
429 t.Run(tt.name, func(t *testing.T) {
430 got := Indent(tt.args.s, tt.args.indent)
431 assert.Equal(t, tt.want, got)
432 })
433 }
434 }
435
436 func TestRemoveDiacritics(t *testing.T) {
437 tests := [][]string{
438
439 {"e", "e"},
440 {"و", "و"},
441 {"И", "И"},
442 {"ж", "ж"},
443 {"私", "私"},
444 {"万", "万"},
445
446
447 {"à", "a"},
448 {"é", "e"},
449 {"è", "e"},
450 {"ô", "o"},
451 {"ᾳ", "α"},
452 {"εͅ", "ε"},
453 {"ῃ", "η"},
454 {"ιͅ", "ι"},
455
456 {"ؤ", "و"},
457
458 {"ā", "a"},
459 {"č", "c"},
460 {"ģ", "g"},
461 {"ķ", "k"},
462 {"ņ", "n"},
463 {"š", "s"},
464 {"ž", "z"},
465
466 {"ŵ", "w"},
467 {"ŷ", "y"},
468 {"ä", "a"},
469 {"ÿ", "y"},
470 {"á", "a"},
471 {"ẁ", "w"},
472 {"ỳ", "y"},
473 {"ō", "o"},
474
475
476 {"Miķelis", "Mikelis"},
477 {"François", "Francois"},
478 {"žluťoučký", "zlutoucky"},
479 {"învățătorița", "invatatorita"},
480 {"Kękę przy łóżku", "Keke przy łozku"},
481 }
482
483 for _, tt := range tests {
484 t.Run(RemoveDiacritics(tt[0]), func(t *testing.T) {
485 assert.Equal(t, tt[1], RemoveDiacritics(tt[0]))
486 })
487 }
488 }
489
View as plain text