...

Source file src/code.rocketnine.space/tslocum/cview/textview_test.go

Documentation: code.rocketnine.space/tslocum/cview

     1  package cview
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"testing"
     7  )
     8  
     9  const (
    10  	// 512 bytes
    11  	randomDataSize = 512
    12  
    13  	// Write randomData 64 times (32768 bytes) before appending
    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 // Capture
    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 // Capture
    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 // Capture
   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 // Capture
   191  
   192  		if c.app {
   193  			continue // Skip for this benchmark
   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 // Capture
   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 // Capture
   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  	// append 100 lines with no limit set:
   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  	// retrieve the total text and see we have the 100 lines:
   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  	// now set the maximum lines to 20, this should clip the buffer:
   327  	tv.SetMaxLines(20)
   328  	// verify buffer was clipped:
   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  	// append 100 more lines:
   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  	// Sice max lines is set to 20, we should still get 20 lines:
   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  	// and those 20 lines should be the last ones:
   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 // WordWrap requires Wrap
   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