Files
cv-site/internal/models/cv/validation_test.go
T

648 lines
14 KiB
Go
Raw Normal View History

package cv_test
import (
"strings"
"testing"
"github.com/juanatsap/cv-site/internal/models/cv"
)
func TestPersonal_Validate(t *testing.T) {
tests := []struct {
name string
personal cv.Personal
wantErr bool
errField string
}{
{
name: "Valid - All fields correct",
personal: cv.Personal{
Name: "John Doe",
Email: "john@example.com",
LinkedIn: "https://linkedin.com/in/johndoe",
GitHub: "https://github.com/johndoe",
Website: "https://johndoe.com",
},
wantErr: false,
},
{
name: "Invalid - Empty name",
personal: cv.Personal{
Name: "",
Email: "john@example.com",
},
wantErr: true,
errField: "name",
},
{
name: "Invalid - Empty email",
personal: cv.Personal{
Name: "John Doe",
Email: "",
},
wantErr: true,
errField: "email",
},
{
name: "Invalid - Bad email format",
personal: cv.Personal{
Name: "John Doe",
Email: "not-an-email",
},
wantErr: true,
errField: "email",
},
{
name: "Invalid - Bad LinkedIn URL",
personal: cv.Personal{
Name: "John Doe",
Email: "john@example.com",
LinkedIn: "not-a-url",
},
wantErr: true,
errField: "linkedin",
},
{
name: "Valid - Optional fields empty",
personal: cv.Personal{
Name: "John Doe",
Email: "john@example.com",
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.personal.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Personal.Validate() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr && err != nil {
errMsg := err.Error()
if !strings.Contains(errMsg, tt.errField) {
t.Errorf("Error should mention field '%s', got: %s", tt.errField, errMsg)
}
}
})
}
}
func TestExperience_Validate(t *testing.T) {
tests := []struct {
name string
experience cv.Experience
wantErr bool
errField string
}{
{
name: "Valid - Current position",
experience: cv.Experience{
Position: "Software Engineer",
Company: "Tech Corp",
StartDate: "2020-01",
Current: true,
},
wantErr: false,
},
{
name: "Valid - Past position with end date",
experience: cv.Experience{
Position: "Software Engineer",
Company: "Tech Corp",
StartDate: "2020-01",
EndDate: "2023-12",
Current: false,
},
wantErr: false,
},
{
name: "Invalid - Empty position",
experience: cv.Experience{
Position: "",
Company: "Tech Corp",
StartDate: "2020-01",
},
wantErr: true,
errField: "position",
},
{
name: "Invalid - Empty company",
experience: cv.Experience{
Position: "Software Engineer",
Company: "",
StartDate: "2020-01",
},
wantErr: true,
errField: "company",
},
{
name: "Invalid - Missing end date for past position",
experience: cv.Experience{
Position: "Software Engineer",
Company: "Tech Corp",
StartDate: "2020-01",
Current: false,
EndDate: "",
},
wantErr: true,
errField: "endDate",
},
{
name: "Invalid - Bad company URL",
experience: cv.Experience{
Position: "Software Engineer",
Company: "Tech Corp",
StartDate: "2020-01",
Current: true,
CompanyURL: "not-a-url",
},
wantErr: true,
errField: "companyURL",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.experience.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Experience.Validate() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr && err != nil {
errMsg := err.Error()
if !strings.Contains(errMsg, tt.errField) {
t.Errorf("Error should mention field '%s', got: %s", tt.errField, errMsg)
}
}
})
}
}
func TestEducation_Validate(t *testing.T) {
tests := []struct {
name string
education cv.Education
wantErr bool
errField string
}{
{
name: "Valid - Complete education",
education: cv.Education{
Degree: "Bachelor of Science",
Institution: "University of Technology",
StartDate: "2015-09",
EndDate: "2019-06",
},
wantErr: false,
},
{
name: "Invalid - Empty degree",
education: cv.Education{
Degree: "",
Institution: "University of Technology",
StartDate: "2015-09",
EndDate: "2019-06",
},
wantErr: true,
errField: "degree",
},
{
name: "Invalid - Empty institution",
education: cv.Education{
Degree: "Bachelor of Science",
Institution: "",
StartDate: "2015-09",
EndDate: "2019-06",
},
wantErr: true,
errField: "institution",
},
{
name: "Invalid - Missing start date",
education: cv.Education{
Degree: "Bachelor of Science",
Institution: "University of Technology",
StartDate: "",
EndDate: "2019-06",
},
wantErr: true,
errField: "startDate",
},
{
name: "Invalid - Missing end date",
education: cv.Education{
Degree: "Bachelor of Science",
Institution: "University of Technology",
StartDate: "2015-09",
EndDate: "",
},
wantErr: true,
errField: "endDate",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.education.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Education.Validate() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr && err != nil {
errMsg := err.Error()
if !strings.Contains(errMsg, tt.errField) {
t.Errorf("Error should mention field '%s', got: %s", tt.errField, errMsg)
}
}
})
}
}
func TestSkills_Validate(t *testing.T) {
tests := []struct {
name string
skills cv.Skills
wantErr bool
errMsg string
}{
{
name: "Valid - Complete skills",
skills: cv.Skills{
Technical: []cv.SkillCategory{
{
Category: "Backend",
Proficiency: 4,
Items: []string{"Go", "Python"},
Sidebar: "left",
},
},
SoftSkills: []string{"Communication", "Leadership"},
},
wantErr: false,
},
{
name: "Invalid - Empty category name",
skills: cv.Skills{
Technical: []cv.SkillCategory{
{
Category: "",
Proficiency: 4,
Items: []string{"Go"},
},
},
},
wantErr: true,
errMsg: "category name is required",
},
{
name: "Invalid - Proficiency too low",
skills: cv.Skills{
Technical: []cv.SkillCategory{
{
Category: "Backend",
Proficiency: 0,
Items: []string{"Go"},
},
},
},
wantErr: true,
errMsg: "proficiency must be between 1 and 10",
},
{
name: "Invalid - Proficiency too high",
skills: cv.Skills{
Technical: []cv.SkillCategory{
{
Category: "Backend",
Proficiency: 11,
Items: []string{"Go"},
},
},
},
wantErr: true,
errMsg: "proficiency must be between 1 and 10",
},
{
name: "Invalid - No skill items",
skills: cv.Skills{
Technical: []cv.SkillCategory{
{
Category: "Backend",
Proficiency: 4,
Items: []string{},
},
},
},
wantErr: true,
errMsg: "at least one skill item is required",
},
{
name: "Invalid - Invalid sidebar value",
skills: cv.Skills{
Technical: []cv.SkillCategory{
{
Category: "Backend",
Proficiency: 4,
Items: []string{"Go"},
Sidebar: "middle",
},
},
},
wantErr: true,
errMsg: "sidebar must be",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.skills.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Skills.Validate() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr && err != nil {
errMsg := err.Error()
if !strings.Contains(errMsg, tt.errMsg) {
t.Errorf("Error should contain '%s', got: %s", tt.errMsg, errMsg)
}
}
})
}
}
func TestLanguage_Validate(t *testing.T) {
tests := []struct {
name string
language cv.Language
wantErr bool
errField string
}{
{
name: "Valid - Complete language",
language: cv.Language{
Language: "English",
Proficiency: "Native",
Level: 5,
},
wantErr: false,
},
{
name: "Invalid - Empty language name",
language: cv.Language{
Language: "",
Proficiency: "Native",
Level: 5,
},
wantErr: true,
errField: "language",
},
{
name: "Invalid - Empty proficiency",
language: cv.Language{
Language: "English",
Proficiency: "",
Level: 5,
},
wantErr: true,
errField: "proficiency",
},
{
name: "Invalid - Level too low",
language: cv.Language{
Language: "English",
Proficiency: "Beginner",
Level: 0,
},
wantErr: true,
errField: "level",
},
{
name: "Invalid - Level too high",
language: cv.Language{
Language: "English",
Proficiency: "Native",
Level: 6,
},
wantErr: true,
errField: "level",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.language.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Language.Validate() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr && err != nil {
errMsg := err.Error()
if !strings.Contains(errMsg, tt.errField) {
t.Errorf("Error should mention field '%s', got: %s", tt.errField, errMsg)
}
}
})
}
}
func TestProject_Validate(t *testing.T) {
tests := []struct {
name string
project cv.Project
wantErr bool
errMsg string
}{
{
name: "Valid - Complete project with URL",
project: cv.Project{
Title: "My Project",
URL: "https://project.com",
GitRepoUrl: "https://github.com/user/project",
Technologies: []string{"Go", "React"},
},
wantErr: false,
},
{
name: "Valid - Project with local git path",
project: cv.Project{
Title: "Local Project",
URL: "https://project.com",
GitRepoUrl: "/Users/user/projects/myproject",
Technologies: []string{"Go"},
},
wantErr: false,
},
{
name: "Invalid - Empty title",
project: cv.Project{
Title: "",
URL: "https://project.com",
},
wantErr: true,
errMsg: "title is required",
},
{
name: "Invalid - Bad project URL",
project: cv.Project{
Title: "My Project",
URL: "not-a-url",
},
wantErr: true,
errMsg: "url",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.project.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Project.Validate() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr && err != nil {
errMsg := err.Error()
if !strings.Contains(errMsg, tt.errMsg) {
t.Errorf("Error should contain '%s', got: %s", tt.errMsg, errMsg)
}
}
})
}
}
func TestMeta_Validate(t *testing.T) {
tests := []struct {
name string
meta cv.Meta
wantErr bool
errField string
}{
{
name: "Valid - Complete meta",
meta: cv.Meta{
Version: "1.0",
Language: "en",
LastUpdated: "2024-01-01",
},
wantErr: false,
},
{
name: "Invalid - Empty version",
meta: cv.Meta{
Version: "",
Language: "en",
},
wantErr: true,
errField: "version",
},
{
name: "Invalid - Empty language",
meta: cv.Meta{
Version: "1.0",
Language: "",
},
wantErr: true,
errField: "language",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.meta.Validate()
if (err != nil) != tt.wantErr {
t.Errorf("Meta.Validate() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr && err != nil {
errMsg := err.Error()
if !strings.Contains(errMsg, tt.errField) {
t.Errorf("Error should mention field '%s', got: %s", tt.errField, errMsg)
}
}
})
}
}
func TestCV_Validate(t *testing.T) {
t.Run("Valid - Complete CV", func(t *testing.T) {
validCV := &cv.CV{
Personal: cv.Personal{
Name: "John Doe",
Email: "john@example.com",
},
Skills: cv.Skills{
Technical: []cv.SkillCategory{
{
Category: "Backend",
Proficiency: 4,
Items: []string{"Go"},
},
},
},
Meta: cv.Meta{
Version: "1.0",
Language: "en",
},
}
err := validCV.Validate()
if err != nil {
t.Errorf("CV.Validate() should not error on valid CV, got: %v", err)
}
})
t.Run("Invalid - Multiple validation errors", func(t *testing.T) {
invalidCV := &cv.CV{
Personal: cv.Personal{
Name: "", // Invalid
Email: "not-an-email", // Invalid
},
Experience: []cv.Experience{
{
Position: "", // Invalid
Company: "Tech Corp",
StartDate: "2020-01",
},
},
Skills: cv.Skills{
Technical: []cv.SkillCategory{
{
Category: "Backend",
Proficiency: 11, // Invalid
Items: []string{"Go"},
},
},
},
Meta: cv.Meta{
Version: "", // Invalid
Language: "en",
},
}
err := invalidCV.Validate()
if err == nil {
t.Error("CV.Validate() should error on invalid CV")
return
}
// Check that multiple errors are reported
errMsg := err.Error()
if !strings.Contains(errMsg, "name") {
t.Error("Error should mention 'name' field")
}
if !strings.Contains(errMsg, "email") {
t.Error("Error should mention 'email' field")
}
if !strings.Contains(errMsg, "position") {
t.Error("Error should mention 'position' field")
}
if !strings.Contains(errMsg, "proficiency") {
t.Error("Error should mention 'proficiency' field")
}
if !strings.Contains(errMsg, "version") {
t.Error("Error should mention 'version' field")
}
})
}