Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 

441 rinda
10 KiB

  1. // Copyright 2012 Gary Burd
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package redis_test
  15. import (
  16. "fmt"
  17. "math"
  18. "reflect"
  19. "testing"
  20. "github.com/garyburd/redigo/redis"
  21. )
  22. var scanConversionTests = []struct {
  23. src interface{}
  24. dest interface{}
  25. }{
  26. {[]byte("-inf"), math.Inf(-1)},
  27. {[]byte("+inf"), math.Inf(1)},
  28. {[]byte("0"), float64(0)},
  29. {[]byte("3.14159"), float64(3.14159)},
  30. {[]byte("3.14"), float32(3.14)},
  31. {[]byte("-100"), int(-100)},
  32. {[]byte("101"), int(101)},
  33. {int64(102), int(102)},
  34. {[]byte("103"), uint(103)},
  35. {int64(104), uint(104)},
  36. {[]byte("105"), int8(105)},
  37. {int64(106), int8(106)},
  38. {[]byte("107"), uint8(107)},
  39. {int64(108), uint8(108)},
  40. {[]byte("0"), false},
  41. {int64(0), false},
  42. {[]byte("f"), false},
  43. {[]byte("1"), true},
  44. {int64(1), true},
  45. {[]byte("t"), true},
  46. {"hello", "hello"},
  47. {[]byte("hello"), "hello"},
  48. {[]byte("world"), []byte("world")},
  49. {[]interface{}{[]byte("foo")}, []interface{}{[]byte("foo")}},
  50. {[]interface{}{[]byte("foo")}, []string{"foo"}},
  51. {[]interface{}{[]byte("hello"), []byte("world")}, []string{"hello", "world"}},
  52. {[]interface{}{[]byte("bar")}, [][]byte{[]byte("bar")}},
  53. {[]interface{}{[]byte("1")}, []int{1}},
  54. {[]interface{}{[]byte("1"), []byte("2")}, []int{1, 2}},
  55. {[]interface{}{[]byte("1"), []byte("2")}, []float64{1, 2}},
  56. {[]interface{}{[]byte("1")}, []byte{1}},
  57. {[]interface{}{[]byte("1")}, []bool{true}},
  58. }
  59. func TestScanConversion(t *testing.T) {
  60. for _, tt := range scanConversionTests {
  61. values := []interface{}{tt.src}
  62. dest := reflect.New(reflect.TypeOf(tt.dest))
  63. values, err := redis.Scan(values, dest.Interface())
  64. if err != nil {
  65. t.Errorf("Scan(%v) returned error %v", tt, err)
  66. continue
  67. }
  68. if !reflect.DeepEqual(tt.dest, dest.Elem().Interface()) {
  69. t.Errorf("Scan(%v) returned %v, want %v", tt, dest.Elem().Interface(), tt.dest)
  70. }
  71. }
  72. }
  73. var scanConversionErrorTests = []struct {
  74. src interface{}
  75. dest interface{}
  76. }{
  77. {[]byte("1234"), byte(0)},
  78. {int64(1234), byte(0)},
  79. {[]byte("-1"), byte(0)},
  80. {int64(-1), byte(0)},
  81. {[]byte("junk"), false},
  82. {redis.Error("blah"), false},
  83. }
  84. func TestScanConversionError(t *testing.T) {
  85. for _, tt := range scanConversionErrorTests {
  86. values := []interface{}{tt.src}
  87. dest := reflect.New(reflect.TypeOf(tt.dest))
  88. values, err := redis.Scan(values, dest.Interface())
  89. if err == nil {
  90. t.Errorf("Scan(%v) did not return error", tt)
  91. }
  92. }
  93. }
  94. func ExampleScan() {
  95. c, err := dial()
  96. if err != nil {
  97. fmt.Println(err)
  98. return
  99. }
  100. defer c.Close()
  101. c.Send("HMSET", "album:1", "title", "Red", "rating", 5)
  102. c.Send("HMSET", "album:2", "title", "Earthbound", "rating", 1)
  103. c.Send("HMSET", "album:3", "title", "Beat")
  104. c.Send("LPUSH", "albums", "1")
  105. c.Send("LPUSH", "albums", "2")
  106. c.Send("LPUSH", "albums", "3")
  107. values, err := redis.Values(c.Do("SORT", "albums",
  108. "BY", "album:*->rating",
  109. "GET", "album:*->title",
  110. "GET", "album:*->rating"))
  111. if err != nil {
  112. fmt.Println(err)
  113. return
  114. }
  115. for len(values) > 0 {
  116. var title string
  117. rating := -1 // initialize to illegal value to detect nil.
  118. values, err = redis.Scan(values, &title, &rating)
  119. if err != nil {
  120. fmt.Println(err)
  121. return
  122. }
  123. if rating == -1 {
  124. fmt.Println(title, "not-rated")
  125. } else {
  126. fmt.Println(title, rating)
  127. }
  128. }
  129. // Output:
  130. // Beat not-rated
  131. // Earthbound 1
  132. // Red 5
  133. }
  134. type s0 struct {
  135. X int
  136. Y int `redis:"y"`
  137. Bt bool
  138. }
  139. type s1 struct {
  140. X int `redis:"-"`
  141. I int `redis:"i"`
  142. U uint `redis:"u"`
  143. S string `redis:"s"`
  144. P []byte `redis:"p"`
  145. B bool `redis:"b"`
  146. Bt bool
  147. Bf bool
  148. s0
  149. }
  150. var scanStructTests = []struct {
  151. title string
  152. reply []string
  153. value interface{}
  154. }{
  155. {"basic",
  156. []string{"i", "-1234", "u", "5678", "s", "hello", "p", "world", "b", "t", "Bt", "1", "Bf", "0", "X", "123", "y", "456"},
  157. &s1{I: -1234, U: 5678, S: "hello", P: []byte("world"), B: true, Bt: true, Bf: false, s0: s0{X: 123, Y: 456}},
  158. },
  159. }
  160. func TestScanStruct(t *testing.T) {
  161. for _, tt := range scanStructTests {
  162. var reply []interface{}
  163. for _, v := range tt.reply {
  164. reply = append(reply, []byte(v))
  165. }
  166. value := reflect.New(reflect.ValueOf(tt.value).Type().Elem())
  167. if err := redis.ScanStruct(reply, value.Interface()); err != nil {
  168. t.Fatalf("ScanStruct(%s) returned error %v", tt.title, err)
  169. }
  170. if !reflect.DeepEqual(value.Interface(), tt.value) {
  171. t.Fatalf("ScanStruct(%s) returned %v, want %v", tt.title, value.Interface(), tt.value)
  172. }
  173. }
  174. }
  175. func TestBadScanStructArgs(t *testing.T) {
  176. x := []interface{}{"A", "b"}
  177. test := func(v interface{}) {
  178. if err := redis.ScanStruct(x, v); err == nil {
  179. t.Errorf("Expect error for ScanStruct(%T, %T)", x, v)
  180. }
  181. }
  182. test(nil)
  183. var v0 *struct{}
  184. test(v0)
  185. var v1 int
  186. test(&v1)
  187. x = x[:1]
  188. v2 := struct{ A string }{}
  189. test(&v2)
  190. }
  191. var scanSliceTests = []struct {
  192. src []interface{}
  193. fieldNames []string
  194. ok bool
  195. dest interface{}
  196. }{
  197. {
  198. []interface{}{[]byte("1"), nil, []byte("-1")},
  199. nil,
  200. true,
  201. []int{1, 0, -1},
  202. },
  203. {
  204. []interface{}{[]byte("1"), nil, []byte("2")},
  205. nil,
  206. true,
  207. []uint{1, 0, 2},
  208. },
  209. {
  210. []interface{}{[]byte("-1")},
  211. nil,
  212. false,
  213. []uint{1},
  214. },
  215. {
  216. []interface{}{[]byte("hello"), nil, []byte("world")},
  217. nil,
  218. true,
  219. [][]byte{[]byte("hello"), nil, []byte("world")},
  220. },
  221. {
  222. []interface{}{[]byte("hello"), nil, []byte("world")},
  223. nil,
  224. true,
  225. []string{"hello", "", "world"},
  226. },
  227. {
  228. []interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
  229. nil,
  230. true,
  231. []struct{ A, B string }{{"a1", "b1"}, {"a2", "b2"}},
  232. },
  233. {
  234. []interface{}{[]byte("a1"), []byte("b1")},
  235. nil,
  236. false,
  237. []struct{ A, B, C string }{{"a1", "b1", ""}},
  238. },
  239. {
  240. []interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
  241. nil,
  242. true,
  243. []*struct{ A, B string }{{"a1", "b1"}, {"a2", "b2"}},
  244. },
  245. {
  246. []interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
  247. []string{"A", "B"},
  248. true,
  249. []struct{ A, C, B string }{{"a1", "", "b1"}, {"a2", "", "b2"}},
  250. },
  251. {
  252. []interface{}{[]byte("a1"), []byte("b1"), []byte("a2"), []byte("b2")},
  253. nil,
  254. false,
  255. []struct{}{},
  256. },
  257. }
  258. func TestScanSlice(t *testing.T) {
  259. for _, tt := range scanSliceTests {
  260. typ := reflect.ValueOf(tt.dest).Type()
  261. dest := reflect.New(typ)
  262. err := redis.ScanSlice(tt.src, dest.Interface(), tt.fieldNames...)
  263. if tt.ok != (err == nil) {
  264. t.Errorf("ScanSlice(%v, []%s, %v) returned error %v", tt.src, typ, tt.fieldNames, err)
  265. continue
  266. }
  267. if tt.ok && !reflect.DeepEqual(dest.Elem().Interface(), tt.dest) {
  268. t.Errorf("ScanSlice(src, []%s) returned %#v, want %#v", typ, dest.Elem().Interface(), tt.dest)
  269. }
  270. }
  271. }
  272. func ExampleScanSlice() {
  273. c, err := dial()
  274. if err != nil {
  275. fmt.Println(err)
  276. return
  277. }
  278. defer c.Close()
  279. c.Send("HMSET", "album:1", "title", "Red", "rating", 5)
  280. c.Send("HMSET", "album:2", "title", "Earthbound", "rating", 1)
  281. c.Send("HMSET", "album:3", "title", "Beat", "rating", 4)
  282. c.Send("LPUSH", "albums", "1")
  283. c.Send("LPUSH", "albums", "2")
  284. c.Send("LPUSH", "albums", "3")
  285. values, err := redis.Values(c.Do("SORT", "albums",
  286. "BY", "album:*->rating",
  287. "GET", "album:*->title",
  288. "GET", "album:*->rating"))
  289. if err != nil {
  290. fmt.Println(err)
  291. return
  292. }
  293. var albums []struct {
  294. Title string
  295. Rating int
  296. }
  297. if err := redis.ScanSlice(values, &albums); err != nil {
  298. fmt.Println(err)
  299. return
  300. }
  301. fmt.Printf("%v\n", albums)
  302. // Output:
  303. // [{Earthbound 1} {Beat 4} {Red 5}]
  304. }
  305. var argsTests = []struct {
  306. title string
  307. actual redis.Args
  308. expected redis.Args
  309. }{
  310. {"struct ptr",
  311. redis.Args{}.AddFlat(&struct {
  312. I int `redis:"i"`
  313. U uint `redis:"u"`
  314. S string `redis:"s"`
  315. P []byte `redis:"p"`
  316. M map[string]string `redis:"m"`
  317. Bt bool
  318. Bf bool
  319. }{
  320. -1234, 5678, "hello", []byte("world"), map[string]string{"hello": "world"}, true, false,
  321. }),
  322. redis.Args{"i", int(-1234), "u", uint(5678), "s", "hello", "p", []byte("world"), "m", map[string]string{"hello": "world"}, "Bt", true, "Bf", false},
  323. },
  324. {"struct",
  325. redis.Args{}.AddFlat(struct{ I int }{123}),
  326. redis.Args{"I", 123},
  327. },
  328. {"slice",
  329. redis.Args{}.Add(1).AddFlat([]string{"a", "b", "c"}).Add(2),
  330. redis.Args{1, "a", "b", "c", 2},
  331. },
  332. {"struct omitempty",
  333. redis.Args{}.AddFlat(&struct {
  334. I int `redis:"i,omitempty"`
  335. U uint `redis:"u,omitempty"`
  336. S string `redis:"s,omitempty"`
  337. P []byte `redis:"p,omitempty"`
  338. M map[string]string `redis:"m,omitempty"`
  339. Bt bool `redis:"Bt,omitempty"`
  340. Bf bool `redis:"Bf,omitempty"`
  341. }{
  342. 0, 0, "", []byte{}, map[string]string{}, true, false,
  343. }),
  344. redis.Args{"Bt", true},
  345. },
  346. }
  347. func TestArgs(t *testing.T) {
  348. for _, tt := range argsTests {
  349. if !reflect.DeepEqual(tt.actual, tt.expected) {
  350. t.Fatalf("%s is %v, want %v", tt.title, tt.actual, tt.expected)
  351. }
  352. }
  353. }
  354. func ExampleArgs() {
  355. c, err := dial()
  356. if err != nil {
  357. fmt.Println(err)
  358. return
  359. }
  360. defer c.Close()
  361. var p1, p2 struct {
  362. Title string `redis:"title"`
  363. Author string `redis:"author"`
  364. Body string `redis:"body"`
  365. }
  366. p1.Title = "Example"
  367. p1.Author = "Gary"
  368. p1.Body = "Hello"
  369. if _, err := c.Do("HMSET", redis.Args{}.Add("id1").AddFlat(&p1)...); err != nil {
  370. fmt.Println(err)
  371. return
  372. }
  373. m := map[string]string{
  374. "title": "Example2",
  375. "author": "Steve",
  376. "body": "Map",
  377. }
  378. if _, err := c.Do("HMSET", redis.Args{}.Add("id2").AddFlat(m)...); err != nil {
  379. fmt.Println(err)
  380. return
  381. }
  382. for _, id := range []string{"id1", "id2"} {
  383. v, err := redis.Values(c.Do("HGETALL", id))
  384. if err != nil {
  385. fmt.Println(err)
  386. return
  387. }
  388. if err := redis.ScanStruct(v, &p2); err != nil {
  389. fmt.Println(err)
  390. return
  391. }
  392. fmt.Printf("%+v\n", p2)
  393. }
  394. // Output:
  395. // {Title:Example Author:Gary Body:Hello}
  396. // {Title:Example2 Author:Steve Body:Map}
  397. }