1 package hstore
2
3 import (
4 "database/sql"
5 "os"
6 "testing"
7
8 _ "github.com/lib/pq"
9 )
10
11 type Fatalistic interface {
12 Fatal(args ...interface{})
13 }
14
15 func openTestConn(t Fatalistic) *sql.DB {
16 datname := os.Getenv("PGDATABASE")
17 sslmode := os.Getenv("PGSSLMODE")
18
19 if datname == "" {
20 os.Setenv("PGDATABASE", "pqgotest")
21 }
22
23 if sslmode == "" {
24 os.Setenv("PGSSLMODE", "disable")
25 }
26
27 conn, err := sql.Open("postgres", "")
28 if err != nil {
29 t.Fatal(err)
30 }
31
32 return conn
33 }
34
35 func TestHstore(t *testing.T) {
36 db := openTestConn(t)
37 defer db.Close()
38
39
40 _, err := db.Exec("CREATE EXTENSION IF NOT EXISTS hstore")
41 if err != nil {
42 t.Skipf("Skipping hstore tests - hstore extension create failed: %s", err.Error())
43 }
44
45 hs := Hstore{}
46
47
48 err = db.QueryRow("SELECT NULL::hstore").Scan(&hs)
49 if err != nil {
50 t.Fatal(err)
51 }
52 if hs.Map != nil {
53 t.Fatalf("expected null map")
54 }
55
56 err = db.QueryRow("SELECT $1::hstore", hs).Scan(&hs)
57 if err != nil {
58 t.Fatalf("re-query null map failed: %s", err.Error())
59 }
60 if hs.Map != nil {
61 t.Fatalf("expected null map")
62 }
63
64
65 err = db.QueryRow("SELECT ''::hstore").Scan(&hs)
66 if err != nil {
67 t.Fatal(err)
68 }
69 if hs.Map == nil {
70 t.Fatalf("expected empty map, got null map")
71 }
72 if len(hs.Map) != 0 {
73 t.Fatalf("expected empty map, got len(map)=%d", len(hs.Map))
74 }
75
76 err = db.QueryRow("SELECT $1::hstore", hs).Scan(&hs)
77 if err != nil {
78 t.Fatalf("re-query empty map failed: %s", err.Error())
79 }
80 if hs.Map == nil {
81 t.Fatalf("expected empty map, got null map")
82 }
83 if len(hs.Map) != 0 {
84 t.Fatalf("expected empty map, got len(map)=%d", len(hs.Map))
85 }
86
87
88 hsOnePair := Hstore{
89 Map: map[string]sql.NullString{
90 "key1": {String: "value1", Valid: true},
91 },
92 }
93
94 hsThreePairs := Hstore{
95 Map: map[string]sql.NullString{
96 "key1": {String: "value1", Valid: true},
97 "key2": {String: "value2", Valid: true},
98 "key3": {String: "value3", Valid: true},
99 },
100 }
101
102 hsSmorgasbord := Hstore{
103 Map: map[string]sql.NullString{
104 "nullstring": {String: "NULL", Valid: true},
105 "actuallynull": {String: "", Valid: false},
106 "NULL": {String: "NULL string key", Valid: true},
107 "withbracket": {String: "value>42", Valid: true},
108 "withequal": {String: "value=42", Valid: true},
109 `"withquotes1"`: {String: `this "should" be fine`, Valid: true},
110 `"withquotes"2"`: {String: `this "should\" also be fine`, Valid: true},
111 "embedded1": {String: "value1=>x1", Valid: true},
112 "embedded2": {String: `"value2"=>x2`, Valid: true},
113 "withnewlines": {String: "\n\nvalue\t=>2", Valid: true},
114 "<<all sorts of crazy>>": {String: `this, "should,\" also, => be fine`, Valid: true},
115 },
116 }
117
118
119 testBidirectional := func(h Hstore) {
120 err = db.QueryRow("SELECT $1::hstore", h).Scan(&hs)
121 if err != nil {
122 t.Fatalf("re-query %d-pair map failed: %s", len(h.Map), err.Error())
123 }
124 if hs.Map == nil {
125 t.Fatalf("expected %d-pair map, got null map", len(h.Map))
126 }
127 if len(hs.Map) != len(h.Map) {
128 t.Fatalf("expected %d-pair map, got len(map)=%d", len(h.Map), len(hs.Map))
129 }
130
131 for key, val := range hs.Map {
132 otherval, found := h.Map[key]
133 if !found {
134 t.Fatalf(" key '%v' not found in %d-pair map", key, len(h.Map))
135 }
136 if otherval.Valid != val.Valid {
137 t.Fatalf(" value %v <> %v in %d-pair map", otherval, val, len(h.Map))
138 }
139 if otherval.String != val.String {
140 t.Fatalf(" value '%v' <> '%v' in %d-pair map", otherval.String, val.String, len(h.Map))
141 }
142 }
143 }
144
145 testBidirectional(hsOnePair)
146 testBidirectional(hsThreePairs)
147 testBidirectional(hsSmorgasbord)
148 }
149
View as plain text