1 package hscan
2
3 import (
4 "math"
5 "strconv"
6 "testing"
7 "time"
8
9 . "github.com/bsm/ginkgo/v2"
10 . "github.com/bsm/gomega"
11
12 "github.com/redis/go-redis/v9/internal/util"
13 )
14
15 type data struct {
16 Omit string `redis:"-"`
17 Empty string
18
19 String string `redis:"string"`
20 Bytes []byte `redis:"byte"`
21 Int int `redis:"int"`
22 Int8 int8 `redis:"int8"`
23 Int16 int16 `redis:"int16"`
24 Int32 int32 `redis:"int32"`
25 Int64 int64 `redis:"int64"`
26 Uint uint `redis:"uint"`
27 Uint8 uint8 `redis:"uint8"`
28 Uint16 uint16 `redis:"uint16"`
29 Uint32 uint32 `redis:"uint32"`
30 Uint64 uint64 `redis:"uint64"`
31 Float float32 `redis:"float"`
32 Float64 float64 `redis:"float64"`
33 Bool bool `redis:"bool"`
34 BoolRef *bool `redis:"boolRef"`
35 }
36
37 type TimeRFC3339Nano struct {
38 time.Time
39 }
40
41 func (t *TimeRFC3339Nano) ScanRedis(s string) (err error) {
42 t.Time, err = time.Parse(time.RFC3339Nano, s)
43 return
44 }
45
46 type TimeData struct {
47 Name string `redis:"name"`
48 Time *TimeRFC3339Nano `redis:"login"`
49 }
50
51 type i []interface{}
52
53 func TestGinkgoSuite(t *testing.T) {
54 RegisterFailHandler(Fail)
55 RunSpecs(t, "hscan")
56 }
57
58 var _ = Describe("Scan", func() {
59 It("catches bad args", func() {
60 var d data
61
62 Expect(Scan(&d, i{}, i{})).NotTo(HaveOccurred())
63 Expect(d).To(Equal(data{}))
64
65 Expect(Scan(&d, i{"key"}, i{})).To(HaveOccurred())
66 Expect(Scan(&d, i{"key"}, i{"1", "2"})).To(HaveOccurred())
67 Expect(Scan(nil, i{"key", "1"}, i{})).To(HaveOccurred())
68
69 var m map[string]interface{}
70 Expect(Scan(&m, i{"key"}, i{"1"})).To(HaveOccurred())
71 Expect(Scan(data{}, i{"key"}, i{"1"})).To(HaveOccurred())
72 Expect(Scan(data{}, i{"key", "string"}, i{nil, nil})).To(HaveOccurred())
73 })
74
75 It("number out of range", func() {
76 f := func(v uint64) string {
77 return strconv.FormatUint(v, 10) + "1"
78 }
79 keys := i{"int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "float64"}
80 vals := i{
81 f(math.MaxInt8), f(math.MaxInt16), f(math.MaxInt32), f(math.MaxInt64),
82 f(math.MaxUint8), f(math.MaxUint16), f(math.MaxUint32), strconv.FormatUint(math.MaxUint64, 10) + "1",
83 "13.4028234663852886e+38", "11.79769313486231570e+308",
84 }
85 for k, v := range keys {
86 var d data
87 Expect(Scan(&d, i{v}, i{vals[k]})).To(HaveOccurred())
88 }
89
90
91 f = func(v uint64) string {
92 return strconv.FormatUint(v, 10)
93 }
94 keys = i{"int8", "int16", "int32", "int64", "uint8", "uint16", "uint32", "uint64", "float", "float64"}
95 vals = i{
96 f(math.MaxInt8), f(math.MaxInt16), f(math.MaxInt32), f(math.MaxInt64),
97 f(math.MaxUint8), f(math.MaxUint16), f(math.MaxUint32), strconv.FormatUint(math.MaxUint64, 10),
98 "3.40282346638528859811704183484516925440e+38", "1.797693134862315708145274237317043567981e+308",
99 }
100 var d data
101 Expect(Scan(&d, keys, vals)).NotTo(HaveOccurred())
102 Expect(d).To(Equal(data{
103 Int8: math.MaxInt8,
104 Int16: math.MaxInt16,
105 Int32: math.MaxInt32,
106 Int64: math.MaxInt64,
107 Uint8: math.MaxUint8,
108 Uint16: math.MaxUint16,
109 Uint32: math.MaxUint32,
110 Uint64: math.MaxUint64,
111 Float: math.MaxFloat32,
112 Float64: math.MaxFloat64,
113 }))
114 })
115
116 It("scans good values", func() {
117 var d data
118
119
120 Expect(Scan(&d, i{"key"}, i{"value"})).NotTo(HaveOccurred())
121 Expect(d).To(Equal(data{}))
122
123 keys := i{"string", "byte", "int", "int64", "uint", "uint64", "float", "float64", "bool", "boolRef"}
124 vals := i{
125 "str!", "bytes!", "123", "123456789123456789", "456", "987654321987654321",
126 "123.456", "123456789123456789.987654321987654321", "1", "1",
127 }
128 Expect(Scan(&d, keys, vals)).NotTo(HaveOccurred())
129 Expect(d).To(Equal(data{
130 String: "str!",
131 Bytes: []byte("bytes!"),
132 Int: 123,
133 Int64: 123456789123456789,
134 Uint: 456,
135 Uint64: 987654321987654321,
136 Float: 123.456,
137 Float64: 1.2345678912345678e+17,
138 Bool: true,
139 BoolRef: util.ToPtr(true),
140 }))
141
142
143
144 type data2 struct {
145 String string `redis:"string"`
146 Bytes []byte `redis:"byte"`
147 Int int `redis:"int"`
148 Uint uint `redis:"uint"`
149 Float float32 `redis:"float"`
150 Bool bool `redis:"bool"`
151 }
152 var d2 data2
153 Expect(Scan(&d2, keys, vals)).NotTo(HaveOccurred())
154 Expect(d2).To(Equal(data2{
155 String: "str!",
156 Bytes: []byte("bytes!"),
157 Int: 123,
158 Uint: 456,
159 Float: 123.456,
160 Bool: true,
161 }))
162
163 Expect(Scan(&d, i{"string", "float", "bool"}, i{"", "1", "t"})).NotTo(HaveOccurred())
164 Expect(d).To(Equal(data{
165 String: "",
166 Bytes: []byte("bytes!"),
167 Int: 123,
168 Int64: 123456789123456789,
169 Uint: 456,
170 Uint64: 987654321987654321,
171 Float: 1.0,
172 Float64: 1.2345678912345678e+17,
173 Bool: true,
174 BoolRef: util.ToPtr(true),
175 }))
176 })
177
178 It("omits untagged fields", func() {
179 var d data
180
181 Expect(Scan(&d, i{"empty", "omit", "string"}, i{"value", "value", "str!"})).NotTo(HaveOccurred())
182 Expect(d).To(Equal(data{
183 String: "str!",
184 }))
185 })
186
187 It("catches bad values", func() {
188 var d data
189
190 Expect(Scan(&d, i{"int"}, i{"a"})).To(HaveOccurred())
191 Expect(Scan(&d, i{"uint"}, i{"a"})).To(HaveOccurred())
192 Expect(Scan(&d, i{"uint"}, i{""})).To(HaveOccurred())
193 Expect(Scan(&d, i{"float"}, i{"b"})).To(HaveOccurred())
194 Expect(Scan(&d, i{"bool"}, i{"-1"})).To(HaveOccurred())
195 Expect(Scan(&d, i{"bool"}, i{""})).To(HaveOccurred())
196 Expect(Scan(&d, i{"bool"}, i{"123"})).To(HaveOccurred())
197 })
198
199 It("Implements Scanner", func() {
200 var td TimeData
201
202 now := time.Now()
203 Expect(Scan(&td, i{"name", "login"}, i{"hello", now.Format(time.RFC3339Nano)})).NotTo(HaveOccurred())
204 Expect(td.Name).To(Equal("hello"))
205 Expect(td.Time.UnixNano()).To(Equal(now.UnixNano()))
206 Expect(td.Time.Format(time.RFC3339Nano)).To(Equal(now.Format(time.RFC3339Nano)))
207 })
208
209 It("should time.Time RFC3339Nano", func() {
210 type TimeTime struct {
211 Time time.Time `redis:"time"`
212 }
213
214 now := time.Now()
215
216 var tt TimeTime
217 Expect(Scan(&tt, i{"time"}, i{now.Format(time.RFC3339Nano)})).NotTo(HaveOccurred())
218 Expect(now.Unix()).To(Equal(tt.Time.Unix()))
219 })
220 })
221
View as plain text