package domain import ( "testing" ) func TestNewDefaultPreferences(t *testing.T) { p := NewDefaultPreferences("user-123") if p.UserID != "user-123" { t.Errorf("expected UserID 'user-123', got '%s'", p.UserID) } if p.Theme != "system" { t.Errorf("expected theme 'system', got '%s'", p.Theme) } if p.Language != "en" { t.Errorf("expected language 'en', got '%s'", p.Language) } if !p.Notifications.Email { t.Error("expected email=true") } if !p.Notifications.Push { t.Error("expected push=true") } if p.Notifications.Digest != "weekly" { t.Errorf("expected digest 'weekly', got '%s'", p.Notifications.Digest) } if p.UpdatedAt.IsZero() { t.Error("expected non-zero UpdatedAt") } } func TestPreferences_Validate(t *testing.T) { tests := []struct { name string modify func(p *Preferences) wantErr error }{ { name: "valid defaults", modify: func(p *Preferences) {}, wantErr: nil, }, { name: "valid light theme", modify: func(p *Preferences) { p.Theme = "light" }, wantErr: nil, }, { name: "valid dark theme", modify: func(p *Preferences) { p.Theme = "dark" }, wantErr: nil, }, { name: "invalid theme", modify: func(p *Preferences) { p.Theme = "blue" }, wantErr: ErrInvalidTheme, }, { name: "empty theme", modify: func(p *Preferences) { p.Theme = "" }, wantErr: ErrInvalidTheme, }, { name: "valid language es", modify: func(p *Preferences) { p.Language = "es" }, wantErr: nil, }, { name: "invalid language - too long", modify: func(p *Preferences) { p.Language = "eng" }, wantErr: ErrInvalidLanguage, }, { name: "invalid language - uppercase", modify: func(p *Preferences) { p.Language = "EN" }, wantErr: ErrInvalidLanguage, }, { name: "invalid language - empty", modify: func(p *Preferences) { p.Language = "" }, wantErr: ErrInvalidLanguage, }, { name: "valid digest daily", modify: func(p *Preferences) { p.Notifications.Digest = "daily" }, wantErr: nil, }, { name: "valid digest never", modify: func(p *Preferences) { p.Notifications.Digest = "never" }, wantErr: nil, }, { name: "invalid digest", modify: func(p *Preferences) { p.Notifications.Digest = "monthly" }, wantErr: ErrInvalidDigest, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { p := NewDefaultPreferences("user-1") tt.modify(p) err := p.Validate() if err != tt.wantErr { t.Errorf("expected error %v, got %v", tt.wantErr, err) } }) } } func TestPreferences_MergeFrom(t *testing.T) { strPtr := func(s string) *string { return &s } boolPtr := func(b bool) *bool { return &b } t.Run("nil update does nothing", func(t *testing.T) { p := NewDefaultPreferences("user-1") p.MergeFrom(nil) if p.Theme != "system" { t.Errorf("expected theme 'system', got '%s'", p.Theme) } }) t.Run("partial update - theme only", func(t *testing.T) { p := NewDefaultPreferences("user-1") p.MergeFrom(&PreferencesUpdate{ Theme: strPtr("dark"), }) if p.Theme != "dark" { t.Errorf("expected theme 'dark', got '%s'", p.Theme) } if p.Language != "en" { t.Errorf("expected language 'en' unchanged, got '%s'", p.Language) } }) t.Run("partial update - language only", func(t *testing.T) { p := NewDefaultPreferences("user-1") p.MergeFrom(&PreferencesUpdate{ Language: strPtr("fr"), }) if p.Language != "fr" { t.Errorf("expected language 'fr', got '%s'", p.Language) } if p.Theme != "system" { t.Errorf("expected theme 'system' unchanged, got '%s'", p.Theme) } }) t.Run("notifications sub-field merge", func(t *testing.T) { p := NewDefaultPreferences("user-1") p.MergeFrom(&PreferencesUpdate{ Notifications: &NotificationSettingsUpdate{ Email: boolPtr(false), }, }) if p.Notifications.Email != false { t.Error("expected email=false") } if p.Notifications.Push != true { t.Error("expected push=true unchanged") } if p.Notifications.Digest != "weekly" { t.Errorf("expected digest 'weekly' unchanged, got '%s'", p.Notifications.Digest) } }) t.Run("full update", func(t *testing.T) { p := NewDefaultPreferences("user-1") p.MergeFrom(&PreferencesUpdate{ Theme: strPtr("light"), Language: strPtr("es"), Notifications: &NotificationSettingsUpdate{ Email: boolPtr(false), Push: boolPtr(false), Digest: strPtr("daily"), }, }) if p.Theme != "light" { t.Errorf("expected theme 'light', got '%s'", p.Theme) } if p.Language != "es" { t.Errorf("expected language 'es', got '%s'", p.Language) } if p.Notifications.Email != false { t.Error("expected email=false") } if p.Notifications.Push != false { t.Error("expected push=false") } if p.Notifications.Digest != "daily" { t.Errorf("expected digest 'daily', got '%s'", p.Notifications.Digest) } }) } func TestUserID(t *testing.T) { id := UserID("test-123") if id.String() != "test-123" { t.Errorf("expected 'test-123', got '%s'", id.String()) } if id.IsZero() { t.Error("expected non-zero") } var empty UserID if !empty.IsZero() { t.Error("expected zero") } }