1 package pgtype_test
2
3 import (
4 "context"
5 "reflect"
6 "testing"
7 "time"
8
9 "github.com/jackc/pgtype"
10 "github.com/jackc/pgtype/testutil"
11 "github.com/stretchr/testify/require"
12 )
13
14 func TestTimestampTranscode(t *testing.T) {
15 testutil.TestSuccessfulTranscodeEqFunc(t, "timestamp", []interface{}{
16 &pgtype.Timestamp{Time: time.Date(1800, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
17 &pgtype.Timestamp{Time: time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
18 &pgtype.Timestamp{Time: time.Date(1905, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
19 &pgtype.Timestamp{Time: time.Date(1940, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
20 &pgtype.Timestamp{Time: time.Date(1960, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
21 &pgtype.Timestamp{Time: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
22 &pgtype.Timestamp{Time: time.Date(1999, 12, 31, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
23 &pgtype.Timestamp{Time: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
24 &pgtype.Timestamp{Time: time.Date(2000, 1, 2, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
25 &pgtype.Timestamp{Time: time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present},
26 &pgtype.Timestamp{Status: pgtype.Null},
27 &pgtype.Timestamp{Status: pgtype.Present, InfinityModifier: pgtype.Infinity},
28 &pgtype.Timestamp{Status: pgtype.Present, InfinityModifier: -pgtype.Infinity},
29 }, func(a, b interface{}) bool {
30 at := a.(pgtype.Timestamp)
31 bt := b.(pgtype.Timestamp)
32
33 return at.Time.Equal(bt.Time) && at.Status == bt.Status && at.InfinityModifier == bt.InfinityModifier
34 })
35 }
36
37
38 func TestTimestampTranscodeBigTimeBinary(t *testing.T) {
39 conn := testutil.MustConnectPgx(t)
40 if _, ok := conn.ConnInfo().DataTypeForName("line"); !ok {
41 t.Skip("Skipping due to no line type")
42 }
43 defer testutil.MustCloseContext(t, conn)
44
45 in := &pgtype.Timestamp{Time: time.Date(294276, 12, 31, 23, 59, 59, 999999000, time.UTC), Status: pgtype.Present}
46 var out pgtype.Timestamp
47
48 err := conn.QueryRow(context.Background(), "select $1::timestamptz", in).Scan(&out)
49 if err != nil {
50 t.Fatal(err)
51 }
52
53 require.Equal(t, in.Status, out.Status)
54 require.Truef(t, in.Time.Equal(out.Time), "expected %v got %v", in.Time, out.Time)
55 }
56
57 func TestTimestampNanosecondsTruncated(t *testing.T) {
58 tests := []struct {
59 input time.Time
60 expected time.Time
61 }{
62 {time.Date(2020, 1, 1, 0, 0, 0, 999999999, time.UTC), time.Date(2020, 1, 1, 0, 0, 0, 999999000, time.UTC)},
63 {time.Date(2020, 1, 1, 0, 0, 0, 999999001, time.UTC), time.Date(2020, 1, 1, 0, 0, 0, 999999000, time.UTC)},
64 }
65 for i, tt := range tests {
66 {
67 ts := pgtype.Timestamp{Time: tt.input, Status: pgtype.Present}
68 buf, err := ts.EncodeText(nil, nil)
69 if err != nil {
70 t.Errorf("%d. EncodeText failed - %v", i, err)
71 }
72
73 ts.DecodeText(nil, buf)
74 if err != nil {
75 t.Errorf("%d. DecodeText failed - %v", i, err)
76 }
77
78 if !(ts.Status == pgtype.Present && ts.Time.Equal(tt.expected)) {
79 t.Errorf("%d. EncodeText did not truncate nanoseconds", i)
80 }
81 }
82
83 {
84 ts := pgtype.Timestamp{Time: tt.input, Status: pgtype.Present}
85 buf, err := ts.EncodeBinary(nil, nil)
86 if err != nil {
87 t.Errorf("%d. EncodeBinary failed - %v", i, err)
88 }
89
90 ts.DecodeBinary(nil, buf)
91 if err != nil {
92 t.Errorf("%d. DecodeBinary failed - %v", i, err)
93 }
94
95 if !(ts.Status == pgtype.Present && ts.Time.Equal(tt.expected)) {
96 t.Errorf("%d. EncodeBinary did not truncate nanoseconds", i)
97 }
98 }
99 }
100 }
101
102
103 func TestTimestampDecodeTextInvalid(t *testing.T) {
104 tstz := &pgtype.Timestamp{}
105 err := tstz.DecodeText(nil, []byte(`eeeee`))
106 require.Error(t, err)
107 }
108
109 func TestTimestampSet(t *testing.T) {
110 type _time time.Time
111
112 successfulTests := []struct {
113 source interface{}
114 result pgtype.Timestamp
115 }{
116 {source: time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC), result: pgtype.Timestamp{Time: time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
117 {source: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), result: pgtype.Timestamp{Time: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
118 {source: time.Date(1999, 12, 31, 12, 59, 59, 0, time.UTC), result: pgtype.Timestamp{Time: time.Date(1999, 12, 31, 12, 59, 59, 0, time.UTC), Status: pgtype.Present}},
119 {source: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), result: pgtype.Timestamp{Time: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
120 {source: time.Date(2000, 1, 1, 0, 0, 1, 0, time.UTC), result: pgtype.Timestamp{Time: time.Date(2000, 1, 1, 0, 0, 1, 0, time.UTC), Status: pgtype.Present}},
121 {source: time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC), result: pgtype.Timestamp{Time: time.Date(2200, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
122 {source: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), result: pgtype.Timestamp{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
123 {source: _time(time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)), result: pgtype.Timestamp{Time: time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
124 {source: pgtype.Infinity, result: pgtype.Timestamp{InfinityModifier: pgtype.Infinity, Status: pgtype.Present}},
125 {source: pgtype.NegativeInfinity, result: pgtype.Timestamp{InfinityModifier: pgtype.NegativeInfinity, Status: pgtype.Present}},
126 {source: "2001-04-05 06:07:08", result: pgtype.Timestamp{Time: time.Date(2001, 4, 5, 6, 7, 8, 0, time.UTC), Status: pgtype.Present}},
127 {source: "0001-01-01 00:00:00.000000000 BC", result: pgtype.Timestamp{Time: time.Date(0000, 01, 01, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}},
128 }
129
130 for i, tt := range successfulTests {
131 var r pgtype.Timestamp
132 err := r.Set(tt.source)
133 if err != nil {
134 t.Errorf("%d: %v", i, err)
135 }
136
137 if r != tt.result {
138 t.Errorf("%d: expected %v to convert to %v, but it was %v", i, tt.source, tt.result, r)
139 }
140 }
141 }
142
143 func TestTimestampAssignTo(t *testing.T) {
144 var tim time.Time
145 var ptim *time.Time
146
147 simpleTests := []struct {
148 src pgtype.Timestamp
149 dst interface{}
150 expected interface{}
151 }{
152 {src: pgtype.Timestamp{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC), Status: pgtype.Present}, dst: &tim, expected: time.Date(2015, 1, 1, 0, 0, 0, 0, time.UTC)},
153 {src: pgtype.Timestamp{Time: time.Time{}, Status: pgtype.Null}, dst: &ptim, expected: ((*time.Time)(nil))},
154 }
155
156 for i, tt := range simpleTests {
157 err := tt.src.AssignTo(tt.dst)
158 if err != nil {
159 t.Errorf("%d: %v", i, err)
160 }
161
162 if dst := reflect.ValueOf(tt.dst).Elem().Interface(); dst != tt.expected {
163 t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
164 }
165 }
166
167 pointerAllocTests := []struct {
168 src pgtype.Timestamp
169 dst interface{}
170 expected interface{}
171 }{
172 {src: pgtype.Timestamp{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), Status: pgtype.Present}, dst: &ptim, expected: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local)},
173 }
174
175 for i, tt := range pointerAllocTests {
176 err := tt.src.AssignTo(tt.dst)
177 if err != nil {
178 t.Errorf("%d: %v", i, err)
179 }
180
181 if dst := reflect.ValueOf(tt.dst).Elem().Elem().Interface(); dst != tt.expected {
182 t.Errorf("%d: expected %v to assign %v, but result was %v", i, tt.src, tt.expected, dst)
183 }
184 }
185
186 errorTests := []struct {
187 src pgtype.Timestamp
188 dst interface{}
189 }{
190 {src: pgtype.Timestamp{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), InfinityModifier: pgtype.Infinity, Status: pgtype.Present}, dst: &tim},
191 {src: pgtype.Timestamp{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), InfinityModifier: pgtype.NegativeInfinity, Status: pgtype.Present}, dst: &tim},
192 {src: pgtype.Timestamp{Time: time.Date(2015, 1, 1, 0, 0, 0, 0, time.Local), Status: pgtype.Null}, dst: &tim},
193 }
194
195 for i, tt := range errorTests {
196 err := tt.src.AssignTo(tt.dst)
197 if err == nil {
198 t.Errorf("%d: expected error but none was returned (%v -> %v)", i, tt.src, tt.dst)
199 }
200 }
201 }
202
View as plain text