initial commit
This commit is contained in:
645
pkg/validation/validation_test.go
Normal file
645
pkg/validation/validation_test.go
Normal file
@@ -0,0 +1,645 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user