-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain_test.go
More file actions
127 lines (101 loc) · 3.11 KB
/
main_test.go
File metadata and controls
127 lines (101 loc) · 3.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main
import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"github.com/spf13/viper"
)
func resetForTest(t *testing.T) string {
t.Helper()
// Isolate filesystem writes (config + history) per test
tmpDir := t.TempDir()
t.Setenv("HOW_CONFIG_DIR", tmpDir)
// Reset global flags/state that can leak between tests
modelFlag = ""
debug = false
runFlag = false
yesFlag = false
// Reset viper to avoid cross-test contamination, then re-init config
viper.Reset()
initConfig()
return tmpDir
}
func TestRoot_NoArgs_ShowsHelp(t *testing.T) {
_ = resetForTest(t)
bOut, bErr := &bytes.Buffer{}, &bytes.Buffer{}
rootCmd.SetOut(bOut)
rootCmd.SetErr(bErr)
rootCmd.SetArgs([]string{})
_, _ = rootCmd.ExecuteC()
all := bOut.String() + bErr.String()
if !strings.Contains(all, "how [query...]") {
t.Fatalf("expected help text, got: %s", all)
}
}
func TestRoot_MissingAPIKey_Errors(t *testing.T) {
_ = resetForTest(t)
viper.Set("api_key", "")
rootCmd.SetArgs([]string{"echo", "hi"})
_, err := rootCmd.ExecuteC()
if err == nil || !strings.Contains(err.Error(), "API key not found") {
t.Fatalf("expected missing key error, got: %v", err)
}
}
func TestSetModel_WritesConfigToConfigDir(t *testing.T) {
cfgDir := resetForTest(t)
// Ensure API key presence doesn't matter for set-model
viper.Set("api_key", "")
rootCmd.SetArgs([]string{"set-model", "new-model"})
_, err := rootCmd.ExecuteC()
if err != nil {
t.Fatalf("expected no error, got: %v", err)
}
// With HOW_CONFIG_DIR, config should be written here:
cfgPath := filepath.Join(cfgDir, "config.yaml")
b, err := os.ReadFile(cfgPath)
if err != nil {
t.Fatalf("expected config file at %s, read error: %v", cfgPath, err)
}
if !strings.Contains(string(b), "model: new-model") {
t.Fatalf("expected model in config, got:\n%s", string(b))
}
}
func TestLast_NoHistory_Errors(t *testing.T) {
_ = resetForTest(t)
rootCmd.SetArgs([]string{"last"})
_, err := rootCmd.ExecuteC()
if err == nil || !strings.Contains(err.Error(), "no history yet") {
t.Fatalf("expected no history error, got: %v", err)
}
}
func TestRoot_Query_PrintsCommand_AndAppendsHistory(t *testing.T) {
cfgDir := resetForTest(t)
// Stub out the LLM call so we don't hit network.
orig := llmQuery
t.Cleanup(func() { llmQuery = orig })
llmQuery = func(endpoint, apiKey, query, model string, refererNeeded bool) (string, error) {
return "echo hi", nil
}
viper.Set("api_key", "dummy-test-key")
bOut, bErr := &bytes.Buffer{}, &bytes.Buffer{}
rootCmd.SetOut(bOut)
rootCmd.SetErr(bErr)
rootCmd.SetArgs([]string{"say", "hi"})
_, err := rootCmd.ExecuteC()
if err != nil {
t.Fatalf("expected no error, got: %v", err)
}
if strings.TrimSpace(bOut.String()) != "echo hi" {
t.Fatalf("expected printed command %q, got %q", "echo hi", bOut.String())
}
histPath := filepath.Join(cfgDir, "history.jsonl")
hb, err := os.ReadFile(histPath)
if err != nil {
t.Fatalf("expected history file at %s, read error: %v\nstderr:%s", histPath, err, bErr.String())
}
if !strings.Contains(string(hb), `"command":"echo hi"`) {
t.Fatalf("expected history to contain command, got:\n%s", string(hb))
}
}