Skip to content

Commit 7ef135c

Browse files
committed
test: add unit tests for default-sender config and surface snapshot update
- Config tests: default value, global config load, set/unset, save/reload, JSON omitempty, Values() output - Cmd tests: normalizeConfigKey hyphen-to-underscore conversion - Update surface snapshot for new --from flags and config get/unset commands
1 parent 0ea120e commit 7ef135c

3 files changed

Lines changed: 225 additions & 0 deletions

File tree

.surface

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,16 @@ hey completion
3232
hey compose
3333
hey compose --bcc
3434
hey compose --cc
35+
hey compose --from
3536
hey compose --message
3637
hey compose --subject
3738
hey compose --thread-id
3839
hey compose --to
3940
hey config
41+
hey config get
4042
hey config set
4143
hey config show
44+
hey config unset
4245
hey doctor
4346
hey drafts
4447
hey drafts --all
@@ -61,6 +64,7 @@ hey recordings --ends-on
6164
hey recordings --limit
6265
hey recordings --starts-on
6366
hey reply
67+
hey reply --from
6468
hey reply --message
6569
hey seen
6670
hey setup

internal/cmd/sender_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package cmd
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestNormalizeConfigKey(t *testing.T) {
8+
tests := []struct {
9+
input string
10+
want string
11+
}{
12+
{"default-sender", "default_sender"},
13+
{"default_sender", "default_sender"},
14+
{"base-url", "base_url"},
15+
{"base_url", "base_url"},
16+
{"no-hyphens", "no_hyphens"},
17+
}
18+
19+
for _, tt := range tests {
20+
t.Run(tt.input, func(t *testing.T) {
21+
got := normalizeConfigKey(tt.input)
22+
if got != tt.want {
23+
t.Errorf("normalizeConfigKey(%q) = %q, want %q", tt.input, got, tt.want)
24+
}
25+
})
26+
}
27+
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
package config
2+
3+
import (
4+
"encoding/json"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
)
9+
10+
func TestDefaultSenderDefault(t *testing.T) {
11+
tmp := t.TempDir()
12+
t.Setenv("XDG_CONFIG_HOME", tmp)
13+
t.Setenv("HEY_BASE_URL", "")
14+
15+
cfg, err := Load()
16+
if err != nil {
17+
t.Fatalf("Load: %v", err)
18+
}
19+
20+
if cfg.DefaultSender != "" {
21+
t.Errorf("DefaultSender = %q, want empty string", cfg.DefaultSender)
22+
}
23+
if src := cfg.SourceOf("default_sender"); src != SourceDefault {
24+
t.Errorf("source = %q, want %q", src, SourceDefault)
25+
}
26+
}
27+
28+
func TestDefaultSenderFromGlobalConfig(t *testing.T) {
29+
tmp := t.TempDir()
30+
t.Setenv("XDG_CONFIG_HOME", tmp)
31+
t.Setenv("HEY_BASE_URL", "")
32+
33+
dir := filepath.Join(tmp, configDirName)
34+
if err := os.MkdirAll(dir, 0700); err != nil {
35+
t.Fatal(err)
36+
}
37+
38+
data, _ := json.Marshal(map[string]string{"default_sender": "erik@parrotapp.com"})
39+
if err := os.WriteFile(filepath.Join(dir, configFile), data, 0600); err != nil {
40+
t.Fatal(err)
41+
}
42+
43+
cfg, err := Load()
44+
if err != nil {
45+
t.Fatalf("Load: %v", err)
46+
}
47+
48+
if cfg.DefaultSender != "erik@parrotapp.com" {
49+
t.Errorf("DefaultSender = %q, want %q", cfg.DefaultSender, "erik@parrotapp.com")
50+
}
51+
if src := cfg.SourceOf("default_sender"); src != SourceGlobal {
52+
t.Errorf("source = %q, want %q", src, SourceGlobal)
53+
}
54+
}
55+
56+
func TestDefaultSenderSetFromFlag(t *testing.T) {
57+
tmp := t.TempDir()
58+
t.Setenv("XDG_CONFIG_HOME", tmp)
59+
t.Setenv("HEY_BASE_URL", "")
60+
61+
cfg, err := Load()
62+
if err != nil {
63+
t.Fatalf("Load: %v", err)
64+
}
65+
66+
if err := cfg.SetFromFlag("default_sender", "test@example.com"); err != nil {
67+
t.Fatalf("SetFromFlag: %v", err)
68+
}
69+
70+
if cfg.DefaultSender != "test@example.com" {
71+
t.Errorf("DefaultSender = %q, want %q", cfg.DefaultSender, "test@example.com")
72+
}
73+
if src := cfg.SourceOf("default_sender"); src != SourceFlag {
74+
t.Errorf("source = %q, want %q", src, SourceFlag)
75+
}
76+
}
77+
78+
func TestDefaultSenderUnset(t *testing.T) {
79+
tmp := t.TempDir()
80+
t.Setenv("XDG_CONFIG_HOME", tmp)
81+
t.Setenv("HEY_BASE_URL", "")
82+
83+
cfg, err := Load()
84+
if err != nil {
85+
t.Fatalf("Load: %v", err)
86+
}
87+
88+
// Set then unset
89+
if err := cfg.SetFromFlag("default_sender", "test@example.com"); err != nil {
90+
t.Fatalf("SetFromFlag: %v", err)
91+
}
92+
cfg.UnsetField("default_sender")
93+
94+
if cfg.DefaultSender != "" {
95+
t.Errorf("DefaultSender = %q after unset, want empty", cfg.DefaultSender)
96+
}
97+
if src := cfg.SourceOf("default_sender"); src != SourceDefault {
98+
t.Errorf("source = %q after unset, want %q", src, SourceDefault)
99+
}
100+
}
101+
102+
func TestDefaultSenderSaveAndReload(t *testing.T) {
103+
tmp := t.TempDir()
104+
t.Setenv("XDG_CONFIG_HOME", tmp)
105+
t.Setenv("HEY_BASE_URL", "")
106+
107+
cfg, err := Load()
108+
if err != nil {
109+
t.Fatalf("Load: %v", err)
110+
}
111+
112+
if err := cfg.SetFromFlag("default_sender", "saved@example.com"); err != nil {
113+
t.Fatalf("SetFromFlag: %v", err)
114+
}
115+
if err := cfg.Save(); err != nil {
116+
t.Fatalf("Save: %v", err)
117+
}
118+
119+
// Reload and verify persistence
120+
cfg2, err := Load()
121+
if err != nil {
122+
t.Fatalf("Load after save: %v", err)
123+
}
124+
125+
if cfg2.DefaultSender != "saved@example.com" {
126+
t.Errorf("DefaultSender after reload = %q, want %q", cfg2.DefaultSender, "saved@example.com")
127+
}
128+
}
129+
130+
func TestDefaultSenderOmittedFromJSONWhenEmpty(t *testing.T) {
131+
tmp := t.TempDir()
132+
t.Setenv("XDG_CONFIG_HOME", tmp)
133+
t.Setenv("HEY_BASE_URL", "")
134+
135+
cfg, err := Load()
136+
if err != nil {
137+
t.Fatalf("Load: %v", err)
138+
}
139+
140+
// Save with empty default_sender
141+
if err := cfg.Save(); err != nil {
142+
t.Fatalf("Save: %v", err)
143+
}
144+
145+
// Read the raw JSON and verify default_sender is not present
146+
configPath := filepath.Join(tmp, configDirName, configFile)
147+
data, err := os.ReadFile(configPath)
148+
if err != nil {
149+
t.Fatalf("ReadFile: %v", err)
150+
}
151+
152+
var raw map[string]any
153+
if err := json.Unmarshal(data, &raw); err != nil {
154+
t.Fatalf("Unmarshal: %v", err)
155+
}
156+
157+
if _, exists := raw["default_sender"]; exists {
158+
t.Errorf("default_sender should be omitted from JSON when empty, got: %s", string(data))
159+
}
160+
}
161+
162+
func TestDefaultSenderInValues(t *testing.T) {
163+
tmp := t.TempDir()
164+
t.Setenv("XDG_CONFIG_HOME", tmp)
165+
t.Setenv("HEY_BASE_URL", "")
166+
167+
cfg, err := Load()
168+
if err != nil {
169+
t.Fatalf("Load: %v", err)
170+
}
171+
172+
if err := cfg.SetFromFlag("default_sender", "val@example.com"); err != nil {
173+
t.Fatalf("SetFromFlag: %v", err)
174+
}
175+
176+
values := cfg.Values()
177+
// Should have at least 2 values (base_url + default_sender)
178+
if len(values) < 2 {
179+
t.Fatalf("Values() returned %d entries, want at least 2", len(values))
180+
}
181+
182+
found := false
183+
for _, v := range values {
184+
if v.Value == "val@example.com" {
185+
found = true
186+
if v.Source != SourceFlag {
187+
t.Errorf("default_sender source = %q, want %q", v.Source, SourceFlag)
188+
}
189+
}
190+
}
191+
if !found {
192+
t.Error("default_sender not found in Values() output")
193+
}
194+
}

0 commit comments

Comments
 (0)