github.com/weaviate/weaviate@v1.24.6/usecases/objects/validation/phone_numbers_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  	"errors"
    17  	"fmt"
    18  	"testing"
    19  
    20  	"github.com/stretchr/testify/assert"
    21  	"github.com/stretchr/testify/require"
    22  	"github.com/weaviate/weaviate/entities/models"
    23  	"github.com/weaviate/weaviate/usecases/config"
    24  )
    25  
    26  func TestPropertyOfTypePhoneNumberValidation(t *testing.T) {
    27  	type test struct {
    28  		name           string
    29  		phone          interface{} // "phone" property in schema
    30  		expectedErr    error
    31  		expectedResult *models.PhoneNumber
    32  	}
    33  
    34  	tests := []test{
    35  		{
    36  			name:  "phone of wrong type",
    37  			phone: "how about a string",
    38  			expectedErr: errors.New("invalid phoneNumber property 'phone' on class 'Person': " +
    39  				"phoneNumber must be a map, but got: string"),
    40  		},
    41  		{
    42  			name:  "phone map missing all keys",
    43  			phone: map[string]interface{}{},
    44  			expectedErr: errors.New("invalid phoneNumber property 'phone' on class 'Person': " +
    45  				"phoneNumber is missing required field 'input'"),
    46  		},
    47  		{
    48  			name: "input is not a string",
    49  			phone: map[string]interface{}{
    50  				"input": 1234,
    51  			},
    52  			expectedErr: errors.New("invalid phoneNumber property 'phone' on class 'Person': " +
    53  				"phoneNumber.input must be a string"),
    54  		},
    55  		{
    56  			name: "default country is not a string",
    57  			phone: map[string]interface{}{
    58  				"input":          "1234",
    59  				"defaultCountry": 7,
    60  			},
    61  			expectedErr: errors.New("invalid phoneNumber property 'phone' on class 'Person': " +
    62  				"phoneNumber.defaultCountry must be a string"),
    63  		},
    64  		{
    65  			name: "with only input set",
    66  			phone: map[string]interface{}{
    67  				"input": "+491711234567",
    68  			},
    69  			expectedErr: nil,
    70  			expectedResult: &models.PhoneNumber{
    71  				Valid:                  true,
    72  				Input:                  "+491711234567",
    73  				InternationalFormatted: "+49 171 1234567",
    74  				CountryCode:            49,
    75  				National:               1711234567,
    76  				NationalFormatted:      "0171 1234567",
    77  			},
    78  		},
    79  		{
    80  			name: "with national number and country uppercased",
    81  			phone: map[string]interface{}{
    82  				"input":          "01711234567",
    83  				"defaultCountry": "DE",
    84  			},
    85  			expectedErr: nil,
    86  			expectedResult: &models.PhoneNumber{
    87  				Valid:                  true,
    88  				DefaultCountry:         "DE",
    89  				Input:                  "01711234567",
    90  				InternationalFormatted: "+49 171 1234567",
    91  				CountryCode:            49,
    92  				National:               1711234567,
    93  				NationalFormatted:      "0171 1234567",
    94  			},
    95  		},
    96  		{
    97  			name: "with national number, but missing defaultCountry",
    98  			phone: map[string]interface{}{
    99  				"input": "01711234567",
   100  			},
   101  			expectedErr: fmt.Errorf("invalid phoneNumber property 'phone' on class 'Person': " +
   102  				"invalid phone number: invalid or missing defaultCountry - " +
   103  				"this field is optional if the specified number is in the international format, " +
   104  				"but required if the number is in national format, use ISO 3166-1 alpha-2"),
   105  		},
   106  		{
   107  			name: "with national number and country uppercased",
   108  			phone: map[string]interface{}{
   109  				"input":          "01711234567",
   110  				"defaultCountry": "de",
   111  			},
   112  			expectedErr: nil,
   113  			expectedResult: &models.PhoneNumber{
   114  				Valid:                  true,
   115  				DefaultCountry:         "DE",
   116  				Input:                  "01711234567",
   117  				InternationalFormatted: "+49 171 1234567",
   118  				CountryCode:            49,
   119  				National:               1711234567,
   120  				NationalFormatted:      "0171 1234567",
   121  			},
   122  		},
   123  		{
   124  			name: "with national number and various special characters",
   125  			phone: map[string]interface{}{
   126  				"input":          "(0)171-123 456 7",
   127  				"defaultCountry": "de",
   128  			},
   129  			expectedErr: nil,
   130  			expectedResult: &models.PhoneNumber{
   131  				Valid:                  true,
   132  				DefaultCountry:         "DE",
   133  				Input:                  "(0)171-123 456 7",
   134  				InternationalFormatted: "+49 171 1234567",
   135  				CountryCode:            49,
   136  				National:               1711234567,
   137  				NationalFormatted:      "0171 1234567",
   138  			},
   139  		},
   140  		{
   141  			name: "with international number and optional zero after country code",
   142  			phone: map[string]interface{}{
   143  				"input":          "+49 (0) 171 123 456 7",
   144  				"defaultCountry": "de",
   145  			},
   146  			expectedErr: nil,
   147  			expectedResult: &models.PhoneNumber{
   148  				Valid:                  true,
   149  				DefaultCountry:         "DE",
   150  				Input:                  "+49 (0) 171 123 456 7",
   151  				InternationalFormatted: "+49 171 1234567",
   152  				CountryCode:            49,
   153  				National:               1711234567,
   154  				NationalFormatted:      "0171 1234567",
   155  			},
   156  		},
   157  	}
   158  
   159  	for _, test := range tests {
   160  		t.Run(test.name, func(t *testing.T) {
   161  			config := &config.WeaviateConfig{}
   162  			validator := New(fakeExists, config, nil)
   163  
   164  			obj := &models.Object{
   165  				Class: "Person",
   166  				Properties: map[string]interface{}{
   167  					"phone": test.phone,
   168  				},
   169  			}
   170  			schema := testSchema()
   171  			err := validator.properties(context.Background(), schema.Objects.Classes[0], obj, nil)
   172  			assert.Equal(t, test.expectedErr, err)
   173  			if err != nil {
   174  				return
   175  			}
   176  			phone, ok := obj.Properties.(map[string]interface{})["phone"]
   177  			require.True(t, ok)
   178  			assert.Equal(t, test.expectedResult, phone)
   179  		})
   180  	}
   181  }