323 lines
6.5 KiB
Go
323 lines
6.5 KiB
Go
package buffer
|
|
|
|
import (
|
|
"math/rand"
|
|
"strings"
|
|
"testing"
|
|
"unicode/utf8"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
lua "github.com/yuin/gopher-lua"
|
|
ulua "github.com/zyedidia/micro/v2/internal/lua"
|
|
"github.com/zyedidia/micro/v2/internal/config"
|
|
)
|
|
|
|
type operation struct {
|
|
start Loc
|
|
end Loc
|
|
text []string
|
|
}
|
|
|
|
func init() {
|
|
ulua.L = lua.NewState()
|
|
config.InitGlobalSettings()
|
|
config.GlobalSettings["backup"] = false
|
|
config.GlobalSettings["fastdirty"] = true
|
|
}
|
|
|
|
func check(t *testing.T, before []string, operations []operation, after []string) {
|
|
assert := assert.New(t)
|
|
|
|
b := NewBufferFromString(strings.Join(before, "\n"), "", BTDefault)
|
|
|
|
assert.NotEqual("", b.GetName())
|
|
assert.Equal(false, b.ExternallyModified())
|
|
assert.Equal(false, b.Modified())
|
|
assert.Equal(1, b.NumCursors())
|
|
|
|
checkText := func(lines []string) {
|
|
assert.Equal([]byte(strings.Join(lines, "\n")), b.Bytes())
|
|
assert.Equal(len(lines), b.LinesNum())
|
|
for i, s := range lines {
|
|
assert.Equal(s, b.Line(i))
|
|
assert.Equal([]byte(s), b.LineBytes(i))
|
|
}
|
|
}
|
|
|
|
checkText(before)
|
|
|
|
var cursors []*Cursor
|
|
|
|
for _, op := range operations {
|
|
cursor := NewCursor(b, op.start)
|
|
cursor.SetSelectionStart(op.start)
|
|
cursor.SetSelectionEnd(op.end)
|
|
b.AddCursor(cursor)
|
|
cursors = append(cursors, cursor)
|
|
}
|
|
|
|
assert.Equal(1+len(operations), b.NumCursors())
|
|
|
|
for i, op := range operations {
|
|
cursor := cursors[i]
|
|
b.SetCurCursor(cursor.Num)
|
|
cursor.DeleteSelection()
|
|
b.Insert(cursor.Loc, strings.Join(op.text, "\n"))
|
|
}
|
|
|
|
checkText(after)
|
|
|
|
// must have exactly two events per operation (delete and insert)
|
|
for range operations {
|
|
b.UndoOneEvent()
|
|
b.UndoOneEvent()
|
|
}
|
|
|
|
checkText(before)
|
|
|
|
for i, op := range operations {
|
|
cursor := cursors[i]
|
|
if op.start == op.end {
|
|
assert.Equal(op.start, cursor.Loc)
|
|
} else {
|
|
assert.Equal(op.start, cursor.CurSelection[0])
|
|
assert.Equal(op.end, cursor.CurSelection[1])
|
|
}
|
|
}
|
|
|
|
for range operations {
|
|
b.RedoOneEvent()
|
|
b.RedoOneEvent()
|
|
}
|
|
|
|
checkText(after)
|
|
|
|
b.Close()
|
|
}
|
|
|
|
const maxLineLength = 200
|
|
|
|
var alphabet = []rune(" abcdeäم📚")
|
|
|
|
func randomString(length int) string {
|
|
runes := make([]rune, length)
|
|
for i := range runes {
|
|
runes[i] = alphabet[rand.Intn(len(alphabet))]
|
|
}
|
|
return string(runes)
|
|
}
|
|
|
|
func randomText(nLines int) string {
|
|
lines := make([]string, nLines)
|
|
for i := range lines {
|
|
lines[i] = randomString(rand.Intn(maxLineLength + 1))
|
|
}
|
|
return strings.Join(lines, "\n")
|
|
}
|
|
|
|
func benchCreateAndClose(testingB *testing.B, nLines int) {
|
|
rand.Seed(int64(nLines))
|
|
|
|
text := randomText(nLines)
|
|
|
|
testingB.ResetTimer()
|
|
|
|
for i := 0; i < testingB.N; i++ {
|
|
b := NewBufferFromString(text, "", BTDefault)
|
|
b.Close()
|
|
}
|
|
}
|
|
|
|
func benchRead(testingB *testing.B, nLines int) {
|
|
rand.Seed(int64(nLines))
|
|
|
|
b := NewBufferFromString(randomText(nLines), "", BTDefault)
|
|
|
|
testingB.ResetTimer()
|
|
|
|
for i := 0; i < testingB.N; i++ {
|
|
b.Bytes()
|
|
for j := 0; j < b.LinesNum(); j++ {
|
|
b.Line(j)
|
|
b.LineBytes(j)
|
|
}
|
|
}
|
|
|
|
testingB.StopTimer()
|
|
|
|
b.Close()
|
|
}
|
|
|
|
func benchEdit(testingB *testing.B, nLines, nCursors int) {
|
|
rand.Seed(int64(nLines + nCursors))
|
|
|
|
b := NewBufferFromString(randomText(nLines), "", BTDefault)
|
|
|
|
regionSize := nLines / nCursors
|
|
|
|
operations := make([]operation, nCursors)
|
|
for i := range operations {
|
|
startLine := (i * regionSize) + rand.Intn(regionSize-5)
|
|
startColumn := rand.Intn(utf8.RuneCountInString(b.Line(startLine)) + 1)
|
|
endLine := startLine + 1 + rand.Intn(5)
|
|
endColumn := rand.Intn(utf8.RuneCountInString(b.Line(endLine)) + 1)
|
|
|
|
operations[i] = operation{
|
|
start: Loc{startColumn, startLine},
|
|
end: Loc{endColumn, endLine},
|
|
text: []string{randomText(2 + rand.Intn(4))},
|
|
}
|
|
}
|
|
|
|
testingB.ResetTimer()
|
|
|
|
for i := 0; i < testingB.N; i++ {
|
|
b.SetCursors([]*Cursor{})
|
|
|
|
var cursors []*Cursor
|
|
|
|
for _, op := range operations {
|
|
cursor := NewCursor(b, op.start)
|
|
cursor.SetSelectionStart(op.start)
|
|
cursor.SetSelectionEnd(op.end)
|
|
b.AddCursor(cursor)
|
|
cursors = append(cursors, cursor)
|
|
}
|
|
|
|
for j, op := range operations {
|
|
cursor := cursors[j]
|
|
b.SetCurCursor(cursor.Num)
|
|
cursor.DeleteSelection()
|
|
b.Insert(cursor.Loc, op.text[0])
|
|
}
|
|
|
|
for b.UndoStack.Peek() != nil {
|
|
b.UndoOneEvent()
|
|
}
|
|
}
|
|
|
|
testingB.StopTimer()
|
|
|
|
b.Close()
|
|
}
|
|
|
|
func BenchmarkCreateAndClose10Lines(b *testing.B) {
|
|
benchCreateAndClose(b, 10)
|
|
}
|
|
|
|
func BenchmarkCreateAndClose100Lines(b *testing.B) {
|
|
benchCreateAndClose(b, 100)
|
|
}
|
|
|
|
func BenchmarkCreateAndClose1000Lines(b *testing.B) {
|
|
benchCreateAndClose(b, 1000)
|
|
}
|
|
|
|
func BenchmarkCreateAndClose10000Lines(b *testing.B) {
|
|
benchCreateAndClose(b, 10000)
|
|
}
|
|
|
|
func BenchmarkCreateAndClose100000Lines(b *testing.B) {
|
|
benchCreateAndClose(b, 100000)
|
|
}
|
|
|
|
func BenchmarkCreateAndClose1000000Lines(b *testing.B) {
|
|
benchCreateAndClose(b, 1000000)
|
|
}
|
|
|
|
func BenchmarkRead10Lines(b *testing.B) {
|
|
benchRead(b, 10)
|
|
}
|
|
|
|
func BenchmarkRead100Lines(b *testing.B) {
|
|
benchRead(b, 100)
|
|
}
|
|
|
|
func BenchmarkRead1000Lines(b *testing.B) {
|
|
benchRead(b, 1000)
|
|
}
|
|
|
|
func BenchmarkRead10000Lines(b *testing.B) {
|
|
benchRead(b, 10000)
|
|
}
|
|
|
|
func BenchmarkRead100000Lines(b *testing.B) {
|
|
benchRead(b, 100000)
|
|
}
|
|
|
|
func BenchmarkRead1000000Lines(b *testing.B) {
|
|
benchRead(b, 1000000)
|
|
}
|
|
|
|
func BenchmarkEdit10Lines1Cursor(b *testing.B) {
|
|
benchEdit(b, 10, 1)
|
|
}
|
|
|
|
func BenchmarkEdit100Lines1Cursor(b *testing.B) {
|
|
benchEdit(b, 100, 1)
|
|
}
|
|
|
|
func BenchmarkEdit100Lines10Cursors(b *testing.B) {
|
|
benchEdit(b, 100, 10)
|
|
}
|
|
|
|
func BenchmarkEdit1000Lines1Cursor(b *testing.B) {
|
|
benchEdit(b, 1000, 1)
|
|
}
|
|
|
|
func BenchmarkEdit1000Lines10Cursors(b *testing.B) {
|
|
benchEdit(b, 1000, 10)
|
|
}
|
|
|
|
func BenchmarkEdit1000Lines100Cursors(b *testing.B) {
|
|
benchEdit(b, 1000, 100)
|
|
}
|
|
|
|
func BenchmarkEdit10000Lines1Cursor(b *testing.B) {
|
|
benchEdit(b, 10000, 1)
|
|
}
|
|
|
|
func BenchmarkEdit10000Lines10Cursors(b *testing.B) {
|
|
benchEdit(b, 10000, 10)
|
|
}
|
|
|
|
func BenchmarkEdit10000Lines100Cursors(b *testing.B) {
|
|
benchEdit(b, 10000, 100)
|
|
}
|
|
|
|
func BenchmarkEdit10000Lines1000Cursors(b *testing.B) {
|
|
benchEdit(b, 10000, 1000)
|
|
}
|
|
|
|
func BenchmarkEdit100000Lines1Cursor(b *testing.B) {
|
|
benchEdit(b, 100000, 1)
|
|
}
|
|
|
|
func BenchmarkEdit100000Lines10Cursors(b *testing.B) {
|
|
benchEdit(b, 100000, 10)
|
|
}
|
|
|
|
func BenchmarkEdit100000Lines100Cursors(b *testing.B) {
|
|
benchEdit(b, 100000, 100)
|
|
}
|
|
|
|
func BenchmarkEdit100000Lines1000Cursors(b *testing.B) {
|
|
benchEdit(b, 100000, 1000)
|
|
}
|
|
|
|
func BenchmarkEdit1000000Lines1Cursor(b *testing.B) {
|
|
benchEdit(b, 1000000, 1)
|
|
}
|
|
|
|
func BenchmarkEdit1000000Lines10Cursors(b *testing.B) {
|
|
benchEdit(b, 1000000, 10)
|
|
}
|
|
|
|
func BenchmarkEdit1000000Lines100Cursors(b *testing.B) {
|
|
benchEdit(b, 1000000, 100)
|
|
}
|
|
|
|
func BenchmarkEdit1000000Lines1000Cursors(b *testing.B) {
|
|
benchEdit(b, 1000000, 1000)
|
|
}
|