github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/internal/value/cast_test.go (about) 1 package value 2 3 import ( 4 "reflect" 5 "testing" 6 "time" 7 8 "github.com/stretchr/testify/require" 9 10 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xtest" 11 ) 12 13 func ptr[T any]() interface{} { 14 var zeroValue T 15 16 return &zeroValue 17 } 18 19 func value2ptr[T any](v T) *T { 20 return &v 21 } 22 23 func unwrapPtr(v interface{}) interface{} { 24 return reflect.ValueOf(v).Elem().Interface() 25 } 26 27 func loadLocation(T *testing.T, name string) *time.Location { 28 loc, err := time.LoadLocation(name) 29 require.NoError(T, err) 30 31 return loc 32 } 33 34 func TestCastTo(t *testing.T) { 35 testsCases := []struct { 36 name string 37 value Value 38 dst interface{} 39 exp interface{} 40 err error 41 }{ 42 { 43 name: xtest.CurrentFileLine(), 44 value: TextValue("test"), 45 dst: (interface{})(nil), 46 err: errNilDestination, 47 }, 48 49 { 50 name: xtest.CurrentFileLine(), 51 value: TextValue("test"), 52 dst: ptr[Value](), 53 exp: TextValue("test"), 54 err: nil, 55 }, 56 { 57 name: xtest.CurrentFileLine(), 58 value: OptionalValue(TextValue("test")), 59 dst: ptr[Value](), 60 exp: OptionalValue(TextValue("test")), 61 err: nil, 62 }, 63 { 64 name: xtest.CurrentFileLine(), 65 value: TextValue("test"), 66 dst: ptr[string](), 67 exp: "test", 68 err: nil, 69 }, 70 { 71 name: xtest.CurrentFileLine(), 72 value: OptionalValue(TextValue("test")), 73 dst: ptr[*string](), 74 exp: value2ptr("test"), 75 err: nil, 76 }, 77 { 78 name: xtest.CurrentFileLine(), 79 value: TextValue("test"), 80 dst: ptr[[]byte](), 81 exp: []byte("test"), 82 err: nil, 83 }, 84 { 85 name: xtest.CurrentFileLine(), 86 value: OptionalValue(TextValue("test")), 87 dst: ptr[*[]byte](), 88 exp: value2ptr([]byte("test")), 89 err: nil, 90 }, 91 { 92 name: xtest.CurrentFileLine(), 93 value: TextValue("test"), 94 dst: ptr[[]byte](), 95 exp: []byte("test"), 96 err: nil, 97 }, 98 { 99 name: xtest.CurrentFileLine(), 100 value: TextValue("test"), 101 dst: ptr[int](), 102 err: ErrCannotCast, 103 }, 104 105 { 106 name: xtest.CurrentFileLine(), 107 value: BytesValue([]byte("test")), 108 dst: ptr[Value](), 109 exp: BytesValue([]byte("test")), 110 err: nil, 111 }, 112 { 113 name: xtest.CurrentFileLine(), 114 value: BytesValue([]byte("test")), 115 dst: ptr[string](), 116 exp: "test", 117 err: nil, 118 }, 119 { 120 name: xtest.CurrentFileLine(), 121 value: BytesValue([]byte("test")), 122 dst: ptr[[]byte](), 123 exp: []byte("test"), 124 err: nil, 125 }, 126 { 127 name: xtest.CurrentFileLine(), 128 value: BytesValue([]byte("test")), 129 dst: ptr[[]byte](), 130 exp: []byte("test"), 131 err: nil, 132 }, 133 { 134 name: xtest.CurrentFileLine(), 135 value: BytesValue([]byte("test")), 136 dst: ptr[int](), 137 err: ErrCannotCast, 138 }, 139 140 { 141 name: xtest.CurrentFileLine(), 142 value: JSONDocumentValue(`{"test": "text"}"`), 143 dst: ptr[string](), 144 exp: `{"test": "text"}"`, 145 err: nil, 146 }, 147 { 148 name: xtest.CurrentFileLine(), 149 value: JSONDocumentValue(`{"test":"text"}"`), 150 dst: ptr[Value](), 151 exp: JSONDocumentValue(`{"test":"text"}"`), 152 err: nil, 153 }, 154 { 155 name: xtest.CurrentFileLine(), 156 value: OptionalValue(JSONDocumentValue(`{"test": "text"}"`)), 157 dst: ptr[*[]byte](), 158 exp: value2ptr([]byte(`{"test": "text"}"`)), 159 err: nil, 160 }, 161 { 162 name: xtest.CurrentFileLine(), 163 value: JSONDocumentValue(`{"test":"text"}"`), 164 dst: ptr[[]byte](), 165 exp: []byte(`{"test":"text"}"`), 166 err: nil, 167 }, 168 169 { 170 name: xtest.CurrentFileLine(), 171 value: BoolValue(true), 172 dst: ptr[bool](), 173 exp: true, 174 err: nil, 175 }, 176 { 177 name: xtest.CurrentFileLine(), 178 value: BoolValue(true), 179 dst: ptr[Value](), 180 exp: BoolValue(true), 181 err: nil, 182 }, 183 { 184 name: xtest.CurrentFileLine(), 185 value: OptionalValue(BoolValue(true)), 186 dst: ptr[*bool](), 187 exp: value2ptr(true), 188 err: nil, 189 }, 190 191 { 192 name: xtest.CurrentFileLine(), 193 value: Int32Value(123), 194 dst: ptr[int32](), 195 exp: int32(123), 196 err: nil, 197 }, 198 { 199 name: xtest.CurrentFileLine(), 200 value: Int32Value(123), 201 dst: ptr[Value](), 202 exp: Int32Value(123), 203 err: nil, 204 }, 205 { 206 name: xtest.CurrentFileLine(), 207 value: Int32Value(123), 208 dst: ptr[int64](), 209 exp: int64(123), 210 err: nil, 211 }, 212 { 213 name: xtest.CurrentFileLine(), 214 value: Int32Value(123), 215 dst: ptr[float32](), 216 exp: float32(123), 217 err: nil, 218 }, 219 { 220 name: xtest.CurrentFileLine(), 221 value: Int32Value(123), 222 dst: ptr[float64](), 223 exp: float64(123), 224 err: nil, 225 }, 226 { 227 name: xtest.CurrentFileLine(), 228 value: OptionalValue(Int32Value(123)), 229 dst: ptr[*int32](), 230 exp: value2ptr(int32(123)), 231 err: nil, 232 }, 233 { 234 name: xtest.CurrentFileLine(), 235 value: Int32Value(123), 236 dst: ptr[string](), 237 exp: "123", 238 err: nil, 239 }, 240 { 241 name: xtest.CurrentFileLine(), 242 value: Int32Value(123), 243 dst: ptr[[]byte](), 244 exp: []byte("123"), 245 err: nil, 246 }, 247 248 { 249 name: xtest.CurrentFileLine(), 250 value: Int64Value(123), 251 dst: ptr[int64](), 252 exp: int64(123), 253 err: nil, 254 }, 255 { 256 name: xtest.CurrentFileLine(), 257 value: Int64Value(123), 258 dst: ptr[Value](), 259 exp: Int64Value(123), 260 err: nil, 261 }, 262 { 263 name: xtest.CurrentFileLine(), 264 value: OptionalValue(Int64Value(123)), 265 dst: ptr[*int64](), 266 exp: value2ptr(int64(123)), 267 err: nil, 268 }, 269 { 270 name: xtest.CurrentFileLine(), 271 value: Int64Value(123), 272 dst: ptr[float64](), 273 exp: float64(123), 274 err: nil, 275 }, 276 { 277 name: xtest.CurrentFileLine(), 278 value: Int64Value(123), 279 dst: ptr[string](), 280 exp: "123", 281 err: nil, 282 }, 283 { 284 name: xtest.CurrentFileLine(), 285 value: Int64Value(123), 286 dst: ptr[[]byte](), 287 exp: []byte("123"), 288 err: nil, 289 }, 290 291 { 292 name: xtest.CurrentFileLine(), 293 value: DoubleValue(1.23), 294 dst: ptr[float64](), 295 exp: 1.23, 296 err: nil, 297 }, 298 { 299 name: xtest.CurrentFileLine(), 300 value: DoubleValue(1.23), 301 dst: ptr[Value](), 302 exp: DoubleValue(1.23), 303 err: nil, 304 }, 305 { 306 name: xtest.CurrentFileLine(), 307 value: OptionalValue(DoubleValue(1.23)), 308 dst: ptr[*float64](), 309 exp: value2ptr(1.23), 310 err: nil, 311 }, 312 313 { 314 name: xtest.CurrentFileLine(), 315 value: IntervalValueFromDuration(time.Second), 316 dst: ptr[time.Duration](), 317 exp: time.Second, 318 err: nil, 319 }, 320 { 321 name: xtest.CurrentFileLine(), 322 value: IntervalValueFromDuration(time.Second), 323 dst: ptr[Value](), 324 exp: IntervalValueFromDuration(time.Second), 325 err: nil, 326 }, 327 328 // nanoseconds are ignored in YDB timestamps 329 { 330 name: xtest.CurrentFileLine(), 331 value: TimestampValueFromTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.Local)), 332 dst: ptr[time.Time](), 333 exp: time.Date(2024, 1, 2, 3, 4, 5, 0, time.Local), 334 err: nil, 335 }, 336 { 337 name: xtest.CurrentFileLine(), 338 value: TimestampValueFromTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.Local)), 339 dst: ptr[Value](), 340 exp: TimestampValueFromTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.Local)), 341 err: nil, 342 }, 343 { 344 name: xtest.CurrentFileLine(), 345 value: TimestampValue(uint64(time.Date(2024, 1, 2, 3, 4, 5, 0, time.Local).Unix())), 346 dst: ptr[uint64](), 347 exp: uint64(time.Date(2024, 1, 2, 3, 4, 5, 0, time.Local).Unix()), 348 err: nil, 349 }, 350 351 // nanoseconds are ignored in YDB timestamps 352 { 353 name: xtest.CurrentFileLine(), 354 value: TzTimestampValue("2024-01-02T03:04:05.000000,Europe/Moscow"), 355 dst: ptr[time.Time](), 356 exp: time.Date(2024, 1, 2, 3, 4, 5, 0, loadLocation(t, "Europe/Moscow")), 357 err: nil, 358 }, 359 { 360 name: xtest.CurrentFileLine(), 361 value: TzTimestampValueFromTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC)), 362 dst: ptr[string](), 363 exp: "2024-01-02T03:04:05.000000Z", 364 err: nil, 365 }, 366 { 367 name: xtest.CurrentFileLine(), 368 value: TzTimestampValueFromTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC)), 369 dst: ptr[[]byte](), 370 exp: []byte("2024-01-02T03:04:05.000000Z"), 371 err: nil, 372 }, 373 { 374 name: xtest.CurrentFileLine(), 375 value: TzTimestampValueFromTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC)), 376 dst: ptr[Value](), 377 exp: TzTimestampValueFromTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC)), 378 err: nil, 379 }, 380 381 { 382 name: xtest.CurrentFileLine(), 383 value: DateValue(uint32(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC).Unix())), 384 dst: ptr[int32](), 385 exp: int32(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC).Unix()), 386 err: nil, 387 }, 388 { 389 name: xtest.CurrentFileLine(), 390 value: DateValueFromTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC)), 391 dst: ptr[uint64](), 392 exp: uint64(DateValueFromTime(time.Date(2024, 1, 2, 3, 4, 5, 0, time.UTC))), 393 err: nil, 394 }, 395 { 396 name: xtest.CurrentFileLine(), 397 value: DateValueFromTime(time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)), 398 dst: ptr[int64](), 399 exp: int64(DateValueFromTime(time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC))), 400 err: nil, 401 }, 402 { 403 name: xtest.CurrentFileLine(), 404 value: DateValueFromTime(time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)), 405 dst: ptr[time.Time](), 406 exp: time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC), 407 err: nil, 408 }, 409 { 410 name: xtest.CurrentFileLine(), 411 value: DateValueFromTime(time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)), 412 dst: ptr[Value](), 413 exp: DateValueFromTime(time.Date(2024, 1, 2, 0, 0, 0, 0, time.UTC)), 414 err: nil, 415 }, 416 } 417 for _, tt := range testsCases { 418 t.Run(tt.name, func(t *testing.T) { 419 if tt.err == nil { 420 require.NoError(t, CastTo(tt.value, tt.dst)) 421 require.Equal(t, tt.exp, unwrapPtr(tt.dst)) 422 } else { 423 require.ErrorIs(t, CastTo(tt.value, tt.dst), tt.err) 424 } 425 }) 426 } 427 }