redcon/resp_test.go

131 lines
3.0 KiB
Go

package redcon
import (
"fmt"
"strconv"
"testing"
)
func isEmptyRESP(resp RESP) bool {
return resp.Type == 0 && resp.Count == 0 &&
resp.Data == nil && resp.Raw == nil
}
func expectBad(t *testing.T, payload string) {
t.Helper()
n, resp := ReadNextRESP([]byte(payload))
if n > 0 || !isEmptyRESP(resp) {
t.Fatalf("expected empty resp")
}
}
func respVOut(a RESP) string {
var data string
var raw string
if a.Data == nil {
data = "nil"
} else {
data = strconv.Quote(string(a.Data))
}
if a.Raw == nil {
raw = "nil"
} else {
raw = strconv.Quote(string(a.Raw))
}
return fmt.Sprintf("{Type: %d, Count: %d, Data: %s, Raw: %s}",
a.Type, a.Count, data, raw,
)
}
func respEquals(a, b RESP) bool {
if a.Count != b.Count {
return false
}
if a.Type != b.Type {
return false
}
if (a.Data == nil && b.Data != nil) || (a.Data != nil && b.Data == nil) {
return false
}
if string(a.Data) != string(b.Data) {
return false
}
if (a.Raw == nil && b.Raw != nil) || (a.Raw != nil && b.Raw == nil) {
return false
}
if string(a.Raw) != string(b.Raw) {
return false
}
return true
}
func expectGood(t *testing.T, payload string, exp RESP) {
t.Helper()
n, resp := ReadNextRESP([]byte(payload))
if n != len(payload) || isEmptyRESP(resp) {
t.Fatalf("expected good resp")
}
if string(resp.Raw) != payload {
t.Fatalf("expected '%s', got '%s'", payload, resp.Raw)
}
exp.Raw = []byte(payload)
switch exp.Type {
case Integer, String, Error:
exp.Data = []byte(payload[1 : len(payload)-2])
}
if !respEquals(resp, exp) {
t.Fatalf("expected %v, got %v", respVOut(exp), respVOut(resp))
}
}
func TestRESP(t *testing.T) {
expectBad(t, "")
expectBad(t, "^hello\r\n")
expectBad(t, "+hello\r")
expectBad(t, "+hello\n")
expectBad(t, ":\r\n")
expectBad(t, ":-\r\n")
expectBad(t, ":-abc\r\n")
expectBad(t, ":abc\r\n")
expectGood(t, ":-123\r\n", RESP{Type: Integer})
expectGood(t, ":123\r\n", RESP{Type: Integer})
expectBad(t, "+\r")
expectBad(t, "+\n")
expectGood(t, "+\r\n", RESP{Type: String})
expectGood(t, "+hello world\r\n", RESP{Type: String})
expectBad(t, "-\r")
expectBad(t, "-\n")
expectGood(t, "-\r\n", RESP{Type: Error})
expectGood(t, "-hello world\r\n", RESP{Type: Error})
expectBad(t, "$")
expectBad(t, "$\r")
expectBad(t, "$\r\n")
expectGood(t, "$-1\r\n", RESP{Type: Bulk})
expectGood(t, "$0\r\n\r\n", RESP{Type: Bulk, Data: []byte("")})
expectBad(t, "$5\r\nhello\r")
expectBad(t, "$5\r\nhello\n\n")
expectGood(t, "$5\r\nhello\r\n", RESP{Type: Bulk, Data: []byte("hello")})
expectBad(t, "*a\r\n")
expectBad(t, "*3\r\n")
expectBad(t, "*3\r\n:hello\r")
expectGood(t, "*3\r\n:1\r\n:2\r\n:3\r\n",
RESP{Type: Array, Count: 3, Data: []byte(":1\r\n:2\r\n:3\r\n")})
var xx int
_, r := ReadNextRESP([]byte("*4\r\n:1\r\n:2\r\n:3\r\n:4\r\n"))
r.ForEach(func(resp RESP) bool {
xx++
x, _ := strconv.Atoi(string(resp.Data))
if x != xx {
t.Fatalf("expected %v, got %v", x, xx)
}
if xx == 3 {
return false
}
return true
})
if xx != 3 {
t.Fatalf("expected %v, got %v", 3, xx)
}
}