// Copyright (c) 2026 Storm Dragon // Authors: Storm Dragon, Angus Kola // SPDX-License-Identifier: GPL-3.0-or-later package config import ( "fmt" "path/filepath" "testing" ) func TestCapitalChoicesPersistIndependently(t *testing.T) { defaults := DefaultSettings() if !defaults.RaisePitchForCapitals || defaults.BeepForCapitals || defaults.SayCapForCapitals { t.Fatal("only capital pitch should default on") } store, err := NewStore(filepath.Join(t.TempDir(), "settings.toml")) if err != nil { t.Fatal(err) } for mask := 0; mask < 8; mask++ { settings := defaults settings.RaisePitchForCapitals = mask&1 != 0 settings.BeepForCapitals = mask&2 != 0 settings.SayCapForCapitals = mask&4 != 0 if err := store.Save(settings); err != nil { t.Fatal(err) } loaded, err := Load(store.path) if err != nil { t.Fatal(err) } checkCapitalChoices(t, loaded, settings) app := defaults if err := store.SaveForApplication("editor", app); err != nil { t.Fatal(err) } loaded, found, err := store.LoadForApplication("editor") if err != nil || !found { t.Fatalf("application load: %v, %v", found, err) } checkCapitalChoices(t, loaded, app) loaded, err = store.Load() if err != nil { t.Fatal(err) } checkCapitalChoices(t, loaded, settings) } } func checkCapitalChoices(t *testing.T, got, want Settings) { t.Helper() if got.RaisePitchForCapitals != want.RaisePitchForCapitals || got.BeepForCapitals != want.BeepForCapitals || got.SayCapForCapitals != want.SayCapForCapitals { t.Fatalf("capital choices: pitch=%v beep=%v cap=%v; want %v %v %v", got.RaisePitchForCapitals, got.BeepForCapitals, got.SayCapForCapitals, want.RaisePitchForCapitals, want.BeepForCapitals, want.SayCapForCapitals) } } func TestOldCapitalStylesMigrate(t *testing.T) { for _, style := range []string{"none", "spell", "icon"} { for _, versioned := range []bool{false, true} { contents := fmt.Sprintf("[general]\ncapitalizationStyle = %q\n", style) if versioned { contents = fmt.Sprintf("schema-version = 2\nactive-profile = 'default'\n[profiles.default.speech]\ncapitalization-style = %q\n", style) } settings, err := Load(writeConfig(t, contents)) if err != nil { t.Fatal(err) } if !settings.RaisePitchForCapitals || settings.BeepForCapitals != (style == "icon") || settings.SayCapForCapitals != (style == "spell") { t.Fatalf("old %s, versioned=%v: %+v", style, versioned, settings) } } } settings, err := Load(writeConfig(t, "schema-version = 2\nactive-profile = 'default'\n[profiles.default.speech]\ncapitalization-style = 'spell'\nsay-cap-for-capitals = false\nbeep-for-capitals = true\nraise-pitch-for-capitals = false\n")) if err != nil { t.Fatal(err) } if settings.RaisePitchForCapitals || settings.SayCapForCapitals || !settings.BeepForCapitals { t.Fatal("explicit independent choices did not override old style") } } func TestCapitalPitchCanBeDisabledWithExplicitUppercaseVoice(t *testing.T) { settings := DefaultSettings() normal, upper := 4.0, 8.0 settings.DefaultVoice.AveragePitch = &normal settings.UppercaseVoice.AveragePitch = &upper settings.RaisePitchForCapitals = false if got := *EffectiveVoice(settings, "uppercase").AveragePitch; got != normal { t.Fatalf("pitch=%v", got) } settings.DefaultVoice.AveragePitch = nil if EffectiveVoice(settings, "uppercase").AveragePitch != nil { t.Fatal("server default pitch was lost") } settings.RaisePitchForCapitals = true if got := *EffectiveVoice(settings, "uppercase").AveragePitch; got != upper { t.Fatalf("pitch=%v", got) } }