1 package cview
2
3 import (
4 "bytes"
5 "fmt"
6 "testing"
7 )
8
9 const (
10
11 randomDataSize = 512
12
13
14 appendSetupWriteCount = 64
15 )
16
17 var (
18 randomData = generateRandomData()
19 textViewTestCases = generateTestCases()
20 )
21
22 type textViewTestCase struct {
23 app bool
24 color bool
25 region bool
26 scroll bool
27 wrap bool
28 wordwrap bool
29 }
30
31 func (c *textViewTestCase) String() string {
32 return fmt.Sprintf("Append=%c/Color=%c/Region=%c/Scroll=%c/Wrap=%c/WordWrap=%c", cl(c.app), cl(c.color), cl(c.region), cl(c.scroll), cl(c.wrap), cl(c.wordwrap))
33 }
34
35 func TestTextViewWrite(t *testing.T) {
36 t.Parallel()
37
38 for _, c := range textViewTestCases {
39 c := c
40
41 t.Run(c.String(), func(t *testing.T) {
42 t.Parallel()
43
44 var (
45 tv = tvc(c)
46 expectedData []byte
47 n int
48 err error
49 )
50
51 if c.app {
52 expectedData, err = prepareAppendTextView(tv)
53 if err != nil {
54 t.Errorf("failed to prepare append TextView: %s", err)
55 }
56
57 expectedData = append(expectedData, randomData...)
58 } else {
59 expectedData = randomData
60 }
61
62 n, err = tv.Write(randomData)
63 if err != nil {
64 t.Errorf("failed to write (successfully wrote %d) bytes: %s", n, err)
65 } else if n != randomDataSize {
66 t.Errorf("failed to write: expected to write %d bytes, wrote %d", randomDataSize, n)
67 }
68
69 contents := tv.GetText(false)
70 if len(contents) != len(expectedData) {
71 t.Errorf("failed to write: incorrect contents: expected %d bytes, got %d", len(contents), len(expectedData))
72 } else if !bytes.Equal([]byte(contents), expectedData) {
73 t.Errorf("failed to write: incorrect contents: values do not match")
74 }
75
76 tv.Clear()
77 })
78 }
79 }
80
81 func BenchmarkTextViewWrite(b *testing.B) {
82 for _, c := range textViewTestCases {
83 c := c
84
85 b.Run(c.String(), func(b *testing.B) {
86 var (
87 tv = tvc(c)
88 n int
89 err error
90 )
91
92 if c.app {
93 _, err = prepareAppendTextView(tv)
94 if err != nil {
95 b.Errorf("failed to prepare append TextView: %s", err)
96 }
97 }
98
99 b.ReportAllocs()
100 b.ResetTimer()
101
102 for i := 0; i < b.N; i++ {
103 n, err = tv.Write(randomData)
104 if err != nil {
105 b.Errorf("failed to write (successfully wrote %d) bytes: %s", n, err)
106 } else if n != randomDataSize {
107 b.Errorf("failed to write: expected to write %d bytes, wrote %d", randomDataSize, n)
108 }
109
110 if !c.app {
111 b.StopTimer()
112 tv.Clear()
113 b.StartTimer()
114 }
115 }
116 })
117 }
118 }
119
120 func BenchmarkTextViewIndex(b *testing.B) {
121 for _, c := range textViewTestCases {
122 c := c
123
124 b.Run(c.String(), func(b *testing.B) {
125 var (
126 tv = tvc(c)
127 n int
128 err error
129 )
130
131 _, err = prepareAppendTextView(tv)
132 if err != nil {
133 b.Errorf("failed to prepare append TextView: %s", err)
134 }
135
136 n, err = tv.Write(randomData)
137 if err != nil {
138 b.Errorf("failed to write (successfully wrote %d) bytes: %s", n, err)
139 } else if n != randomDataSize {
140 b.Errorf("failed to write: expected to write %d bytes, wrote %d", randomDataSize, n)
141 }
142
143 tv.index = nil
144 tv.reindexBuffer(80)
145
146 b.ReportAllocs()
147 b.ResetTimer()
148
149 for i := 0; i < b.N; i++ {
150 tv.index = nil
151 tv.reindexBuffer(80)
152 }
153 })
154 }
155 }
156
157 func TestTextViewGetText(t *testing.T) {
158 t.Parallel()
159
160 tv := NewTextView()
161 tv.SetDynamicColors(true)
162 tv.SetRegions(true)
163
164 n, err := tv.Write(randomData)
165 if err != nil {
166 t.Errorf("failed to write (successfully wrote %d) bytes: %s", n, err)
167 } else if n != randomDataSize {
168 t.Errorf("failed to write: expected to write %d bytes, wrote %d", randomDataSize, n)
169 }
170
171 suffix := []byte(`["start"]outer[b]inner[-]outer[""]`)
172 suffixStripped := []byte("outerinnerouter")
173
174 n, err = tv.Write(suffix)
175 if err != nil {
176 t.Errorf("failed to write (successfully wrote %d) bytes: %s", n, err)
177 }
178
179 if !bytes.Equal(tv.GetBytes(false), append(randomData, suffix...)) {
180 t.Error("failed to get un-stripped text: unexpected suffix")
181 }
182
183 if !bytes.Equal(tv.GetBytes(true), append(randomData, suffixStripped...)) {
184 t.Error("failed to get text stripped text: unexpected suffix")
185 }
186 }
187
188 func BenchmarkTextViewGetText(b *testing.B) {
189 for _, c := range textViewTestCases {
190 c := c
191
192 if c.app {
193 continue
194 }
195
196 b.Run(c.String(), func(b *testing.B) {
197 var (
198 tv = tvc(c)
199 n int
200 err error
201 v []byte
202 )
203
204 _, err = prepareAppendTextView(tv)
205 if err != nil {
206 b.Errorf("failed to prepare append TextView: %s", err)
207 }
208
209 n, err = tv.Write(randomData)
210 if err != nil {
211 b.Errorf("failed to write (successfully wrote %d) bytes: %s", n, err)
212 } else if n != randomDataSize {
213 b.Errorf("failed to write: expected to write %d bytes, wrote %d", randomDataSize, n)
214 }
215
216 v = tv.GetBytes(true)
217
218 b.ReportAllocs()
219 b.ResetTimer()
220
221 for i := 0; i < b.N; i++ {
222 v = tv.GetBytes(true)
223 }
224
225 _ = v
226 })
227 }
228 }
229
230 func TestTextViewDraw(t *testing.T) {
231 t.Parallel()
232
233 for _, c := range textViewTestCases {
234 c := c
235
236 t.Run(c.String(), func(t *testing.T) {
237 t.Parallel()
238
239 tv := tvc(c)
240
241 app, err := newTestApp(tv)
242 if err != nil {
243 t.Errorf("failed to initialize Application: %s", err)
244 }
245
246 if c.app {
247 _, err = prepareAppendTextView(tv)
248 if err != nil {
249 t.Errorf("failed to prepare append TextView: %s", err)
250 }
251
252 tv.Draw(app.screen)
253 }
254
255 n, err := tv.Write(randomData)
256 if err != nil {
257 t.Errorf("failed to write (successfully wrote %d) bytes: %s", n, err)
258 } else if n != randomDataSize {
259 t.Errorf("failed to write: expected to write %d bytes, wrote %d", randomDataSize, n)
260 }
261
262 tv.Draw(app.screen)
263 })
264 }
265 }
266
267 func BenchmarkTextViewDraw(b *testing.B) {
268 for _, c := range textViewTestCases {
269 c := c
270
271 b.Run(c.String(), func(b *testing.B) {
272 tv := tvc(c)
273
274 app, err := newTestApp(tv)
275 if err != nil {
276 b.Errorf("failed to initialize Application: %s", err)
277 }
278
279 if c.app {
280 _, err = prepareAppendTextView(tv)
281 if err != nil {
282 b.Errorf("failed to prepare append TextView: %s", err)
283 }
284
285 tv.Draw(app.screen)
286 }
287
288 n, err := tv.Write(randomData)
289 if err != nil {
290 b.Errorf("failed to write (successfully wrote %d) bytes: %s", n, err)
291 } else if n != randomDataSize {
292 b.Errorf("failed to write: expected to write %d bytes, wrote %d", randomDataSize, n)
293 }
294
295 tv.Draw(app.screen)
296
297 b.ReportAllocs()
298 b.ResetTimer()
299
300 for i := 0; i < b.N; i++ {
301 tv.Draw(app.screen)
302 }
303 })
304 }
305 }
306
307 func TestTextViewMaxLines(t *testing.T) {
308 t.Parallel()
309
310 tv := NewTextView()
311
312
313 for i := 0; i < 100; i++ {
314 _, err := tv.Write([]byte(fmt.Sprintf("L%d\n", i)))
315 if err != nil {
316 t.Errorf("failed to write to TextView: %s", err)
317 }
318 }
319
320
321 count := bytes.Count(tv.GetBytes(true), []byte("\n"))
322 if count != 100 {
323 t.Errorf("expected 100 lines, got %d", count)
324 }
325
326
327 tv.SetMaxLines(20)
328
329 count = len(bytes.Split(tv.GetBytes(true), []byte("\n")))
330 if count != 20 {
331 t.Errorf("expected 20 lines, got %d", count)
332 }
333
334
335 for i := 100; i < 200; i++ {
336 _, err := tv.Write([]byte(fmt.Sprintf("L%d\n", i)))
337 if err != nil {
338 t.Errorf("failed to write to TextView: %s", err)
339 }
340 }
341
342
343 txt := tv.GetBytes(true)
344 lines := bytes.Split(txt, []byte("\n"))
345 count = len(lines)
346 if count != 20 {
347 t.Errorf("expected 20 lines, got %d", count)
348 }
349
350
351 if !bytes.Equal(lines[0], []byte("L181")) {
352 t.Errorf("expected to get L181, got %s", lines[0])
353 }
354 }
355
356 func generateTestCases() []*textViewTestCase {
357 var cases []*textViewTestCase
358 for i := 0; i < 2; i++ {
359 app := i == 1
360 for i := 0; i < 2; i++ {
361 color := i == 1
362 for i := 0; i < 2; i++ {
363 region := i == 1
364 for i := 0; i < 2; i++ {
365 scroll := i == 1
366 for i := 0; i < 2; i++ {
367 wrap := i == 1
368 for i := 0; i < 2; i++ {
369 wordwrap := i == 1
370 if !wrap && wordwrap {
371 continue
372 }
373 cases = append(cases, &textViewTestCase{app, color, region, scroll, wrap, wordwrap})
374 }
375 }
376 }
377 }
378 }
379 }
380 return cases
381 }
382
383 func generateRandomData() []byte {
384 var (
385 b bytes.Buffer
386 r = 33
387 )
388
389 for i := 0; i < randomDataSize; i++ {
390 if i%80 == 0 && i <= 160 {
391 b.WriteRune('\n')
392 } else if i%7 == 0 {
393 b.WriteRune(' ')
394 } else {
395 b.WriteRune(rune(r))
396 }
397
398 r++
399 if r == 127 {
400 r = 33
401 }
402 }
403
404 return b.Bytes()
405 }
406
407 func tvc(c *textViewTestCase) *TextView {
408 tv := NewTextView()
409 tv.SetDynamicColors(c.color)
410 tv.SetRegions(c.region)
411 tv.SetScrollable(c.scroll)
412 tv.SetWrap(c.wrap)
413 tv.SetWordWrap(c.wordwrap)
414 return tv
415 }
416
417 func cl(v bool) rune {
418 if v {
419 return 'Y'
420 }
421 return 'N'
422 }
423
424 func prepareAppendTextView(t *TextView) ([]byte, error) {
425 var b []byte
426 for i := 0; i < appendSetupWriteCount; i++ {
427 b = append(b, randomData...)
428
429 n, err := t.Write(randomData)
430 if err != nil {
431 return nil, fmt.Errorf("failed to write (successfully wrote %d) bytes: %s", n, err)
432 } else if n != randomDataSize {
433 return nil, fmt.Errorf("failed to write: expected to write %d bytes, wrote %d", randomDataSize, n)
434 }
435 }
436
437 return b, nil
438 }
439
View as plain text