decode_sqlnull_test.go (8868B)
1 package gojay 2 3 import ( 4 "database/sql" 5 "strings" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 ) 11 12 func TestDecodeSQLNullString(t *testing.T) { 13 testCases := []struct { 14 name string 15 json string 16 expectedNullString sql.NullString 17 err bool 18 }{ 19 { 20 name: "basic", 21 json: `"test"`, 22 expectedNullString: sql.NullString{String: "test", Valid: true}, 23 }, 24 { 25 name: "basic", 26 json: `"test`, 27 expectedNullString: sql.NullString{String: "test", Valid: true}, 28 err: true, 29 }, 30 } 31 for _, testCase := range testCases { 32 t.Run(testCase.name, func(t *testing.T) { 33 nullString := sql.NullString{} 34 dec := NewDecoder(strings.NewReader(testCase.json)) 35 err := dec.DecodeSQLNullString(&nullString) 36 if testCase.err { 37 assert.NotNil(t, err) 38 } else { 39 assert.Nil(t, err) 40 assert.Equal(t, testCase.expectedNullString, nullString) 41 } 42 }) 43 } 44 t.Run( 45 "should panic because decoder is pooled", 46 func(t *testing.T) { 47 dec := NewDecoder(nil) 48 dec.Release() 49 defer func() { 50 err := recover() 51 assert.NotNil(t, err, "err shouldnt be nil") 52 assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError") 53 }() 54 _ = dec.DecodeSQLNullString(&sql.NullString{}) 55 assert.True(t, false, "should not be called as decoder should have panicked") 56 }, 57 ) 58 } 59 60 func TestDecodeSQLNullInt64(t *testing.T) { 61 testCases := []struct { 62 name string 63 json string 64 expectedNullInt64 sql.NullInt64 65 err bool 66 }{ 67 { 68 name: "basic", 69 json: `1`, 70 expectedNullInt64: sql.NullInt64{Int64: 1, Valid: true}, 71 }, 72 { 73 name: "basic", 74 json: `"test`, 75 expectedNullInt64: sql.NullInt64{Int64: 1, Valid: true}, 76 err: true, 77 }, 78 } 79 for _, testCase := range testCases { 80 t.Run(testCase.name, func(t *testing.T) { 81 nullInt64 := sql.NullInt64{} 82 dec := NewDecoder(strings.NewReader(testCase.json)) 83 err := dec.DecodeSQLNullInt64(&nullInt64) 84 if testCase.err { 85 assert.NotNil(t, err) 86 } else { 87 assert.Nil(t, err) 88 assert.Equal(t, testCase.expectedNullInt64, nullInt64) 89 } 90 }) 91 } 92 t.Run( 93 "should panic because decoder is pooled", 94 func(t *testing.T) { 95 dec := NewDecoder(nil) 96 dec.Release() 97 defer func() { 98 err := recover() 99 assert.NotNil(t, err, "err shouldnt be nil") 100 assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError") 101 }() 102 _ = dec.DecodeSQLNullInt64(&sql.NullInt64{}) 103 assert.True(t, false, "should not be called as decoder should have panicked") 104 }, 105 ) 106 } 107 108 func TestDecodeSQLNullFloat64(t *testing.T) { 109 testCases := []struct { 110 name string 111 json string 112 expectedNullFloat64 sql.NullFloat64 113 err bool 114 }{ 115 { 116 name: "basic", 117 json: `1`, 118 expectedNullFloat64: sql.NullFloat64{Float64: 1, Valid: true}, 119 }, 120 { 121 name: "basic", 122 json: `"test`, 123 expectedNullFloat64: sql.NullFloat64{Float64: 1, Valid: true}, 124 err: true, 125 }, 126 } 127 for _, testCase := range testCases { 128 t.Run(testCase.name, func(t *testing.T) { 129 nullFloat64 := sql.NullFloat64{} 130 dec := NewDecoder(strings.NewReader(testCase.json)) 131 err := dec.DecodeSQLNullFloat64(&nullFloat64) 132 if testCase.err { 133 assert.NotNil(t, err) 134 } else { 135 assert.Nil(t, err) 136 assert.Equal(t, testCase.expectedNullFloat64, nullFloat64) 137 } 138 }) 139 } 140 t.Run( 141 "should panic because decoder is pooled", 142 func(t *testing.T) { 143 dec := NewDecoder(nil) 144 dec.Release() 145 defer func() { 146 err := recover() 147 assert.NotNil(t, err, "err shouldnt be nil") 148 assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError") 149 }() 150 _ = dec.DecodeSQLNullFloat64(&sql.NullFloat64{}) 151 assert.True(t, false, "should not be called as decoder should have panicked") 152 }, 153 ) 154 } 155 156 func TestDecodeSQLNullBool(t *testing.T) { 157 testCases := []struct { 158 name string 159 json string 160 expectedNullBool sql.NullBool 161 err bool 162 }{ 163 { 164 name: "basic", 165 json: `true`, 166 expectedNullBool: sql.NullBool{Bool: true, Valid: true}, 167 }, 168 { 169 name: "basic", 170 json: `"&`, 171 expectedNullBool: sql.NullBool{Bool: true, Valid: true}, 172 err: true, 173 }, 174 } 175 for _, testCase := range testCases { 176 t.Run(testCase.name, func(t *testing.T) { 177 nullBool := sql.NullBool{} 178 dec := NewDecoder(strings.NewReader(testCase.json)) 179 err := dec.DecodeSQLNullBool(&nullBool) 180 if testCase.err { 181 assert.NotNil(t, err) 182 } else { 183 assert.Nil(t, err) 184 assert.Equal(t, testCase.expectedNullBool, nullBool) 185 } 186 }) 187 } 188 t.Run( 189 "should panic because decoder is pooled", 190 func(t *testing.T) { 191 dec := NewDecoder(nil) 192 dec.Release() 193 defer func() { 194 err := recover() 195 assert.NotNil(t, err, "err shouldnt be nil") 196 assert.IsType(t, InvalidUsagePooledDecoderError(""), err, "err should be of type InvalidUsagePooledDecoderError") 197 }() 198 _ = dec.DecodeSQLNullBool(&sql.NullBool{}) 199 assert.True(t, false, "should not be called as decoder should have panicked") 200 }, 201 ) 202 } 203 204 type SQLDecodeObject struct { 205 S sql.NullString 206 F sql.NullFloat64 207 I sql.NullInt64 208 B sql.NullBool 209 } 210 211 func (s *SQLDecodeObject) UnmarshalJSONObject(dec *Decoder, k string) error { 212 switch k { 213 case "s": 214 return dec.AddSQLNullString(&s.S) 215 case "f": 216 return dec.AddSQLNullFloat64(&s.F) 217 case "i": 218 return dec.AddSQLNullInt64(&s.I) 219 case "b": 220 return dec.AddSQLNullBool(&s.B) 221 } 222 return nil 223 } 224 225 func (s *SQLDecodeObject) NKeys() int { 226 return 0 227 } 228 229 func TestDecodeSQLNullKeys(t *testing.T) { 230 var testCases = []struct { 231 name string 232 json string 233 expectedResult *SQLDecodeObject 234 err bool 235 }{ 236 { 237 name: "basic all valid", 238 json: `{ 239 "s": "foo", 240 "f": 0.3, 241 "i": 3, 242 "b": true 243 }`, 244 expectedResult: &SQLDecodeObject{ 245 S: sql.NullString{ 246 String: "foo", 247 Valid: true, 248 }, 249 F: sql.NullFloat64{ 250 Float64: 0.3, 251 Valid: true, 252 }, 253 I: sql.NullInt64{ 254 Int64: 3, 255 Valid: true, 256 }, 257 B: sql.NullBool{ 258 Bool: true, 259 Valid: true, 260 }, 261 }, 262 }, 263 { 264 name: "string not valid", 265 json: `{ 266 "s": null, 267 "f": 0.3, 268 "i": 3, 269 "b": true 270 }`, 271 expectedResult: &SQLDecodeObject{ 272 S: sql.NullString{ 273 Valid: false, 274 }, 275 F: sql.NullFloat64{ 276 Float64: 0.3, 277 Valid: true, 278 }, 279 I: sql.NullInt64{ 280 Int64: 3, 281 Valid: true, 282 }, 283 B: sql.NullBool{ 284 Bool: true, 285 Valid: true, 286 }, 287 }, 288 }, 289 { 290 name: "string not valid, int not valid", 291 json: `{ 292 "s": null, 293 "f": 0.3, 294 "i": null, 295 "b": true 296 }`, 297 expectedResult: &SQLDecodeObject{ 298 S: sql.NullString{ 299 Valid: false, 300 }, 301 F: sql.NullFloat64{ 302 Float64: 0.3, 303 Valid: true, 304 }, 305 I: sql.NullInt64{ 306 Valid: false, 307 }, 308 B: sql.NullBool{ 309 Bool: true, 310 Valid: true, 311 }, 312 }, 313 }, 314 { 315 name: "keys absent", 316 json: `{ 317 "f": 0.3, 318 "i": 3, 319 "b": true 320 }`, 321 expectedResult: &SQLDecodeObject{ 322 S: sql.NullString{ 323 Valid: false, 324 }, 325 F: sql.NullFloat64{ 326 Float64: 0.3, 327 Valid: true, 328 }, 329 I: sql.NullInt64{ 330 Valid: true, 331 Int64: 3, 332 }, 333 B: sql.NullBool{ 334 Bool: true, 335 Valid: true, 336 }, 337 }, 338 }, 339 { 340 name: "keys all null", 341 json: `{ 342 "s": null, 343 "f": null, 344 "i": null, 345 "b": null 346 }`, 347 expectedResult: &SQLDecodeObject{ 348 S: sql.NullString{ 349 Valid: false, 350 }, 351 F: sql.NullFloat64{ 352 Valid: false, 353 }, 354 I: sql.NullInt64{ 355 Valid: false, 356 }, 357 B: sql.NullBool{ 358 Valid: false, 359 }, 360 }, 361 }, 362 { 363 name: "err string key", 364 json: `{ 365 "s": "`, 366 err: true, 367 }, 368 { 369 name: "err float key", 370 json: `{ 371 "s": null, 372 "f": 1", 373 "i": null, 374 "b": null 375 }`, 376 err: true, 377 }, 378 { 379 name: "err int key", 380 json: `{ 381 "s": null, 382 "f": null, 383 "i": 1", 384 "b": null 385 }`, 386 err: true, 387 }, 388 { 389 name: "err bool key", 390 json: `{ 391 "s": null, 392 "f": null, 393 "i": null, 394 "b": tra 395 }`, 396 err: true, 397 }, 398 } 399 400 for _, testCase := range testCases { 401 t.Run(testCase.name, func(t *testing.T) { 402 var o = &SQLDecodeObject{} 403 var dec = NewDecoder(strings.NewReader(testCase.json)) 404 var err = dec.Decode(o) 405 406 if testCase.err { 407 require.NotNil(t, err) 408 return 409 } 410 411 require.Nil(t, err) 412 require.Equal( 413 t, 414 testCase.expectedResult, 415 o, 416 ) 417 }) 418 } 419 420 }