First real commit. Setting up for full CI/CD and testing pipeline
This commit is contained in:
64
internal/settings/settings.go
Normal file
64
internal/settings/settings.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package settings
|
||||
|
||||
import "strings"
|
||||
|
||||
const (
|
||||
MinReadingSpeed = 100
|
||||
MaxReadingSpeed = 1000
|
||||
|
||||
MinFontSize = 24
|
||||
MaxFontSize = 96
|
||||
|
||||
ThemeDark = "dark"
|
||||
ThemeLight = "light"
|
||||
)
|
||||
|
||||
// Settings contains user preferences.
|
||||
type Settings struct {
|
||||
ReadingSpeed int `json:"readingSpeed"`
|
||||
FontSize int `json:"fontSize"`
|
||||
Theme string `json:"theme"`
|
||||
}
|
||||
|
||||
// Default returns the default application settings.
|
||||
func Default() Settings {
|
||||
return Settings{
|
||||
ReadingSpeed: 300,
|
||||
FontSize: 48,
|
||||
Theme: ThemeDark,
|
||||
}
|
||||
}
|
||||
|
||||
// Validate checks whether all settings contain supported values.
|
||||
func (s Settings) Validate() bool {
|
||||
return s.ReadingSpeed >= MinReadingSpeed &&
|
||||
s.ReadingSpeed <= MaxReadingSpeed &&
|
||||
s.FontSize >= MinFontSize &&
|
||||
s.FontSize <= MaxFontSize &&
|
||||
(s.Theme == ThemeDark || s.Theme == ThemeLight)
|
||||
}
|
||||
|
||||
// Normalize returns settings with values restricted to supported options.
|
||||
func (s Settings) Normalize() Settings {
|
||||
defaults := Default()
|
||||
|
||||
if s.ReadingSpeed < MinReadingSpeed {
|
||||
s.ReadingSpeed = MinReadingSpeed
|
||||
} else if s.ReadingSpeed > MaxReadingSpeed {
|
||||
s.ReadingSpeed = MaxReadingSpeed
|
||||
}
|
||||
|
||||
if s.FontSize < MinFontSize {
|
||||
s.FontSize = MinFontSize
|
||||
} else if s.FontSize > MaxFontSize {
|
||||
s.FontSize = MaxFontSize
|
||||
}
|
||||
|
||||
s.Theme = strings.ToLower(strings.TrimSpace(s.Theme))
|
||||
|
||||
if s.Theme != ThemeDark && s.Theme != ThemeLight {
|
||||
s.Theme = defaults.Theme
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
214
internal/settings/settings_test.go
Normal file
214
internal/settings/settings_test.go
Normal file
@@ -0,0 +1,214 @@
|
||||
package settings
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDefault(t *testing.T) {
|
||||
got := Default()
|
||||
|
||||
if got.ReadingSpeed != 300 {
|
||||
t.Errorf("ReadingSpeed = %d, want 300", got.ReadingSpeed)
|
||||
}
|
||||
|
||||
if got.FontSize != 48 {
|
||||
t.Errorf("FontSize = %d, want 48", got.FontSize)
|
||||
}
|
||||
|
||||
if got.Theme != ThemeDark {
|
||||
t.Errorf("Theme = %q, want %q", got.Theme, ThemeDark)
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
settings Settings
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "valid defaults",
|
||||
settings: Default(),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "minimum values",
|
||||
settings: Settings{
|
||||
ReadingSpeed: MinReadingSpeed,
|
||||
FontSize: MinFontSize,
|
||||
Theme: ThemeDark,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "maximum values",
|
||||
settings: Settings{
|
||||
ReadingSpeed: MaxReadingSpeed,
|
||||
FontSize: MaxFontSize,
|
||||
Theme: ThemeLight,
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "invalid reading speed",
|
||||
settings: Settings{
|
||||
ReadingSpeed: 50,
|
||||
FontSize: 48,
|
||||
Theme: ThemeDark,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "reading speed too high",
|
||||
settings: Settings{
|
||||
ReadingSpeed: 1500,
|
||||
FontSize: 48,
|
||||
Theme: ThemeDark,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "invalid font size",
|
||||
settings: Settings{
|
||||
ReadingSpeed: 300,
|
||||
FontSize: 10,
|
||||
Theme: ThemeDark,
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "invalid theme",
|
||||
settings: Settings{
|
||||
ReadingSpeed: 300,
|
||||
FontSize: 48,
|
||||
Theme: "purple",
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := tt.settings.Validate(); got != tt.want {
|
||||
t.Errorf("Validate() = %t, want %t", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
func TestNormalize(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input Settings
|
||||
want Settings
|
||||
}{
|
||||
{
|
||||
name: "valid settings unchanged",
|
||||
input: Default(),
|
||||
want: Default(),
|
||||
},
|
||||
{
|
||||
name: "speed below minimum clamped",
|
||||
input: Settings{
|
||||
ReadingSpeed: 50,
|
||||
FontSize: 48,
|
||||
Theme: ThemeDark,
|
||||
},
|
||||
want: Settings{
|
||||
ReadingSpeed: MinReadingSpeed,
|
||||
FontSize: 48,
|
||||
Theme: ThemeDark,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "speed above maximum clamped",
|
||||
input: Settings{
|
||||
ReadingSpeed: 1200,
|
||||
FontSize: 48,
|
||||
Theme: ThemeDark,
|
||||
},
|
||||
want: Settings{
|
||||
ReadingSpeed: MaxReadingSpeed,
|
||||
FontSize: 48,
|
||||
Theme: ThemeDark,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "font below minimum clamped",
|
||||
input: Settings{
|
||||
ReadingSpeed: 400,
|
||||
FontSize: 10,
|
||||
Theme: ThemeLight,
|
||||
},
|
||||
want: Settings{
|
||||
ReadingSpeed: 400,
|
||||
FontSize: MinFontSize,
|
||||
Theme: ThemeLight,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "font above maximum clamped",
|
||||
input: Settings{
|
||||
ReadingSpeed: 400,
|
||||
FontSize: 120,
|
||||
Theme: ThemeLight,
|
||||
},
|
||||
want: Settings{
|
||||
ReadingSpeed: 400,
|
||||
FontSize: MaxFontSize,
|
||||
Theme: ThemeLight,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid theme replaced",
|
||||
input: Settings{
|
||||
ReadingSpeed: 400,
|
||||
FontSize: 48,
|
||||
Theme: "purple",
|
||||
},
|
||||
want: Settings{
|
||||
ReadingSpeed: 400,
|
||||
FontSize: 48,
|
||||
Theme: ThemeDark,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "theme whitespace and case normalized",
|
||||
input: Settings{
|
||||
ReadingSpeed: 400,
|
||||
FontSize: 48,
|
||||
Theme: " LIGHT ",
|
||||
},
|
||||
want: Settings{
|
||||
ReadingSpeed: 400,
|
||||
FontSize: 48,
|
||||
Theme: ThemeLight,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := tt.input.Normalize()
|
||||
|
||||
if got != tt.want {
|
||||
t.Errorf("Normalize() = %+v, want %+v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNormalizeAlwaysProducesValidSettings(t *testing.T) {
|
||||
tests := []Settings{
|
||||
{},
|
||||
{ReadingSpeed: -1, FontSize: -1, Theme: "invalid"},
|
||||
{ReadingSpeed: 2000, FontSize: 200, Theme: " BLUE "},
|
||||
{ReadingSpeed: 300, FontSize: 48, Theme: " LIGHT "},
|
||||
}
|
||||
|
||||
for _, input := range tests {
|
||||
got := input.Normalize()
|
||||
|
||||
if !got.Validate() {
|
||||
t.Errorf("Normalize(%+v) produced invalid settings: %+v",
|
||||
input, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user