Coverage priorities 1-5: test pure functions, extract interfaces, mock-based handler tests
- Priority 1: Test NewSendEmailTask + NewSendPushTask (5 tests) - Priority 2: Test customHTTPErrorHandler — all 15+ branches (21 tests) - Priority 3: Extract Enqueuer interface + payload builders in worker pkg (5 tests) - Priority 4: Extract ClassifyFile/ComputeRelPath in migrate-encrypt (6 tests) - Priority 5: Define Handler interfaces, refactor to accept them, mock-based tests (14 tests) - Fix .gitignore: /worker instead of worker to stop ignoring internal/worker/ Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
package validator
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
govalidator "github.com/go-playground/validator/v10"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestValidatePasswordComplexity(t *testing.T) {
|
||||
@@ -113,3 +116,118 @@ func TestFormatMessagePasswordComplexity(t *testing.T) {
|
||||
t.Errorf("expected tag 'password_complexity', got %q", field.Tag)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPasswordComplexity_AdditionalCases(t *testing.T) {
|
||||
cv := NewCustomValidator()
|
||||
|
||||
type request struct {
|
||||
Password string `json:"password" validate:"required,min=8,password_complexity"`
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
pw string
|
||||
valid bool
|
||||
}{
|
||||
{"no uppercase no digit", "password", false},
|
||||
{"no lowercase", "PASSWORD1", false},
|
||||
{"no digit", "Password", false},
|
||||
{"too short", "Pass1", false},
|
||||
{"valid standard", "Password1", true},
|
||||
{"valid with special chars", "P@ssw0rd", true},
|
||||
{"spaces with complexity", "Pass 1234", true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
r := request{Password: tc.pw}
|
||||
err := cv.Validate(r)
|
||||
if tc.valid {
|
||||
assert.NoError(t, err, "expected %q to be valid", tc.pw)
|
||||
} else {
|
||||
assert.Error(t, err, "expected %q to be invalid", tc.pw)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatValidationErrors_AllTags(t *testing.T) {
|
||||
cv := NewCustomValidator()
|
||||
|
||||
type allTags struct {
|
||||
Required string `json:"required" validate:"required"`
|
||||
Email string `json:"email" validate:"email"`
|
||||
MinLen string `json:"min_len" validate:"min=5"`
|
||||
MaxLen string `json:"max_len" validate:"max=3"`
|
||||
OneOf string `json:"one_of" validate:"oneof=a b c"`
|
||||
URL string `json:"url" validate:"url"`
|
||||
}
|
||||
|
||||
input := allTags{
|
||||
Required: "", // fails required
|
||||
Email: "bad", // fails email
|
||||
MinLen: "ab", // fails min=5
|
||||
MaxLen: "abcde", // fails max=3
|
||||
OneOf: "z", // fails oneof
|
||||
URL: "nope", // fails url
|
||||
}
|
||||
|
||||
err := cv.Validate(input)
|
||||
require.Error(t, err)
|
||||
|
||||
resp := FormatValidationErrors(err)
|
||||
require.NotNil(t, resp)
|
||||
assert.Equal(t, "Validation failed", resp.Error)
|
||||
|
||||
expectedMessages := map[string]string{
|
||||
"required": "This field is required",
|
||||
"email": "Must be a valid email address",
|
||||
"min_len": "Must be at least 5 characters",
|
||||
"max_len": "Must be at most 3 characters",
|
||||
"one_of": "Must be one of: a b c",
|
||||
"url": "Must be a valid URL",
|
||||
}
|
||||
|
||||
for field, expectedMsg := range expectedMessages {
|
||||
fe, ok := resp.Fields[field]
|
||||
assert.True(t, ok, "expected field %q in error response", field)
|
||||
if ok {
|
||||
assert.Equal(t, expectedMsg, fe.Message, "message mismatch for field %q", field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatValidationErrors_NonValidationError(t *testing.T) {
|
||||
err := fmt.Errorf("some random error")
|
||||
resp := FormatValidationErrors(err)
|
||||
require.NotNil(t, resp)
|
||||
assert.Equal(t, "some random error", resp.Error)
|
||||
assert.Nil(t, resp.Fields)
|
||||
}
|
||||
|
||||
func TestNewCustomValidator_UsesJSONTagNames(t *testing.T) {
|
||||
cv := NewCustomValidator()
|
||||
|
||||
type request struct {
|
||||
FirstName string `json:"first_name" validate:"required"`
|
||||
}
|
||||
|
||||
err := cv.Validate(request{})
|
||||
require.Error(t, err)
|
||||
|
||||
resp := FormatValidationErrors(err)
|
||||
require.NotNil(t, resp)
|
||||
_, ok := resp.Fields["first_name"]
|
||||
assert.True(t, ok, "expected JSON tag name 'first_name' in error fields")
|
||||
}
|
||||
|
||||
func TestCustomValidator_Validate_Success(t *testing.T) {
|
||||
cv := NewCustomValidator()
|
||||
|
||||
type request struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
}
|
||||
|
||||
err := cv.Validate(request{Name: "test"})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user