Files
mysql-tunnel/internal/navicat/parser_test.go
T
2026-09-21 16:46:55 +08:00

206 lines
4.8 KiB
Go

package navicat
import (
"bytes"
"strings"
"testing"
)
func TestBlockRoundTripShortAndLong(t *testing.T) {
cases := [][]byte{
{},
[]byte("a"),
bytes.Repeat([]byte("x"), 253),
bytes.Repeat([]byte("y"), 254),
bytes.Repeat([]byte("z"), 1024),
[]byte("你好世界"),
}
for _, in := range cases {
enc := AppendBlock(nil, in)
r := newReader(enc)
got, isNull, err := r.block(false)
if err != nil {
t.Fatalf("len=%d: %v", len(in), err)
}
if isNull {
t.Fatal("null")
}
if !bytes.Equal(got, in) {
t.Fatalf("mismatch len=%d", len(in))
}
}
}
func TestNullCell(t *testing.T) {
enc := AppendNull(nil)
r := newReader(enc)
_, isNull, err := r.block(true)
if err != nil || !isNull {
t.Fatalf("err=%v null=%v", err, isNull)
}
}
func TestHeader202And206(t *testing.T) {
for _, ver := range []uint16{Version202, Version206} {
body := AppendHeader(nil, ver, 0)
h, _, err := ParseHeader(body)
if err != nil {
t.Fatal(err)
}
if h.Version != ver || !h.OK() {
t.Fatalf("%+v", h)
}
}
}
func TestHeaderError204(t *testing.T) {
body := encodeHeaderError(ErrnoInvalidToken, "invalid access token")
h, _, err := ParseHeader(body)
if err != nil {
t.Fatal(err)
}
if h.Errno != ErrnoInvalidToken || h.Message != "invalid access token" {
t.Fatalf("%+v", h)
}
}
func TestConnectParse(t *testing.T) {
body := encodeConnectOK("127.0.0.1 via TCP/IP", "10", "8.0.36")
resp, err := ParseConnect(body)
if err != nil {
t.Fatal(err)
}
if resp.Conn.ProtoInfo != "10" || resp.Conn.ServerInfo != "8.0.36" {
t.Fatalf("%+v", resp.Conn)
}
}
func TestQuerySelect1(t *testing.T) {
body := encodeQueryResults([]Result{selectLiteral("1", "1", 8, 20)})
resp, err := ParseQuery(body)
if err != nil {
t.Fatal(err)
}
if len(resp.Results) != 1 {
t.Fatalf("results=%d", len(resp.Results))
}
r := resp.Results[0]
if !r.IsResultSet() || r.NumRows != 1 {
t.Fatalf("%+v", r)
}
if r.Rows[0][0].Null || r.Rows[0][0].Text() != "1" {
t.Fatalf("cell=%+v", r.Rows[0][0])
}
}
func TestNullDecimalBigintUTF8(t *testing.T) {
body := encodeQueryResults([]Result{
{
NumFields: 4,
NumRows: 1,
Fields: []Field{
{Name: "n", Type: 6},
{Name: "b", Type: 8, Length: 20},
{Name: "d", Type: 246, Length: 32},
{Name: "z", Type: 253, Length: 12},
},
Rows: [][]Cell{{
{Null: true},
{Bytes: []byte("18446744073709551615")},
{Bytes: []byte("1234567890.123456789")},
{Bytes: []byte("你好世界")},
}},
},
})
resp, err := ParseQuery(body)
if err != nil {
t.Fatal(err)
}
row := resp.Results[0].Rows[0]
if !row[0].Null {
t.Fatal("expected NULL")
}
if row[1].Text() != "18446744073709551615" {
t.Fatalf("bigint parsed badly: %q", row[1].Text())
}
if row[2].Text() != "1234567890.123456789" {
t.Fatalf("decimal parsed badly: %q", row[2].Text())
}
if row[3].Text() != "你好世界" {
t.Fatalf("utf8: %q", row[3].Text())
}
}
func TestSQLError(t *testing.T) {
body := encodeQueryResults([]Result{{Errno: 1064, Message: "You have an error in your SQL syntax"}})
resp, err := ParseQuery(body)
if err != nil {
t.Fatal(err)
}
if !resp.Results[0].IsError() || !strings.Contains(resp.Results[0].Message, "syntax") {
t.Fatalf("%+v", resp.Results[0])
}
}
func TestDMLOk(t *testing.T) {
body := encodeQueryResults([]Result{{AffectedRows: 3, InsertID: 9, Info: "Rows matched: 3"}})
resp, err := ParseQuery(body)
if err != nil {
t.Fatal(err)
}
r := resp.Results[0]
if r.IsResultSet() || r.AffectedRows != 3 || r.InsertID != 9 {
t.Fatalf("%+v", r)
}
}
func TestHTMLRejected(t *testing.T) {
_, err := ParseConnect([]byte("<html>nope</html>"))
if err == nil {
t.Fatal("expected error")
}
}
func TestRequestOmitsEmptyQueriesAndEncodesArray(t *testing.T) {
enc := Request{
Action: ActionQuery,
Host: "mysql",
Port: 3306,
Login: "root",
Queries: []string{"SELECT 1", "", "SELECT 2"},
}.Encode()
if strings.Contains(enc, "password=secret") {
t.Fatal("unexpected")
}
if !strings.Contains(enc, "q%5B%5D=SELECT+1") && !strings.Contains(enc, "q%5B%5D=SELECT%201") {
t.Fatalf("q[] missing: %s", enc)
}
if strings.Count(enc, "q%5B%5D=") != 2 {
t.Fatalf("empty query not skipped: %s", enc)
}
}
func TestRequestBase64(t *testing.T) {
enc := Request{
Action: ActionQuery,
Host: "mysql",
Port: 3306,
Login: "root",
Queries: []string{"SELECT 1"},
EncodeBase64: true,
}.Encode()
if !strings.Contains(enc, "encodeBase64=1") {
t.Fatal(enc)
}
if strings.Contains(enc, "SELECT+1") {
t.Fatalf("sql should be base64: %s", enc)
}
}
func TestErrorDoesNotEmbedPassword(t *testing.T) {
e := &Error{Kind: "mysql", Errno: 1045, Message: "Access denied for user 'root'@'localhost'"}
if strings.Contains(e.Error(), "password") && strings.Contains(e.Error(), "=") {
t.Fatal(e.Error())
}
}