mirror of
https://github.com/redis/go-redis.git
synced 2026-10-24 07:59:20 +03:00
* fix(cmd): accept RESP3 doubles in Cmd.Float64 With RESP3, the default protocol, ReadReply returns a double reply (for example from ZSCORE) as float64. toFloat64 and toFloat32 only handled int64 and string, so Cmd.Float64, Float32, Float64Slice and Float32Slice failed with "unexpected type=float64". Handle float64 the same way toBool handles the RESP3 boolean. * fix(cmd): keep Float32 range error on RESP3 float32(val) turns a RESP3 double outside the float32 range into an infinity without an error, while the RESP2 bulk string path returns the ParseFloat range error. Return the same error for the RESP3 double. An infinity sent by the server is still returned as is. --------- Co-authored-by: Nedyalko Dyakov <1547186+ndyakov@users.noreply.github.com>
71 lines
2.3 KiB
Go
71 lines
2.3 KiB
Go
package redis
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"math"
|
|
"reflect"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/redis/go-redis/v9/internal/proto"
|
|
)
|
|
|
|
// RESP3 sends a double reply, for example from ZSCORE, as a float64 value.
|
|
// The float helpers of Cmd must accept it, as they accept the RESP2 bulk
|
|
// string.
|
|
func TestCmdFloatFromDoubleReply(t *testing.T) {
|
|
read := func(t *testing.T, reply string) *Cmd {
|
|
t.Helper()
|
|
cmd := NewCmd(context.Background())
|
|
if err := cmd.readReply(proto.NewReader(strings.NewReader(reply))); err != nil {
|
|
t.Fatalf("readReply(%q): %v", reply, err)
|
|
}
|
|
return cmd
|
|
}
|
|
|
|
for _, reply := range []string{",1.5\r\n", "$3\r\n1.5\r\n"} {
|
|
cmd := read(t, reply)
|
|
if got, err := cmd.Float64(); err != nil || got != 1.5 {
|
|
t.Errorf("Float64() for %q = %v, %v; want 1.5, nil", reply, got, err)
|
|
}
|
|
if got, err := cmd.Float32(); err != nil || got != 1.5 {
|
|
t.Errorf("Float32() for %q = %v, %v; want 1.5, nil", reply, got, err)
|
|
}
|
|
}
|
|
|
|
for _, reply := range []string{"*2\r\n,1.5\r\n,2\r\n", "*2\r\n$3\r\n1.5\r\n$1\r\n2\r\n"} {
|
|
cmd := read(t, reply)
|
|
if got, err := cmd.Float64Slice(); err != nil || !reflect.DeepEqual(got, []float64{1.5, 2}) {
|
|
t.Errorf("Float64Slice() for %q = %v, %v; want [1.5 2], nil", reply, got, err)
|
|
}
|
|
if got, err := cmd.Float32Slice(); err != nil || !reflect.DeepEqual(got, []float32{1.5, 2}) {
|
|
t.Errorf("Float32Slice() for %q = %v, %v; want [1.5 2], nil", reply, got, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A double outside the float32 range must give the same range error from
|
|
// Float32 for a RESP3 double as for a RESP2 bulk string. An infinity sent by
|
|
// the server is not an error.
|
|
func TestCmdFloat32FromDoubleReplyOutOfRange(t *testing.T) {
|
|
for _, reply := range []string{",1e100\r\n", "$5\r\n1e100\r\n"} {
|
|
cmd := NewCmd(context.Background())
|
|
if err := cmd.readReply(proto.NewReader(strings.NewReader(reply))); err != nil {
|
|
t.Fatalf("readReply(%q): %v", reply, err)
|
|
}
|
|
if got, err := cmd.Float32(); !errors.Is(err, strconv.ErrRange) {
|
|
t.Errorf("Float32() for %q = %v, %v; want strconv.ErrRange", reply, got, err)
|
|
}
|
|
}
|
|
|
|
cmd := NewCmd(context.Background())
|
|
if err := cmd.readReply(proto.NewReader(strings.NewReader(",inf\r\n"))); err != nil {
|
|
t.Fatalf("readReply: %v", err)
|
|
}
|
|
if got, err := cmd.Float32(); err != nil || !math.IsInf(float64(got), 1) {
|
|
t.Errorf("Float32() for inf = %v, %v; want +Inf, nil", got, err)
|
|
}
|
|
}
|