-
Notifications
You must be signed in to change notification settings - Fork 366
/
wrap_test.go
145 lines (125 loc) · 3.52 KB
/
wrap_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2014 Oleku Konko All rights reserved.
// Use of this source code is governed by a MIT
// license that can be found in the LICENSE file.
// This module is a Table Writer API for the Go Programming Language.
// The protocols were written in pure Go and works on windows and unix systems
package tablewriter
import (
"os"
"reflect"
"runtime"
"strings"
"testing"
"github.com/mattn/go-runewidth"
)
var text = "The quick brown fox jumps over the lazy dog."
func TestWrap(t *testing.T) {
exp := []string{
"The", "quick", "brown", "fox",
"jumps", "over", "the", "lazy", "dog."}
got, _ := WrapString(text, 6)
checkEqual(t, len(got), len(exp))
}
func TestWrapOneLine(t *testing.T) {
exp := "The quick brown fox jumps over the lazy dog."
words, _ := WrapString(text, 500)
checkEqual(t, strings.Join(words, string(sp)), exp)
}
func TestUnicode(t *testing.T) {
input := "Česká řeřicha"
var wordsUnicode []string
if runewidth.IsEastAsian() {
wordsUnicode, _ = WrapString(input, 14)
} else {
wordsUnicode, _ = WrapString(input, 13)
}
// input contains 13 (or 14 for CJK) runes, so it fits on one line.
checkEqual(t, len(wordsUnicode), 1)
}
func TestDisplayWidth(t *testing.T) {
input := "Česká řeřicha"
want := 13
if runewidth.IsEastAsian() {
want = 14
}
if n := DisplayWidth(input); n != want {
t.Errorf("Wants: %d Got: %d", want, n)
}
input = "\033[43;30m" + input + "\033[00m"
checkEqual(t, DisplayWidth(input), want)
}
// WrapString was extremely memory greedy, it performed insane number of
// allocations for what it was doing. See BenchmarkWrapString for details.
func TestWrapStringAllocation(t *testing.T) {
originalTextBytes, err := os.ReadFile("testdata/long-text.txt")
if err != nil {
t.Fatal(err)
}
originalText := string(originalTextBytes)
wantWrappedBytes, err := os.ReadFile("testdata/long-text-wrapped.txt")
if err != nil {
t.Fatal(err)
}
wantWrappedText := string(wantWrappedBytes)
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
heapAllocBefore := int64(ms.HeapAlloc / 1024 / 1024)
// When
gotLines, gotLim := WrapString(originalText, 80)
// Then
wantLim := 80
if gotLim != wantLim {
t.Errorf("Invalid limit: want=%d, got=%d", wantLim, gotLim)
}
gotWrappedText := strings.Join(gotLines, "\n")
if gotWrappedText != wantWrappedText {
t.Errorf("Invalid lines: want=\n%s\n got=\n%s", wantWrappedText, gotWrappedText)
}
runtime.ReadMemStats(&ms)
heapAllocAfter := int64(ms.HeapAlloc / 1024 / 1024)
heapAllocDelta := heapAllocAfter - heapAllocBefore
if heapAllocDelta > 1 {
t.Fatalf("heap allocation should not be greater than 1Mb, got=%dMb", heapAllocDelta)
}
}
// Before optimization:
// BenchmarkWrapString-16 1 2490331031 ns/op 2535184104 B/op 50905550 allocs/op
// After optimization:
// BenchmarkWrapString-16 1652 658098 ns/op 230223 B/op 5176 allocs/op
func BenchmarkWrapString(b *testing.B) {
d, err := os.ReadFile("testdata/long-text.txt")
if err != nil {
b.Fatal(err)
}
for i := 0; i < b.N; i++ {
WrapString(string(d), 128)
}
}
func TestSplitWords(t *testing.T) {
for _, tt := range []struct {
in string
out []string
}{{
in: "",
out: []string{},
}, {
in: "a",
out: []string{"a"},
}, {
in: "a b",
out: []string{"a", "b"},
}, {
in: " a b ",
out: []string{"a", "b"},
}, {
in: "\r\na\t\t \r\t b\r\n ",
out: []string{"a", "b"},
}} {
t.Run(tt.in, func(t *testing.T) {
got := splitWords(tt.in)
if !reflect.DeepEqual(tt.out, got) {
t.Errorf("want=%s, got=%s", tt.out, got)
}
})
}
}