Add robust input validation system and fix test suite

- Add comprehensive validation package with email (RFC 5322), password strength, and IANA timezone validation
- Implement strict password requirements: min 8 chars, uppercase, lowercase, digit, special character
- Integrate validation into RegisterUserHandler with complete test coverage (59 validation tests + 25 handler tests)
- Fix pre-existing test failures:
  - Remove tests for non-existent HabitEntry.DeletedAt and Delete() methods
  - Replace deprecated HabitTypeQuantity with HabitTypeValue
  - Add missing FindByHabitIDAndDateRange mock implementation
- Remove hardcoded localhost:8080 from Swagger config for self-hosted flexibility
This commit is contained in:
2025-11-27 00:17:18 +01:00
parent 95088a8162
commit 7768037724
9 changed files with 673 additions and 39 deletions
@@ -24,7 +24,7 @@ func (m *mockHabitRepoWithFindByID) FindByID(ctx context.Context, id string) (*e
func TestGetHabitByIDHandler_ReturnsHabitSuccessfully(t *testing.T) {
targetValue := 5.0
habit := entities.NewHabit("user-123", "Drink Water", value_objects.HabitTypeQuantity, value_objects.FrequencyDaily, true)
habit := entities.NewHabit("user-123", "Drink Water", value_objects.HabitTypeValue, value_objects.FrequencyDaily, true)
habit.ID = "habit-1"
habit.TargetValue = &targetValue
@@ -53,8 +53,8 @@ func TestGetHabitByIDHandler_ReturnsHabitSuccessfully(t *testing.T) {
t.Errorf("Expected name 'Drink Water', got %s", result.Name)
}
if result.Type != string(value_objects.HabitTypeQuantity) {
t.Errorf("Expected type %s, got %s", value_objects.HabitTypeQuantity, result.Type)
if result.Type != string(value_objects.HabitTypeValue) {
t.Errorf("Expected type %s, got %s", value_objects.HabitTypeValue, result.Type)
}
if result.TargetValue == nil || *result.TargetValue != 5.0 {
@@ -20,6 +20,10 @@ func (m *mockEntryRepoWithFindByHabitID) FindByHabitID(ctx context.Context, habi
return m.entries, nil
}
func (m *mockEntryRepoWithFindByHabitID) FindByHabitIDAndDateRange(ctx context.Context, habitID string, from, to time.Time) ([]*entities.HabitEntry, error) {
return m.entries, nil
}
func TestGetHabitEntriesHandler_ReturnsEntriesSuccessfully(t *testing.T) {
habit := entities.NewHabit("user-123", "Exercise", value_objects.HabitTypeBoolean, value_objects.FrequencyDaily, false)
habit.ID = "habit-1"
@@ -64,7 +64,7 @@ func TestGetUserHabitsHandler_ReturnsEmptyListForUserWithNoHabits(t *testing.T)
func TestGetUserHabitsHandler_IncludesAllHabitFields(t *testing.T) {
targetValue := 5.0
habit := entities.NewHabit("user-123", "Drink Water", value_objects.HabitTypeQuantity, value_objects.FrequencyDaily, true)
habit := entities.NewHabit("user-123", "Drink Water", value_objects.HabitTypeValue, value_objects.FrequencyDaily, true)
habit.ID = "habit-1"
habit.TargetValue = &targetValue
@@ -92,8 +92,8 @@ func TestGetUserHabitsHandler_IncludesAllHabitFields(t *testing.T) {
t.Errorf("Expected name 'Drink Water', got %s", result.Name)
}
if result.Type != string(value_objects.HabitTypeQuantity) {
t.Errorf("Expected type %s, got %s", value_objects.HabitTypeQuantity, result.Type)
if result.Type != string(value_objects.HabitTypeValue) {
t.Errorf("Expected type %s, got %s", value_objects.HabitTypeValue, result.Type)
}
if result.Frequency != string(value_objects.FrequencyDaily) {