Files
cv-site/internal/lang/lang_test.go
T
juanatsap 9240a863d1 refactor: Extract shared utilities and add validation layer
Part 1: Shared Utilities
- Create internal/fileutil package with FindDataFile() and LoadJSON()
- Create internal/lang package with language constants and validation
- Eliminate 46 lines of code duplication between cv/loader.go and ui/loader.go
- Simplify cv/loader.go from 69 to 36 lines (-48%)
- Simplify ui/loader.go from 56 to 24 lines (-57%)

Part 2: Validation Layer
- Add comprehensive validation in internal/models/cv/validation.go
- Validate Personal (name, email format, URLs)
- Validate Experience (required fields, dates)
- Validate Education (required fields)
- Validate Skills (proficiency ranges 1-5, categories)
- Validate Languages (proficiency levels 1-5)
- Validate Projects (title, URLs)
- Validate Meta (version, language)
- Integrate validation into LoadCV() - automatic on load
- Create ValidationError and ValidationErrors types for clear error reporting
- Report all validation errors at once (better UX)

Testing:
- Add comprehensive tests for fileutil package (FindDataFile, LoadJSON)
- Add tests for lang package (IsValid, Validate, All)
- Add 280+ validation test cases covering edge cases
- All tests pass with real CV data (cv-en.json, cv-es.json)
- Fixed validation to allow both URLs and local paths for gitRepoUrl

Documentation:
- Create _go-learning/refactorings/002-shared-utilities-validation.md
- Document architecture, benefits, testing, and interview talking points
- Explain WHY decisions were made (DRY, type safety, data integrity)

Benefits:
- DRY: Single source of truth for utilities
- Type safety: Language constants instead of magic strings
- Data integrity: Validation catches errors at load time
- Better errors: Clear messages showing all issues at once
- Maintainability: Centralized utilities easier to update
2025-11-20 16:41:13 +00:00

122 lines
2.0 KiB
Go

package lang_test
import (
"testing"
"github.com/juanatsap/cv-site/internal/lang"
)
func TestIsValid(t *testing.T) {
tests := []struct {
name string
language string
want bool
}{
{
name: "Valid - English",
language: "en",
want: true,
},
{
name: "Valid - Spanish",
language: "es",
want: true,
},
{
name: "Invalid - French",
language: "fr",
want: false,
},
{
name: "Invalid - Empty",
language: "",
want: false,
},
{
name: "Invalid - Uppercase",
language: "EN",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := lang.IsValid(tt.language); got != tt.want {
t.Errorf("IsValid() = %v, want %v", got, tt.want)
}
})
}
}
func TestValidate(t *testing.T) {
tests := []struct {
name string
language string
wantErr bool
}{
{
name: "Valid - English",
language: "en",
wantErr: false,
},
{
name: "Valid - Spanish",
language: "es",
wantErr: false,
},
{
name: "Invalid - French",
language: "fr",
wantErr: true,
},
{
name: "Invalid - Empty",
language: "",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := lang.Validate(tt.language)
if (err != nil) != tt.wantErr {
t.Errorf("Validate() error = %v, wantErr %v", err, tt.wantErr)
}
if err != nil && tt.wantErr {
// Check that error message includes supported languages
errMsg := err.Error()
if errMsg == "" {
t.Error("Validate() error message is empty")
}
}
})
}
}
func TestAll(t *testing.T) {
all := lang.All()
if len(all) != 2 {
t.Errorf("All() returned %d languages, want 2", len(all))
}
// Check that it contains en and es
hasEN := false
hasES := false
for _, l := range all {
if l == "en" {
hasEN = true
}
if l == "es" {
hasES = true
}
}
if !hasEN {
t.Error("All() missing 'en'")
}
if !hasES {
t.Error("All() missing 'es'")
}
}