package validation import ( "testing" ) func TestExistKey(t *testing.T) { tests := []struct { name string key string mapItem map[string]interface{} message string wantErr bool }{ { name: "key exists", key: "name", mapItem: map[string]interface{}{"name": "John"}, message: "Name is required", wantErr: false, }, { name: "key does not exist", key: "age", mapItem: map[string]interface{}{"name": "John"}, message: "Age is required", wantErr: true, }, { name: "empty map", key: "name", mapItem: map[string]interface{}{}, message: "Name is required", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := ExistKey(tt.key, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("ExistKey() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("ExistKey() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestNotBlank(t *testing.T) { tests := []struct { name string key string mapItem map[string]interface{} message string wantErr bool }{ { name: "valid string", key: "name", mapItem: map[string]interface{}{"name": "John"}, message: "Name cannot be blank", wantErr: false, }, { name: "nil value", key: "name", mapItem: map[string]interface{}{"name": nil}, message: "Name cannot be blank", wantErr: true, }, { name: "empty string", key: "name", mapItem: map[string]interface{}{"name": ""}, message: "Name cannot be blank", wantErr: true, }, { name: "empty slice", key: "tags", mapItem: map[string]interface{}{"tags": []interface{}{}}, message: "Tags cannot be blank", wantErr: true, }, { name: "non-empty slice", key: "tags", mapItem: map[string]interface{}{"tags": []interface{}{"tag1"}}, message: "Tags cannot be blank", wantErr: false, }, { name: "key does not exist", key: "name", mapItem: map[string]interface{}{"age": 25}, message: "Name cannot be blank", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := NotBlank(tt.key, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("NotBlank() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("NotBlank() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestIsString(t *testing.T) { tests := []struct { name string key string mapItem map[string]interface{} message string wantErr bool }{ { name: "valid string", key: "name", mapItem: map[string]interface{}{"name": "John"}, message: "Name must be a string", wantErr: false, }, { name: "integer value", key: "name", mapItem: map[string]interface{}{"name": 123}, message: "Name must be a string", wantErr: true, }, { name: "boolean value", key: "name", mapItem: map[string]interface{}{"name": true}, message: "Name must be a string", wantErr: true, }, { name: "key does not exist", key: "name", mapItem: map[string]interface{}{"age": 25}, message: "Name must be a string", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := IsString(tt.key, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("IsString() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("IsString() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestIsInt(t *testing.T) { tests := []struct { name string key string mapItem map[string]interface{} message string wantErr bool }{ { name: "valid integer", key: "age", mapItem: map[string]interface{}{"age": 25.0}, message: "Age must be an integer", wantErr: false, }, { name: "float value", key: "age", mapItem: map[string]interface{}{"age": 25.5}, message: "Age must be an integer", wantErr: true, }, { name: "string value", key: "age", mapItem: map[string]interface{}{"age": "25"}, message: "Age must be an integer", wantErr: true, }, { name: "too large value", key: "age", mapItem: map[string]interface{}{"age": float64(1<<32 + 1)}, message: "Age must be an integer", wantErr: true, }, { name: "key does not exist", key: "age", mapItem: map[string]interface{}{"name": "John"}, message: "Age must be an integer", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := IsInt(tt.key, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("IsInt() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("IsInt() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestIsFloat64(t *testing.T) { tests := []struct { name string key string mapItem map[string]interface{} message string wantErr bool }{ { name: "valid float", key: "price", mapItem: map[string]interface{}{"price": 25.5}, message: "Price must be a number", wantErr: false, }, { name: "integer value", key: "price", mapItem: map[string]interface{}{"price": 25.0}, message: "Price must be a number", wantErr: false, }, { name: "string value", key: "price", mapItem: map[string]interface{}{"price": "25.5"}, message: "Price must be a number", wantErr: true, }, { name: "key does not exist", key: "price", mapItem: map[string]interface{}{"name": "John"}, message: "Price must be a number", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := IsFloat64(tt.key, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("IsFloat64() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("IsFloat64() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestIsBool(t *testing.T) { tests := []struct { name string key string mapItem map[string]interface{} message string wantErr bool }{ { name: "valid boolean true", key: "active", mapItem: map[string]interface{}{"active": true}, message: "Active must be a boolean", wantErr: false, }, { name: "valid boolean false", key: "active", mapItem: map[string]interface{}{"active": false}, message: "Active must be a boolean", wantErr: false, }, { name: "string value", key: "active", mapItem: map[string]interface{}{"active": "true"}, message: "Active must be a boolean", wantErr: true, }, { name: "integer value", key: "active", mapItem: map[string]interface{}{"active": 1}, message: "Active must be a boolean", wantErr: true, }, { name: "key does not exist", key: "active", mapItem: map[string]interface{}{"name": "John"}, message: "Active must be a boolean", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := IsBool(tt.key, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("IsBool() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("IsBool() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestAtLeastOneFieldMustBePresent(t *testing.T) { tests := []struct { name string keys string mapItem map[string]interface{} message string wantErr bool }{ { name: "one field present", keys: "name,email,phone", mapItem: map[string]interface{}{"name": "John", "age": 25}, message: "At least one field must be present", wantErr: false, }, { name: "multiple fields present", keys: "name,email,phone", mapItem: map[string]interface{}{"name": "John", "email": "john@example.com"}, message: "At least one field must be present", wantErr: false, }, { name: "no fields present", keys: "name,email,phone", mapItem: map[string]interface{}{"age": 25, "city": "NYC"}, message: "At least one field must be present", wantErr: true, }, { name: "empty map", keys: "name,email,phone", mapItem: map[string]interface{}{}, message: "At least one field must be present", wantErr: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := AtLeastOneFieldMustBePresent(tt.keys, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("AtLeastOneFieldMustBePresent() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("AtLeastOneFieldMustBePresent() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestUnexpectedField(t *testing.T) { tests := []struct { name string keys string mapItem map[string]interface{} message string wantErr bool }{ { name: "all fields expected", keys: "name,age,email", mapItem: map[string]interface{}{"name": "John", "age": 25, "email": "john@example.com"}, message: "Unexpected field found", wantErr: false, }, { name: "subset of expected fields", keys: "name,age,email", mapItem: map[string]interface{}{"name": "John", "age": 25}, message: "Unexpected field found", wantErr: false, }, { name: "unexpected field present", keys: "name,age", mapItem: map[string]interface{}{"name": "John", "age": 25, "unexpected": "value"}, message: "Unexpected field found", wantErr: true, }, { name: "empty map", keys: "name,age", mapItem: map[string]interface{}{}, message: "Unexpected field found", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := UnexpectedField(tt.keys, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("UnexpectedField() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("UnexpectedField() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestMaxRange(t *testing.T) { tests := []struct { name string key string max int mapItem map[string]interface{} message string wantErr bool }{ { name: "value within range", key: "age", max: 100, mapItem: map[string]interface{}{"age": 25.0}, message: "Age must be less than 100", wantErr: false, }, { name: "value at maximum", key: "age", max: 100, mapItem: map[string]interface{}{"age": 100.0}, message: "Age must be less than 100", wantErr: false, }, { name: "value exceeds maximum", key: "age", max: 100, mapItem: map[string]interface{}{"age": 150.0}, message: "Age must be less than 100", wantErr: true, }, { name: "key does not exist", key: "age", max: 100, mapItem: map[string]interface{}{"name": "John"}, message: "Age must be less than 100", wantErr: false, }, { name: "non-numeric value", key: "age", max: 100, mapItem: map[string]interface{}{"age": "25"}, message: "Age must be less than 100", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := MaxRange(tt.key, tt.max, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("MaxRange() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("MaxRange() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestMinRange(t *testing.T) { tests := []struct { name string key string min int mapItem map[string]interface{} message string wantErr bool }{ { name: "value within range", key: "age", min: 18, mapItem: map[string]interface{}{"age": 25.0}, message: "Age must be at least 18", wantErr: false, }, { name: "value at minimum", key: "age", min: 18, mapItem: map[string]interface{}{"age": 18.0}, message: "Age must be at least 18", wantErr: false, }, { name: "value below minimum", key: "age", min: 18, mapItem: map[string]interface{}{"age": 15.0}, message: "Age must be at least 18", wantErr: true, }, { name: "key does not exist", key: "age", min: 18, mapItem: map[string]interface{}{"name": "John"}, message: "Age must be at least 18", wantErr: false, }, { name: "non-numeric value", key: "age", min: 18, mapItem: map[string]interface{}{"age": "25"}, message: "Age must be at least 18", wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := MinRange(tt.key, tt.min, tt.mapItem, tt.message) if (err != nil) != tt.wantErr { t.Errorf("MinRange() error = %v, wantErr %v", err, tt.wantErr) } if err != nil && err.Error() != tt.message { t.Errorf("MinRange() error message = %v, want %v", err.Error(), tt.message) } }) } } func TestContains(t *testing.T) { tests := []struct { name string limitedSoftwareTypes []int currentSoftwareType int expected bool }{ { name: "value found", limitedSoftwareTypes: []int{1, 2, 3, 4, 5}, currentSoftwareType: 3, expected: true, }, { name: "value not found", limitedSoftwareTypes: []int{1, 2, 3, 4, 5}, currentSoftwareType: 6, expected: false, }, { name: "empty slice", limitedSoftwareTypes: []int{}, currentSoftwareType: 1, expected: false, }, { name: "single value found", limitedSoftwareTypes: []int{42}, currentSoftwareType: 42, expected: true, }, { name: "single value not found", limitedSoftwareTypes: []int{42}, currentSoftwareType: 43, expected: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := Contains(tt.limitedSoftwareTypes, tt.currentSoftwareType) if result != tt.expected { t.Errorf("Contains() = %v, want %v", result, tt.expected) } }) } } func TestValidationError(t *testing.T) { // Test Error() method err := Error{Message: "Test error"} if err.Error() != "Test error" { t.Errorf("ValidationError.Error() = %v, want %v", err.Error(), "Test error") } // Test SetMessage() method newErr := err.SetMessage("New error message") if newErr.Message != "New error message" { t.Errorf("SetMessage() = %v, want %v", newErr.Message, "New error message") } // Original error should not be modified if err.Message != "Test error" { t.Errorf("Original error was modified, got %v, want %v", err.Message, "Test error") } } func TestErrBadRequest(t *testing.T) { if ErrBadRequest.Message != "Bad Request" { t.Errorf("ErrBadRequest.Message = %v, want %v", ErrBadRequest.Message, "Bad Request") } // Test that ErrBadRequest can be used with SetMessage customErr := ErrBadRequest.SetMessage("Custom error") if customErr.Message != "Custom error" { t.Errorf("SetMessage() = %v, want %v", customErr.Message, "Custom error") } // Original ErrBadRequest should not be modified if ErrBadRequest.Message != "Bad Request" { t.Errorf("ErrBadRequest was modified, got %v, want %v", ErrBadRequest.Message, "Bad Request") } }