Files
base/pkg/validation/validation_test.go
2026-04-10 18:25:21 +03:30

646 lines
16 KiB
Go

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")
}
}