github.com/weaviate/weaviate@v1.24.6/usecases/objects/validation/properties_validation_test.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package validation 13 14 import ( 15 "context" 16 "encoding/json" 17 "fmt" 18 "reflect" 19 "testing" 20 "time" 21 22 "github.com/go-openapi/strfmt" 23 "github.com/google/uuid" 24 "github.com/stretchr/testify/assert" 25 "github.com/stretchr/testify/require" 26 "github.com/weaviate/weaviate/entities/additional" 27 "github.com/weaviate/weaviate/entities/models" 28 "github.com/weaviate/weaviate/entities/schema" 29 "github.com/weaviate/weaviate/usecases/config" 30 ) 31 32 func TestValidator_extractAndValidateProperty(t *testing.T) { 33 type fields struct { 34 schema schema.Schema 35 exists exists 36 config *config.WeaviateConfig 37 } 38 type args struct { 39 ctx context.Context 40 propertyName string 41 pv interface{} 42 className string 43 dataType *schema.DataType 44 } 45 validatorFields := fields{ 46 schema: schema.Schema{ 47 Objects: &models.Schema{ 48 Classes: []*models.Class{ 49 { 50 Class: "BlobClass", 51 Properties: []*models.Property{ 52 { 53 DataType: []string{"blob"}, 54 Name: "blobProperty", 55 }, 56 }, 57 }, 58 }, 59 }, 60 }, 61 } 62 tests := []struct { 63 name string 64 fields fields 65 args args 66 want interface{} 67 wantErr bool 68 }{ 69 { 70 name: "Validate blob - empty base64 encoded image string", 71 fields: validatorFields, 72 args: args{ 73 ctx: context.Background(), 74 propertyName: "blobProperty", 75 pv: "", 76 className: "BlobClass", 77 dataType: getDataType(schema.DataTypeBlob), 78 }, 79 want: nil, 80 wantErr: true, 81 }, 82 { 83 name: "Validate blob - invalid base64 encoded image string", 84 fields: validatorFields, 85 args: args{ 86 ctx: context.Background(), 87 propertyName: "blobProperty", 88 pv: "image", 89 className: "BlobClass", 90 dataType: getDataType(schema.DataTypeBlob), 91 }, 92 want: nil, 93 wantErr: true, 94 }, 95 { 96 name: "Validate blob - valid base64 encoded string but with type definition before image string", 97 fields: validatorFields, 98 args: args{ 99 ctx: context.Background(), 100 propertyName: "blobProperty", 101 pv: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAA/CAYAAAAfQM0aAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCRjQ5NEM3RDI5QTkxMUUyOTc1NENCMzI4N0QwNDNCOSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCRjQ5NEM3RTI5QTkxMUUyOTc1NENCMzI4N0QwNDNCOSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkJGNDk0QzdCMjlBOTExRTI5NzU0Q0IzMjg3RDA0M0I5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkJGNDk0QzdDMjlBOTExRTI5NzU0Q0IzMjg3RDA0M0I5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+WeGRxAAAB2hJREFUeNrUXFts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", 102 className: "BlobClass", 103 dataType: getDataType(schema.DataTypeBlob), 104 }, 105 want: nil, 106 wantErr: true, 107 }, 108 { 109 name: "Validate blob - valid base64 encoded string", 110 fields: validatorFields, 111 args: args{ 112 ctx: context.Background(), 113 propertyName: "blobProperty", 114 pv: "iVBORw0KGgoAAAANSUhEUgAAAGAAAAA/CAYAAAAfQM0aAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCRjQ5NEM3RDI5QTkxMUUyOTc1NENCMzI4N0QwNDNCOSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCRjQ5NEM3RTI5QTkxMUUyOTc1NENCMzI4N0QwNDNCOSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkJGNDk0QzdCMjlBOTExRTI5NzU0Q0IzMjg3RDA0M0I5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkJGNDk0QzdDMjlBOTExRTI5NzU0Q0IzMjg3RDA0M0I5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+WeGRxAAAB2hJREFUeNrUXFts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", 115 className: "BlobClass", 116 dataType: getDataType(schema.DataTypeBlob), 117 }, 118 want: "iVBORw0KGgoAAAANSUhEUgAAAGAAAAA/CAYAAAAfQM0aAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpCRjQ5NEM3RDI5QTkxMUUyOTc1NENCMzI4N0QwNDNCOSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpCRjQ5NEM3RTI5QTkxMUUyOTc1NENCMzI4N0QwNDNCOSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkJGNDk0QzdCMjlBOTExRTI5NzU0Q0IzMjg3RDA0M0I5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkJGNDk0QzdDMjlBOTExRTI5NzU0Q0IzMjg3RDA0M0I5Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+WeGRxAAAB2hJREFUeNrUXFts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", 119 wantErr: false, 120 }, 121 { 122 name: "Validate blob - nil entry", 123 fields: validatorFields, 124 args: args{ 125 ctx: context.Background(), 126 propertyName: "blobProperty", 127 pv: nil, 128 className: "BlobClass", 129 dataType: getDataType(schema.DataTypeBlob), 130 }, 131 want: nil, 132 wantErr: true, 133 }, 134 } 135 for _, tt := range tests { 136 t.Run(tt.name, func(t *testing.T) { 137 v := &Validator{ 138 exists: tt.fields.exists, 139 config: tt.fields.config, 140 } 141 got, err := v.extractAndValidateProperty(tt.args.ctx, tt.args.propertyName, tt.args.pv, tt.args.className, tt.args.dataType, "") 142 if (err != nil) != tt.wantErr { 143 t.Errorf("Validator.extractAndValidateProperty() error = %v, wantErr %v", err, tt.wantErr) 144 return 145 } 146 if !reflect.DeepEqual(got, tt.want) { 147 t.Errorf("Validator.extractAndValidateProperty() = %v, want %v", got, tt.want) 148 } 149 }) 150 } 151 } 152 153 func getDataType(dataType schema.DataType) *schema.DataType { 154 return &dataType 155 } 156 157 func TestProperties(t *testing.T) { 158 const myBeacon = "weaviate://localhost/things/8e555f0d-8590-48c2-a9a6-70772ed14c0a" 159 myJournalClass := &models.Class{ 160 Properties: []*models.Property{{Name: "inJournal", DataType: []string{"Journal"}}}, 161 } 162 specs := map[string]struct { 163 class *models.Class 164 obj *models.Object 165 expErr bool 166 expBeacon strfmt.URI 167 }{ 168 "incorrect cref body - example from issue #1253": { 169 class: myJournalClass, 170 obj: &models.Object{ 171 Properties: map[string]any{"inJournal": []any{map[string]any{ 172 "beacon": map[string]any{"beacon": myBeacon}, 173 }}}, 174 }, 175 expErr: true, 176 }, 177 "complete beacon": { 178 class: myJournalClass, 179 obj: &models.Object{ 180 Properties: map[string]any{"inJournal": []any{map[string]any{ 181 "beacon": myBeacon, 182 }}}, 183 }, 184 expBeacon: myBeacon, 185 }, 186 "beacon without class": { 187 class: myJournalClass, 188 obj: &models.Object{ 189 Properties: map[string]any{"inJournal": []any{map[string]any{ 190 "beacon": "weaviate://foo/8e555f0d-8590-48c2-a9a6-70772ed14c0a", 191 }}}, 192 }, 193 expBeacon: "weaviate://localhost/Journal/8e555f0d-8590-48c2-a9a6-70772ed14c0a", 194 }, 195 } 196 for name, spec := range specs { 197 t.Run(name, func(t *testing.T) { 198 validator := &Validator{exists: func(_ context.Context, class string, _ strfmt.UUID, _ *additional.ReplicationProperties, _ string) (bool, error) { 199 return true, nil 200 }} 201 gotErr := validator.properties(context.Background(), spec.class, spec.obj, nil) 202 if spec.expErr { 203 require.Error(t, gotErr) 204 return 205 } 206 require.NoError(t, gotErr) 207 props := spec.obj.Properties 208 gotBeacon := extractBeacon(t, props) 209 assert.Equal(t, spec.expBeacon, gotBeacon) 210 }) 211 } 212 } 213 214 func extractBeacon(t *testing.T, props models.PropertySchema) strfmt.URI { 215 require.IsType(t, map[string]any{}, props) 216 require.Contains(t, props.(map[string]any), "inJournal") 217 journalProp := props.(map[string]any)["inJournal"] 218 require.IsType(t, models.MultipleRef{}, journalProp) 219 require.Len(t, journalProp.(models.MultipleRef), 1) 220 gotBeacon := journalProp.(models.MultipleRef)[0].Beacon 221 return gotBeacon 222 } 223 224 func TestValidator_ValuesCasting(t *testing.T) { 225 t.Run("int(s)", func(t *testing.T) { 226 type testCase struct { 227 value interface{} 228 expectedValue float64 229 expectedErr bool 230 } 231 232 testCases := []testCase{ 233 { 234 value: json.Number("123"), 235 expectedValue: float64(123), 236 expectedErr: false, 237 }, 238 { 239 value: int64(123), 240 expectedValue: float64(123), 241 expectedErr: false, 242 }, 243 { 244 value: float64(123), 245 expectedValue: float64(123), 246 expectedErr: false, 247 }, 248 249 { 250 value: json.Number("123.5"), 251 expectedValue: float64(0), 252 expectedErr: true, 253 }, 254 { 255 value: float64(123.5), 256 expectedValue: float64(0), 257 expectedErr: true, 258 }, 259 { 260 value: "123.5", 261 expectedValue: float64(0), 262 expectedErr: true, 263 }, 264 { 265 value: "something", 266 expectedValue: float64(0), 267 expectedErr: true, 268 }, 269 { 270 value: true, 271 expectedValue: float64(0), 272 expectedErr: true, 273 }, 274 } 275 276 for i, tc := range testCases { 277 t.Run(fmt.Sprintf("int #%d", i), func(t *testing.T) { 278 value, err := intVal(tc.value) 279 280 if tc.expectedErr { 281 assert.Error(t, err) 282 } else { 283 assert.NoError(t, err) 284 } 285 assert.Equal(t, tc.expectedValue, value) 286 }) 287 } 288 for i, tc := range testCases { 289 t.Run(fmt.Sprintf("ints (single) #%d", i), func(t *testing.T) { 290 value, err := intArrayVal(tc.value) 291 292 assert.Error(t, err) 293 assert.Nil(t, value) 294 }) 295 t.Run(fmt.Sprintf("ints (array) #%d", i), func(t *testing.T) { 296 value, err := intArrayVal([]interface{}{tc.value}) 297 298 if tc.expectedErr { 299 assert.Error(t, err) 300 assert.Nil(t, value) 301 } else { 302 assert.NoError(t, err) 303 assert.Equal(t, []float64{tc.expectedValue}, value) 304 } 305 }) 306 } 307 }) 308 309 t.Run("number(s)", func(t *testing.T) { 310 type testCase struct { 311 value interface{} 312 expectedValue float64 313 expectedErr bool 314 } 315 316 testCases := []testCase{ 317 { 318 value: json.Number("123"), 319 expectedValue: float64(123), 320 expectedErr: false, 321 }, 322 { 323 value: int64(123), 324 expectedValue: float64(123), 325 expectedErr: false, 326 }, 327 { 328 value: float64(123), 329 expectedValue: float64(123), 330 expectedErr: false, 331 }, 332 { 333 value: json.Number("123.5"), 334 expectedValue: float64(123.5), 335 expectedErr: false, 336 }, 337 { 338 value: float64(123.5), 339 expectedValue: float64(123.5), 340 expectedErr: false, 341 }, 342 343 { 344 value: "123.5", 345 expectedValue: float64(0), 346 expectedErr: true, 347 }, 348 { 349 value: "something", 350 expectedValue: float64(0), 351 expectedErr: true, 352 }, 353 { 354 value: true, 355 expectedValue: float64(0), 356 expectedErr: true, 357 }, 358 } 359 360 for i, tc := range testCases { 361 t.Run(fmt.Sprintf("number #%d", i), func(t *testing.T) { 362 value, err := numberVal(tc.value) 363 364 if tc.expectedErr { 365 assert.Error(t, err) 366 } else { 367 assert.NoError(t, err) 368 } 369 assert.Equal(t, tc.expectedValue, value) 370 }) 371 } 372 for i, tc := range testCases { 373 t.Run(fmt.Sprintf("numbers (single) #%d", i), func(t *testing.T) { 374 value, err := numberArrayVal(tc.value) 375 376 assert.Error(t, err) 377 assert.Nil(t, value) 378 }) 379 t.Run(fmt.Sprintf("numbers (array) #%d", i), func(t *testing.T) { 380 value, err := numberArrayVal([]interface{}{tc.value}) 381 382 if tc.expectedErr { 383 assert.Error(t, err) 384 assert.Nil(t, value) 385 } else { 386 assert.NoError(t, err) 387 assert.Equal(t, []float64{tc.expectedValue}, value) 388 } 389 }) 390 } 391 }) 392 393 t.Run("string(s)", func(t *testing.T) { 394 type testCase struct { 395 value interface{} 396 expectedValue string 397 expectedErr bool 398 } 399 400 testCases := []testCase{ 401 { 402 value: "123.5", 403 expectedValue: "123.5", 404 expectedErr: false, 405 }, 406 { 407 value: "something", 408 expectedValue: "something", 409 expectedErr: false, 410 }, 411 412 { 413 value: json.Number("123"), 414 expectedValue: "", 415 expectedErr: true, 416 }, 417 { 418 value: int64(123), 419 expectedValue: "", 420 expectedErr: true, 421 }, 422 { 423 value: float64(123), 424 expectedValue: "", 425 expectedErr: true, 426 }, 427 { 428 value: []byte("something"), 429 expectedValue: "", 430 expectedErr: true, 431 }, 432 { 433 value: true, 434 expectedValue: "", 435 expectedErr: true, 436 }, 437 } 438 439 for i, tc := range testCases { 440 t.Run(fmt.Sprintf("string #%d", i), func(t *testing.T) { 441 value, err := stringVal(tc.value) 442 443 if tc.expectedErr { 444 assert.Error(t, err) 445 } else { 446 assert.NoError(t, err) 447 } 448 assert.Equal(t, tc.expectedValue, value) 449 }) 450 } 451 for i, tc := range testCases { 452 t.Run(fmt.Sprintf("strings (single) #%d", i), func(t *testing.T) { 453 value, err := stringArrayVal(tc.value, "text") 454 455 assert.Error(t, err) 456 assert.Nil(t, value) 457 }) 458 t.Run(fmt.Sprintf("strings (array) #%d", i), func(t *testing.T) { 459 value, err := stringArrayVal([]interface{}{tc.value}, "text") 460 461 if tc.expectedErr { 462 assert.Error(t, err) 463 assert.Nil(t, value) 464 } else { 465 assert.NoError(t, err) 466 assert.Equal(t, []string{tc.expectedValue}, value) 467 } 468 }) 469 } 470 }) 471 472 t.Run("bool(s)", func(t *testing.T) { 473 type testCase struct { 474 value interface{} 475 expectedValue bool 476 expectedErr bool 477 } 478 479 testCases := []testCase{ 480 { 481 value: true, 482 expectedValue: true, 483 expectedErr: false, 484 }, 485 { 486 value: false, 487 expectedValue: false, 488 expectedErr: false, 489 }, 490 491 { 492 value: float64(1), 493 expectedValue: false, 494 expectedErr: true, 495 }, 496 { 497 value: int64(1), 498 expectedValue: false, 499 expectedErr: true, 500 }, 501 { 502 value: "1", 503 expectedValue: false, 504 expectedErr: true, 505 }, 506 { 507 value: "true", 508 expectedValue: false, 509 expectedErr: true, 510 }, 511 { 512 value: "something", 513 expectedValue: false, 514 expectedErr: true, 515 }, 516 } 517 518 for i, tc := range testCases { 519 t.Run(fmt.Sprintf("bool #%d", i), func(t *testing.T) { 520 value, err := boolVal(tc.value) 521 522 if tc.expectedErr { 523 assert.Error(t, err) 524 } else { 525 assert.NoError(t, err) 526 } 527 assert.Equal(t, tc.expectedValue, value) 528 }) 529 } 530 for i, tc := range testCases { 531 t.Run(fmt.Sprintf("bools (single) #%d", i), func(t *testing.T) { 532 value, err := boolArrayVal(tc.value) 533 534 assert.Error(t, err) 535 assert.Nil(t, value) 536 }) 537 t.Run(fmt.Sprintf("bools (array) #%d", i), func(t *testing.T) { 538 value, err := boolArrayVal([]interface{}{tc.value}) 539 540 if tc.expectedErr { 541 assert.Error(t, err) 542 assert.Nil(t, value) 543 } else { 544 assert.NoError(t, err) 545 assert.Equal(t, []bool{tc.expectedValue}, value) 546 } 547 }) 548 } 549 }) 550 551 t.Run("uuid(s)", func(t *testing.T) { 552 type testCase struct { 553 value interface{} 554 expectedValue uuid.UUID 555 expectedErr bool 556 } 557 558 testCases := []testCase{ 559 { 560 value: "e780b0a4-8d0e-4c09-898e-19d6b81e1e63", 561 expectedValue: uuid.MustParse("e780b0a4-8d0e-4c09-898e-19d6b81e1e63"), 562 expectedErr: false, 563 }, 564 { 565 value: "e780b0a48d0e4c09898e19d6b81e1e63", 566 expectedValue: uuid.MustParse("e780b0a4-8d0e-4c09-898e-19d6b81e1e63"), 567 expectedErr: false, 568 }, 569 570 { 571 value: float64(123), 572 expectedValue: [16]byte{}, 573 expectedErr: true, 574 }, 575 { 576 value: int64(123), 577 expectedValue: [16]byte{}, 578 expectedErr: true, 579 }, 580 { 581 value: "123", 582 expectedValue: [16]byte{}, 583 expectedErr: true, 584 }, 585 { 586 value: "something", 587 expectedValue: [16]byte{}, 588 expectedErr: true, 589 }, 590 { 591 value: true, 592 expectedValue: [16]byte{}, 593 expectedErr: true, 594 }, 595 } 596 597 for i, tc := range testCases { 598 t.Run(fmt.Sprintf("uuid #%d", i), func(t *testing.T) { 599 value, err := uuidVal(tc.value) 600 601 if tc.expectedErr { 602 assert.Error(t, err) 603 } else { 604 assert.NoError(t, err) 605 } 606 assert.Equal(t, tc.expectedValue, value) 607 }) 608 } 609 for i, tc := range testCases { 610 t.Run(fmt.Sprintf("uuids (single) #%d", i), func(t *testing.T) { 611 value, err := uuidArrayVal(tc.value) 612 613 assert.Error(t, err) 614 assert.Nil(t, value) 615 }) 616 t.Run(fmt.Sprintf("uuids (array) #%d", i), func(t *testing.T) { 617 value, err := uuidArrayVal([]interface{}{tc.value}) 618 619 if tc.expectedErr { 620 assert.Error(t, err) 621 assert.Nil(t, value) 622 } else { 623 assert.NoError(t, err) 624 assert.Equal(t, []uuid.UUID{tc.expectedValue}, value) 625 } 626 }) 627 } 628 }) 629 630 t.Run("date(s)", func(t *testing.T) { 631 type testCase struct { 632 value interface{} 633 expectedValue time.Time 634 expectedErr bool 635 } 636 637 testCases := []testCase{ 638 { 639 value: "2024-01-02T03:04:05.00Z", 640 expectedValue: time.Unix(1704164645, 0).UTC(), 641 expectedErr: false, 642 }, 643 644 { 645 value: float64(123), 646 expectedValue: time.Time{}, 647 expectedErr: true, 648 }, 649 { 650 value: int64(123), 651 expectedValue: time.Time{}, 652 expectedErr: true, 653 }, 654 { 655 value: "123", 656 expectedValue: time.Time{}, 657 expectedErr: true, 658 }, 659 { 660 value: "something", 661 expectedValue: time.Time{}, 662 expectedErr: true, 663 }, 664 { 665 value: true, 666 expectedValue: time.Time{}, 667 expectedErr: true, 668 }, 669 } 670 671 for i, tc := range testCases { 672 t.Run(fmt.Sprintf("date #%d", i), func(t *testing.T) { 673 value, err := dateVal(tc.value) 674 675 if tc.expectedErr { 676 assert.Error(t, err) 677 } else { 678 assert.NoError(t, err) 679 } 680 assert.Equal(t, tc.expectedValue, value) 681 }) 682 } 683 for i, tc := range testCases { 684 t.Run(fmt.Sprintf("dates (single) #%d", i), func(t *testing.T) { 685 value, err := dateArrayVal(tc.value) 686 687 assert.Error(t, err) 688 assert.Nil(t, value) 689 }) 690 t.Run(fmt.Sprintf("dates (array) #%d", i), func(t *testing.T) { 691 value, err := dateArrayVal([]interface{}{tc.value}) 692 693 if tc.expectedErr { 694 assert.Error(t, err) 695 assert.Nil(t, value) 696 } else { 697 assert.NoError(t, err) 698 assert.Equal(t, []time.Time{tc.expectedValue}, value) 699 } 700 }) 701 } 702 }) 703 }