test: improve coverage across package
This commit is contained in:
321
analyzer/utils/bytebuffer_test.go
Normal file
321
analyzer/utils/bytebuffer_test.go
Normal file
@@ -0,0 +1,321 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestByteBuffer_Append(t *testing.T) {
|
||||
b := &ByteBuffer{}
|
||||
b.Append([]byte("hello"))
|
||||
b.Append([]byte(" "))
|
||||
b.Append([]byte("world"))
|
||||
if string(b.Buf) != "hello world" {
|
||||
t.Errorf("Append() result = %q, want %q", string(b.Buf), "hello world")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_Len(t *testing.T) {
|
||||
b := &ByteBuffer{}
|
||||
if b.Len() != 0 {
|
||||
t.Errorf("Len() = %d, want 0", b.Len())
|
||||
}
|
||||
b.Append([]byte("abc"))
|
||||
if b.Len() != 3 {
|
||||
t.Errorf("Len() = %d, want 3", b.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_Index(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("hello world")}
|
||||
if i := b.Index([]byte("world")); i != 6 {
|
||||
t.Errorf("Index('world') = %d, want 6", i)
|
||||
}
|
||||
if i := b.Index([]byte("xyz")); i != -1 {
|
||||
t.Errorf("Index('xyz') = %d, want -1", i)
|
||||
}
|
||||
if i := b.Index([]byte{}); i != 0 {
|
||||
t.Errorf("Index('') = %d, want 0", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_Get(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("abcdef")}
|
||||
|
||||
data, ok := b.Get(3, true)
|
||||
if !ok {
|
||||
t.Fatal("Get(3, true) returned false")
|
||||
}
|
||||
if !bytes.Equal(data, []byte("abc")) {
|
||||
t.Errorf("Get(3, true) data = %q, want %q", data, "abc")
|
||||
}
|
||||
if !bytes.Equal(b.Buf, []byte("def")) {
|
||||
t.Errorf("after consume, Buf = %q, want %q", b.Buf, "def")
|
||||
}
|
||||
|
||||
data, ok = b.Get(4, false)
|
||||
if ok {
|
||||
t.Fatal("Get(4, false) should return false (only 3 bytes left)")
|
||||
}
|
||||
|
||||
data, ok = b.Get(2, false)
|
||||
if !ok {
|
||||
t.Fatal("Get(2, false) returned false")
|
||||
}
|
||||
if !bytes.Equal(data, []byte("de")) {
|
||||
t.Errorf("Get(2, false) data = %q, want %q", data, "de")
|
||||
}
|
||||
if !bytes.Equal(b.Buf, []byte("def")) {
|
||||
t.Errorf("after non-consume, Buf = %q, want %q (unchanged)", b.Buf, "def")
|
||||
}
|
||||
|
||||
data, ok = b.Get(3, true)
|
||||
if !ok {
|
||||
t.Fatal("Get(3, true) returned false")
|
||||
}
|
||||
if !bytes.Equal(data, []byte("def")) {
|
||||
t.Errorf("Get(3, true) data = %q, want %q", data, "def")
|
||||
}
|
||||
if b.Len() != 0 {
|
||||
t.Errorf("after consume all, Len() = %d, want 0", b.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_GetString(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("hello world")}
|
||||
|
||||
s, ok := b.GetString(5, true)
|
||||
if !ok {
|
||||
t.Fatal("GetString(5, true) returned false")
|
||||
}
|
||||
if s != "hello" {
|
||||
t.Errorf("GetString() = %q, want %q", s, "hello")
|
||||
}
|
||||
if b.Len() != 6 {
|
||||
t.Errorf("after consume, Len() = %d, want 6", b.Len())
|
||||
}
|
||||
|
||||
s, ok = b.GetString(7, false)
|
||||
if ok {
|
||||
t.Fatal("GetString(7, false) should return false")
|
||||
}
|
||||
|
||||
s, ok = b.GetString(6, false)
|
||||
if !ok {
|
||||
t.Fatal("GetString(6, false) returned false")
|
||||
}
|
||||
if s != " world" {
|
||||
t.Errorf("GetString() = %q, want %q", s, " world")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_GetByte(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("abc")}
|
||||
|
||||
bt, ok := b.GetByte(true)
|
||||
if !ok {
|
||||
t.Fatal("GetByte(true) returned false")
|
||||
}
|
||||
if bt != 'a' {
|
||||
t.Errorf("GetByte() = %c, want 'a'", bt)
|
||||
}
|
||||
if b.Len() != 2 {
|
||||
t.Errorf("after consume, Len() = %d, want 2", b.Len())
|
||||
}
|
||||
|
||||
bt, ok = b.GetByte(false)
|
||||
if !ok {
|
||||
t.Fatal("GetByte(false) returned false")
|
||||
}
|
||||
if bt != 'b' {
|
||||
t.Errorf("GetByte() = %c, want 'b'", bt)
|
||||
}
|
||||
if b.Len() != 2 {
|
||||
t.Errorf("after non-consume, Len() = %d, want 2 (unchanged)", b.Len())
|
||||
}
|
||||
|
||||
b.GetByte(true)
|
||||
b.GetByte(true)
|
||||
bt, ok = b.GetByte(true)
|
||||
if ok {
|
||||
t.Fatal("GetByte(true) on empty buffer should return false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_GetUint16(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte{0x01, 0x02, 0x03, 0x04}}
|
||||
|
||||
v, ok := b.GetUint16(false, true)
|
||||
if !ok {
|
||||
t.Fatal("GetUint16(bigEndian) returned false")
|
||||
}
|
||||
if v != 0x0102 {
|
||||
t.Errorf("GetUint16(bigEndian) = 0x%04x, want 0x0102", v)
|
||||
}
|
||||
if b.Len() != 2 {
|
||||
t.Errorf("after consume, Len() = %d, want 2", b.Len())
|
||||
}
|
||||
|
||||
v, ok = b.GetUint16(true, true)
|
||||
if !ok {
|
||||
t.Fatal("GetUint16(littleEndian) returned false")
|
||||
}
|
||||
if v != 0x0403 {
|
||||
t.Errorf("GetUint16(littleEndian) = 0x%04x, want 0x0403", v)
|
||||
}
|
||||
|
||||
v, ok = b.GetUint16(false, false)
|
||||
if ok {
|
||||
t.Fatal("GetUint16 on empty buffer should return false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_GetUint32(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}
|
||||
|
||||
v, ok := b.GetUint32(false, true)
|
||||
if !ok {
|
||||
t.Fatal("GetUint32(bigEndian) returned false")
|
||||
}
|
||||
if v != 0x01020304 {
|
||||
t.Errorf("GetUint32(bigEndian) = 0x%08x, want 0x01020304", v)
|
||||
}
|
||||
if b.Len() != 4 {
|
||||
t.Errorf("after consume, Len() = %d, want 4", b.Len())
|
||||
}
|
||||
|
||||
v, ok = b.GetUint32(true, true)
|
||||
if !ok {
|
||||
t.Fatal("GetUint32(littleEndian) returned false")
|
||||
}
|
||||
if v != 0x08070605 {
|
||||
t.Errorf("GetUint32(littleEndian) = 0x%08x, want 0x08070605", v)
|
||||
}
|
||||
|
||||
v, ok = b.GetUint32(false, false)
|
||||
if ok {
|
||||
t.Fatal("GetUint32 on empty buffer should return false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_GetUntil(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("hello\r\nworld\r\n")}
|
||||
|
||||
data, ok := b.GetUntil([]byte("\r\n"), true, true)
|
||||
if !ok {
|
||||
t.Fatal("GetUntil(sep, include) returned false")
|
||||
}
|
||||
if !bytes.Equal(data, []byte("hello\r\n")) {
|
||||
t.Errorf("GetUntil(include) = %q, want %q", data, "hello\\r\\n")
|
||||
}
|
||||
|
||||
data, ok = b.GetUntil([]byte("\r\n"), false, false)
|
||||
if !ok {
|
||||
t.Fatal("GetUntil(sep, exclude, non-consume) returned false")
|
||||
}
|
||||
if !bytes.Equal(data, []byte("world")) {
|
||||
t.Errorf("GetUntil(exclude) = %q, want %q", data, "world")
|
||||
}
|
||||
if b.Len() != 7 {
|
||||
t.Errorf("after non-consume, Len() = %d, want 7", b.Len())
|
||||
}
|
||||
|
||||
data, ok = b.GetUntil([]byte("\r\n"), true, true)
|
||||
if !ok {
|
||||
t.Fatal("GetUntil second (consume) returned false")
|
||||
}
|
||||
if !bytes.Equal(data, []byte("world\r\n")) {
|
||||
t.Errorf("GetUntil second = %q, want %q", data, "world\\r\\n")
|
||||
}
|
||||
|
||||
_, ok = b.GetUntil([]byte("xyz"), false, false)
|
||||
if ok {
|
||||
t.Fatal("GetUntil(not found) should return false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_GetSubBuffer(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("hello world")}
|
||||
|
||||
sub, ok := b.GetSubBuffer(5, true)
|
||||
if !ok {
|
||||
t.Fatal("GetSubBuffer() returned false")
|
||||
}
|
||||
if !bytes.Equal(sub.Buf, []byte("hello")) {
|
||||
t.Errorf("GetSubBuffer() = %q, want %q", sub.Buf, "hello")
|
||||
}
|
||||
if b.Len() != 6 {
|
||||
t.Errorf("after consume, Len() = %d, want 6", b.Len())
|
||||
}
|
||||
|
||||
_, ok = b.GetSubBuffer(7, false)
|
||||
if ok {
|
||||
t.Fatal("GetSubBuffer(7) should return false (only 6 bytes left)")
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_Skip(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("abcdef")}
|
||||
|
||||
ok := b.Skip(2)
|
||||
if !ok {
|
||||
t.Fatal("Skip(2) returned false")
|
||||
}
|
||||
if !bytes.Equal(b.Buf, []byte("cdef")) {
|
||||
t.Errorf("after Skip(2), Buf = %q, want %q", b.Buf, "cdef")
|
||||
}
|
||||
|
||||
ok = b.Skip(10)
|
||||
if ok {
|
||||
t.Fatal("Skip(10) should return false")
|
||||
}
|
||||
if !bytes.Equal(b.Buf, []byte("cdef")) {
|
||||
t.Errorf("after failed Skip, Buf = %q, want %q (unchanged)", b.Buf, "cdef")
|
||||
}
|
||||
|
||||
ok = b.Skip(4)
|
||||
if !ok {
|
||||
t.Fatal("Skip(4) returned false")
|
||||
}
|
||||
if b.Len() != 0 {
|
||||
t.Errorf("after Skip all, Len() = %d, want 0", b.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_Reset(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("data")}
|
||||
b.Reset()
|
||||
if b.Buf != nil {
|
||||
t.Errorf("after Reset, Buf = %v, want nil", b.Buf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_GetZeroLength(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("abc")}
|
||||
|
||||
data, ok := b.Get(0, true)
|
||||
if !ok {
|
||||
t.Fatal("Get(0) returned false")
|
||||
}
|
||||
if len(data) != 0 {
|
||||
t.Errorf("Get(0) len = %d, want 0", len(data))
|
||||
}
|
||||
if b.Len() != 3 {
|
||||
t.Errorf("after Get(0, consume), Len() = %d, want 3 (0-length consume is no-op)", b.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestByteBuffer_GetConsumeDoesNotMutateReturnedSlice(t *testing.T) {
|
||||
b := &ByteBuffer{Buf: []byte("hello")}
|
||||
data, ok := b.Get(5, true)
|
||||
if !ok {
|
||||
t.Fatal("Get() returned false")
|
||||
}
|
||||
if !reflect.DeepEqual(data, []byte("hello")) {
|
||||
t.Errorf("Get() returned wrong data: %v", data)
|
||||
}
|
||||
if b.Len() != 0 {
|
||||
t.Errorf("after consume, Len() should be 0")
|
||||
}
|
||||
}
|
||||
185
analyzer/utils/lsm_test.go
Normal file
185
analyzer/utils/lsm_test.go
Normal file
@@ -0,0 +1,185 @@
|
||||
package utils
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLinearStateMachine_RunPause(t *testing.T) {
|
||||
callCount := 0
|
||||
lsm := NewLinearStateMachine(
|
||||
func() LSMAction {
|
||||
callCount++
|
||||
return LSMActionPause
|
||||
},
|
||||
)
|
||||
cancelled, done := lsm.Run()
|
||||
if cancelled {
|
||||
t.Error("unexpected cancelled=true")
|
||||
}
|
||||
if done {
|
||||
t.Error("unexpected done=true")
|
||||
}
|
||||
if callCount != 1 {
|
||||
t.Errorf("callCount = %d, want 1", callCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinearStateMachine_RunNext(t *testing.T) {
|
||||
callOrder := []int{}
|
||||
lsm := NewLinearStateMachine(
|
||||
func() LSMAction { callOrder = append(callOrder, 1); return LSMActionNext },
|
||||
func() LSMAction { callOrder = append(callOrder, 2); return LSMActionNext },
|
||||
func() LSMAction { callOrder = append(callOrder, 3); return LSMActionNext },
|
||||
)
|
||||
cancelled, done := lsm.Run()
|
||||
if cancelled {
|
||||
t.Error("unexpected cancelled=true")
|
||||
}
|
||||
if !done {
|
||||
t.Error("unexpected done=false")
|
||||
}
|
||||
if len(callOrder) != 3 {
|
||||
t.Fatalf("callOrder len = %d, want 3", len(callOrder))
|
||||
}
|
||||
for i, v := range []int{1, 2, 3} {
|
||||
if callOrder[i] != v {
|
||||
t.Errorf("callOrder[%d] = %d, want %d", i, callOrder[i], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinearStateMachine_RunReset(t *testing.T) {
|
||||
callCount := 0
|
||||
lsm := NewLinearStateMachine(
|
||||
func() LSMAction {
|
||||
callCount++
|
||||
if callCount == 1 {
|
||||
return LSMActionReset
|
||||
}
|
||||
return LSMActionNext
|
||||
},
|
||||
func() LSMAction { callCount++; return LSMActionNext },
|
||||
)
|
||||
cancelled, done := lsm.Run()
|
||||
if cancelled {
|
||||
t.Error("unexpected cancelled=true")
|
||||
}
|
||||
if !done {
|
||||
t.Error("unexpected done=false")
|
||||
}
|
||||
if callCount != 3 {
|
||||
t.Errorf("callCount = %d, want 3 (step0 reset, step0 next, step1 next)", callCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinearStateMachine_RunCancel(t *testing.T) {
|
||||
callCount := 0
|
||||
lsm := NewLinearStateMachine(
|
||||
func() LSMAction { callCount++; return LSMActionNext },
|
||||
func() LSMAction { callCount++; return LSMActionCancel },
|
||||
func() LSMAction { callCount++; return LSMActionNext },
|
||||
)
|
||||
cancelled, done := lsm.Run()
|
||||
if !cancelled {
|
||||
t.Error("unexpected cancelled=false")
|
||||
}
|
||||
if !done {
|
||||
t.Error("unexpected done=false")
|
||||
}
|
||||
if callCount != 2 {
|
||||
t.Errorf("callCount = %d, want 2 (third step should not execute)", callCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinearStateMachine_RunMixed(t *testing.T) {
|
||||
pauseCount := 0
|
||||
lsm := NewLinearStateMachine(
|
||||
func() LSMAction { return LSMActionNext },
|
||||
func() LSMAction {
|
||||
pauseCount++
|
||||
if pauseCount == 1 {
|
||||
return LSMActionPause
|
||||
}
|
||||
return LSMActionNext
|
||||
},
|
||||
func() LSMAction { return LSMActionNext },
|
||||
func() LSMAction { return LSMActionNext },
|
||||
)
|
||||
cancelled, done := lsm.Run()
|
||||
if cancelled {
|
||||
t.Error("unexpected cancelled=true")
|
||||
}
|
||||
if done {
|
||||
t.Error("unexpected done=true on first run")
|
||||
}
|
||||
cancelled, done = lsm.Run()
|
||||
if cancelled {
|
||||
t.Error("unexpected cancelled=true on second run")
|
||||
}
|
||||
if !done {
|
||||
t.Error("unexpected done=false on second run")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinearStateMachine_RunEmpty(t *testing.T) {
|
||||
lsm := NewLinearStateMachine()
|
||||
cancelled, done := lsm.Run()
|
||||
if cancelled {
|
||||
t.Error("unexpected cancelled=true")
|
||||
}
|
||||
if !done {
|
||||
t.Error("unexpected done=false for empty LSM")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinearStateMachine_AppendSteps(t *testing.T) {
|
||||
lsm := NewLinearStateMachine(
|
||||
func() LSMAction { return LSMActionNext },
|
||||
)
|
||||
lsm.Run()
|
||||
lsm.AppendSteps(
|
||||
func() LSMAction { return LSMActionNext },
|
||||
)
|
||||
_, done := lsm.Run()
|
||||
if !done {
|
||||
t.Error("unexpected done=false after AppendSteps")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinearStateMachine_Reset(t *testing.T) {
|
||||
callCount := 0
|
||||
lsm := NewLinearStateMachine(
|
||||
func() LSMAction { callCount++; return LSMActionCancel },
|
||||
)
|
||||
lsm.Run()
|
||||
if !lsm.cancelled {
|
||||
t.Error("expected cancelled=true after cancel")
|
||||
}
|
||||
lsm.Reset()
|
||||
if lsm.cancelled {
|
||||
t.Error("expected cancelled=false after Reset")
|
||||
}
|
||||
if lsm.index != 0 {
|
||||
t.Errorf("expected index=0 after Reset, got %d", lsm.index)
|
||||
}
|
||||
_, done := lsm.Run()
|
||||
if !done {
|
||||
t.Error("expected done=true, step executed again after Reset")
|
||||
}
|
||||
if callCount != 2 {
|
||||
t.Errorf("callCount = %d, want 2 (first run + reset run)", callCount)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLSMActionConstants(t *testing.T) {
|
||||
if LSMActionPause != 0 {
|
||||
t.Errorf("LSMActionPause = %d, want 0", LSMActionPause)
|
||||
}
|
||||
if LSMActionNext != 1 {
|
||||
t.Errorf("LSMActionNext = %d, want 1", LSMActionNext)
|
||||
}
|
||||
if LSMActionReset != 2 {
|
||||
t.Errorf("LSMActionReset = %d, want 2", LSMActionReset)
|
||||
}
|
||||
if LSMActionCancel != 3 {
|
||||
t.Errorf("LSMActionCancel = %d, want 3", LSMActionCancel)
|
||||
}
|
||||
}
|
||||
29
analyzer/utils/string_test.go
Normal file
29
analyzer/utils/string_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestByteSlicesToStrings(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input [][]byte
|
||||
want []string
|
||||
}{
|
||||
{"nil", nil, []string{}},
|
||||
{"empty", [][]byte{}, []string{}},
|
||||
{"single", [][]byte{[]byte("hello")}, []string{"hello"}},
|
||||
{"multiple", [][]byte{[]byte("foo"), []byte("bar"), []byte("baz")}, []string{"foo", "bar", "baz"}},
|
||||
{"empty element", [][]byte{[]byte("a"), []byte{}, []byte("b")}, []string{"a", "", "b"}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := ByteSlicesToStrings(tt.input)
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("ByteSlicesToStrings() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user