All checks were successful
Run Test Suite / test (push) Successful in 56s
Not sure if this is perfect, but it seems to be working
456 lines
12 KiB
Go
456 lines
12 KiB
Go
package core
|
|
|
|
import "testing"
|
|
|
|
func TestGapBufferString(t *testing.T) {
|
|
t.Run("gapBuffer.String() on empty buffer returns \"\"", func(t *testing.T) {
|
|
buf := NewEmptyGapBuffer()
|
|
str := buf.String()
|
|
if str != "" {
|
|
t.Fatalf("buf.String() expected '', got '%s'", str)
|
|
}
|
|
})
|
|
|
|
t.Run("gapBuffer.String() on string returns the string", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
str := buf.String()
|
|
if str != "Hello world" {
|
|
t.Fatalf("buf.String() expected 'Hello world', got '%s'", str)
|
|
}
|
|
})
|
|
|
|
t.Run("gapBuffer.String() after moving gap returns the string", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.moveGap(6)
|
|
str := buf.String()
|
|
if str != "Hello world" {
|
|
t.Fatalf("buf.String() expected 'Hello world', got '%s'", str)
|
|
}
|
|
})
|
|
|
|
t.Run("gapBuffer.String() after growing gap returns the string", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.grow(16)
|
|
str := buf.String()
|
|
if str != "Hello world" {
|
|
t.Fatalf("buf.String() expected 'Hello world', got '%s'", str)
|
|
}
|
|
})
|
|
|
|
t.Run("gapBuffer.String() handles unicode characters", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello 世界 🌍")
|
|
str := buf.String()
|
|
if str != "Hello 世界 🌍" {
|
|
t.Fatalf("buf.String() expected 'Hello 世界 🌍', got '%s'", str)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGapBufferLen(t *testing.T) {
|
|
t.Run("empty buffer has length 0", func(t *testing.T) {
|
|
buf := NewEmptyGapBuffer()
|
|
if buf.Len() != 0 {
|
|
t.Fatalf("expected length 0, got %d", buf.Len())
|
|
}
|
|
})
|
|
|
|
t.Run("buffer with content returns correct length", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
if buf.Len() != 5 {
|
|
t.Fatalf("expected length 5, got %d", buf.Len())
|
|
}
|
|
})
|
|
|
|
t.Run("length with unicode characters", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hi 🌍")
|
|
if buf.Len() != 4 {
|
|
t.Fatalf("expected length 4, got %d", buf.Len())
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGapBufferInsert(t *testing.T) {
|
|
t.Run("insert at beginning", func(t *testing.T) {
|
|
buf := NewGapBuffer("world")
|
|
buf.Insert(0, "Hello ")
|
|
if buf.String() != "Hello world" {
|
|
t.Fatalf("expected 'Hello world', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("insert at end", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Insert(5, " world")
|
|
if buf.String() != "Hello world" {
|
|
t.Fatalf("expected 'Hello world', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("insert in middle", func(t *testing.T) {
|
|
buf := NewGapBuffer("Helloworld")
|
|
buf.Insert(5, " ")
|
|
if buf.String() != "Hello world" {
|
|
t.Fatalf("expected 'Hello world', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("insert into empty buffer", func(t *testing.T) {
|
|
buf := NewEmptyGapBuffer()
|
|
buf.Insert(0, "Hello")
|
|
if buf.String() != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("insert empty string does nothing", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Insert(2, "")
|
|
if buf.String() != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("insert at invalid position does nothing", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Insert(-1, "X")
|
|
if buf.String() != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.String())
|
|
}
|
|
buf.Insert(100, "X")
|
|
if buf.String() != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("insert unicode characters", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Insert(5, " 世界")
|
|
if buf.String() != "Hello 世界" {
|
|
t.Fatalf("expected 'Hello 世界', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("multiple consecutive insertions", func(t *testing.T) {
|
|
buf := NewEmptyGapBuffer()
|
|
buf.Insert(0, "a")
|
|
buf.Insert(1, "b")
|
|
buf.Insert(2, "c")
|
|
if buf.String() != "abc" {
|
|
t.Fatalf("expected 'abc', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("insert large text triggers grow", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
longText := "Lorem ipsum dolor sit amet, consectetur adipiscing elit"
|
|
buf.Insert(5, longText)
|
|
expected := "Hello" + longText
|
|
if buf.String() != expected {
|
|
t.Fatalf("expected '%s', got '%s'", expected, buf.String())
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGapBufferDelete(t *testing.T) {
|
|
t.Run("delete from beginning", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.Delete(0, 6)
|
|
if buf.String() != "world" {
|
|
t.Fatalf("expected 'world', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("delete from end", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.Delete(5, 6)
|
|
if buf.String() != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("delete from middle", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.Delete(5, 1)
|
|
if buf.String() != "Helloworld" {
|
|
t.Fatalf("expected 'Helloworld', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("delete single character", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Delete(1, 1)
|
|
if buf.String() != "Hllo" {
|
|
t.Fatalf("expected 'Hllo', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("delete all content", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Delete(0, 5)
|
|
if buf.String() != "" {
|
|
t.Fatalf("expected '', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("delete with count exceeding length", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Delete(2, 100)
|
|
if buf.String() != "He" {
|
|
t.Fatalf("expected 'He', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("delete at invalid position does nothing", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Delete(-1, 2)
|
|
if buf.String() != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.String())
|
|
}
|
|
buf.Delete(100, 2)
|
|
if buf.String() != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("delete with zero count does nothing", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Delete(2, 0)
|
|
if buf.String() != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("delete unicode characters", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello 世界")
|
|
buf.Delete(6, 2)
|
|
if buf.String() != "Hello " {
|
|
t.Fatalf("expected 'Hello ', got '%s'", buf.String())
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGapBufferRuneAt(t *testing.T) {
|
|
t.Run("get rune at valid position", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
if buf.RuneAt(0) != 'H' {
|
|
t.Fatalf("expected 'H', got '%c'", buf.RuneAt(0))
|
|
}
|
|
if buf.RuneAt(4) != 'o' {
|
|
t.Fatalf("expected 'o', got '%c'", buf.RuneAt(4))
|
|
}
|
|
})
|
|
|
|
t.Run("get rune before gap", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.moveGap(6)
|
|
if buf.RuneAt(5) != ' ' {
|
|
t.Fatalf("expected ' ', got '%c'", buf.RuneAt(5))
|
|
}
|
|
})
|
|
|
|
t.Run("get rune after gap", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.moveGap(6)
|
|
if buf.RuneAt(6) != 'w' {
|
|
t.Fatalf("expected 'w', got '%c'", buf.RuneAt(6))
|
|
}
|
|
})
|
|
|
|
t.Run("get rune at invalid position returns 0", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
if buf.RuneAt(-1) != 0 {
|
|
t.Fatalf("expected 0, got '%c'", buf.RuneAt(-1))
|
|
}
|
|
if buf.RuneAt(100) != 0 {
|
|
t.Fatalf("expected 0, got '%c'", buf.RuneAt(100))
|
|
}
|
|
})
|
|
|
|
t.Run("get unicode rune", func(t *testing.T) {
|
|
buf := NewGapBuffer("🌍世界")
|
|
if buf.RuneAt(0) != '🌍' {
|
|
t.Fatalf("expected '🌍', got '%c'", buf.RuneAt(0))
|
|
}
|
|
if buf.RuneAt(1) != '世' {
|
|
t.Fatalf("expected '世', got '%c'", buf.RuneAt(1))
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGapBufferSubstring(t *testing.T) {
|
|
t.Run("substring from middle", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
if buf.Substring(0, 5) != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.Substring(0, 5))
|
|
}
|
|
if buf.Substring(6, 11) != "world" {
|
|
t.Fatalf("expected 'world', got '%s'", buf.Substring(6, 11))
|
|
}
|
|
})
|
|
|
|
t.Run("substring entire content", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
if buf.Substring(0, 5) != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.Substring(0, 5))
|
|
}
|
|
})
|
|
|
|
t.Run("substring with start >= end returns empty", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
if buf.Substring(3, 3) != "" {
|
|
t.Fatalf("expected '', got '%s'", buf.Substring(3, 3))
|
|
}
|
|
if buf.Substring(3, 2) != "" {
|
|
t.Fatalf("expected '', got '%s'", buf.Substring(3, 2))
|
|
}
|
|
})
|
|
|
|
t.Run("substring clamps to buffer bounds", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
if buf.Substring(-5, 3) != "Hel" {
|
|
t.Fatalf("expected 'Hel', got '%s'", buf.Substring(-5, 3))
|
|
}
|
|
if buf.Substring(2, 100) != "llo" {
|
|
t.Fatalf("expected 'llo', got '%s'", buf.Substring(2, 100))
|
|
}
|
|
})
|
|
|
|
t.Run("substring with gap in middle", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.moveGap(6)
|
|
if buf.Substring(0, 11) != "Hello world" {
|
|
t.Fatalf("expected 'Hello world', got '%s'", buf.Substring(0, 11))
|
|
}
|
|
})
|
|
|
|
t.Run("substring with unicode", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hi 世界")
|
|
if buf.Substring(3, 5) != "世界" {
|
|
t.Fatalf("expected '世界', got '%s'", buf.Substring(3, 5))
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGapBufferSet(t *testing.T) {
|
|
t.Run("set replaces content", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Set("Goodbye")
|
|
if buf.String() != "Goodbye" {
|
|
t.Fatalf("expected 'Goodbye', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("set to empty string", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Set("")
|
|
if buf.String() != "" {
|
|
t.Fatalf("expected '', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("set on empty buffer", func(t *testing.T) {
|
|
buf := NewEmptyGapBuffer()
|
|
buf.Set("Hello")
|
|
if buf.String() != "Hello" {
|
|
t.Fatalf("expected 'Hello', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("set resets gap position", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.moveGap(2)
|
|
buf.Set("World")
|
|
if buf.String() != "World" {
|
|
t.Fatalf("expected 'World', got '%s'", buf.String())
|
|
}
|
|
if buf.gapStart != 5 {
|
|
t.Fatalf("expected gap start at 5, got %d", buf.gapStart)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGapBufferClear(t *testing.T) {
|
|
t.Run("clear removes all content", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.Clear()
|
|
if buf.String() != "" {
|
|
t.Fatalf("expected '', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("clear on empty buffer", func(t *testing.T) {
|
|
buf := NewEmptyGapBuffer()
|
|
buf.Clear()
|
|
if buf.String() != "" {
|
|
t.Fatalf("expected '', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("clear resets gap to start", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
buf.Clear()
|
|
if buf.gapStart != 0 {
|
|
t.Fatalf("expected gap start at 0, got %d", buf.gapStart)
|
|
}
|
|
if buf.gapEnd != len(buf.buffer) {
|
|
t.Fatalf("expected gap end at %d, got %d", len(buf.buffer), buf.gapEnd)
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGapBufferGapSize(t *testing.T) {
|
|
t.Run("gap size on new buffer", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
if buf.GapSize() != 16 {
|
|
t.Fatalf("expected gap size 16, got %d", buf.GapSize())
|
|
}
|
|
})
|
|
|
|
t.Run("gap size on empty buffer", func(t *testing.T) {
|
|
buf := NewEmptyGapBuffer()
|
|
if buf.GapSize() != 16 {
|
|
t.Fatalf("expected gap size 16, got %d", buf.GapSize())
|
|
}
|
|
})
|
|
|
|
t.Run("gap size decreases after insert", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello")
|
|
initialGapSize := buf.GapSize()
|
|
buf.Insert(5, "XX")
|
|
if buf.GapSize() != initialGapSize-2 {
|
|
t.Fatalf("expected gap size %d, got %d", initialGapSize-2, buf.GapSize())
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestGapBufferComplex(t *testing.T) {
|
|
t.Run("sequence of operations", func(t *testing.T) {
|
|
buf := NewEmptyGapBuffer()
|
|
buf.Insert(0, "Hello")
|
|
buf.Insert(5, " world")
|
|
buf.Delete(5, 1)
|
|
buf.Insert(5, ", ")
|
|
if buf.String() != "Hello, world" {
|
|
t.Fatalf("expected 'Hello, world', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("insert and delete at different positions", func(t *testing.T) {
|
|
buf := NewGapBuffer("abcdefgh")
|
|
buf.Delete(2, 4)
|
|
buf.Insert(2, "XX")
|
|
if buf.String() != "abXXgh" {
|
|
t.Fatalf("expected 'abXXgh', got '%s'", buf.String())
|
|
}
|
|
})
|
|
|
|
t.Run("editing with gap movement", func(t *testing.T) {
|
|
buf := NewGapBuffer("Hello world")
|
|
buf.Insert(0, ">> ")
|
|
buf.Insert(buf.Len(), " <<")
|
|
if buf.String() != ">> Hello world <<" {
|
|
t.Fatalf("expected '>> Hello world <<', got '%s'", buf.String())
|
|
}
|
|
})
|
|
}
|