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("nope")) 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()) } }