First real commit. Setting up for full CI/CD and testing pipeline
This commit is contained in:
121
app/app.go
Normal file
121
app/app.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"fast_reader/internal/reader"
|
||||
"fast_reader/internal/settings"
|
||||
"fast_reader/internal/storage"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
ctx context.Context
|
||||
mu sync.RWMutex
|
||||
settings settings.Settings
|
||||
settingsPath string
|
||||
}
|
||||
|
||||
func NewApp() *App {
|
||||
return &App{
|
||||
settings: settings.Default(),
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) Startup(ctx context.Context) {
|
||||
a.ctx = ctx
|
||||
|
||||
configDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
log.Printf("Could not locate user config directory: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
a.settingsPath = filepath.Join(
|
||||
configDir,
|
||||
"fast_reader",
|
||||
"settings.json",
|
||||
)
|
||||
|
||||
var saved settings.Settings
|
||||
|
||||
err = storage.Load(a.settingsPath, &saved)
|
||||
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
log.Printf("Could not load settings: %v", err)
|
||||
}
|
||||
|
||||
a.settings = settings.Default()
|
||||
return
|
||||
}
|
||||
|
||||
a.settings = saved.Normalize()
|
||||
|
||||
log.Println("Settings loaded successfully")
|
||||
}
|
||||
|
||||
// PrepareText converts pasted text into a sequence of words
|
||||
// ready for RSVP playback.
|
||||
func (a *App) PrepareText(text string) []reader.Word {
|
||||
return reader.Tokenize(text)
|
||||
}
|
||||
|
||||
// GetVersion returns the application version.
|
||||
func (a *App) GetVersion() string {
|
||||
return "0.1.0"
|
||||
}
|
||||
|
||||
// GetSettings returns the current application settings.
|
||||
func (a *App) GetSettings() settings.Settings {
|
||||
a.mu.RLock()
|
||||
defer a.mu.RUnlock()
|
||||
|
||||
return a.settings
|
||||
}
|
||||
|
||||
// SaveSettings validates and persists application settings.
|
||||
func (a *App) SaveSettings(input settings.Settings) error {
|
||||
normalized := input.Normalize()
|
||||
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
|
||||
if a.settingsPath == "" {
|
||||
configDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.settingsPath = filepath.Join(
|
||||
configDir,
|
||||
"fast_reader",
|
||||
"settings.json",
|
||||
)
|
||||
}
|
||||
|
||||
if err := storage.Save(a.settingsPath, normalized); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.settings = normalized
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ResetSettings restores and persists the default settings.
|
||||
func (a *App) ResetSettings() (settings.Settings, error) {
|
||||
defaults := settings.Default()
|
||||
|
||||
if err := a.SaveSettings(defaults); err != nil {
|
||||
return settings.Settings{}, err
|
||||
}
|
||||
|
||||
return defaults, nil
|
||||
}
|
||||
154
app/app_test.go
Normal file
154
app/app_test.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"fast_reader/internal/settings"
|
||||
)
|
||||
|
||||
func TestNewApp(t *testing.T) {
|
||||
a := NewApp()
|
||||
|
||||
if a == nil {
|
||||
t.Fatal("NewApp() returned nil")
|
||||
}
|
||||
|
||||
if got := a.GetSettings(); got != settings.Default() {
|
||||
t.Errorf("initial settings = %+v, want %+v",
|
||||
got, settings.Default())
|
||||
}
|
||||
}
|
||||
|
||||
func TestStartup(t *testing.T) {
|
||||
application := NewApp()
|
||||
ctx := context.Background()
|
||||
|
||||
// Startup should store the Wails application context.
|
||||
application.Startup(ctx)
|
||||
|
||||
if application.ctx != ctx {
|
||||
t.Error("Startup() did not store the application context")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareText(t *testing.T) {
|
||||
a := NewApp()
|
||||
|
||||
words := a.PrepareText("Hello world")
|
||||
|
||||
if len(words) != 2 {
|
||||
t.Fatalf("PrepareText() returned %d words, want 2", len(words))
|
||||
}
|
||||
|
||||
if words[0].Text != "Hello" || words[1].Text != "world" {
|
||||
t.Errorf("unexpected words: %+v", words)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareEmptyText(t *testing.T) {
|
||||
application := NewApp()
|
||||
|
||||
got := application.PrepareText("")
|
||||
|
||||
if len(got) != 0 {
|
||||
t.Errorf("PrepareText() returned %d words for empty input, want 0", len(got))
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetVersion(t *testing.T) {
|
||||
a := NewApp()
|
||||
|
||||
if got := a.GetVersion(); got != "0.1.0" {
|
||||
t.Errorf("GetVersion() = %q, want %q", got, "0.1.0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveAndLoadSettings(t *testing.T) {
|
||||
configDir := t.TempDir()
|
||||
t.Setenv("XDG_CONFIG_HOME", configDir)
|
||||
|
||||
first := NewApp()
|
||||
first.Startup(context.Background())
|
||||
|
||||
expected := settings.Settings{
|
||||
ReadingSpeed: 500,
|
||||
FontSize: 64,
|
||||
Theme: settings.ThemeLight,
|
||||
}
|
||||
|
||||
if err := first.SaveSettings(expected); err != nil {
|
||||
t.Fatalf("SaveSettings() error = %v", err)
|
||||
}
|
||||
|
||||
if got := first.GetSettings(); got != expected {
|
||||
t.Errorf("settings = %+v, want %+v", got, expected)
|
||||
}
|
||||
|
||||
// Simulate restarting the application.
|
||||
second := NewApp()
|
||||
second.Startup(context.Background())
|
||||
|
||||
if got := second.GetSettings(); got != expected {
|
||||
t.Errorf("reloaded settings = %+v, want %+v", got, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSaveSettingsNormalizesValues(t *testing.T) {
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
|
||||
a := NewApp()
|
||||
a.Startup(context.Background())
|
||||
|
||||
input := settings.Settings{
|
||||
ReadingSpeed: 2000,
|
||||
FontSize: 10,
|
||||
Theme: "invalid",
|
||||
}
|
||||
|
||||
if err := a.SaveSettings(input); err != nil {
|
||||
t.Fatalf("SaveSettings() error = %v", err)
|
||||
}
|
||||
|
||||
expected := settings.Settings{
|
||||
ReadingSpeed: settings.MaxReadingSpeed,
|
||||
FontSize: settings.MinFontSize,
|
||||
Theme: settings.ThemeDark,
|
||||
}
|
||||
|
||||
if got := a.GetSettings(); got != expected {
|
||||
t.Errorf("settings = %+v, want %+v", got, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResetSettings(t *testing.T) {
|
||||
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
|
||||
|
||||
a := NewApp()
|
||||
a.Startup(context.Background())
|
||||
|
||||
custom := settings.Settings{
|
||||
ReadingSpeed: 600,
|
||||
FontSize: 72,
|
||||
Theme: settings.ThemeLight,
|
||||
}
|
||||
|
||||
if err := a.SaveSettings(custom); err != nil {
|
||||
t.Fatalf("SaveSettings() error = %v", err)
|
||||
}
|
||||
|
||||
got, err := a.ResetSettings()
|
||||
if err != nil {
|
||||
t.Fatalf("ResetSettings() error = %v", err)
|
||||
}
|
||||
|
||||
if got != settings.Default() {
|
||||
t.Errorf("ResetSettings() = %+v, want %+v",
|
||||
got, settings.Default())
|
||||
}
|
||||
|
||||
if current := a.GetSettings(); current != settings.Default() {
|
||||
t.Errorf("current settings = %+v, want defaults %+v",
|
||||
current, settings.Default())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user