test(cmd): add unit tests for completion, root execution, config, errors, and logger
- Add tests for shell completion generation in completion_test.go - Add tests for root command execution and flags in root_test.go - Expand config tests for temperature, timeout, and log level getters - Add APIError unwrap test in errors_test.go - Add WithContext tests in logger_test.go - Stage test output artifact in .output.txt
This commit is contained in:
parent
c54bc511c9
commit
ebb0cbcf3a
300
.output.txt
Normal file
300
.output.txt
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
=== RUN TestAgentCommand_PlanGeneration
|
||||||
|
agent_test.go:8: Agent plan generation test placeholder — ready for expansion
|
||||||
|
--- PASS: TestAgentCommand_PlanGeneration (0.00s)
|
||||||
|
=== RUN TestAgentCommand_CleanCodeResponseIntegration
|
||||||
|
--- PASS: TestAgentCommand_CleanCodeResponseIntegration (0.00s)
|
||||||
|
=== RUN TestGetChatHistoryFile
|
||||||
|
--- PASS: TestGetChatHistoryFile (0.00s)
|
||||||
|
=== RUN TestLoadChatHistory_NoFile
|
||||||
|
--- PASS: TestLoadChatHistory_NoFile (0.00s)
|
||||||
|
=== RUN TestSaveAndLoadChatHistory
|
||||||
|
--- PASS: TestSaveAndLoadChatHistory (0.00s)
|
||||||
|
=== RUN TestLoadChatHistory_InvalidJSON
|
||||||
|
--- PASS: TestLoadChatHistory_InvalidJSON (0.00s)
|
||||||
|
=== RUN TestBuildCommitMessages
|
||||||
|
=== RUN TestBuildCommitMessages/normal_diff
|
||||||
|
=== RUN TestBuildCommitMessages/empty_diff
|
||||||
|
--- PASS: TestBuildCommitMessages (0.00s)
|
||||||
|
--- PASS: TestBuildCommitMessages/normal_diff (0.00s)
|
||||||
|
--- PASS: TestBuildCommitMessages/empty_diff (0.00s)
|
||||||
|
=== RUN TestBuildDocsMessages
|
||||||
|
=== RUN TestBuildDocsMessages/Go
|
||||||
|
=== RUN TestBuildDocsMessages/Python
|
||||||
|
=== RUN TestBuildDocsMessages/C
|
||||||
|
=== RUN TestBuildDocsMessages/C++
|
||||||
|
=== RUN TestBuildDocsMessages/JavaScript
|
||||||
|
=== RUN TestBuildDocsMessages/TypeScript
|
||||||
|
=== RUN TestBuildDocsMessages/Rust
|
||||||
|
=== RUN TestBuildDocsMessages/Ruby
|
||||||
|
=== RUN TestBuildDocsMessages/Java
|
||||||
|
=== RUN TestBuildDocsMessages/Shell
|
||||||
|
--- PASS: TestBuildDocsMessages (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/Go (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/Python (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/C (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/C++ (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/JavaScript (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/TypeScript (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/Rust (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/Ruby (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/Java (0.00s)
|
||||||
|
--- PASS: TestBuildDocsMessages/Shell (0.00s)
|
||||||
|
=== RUN TestDocStyle
|
||||||
|
=== RUN TestDocStyle/go
|
||||||
|
=== RUN TestDocStyle/Go
|
||||||
|
=== RUN TestDocStyle/python
|
||||||
|
=== RUN TestDocStyle/c
|
||||||
|
=== RUN TestDocStyle/c++
|
||||||
|
=== RUN TestDocStyle/javascript
|
||||||
|
=== RUN TestDocStyle/typescript
|
||||||
|
=== RUN TestDocStyle/rust
|
||||||
|
=== RUN TestDocStyle/ruby
|
||||||
|
=== RUN TestDocStyle/java
|
||||||
|
=== RUN TestDocStyle/shell
|
||||||
|
=== RUN TestDocStyle/bash
|
||||||
|
=== RUN TestDocStyle/unknown
|
||||||
|
--- PASS: TestDocStyle (0.00s)
|
||||||
|
--- PASS: TestDocStyle/go (0.00s)
|
||||||
|
--- PASS: TestDocStyle/Go (0.00s)
|
||||||
|
--- PASS: TestDocStyle/python (0.00s)
|
||||||
|
--- PASS: TestDocStyle/c (0.00s)
|
||||||
|
--- PASS: TestDocStyle/c++ (0.00s)
|
||||||
|
--- PASS: TestDocStyle/javascript (0.00s)
|
||||||
|
--- PASS: TestDocStyle/typescript (0.00s)
|
||||||
|
--- PASS: TestDocStyle/rust (0.00s)
|
||||||
|
--- PASS: TestDocStyle/ruby (0.00s)
|
||||||
|
--- PASS: TestDocStyle/java (0.00s)
|
||||||
|
--- PASS: TestDocStyle/shell (0.00s)
|
||||||
|
--- PASS: TestDocStyle/bash (0.00s)
|
||||||
|
--- PASS: TestDocStyle/unknown (0.00s)
|
||||||
|
=== RUN TestRemoveLastModifiedComments
|
||||||
|
=== RUN TestRemoveLastModifiedComments/removes_last_modified_comment
|
||||||
|
=== RUN TestRemoveLastModifiedComments/removes_multiple_last_modified_comments
|
||||||
|
=== RUN TestRemoveLastModifiedComments/preserves_code_without_last_modified
|
||||||
|
=== RUN TestRemoveLastModifiedComments/handles_empty_string
|
||||||
|
=== RUN TestRemoveLastModifiedComments/preserves_other_comments
|
||||||
|
=== RUN TestRemoveLastModifiedComments/handles_line_with_only_last_modified
|
||||||
|
--- PASS: TestRemoveLastModifiedComments (0.00s)
|
||||||
|
--- PASS: TestRemoveLastModifiedComments/removes_last_modified_comment (0.00s)
|
||||||
|
--- PASS: TestRemoveLastModifiedComments/removes_multiple_last_modified_comments (0.00s)
|
||||||
|
--- PASS: TestRemoveLastModifiedComments/preserves_code_without_last_modified (0.00s)
|
||||||
|
--- PASS: TestRemoveLastModifiedComments/handles_empty_string (0.00s)
|
||||||
|
--- PASS: TestRemoveLastModifiedComments/preserves_other_comments (0.00s)
|
||||||
|
--- PASS: TestRemoveLastModifiedComments/handles_line_with_only_last_modified (0.00s)
|
||||||
|
=== RUN TestEditCommand
|
||||||
|
--- PASS: TestEditCommand (0.94s)
|
||||||
|
=== RUN TestBuildHistoryMessages
|
||||||
|
=== RUN TestBuildHistoryMessages/with_recent_commits
|
||||||
|
=== RUN TestBuildHistoryMessages/empty_log
|
||||||
|
--- PASS: TestBuildHistoryMessages (0.00s)
|
||||||
|
--- PASS: TestBuildHistoryMessages/with_recent_commits (0.00s)
|
||||||
|
--- PASS: TestBuildHistoryMessages/empty_log (0.00s)
|
||||||
|
=== RUN TestBuildLintFixMessages
|
||||||
|
=== RUN TestBuildLintFixMessages/go_file_with_issues
|
||||||
|
=== RUN TestBuildLintFixMessages/python_file_with_issues
|
||||||
|
--- PASS: TestBuildLintFixMessages (0.00s)
|
||||||
|
--- PASS: TestBuildLintFixMessages/go_file_with_issues (0.00s)
|
||||||
|
--- PASS: TestBuildLintFixMessages/python_file_with_issues (0.00s)
|
||||||
|
=== RUN TestBuildPRDescribeMessages
|
||||||
|
=== RUN TestBuildPRDescribeMessages/branch_with_changes
|
||||||
|
=== RUN TestBuildPRDescribeMessages/empty_diff
|
||||||
|
--- PASS: TestBuildPRDescribeMessages (0.00s)
|
||||||
|
--- PASS: TestBuildPRDescribeMessages/branch_with_changes (0.00s)
|
||||||
|
--- PASS: TestBuildPRDescribeMessages/empty_diff (0.00s)
|
||||||
|
=== RUN TestBuildReviewMessages
|
||||||
|
=== RUN TestBuildReviewMessages/with_status_and_diff
|
||||||
|
=== RUN TestBuildReviewMessages/empty_diff
|
||||||
|
--- PASS: TestBuildReviewMessages (0.00s)
|
||||||
|
--- PASS: TestBuildReviewMessages/with_status_and_diff (0.00s)
|
||||||
|
--- PASS: TestBuildReviewMessages/empty_diff (0.00s)
|
||||||
|
=== RUN TestExecute
|
||||||
|
=== RUN TestExecute/version
|
||||||
|
grokkit version dev (commit )\n=== RUN TestExecute/help
|
||||||
|
A fast, native Go CLI for Grok. Chat, edit files, and supercharge your git workflow.
|
||||||
|
Usage:
|
||||||
|
grokkit [command]
|
||||||
|
Available Commands:
|
||||||
|
agent Multi-file agent — Grok intelligently edits multiple files with preview
|
||||||
|
chat Simple interactive CLI chat with Grok (full history + streaming)
|
||||||
|
commit Generate message and commit staged changes
|
||||||
|
commit-msg Generate conventional commit message from staged changes
|
||||||
|
completion Generate shell completion script
|
||||||
|
docs Generate documentation comments for source files
|
||||||
|
edit Edit a file in-place with Grok (safe preview + backup)
|
||||||
|
help Help about any command
|
||||||
|
history Summarize recent git history
|
||||||
|
lint Lint a file and optionally apply AI-suggested fixes
|
||||||
|
pr-describe Generate full PR description from current branch
|
||||||
|
review Review the current repository or directory
|
||||||
|
testgen Generate AI unit tests for files (Go/Python/C/C++, preview/apply)
|
||||||
|
version Print the version information
|
||||||
|
Flags:
|
||||||
|
--debug Enable debug logging (logs to stderr and file)
|
||||||
|
-h, --help help for grokkit
|
||||||
|
-m, --model string Grok model to use (overrides config)
|
||||||
|
-v, --verbose Enable verbose logging
|
||||||
|
Use "grokkit [command] --help" for more information about a command.
|
||||||
|
=== RUN TestExecute/debug_flag
|
||||||
|
{"time":"2026-03-02T22:04:53.521338713Z","level":"INFO","msg":"grokkit starting","command":"version","log_level":"debug"}
|
||||||
|
grokkit version dev (commit )\n root_test.go:47: log level not debug:
|
||||||
|
{"time":"2026-03-02T22:04:53.521338713Z","level":"INFO","msg":"grokkit starting","command":"version","log_level":"debug"}
|
||||||
|
=== RUN TestExecute/verbose_flag
|
||||||
|
grokkit version dev (commit )\n root_test.go:47: log level not info:
|
||||||
|
{"time":"2026-03-02T22:04:53.521751225Z","level":"INFO","msg":"grokkit starting","command":"version","log_level":"info"}
|
||||||
|
--- FAIL: TestExecute (0.00s)
|
||||||
|
--- PASS: TestExecute/version (0.00s)
|
||||||
|
--- PASS: TestExecute/help (0.00s)
|
||||||
|
--- FAIL: TestExecute/debug_flag (0.00s)
|
||||||
|
--- FAIL: TestExecute/verbose_flag (0.00s)
|
||||||
|
=== RUN TestRunHistory
|
||||||
|
=== RUN TestRunHistory/calls_AI_with_log_output
|
||||||
|
Summarizing recent commits...
|
||||||
|
=== RUN TestRunHistory/no_commits_—_skips_AI
|
||||||
|
No commits found.
|
||||||
|
=== RUN TestRunHistory/git_error_—_skips_AI
|
||||||
|
Failed to get git log: not a git repo
|
||||||
|
--- PASS: TestRunHistory (0.00s)
|
||||||
|
--- PASS: TestRunHistory/calls_AI_with_log_output (0.00s)
|
||||||
|
--- PASS: TestRunHistory/no_commits_—_skips_AI (0.00s)
|
||||||
|
--- PASS: TestRunHistory/git_error_—_skips_AI (0.00s)
|
||||||
|
=== RUN TestRunReview
|
||||||
|
=== RUN TestRunReview/reviews_with_diff_and_status
|
||||||
|
Grok is reviewing the repo...
|
||||||
|
=== RUN TestRunReview/git_diff_error_—_skips_AI
|
||||||
|
Failed to get git diff: git error
|
||||||
|
=== RUN TestRunReview/git_status_error_—_skips_AI
|
||||||
|
Failed to get git status: git error
|
||||||
|
--- PASS: TestRunReview (0.00s)
|
||||||
|
--- PASS: TestRunReview/reviews_with_diff_and_status (0.00s)
|
||||||
|
--- PASS: TestRunReview/git_diff_error_—_skips_AI (0.00s)
|
||||||
|
--- PASS: TestRunReview/git_status_error_—_skips_AI (0.00s)
|
||||||
|
=== RUN TestRunCommit
|
||||||
|
=== RUN TestRunCommit/no_staged_changes_—_skips_AI
|
||||||
|
No staged changes!
|
||||||
|
=== RUN TestRunCommit/git_error_—_skips_AI
|
||||||
|
Failed to get staged changes: not a git repo
|
||||||
|
=== RUN TestRunCommit/with_staged_changes_—_calls_AI_then_cancels_via_stdin
|
||||||
|
Generating commit message...
|
||||||
|
Proposed commit message:
|
||||||
|
feat(cmd): add thing
|
||||||
|
Commit with this message? (y/n):
|
||||||
|
Aborted.
|
||||||
|
--- PASS: TestRunCommit (0.00s)
|
||||||
|
--- PASS: TestRunCommit/no_staged_changes_—_skips_AI (0.00s)
|
||||||
|
--- PASS: TestRunCommit/git_error_—_skips_AI (0.00s)
|
||||||
|
--- PASS: TestRunCommit/with_staged_changes_—_calls_AI_then_cancels_via_stdin (0.00s)
|
||||||
|
=== RUN TestRunCommitMsg
|
||||||
|
=== RUN TestRunCommitMsg/no_staged_changes_—_skips_AI
|
||||||
|
No staged changes!
|
||||||
|
=== RUN TestRunCommitMsg/with_staged_changes_—_calls_AI_and_prints_message
|
||||||
|
Generating commit message...
|
||||||
|
--- PASS: TestRunCommitMsg (0.00s)
|
||||||
|
--- PASS: TestRunCommitMsg/no_staged_changes_—_skips_AI (0.00s)
|
||||||
|
--- PASS: TestRunCommitMsg/with_staged_changes_—_calls_AI_and_prints_message (0.00s)
|
||||||
|
=== RUN TestRunPRDescribe
|
||||||
|
=== RUN TestRunPRDescribe/no_changes_on_branch_—_skips_AI
|
||||||
|
No changes on this branch compared to main/origin/main.
|
||||||
|
=== RUN TestRunPRDescribe/first_diff_succeeds_—_calls_AI
|
||||||
|
Writing PR description...
|
||||||
|
=== RUN TestRunPRDescribe/first_diff_empty,_second_succeeds_—_calls_AI
|
||||||
|
Writing PR description...
|
||||||
|
=== RUN TestRunPRDescribe/second_diff_error_—_skips_AI
|
||||||
|
Failed to get branch diff: no remote
|
||||||
|
--- PASS: TestRunPRDescribe (0.00s)
|
||||||
|
--- PASS: TestRunPRDescribe/no_changes_on_branch_—_skips_AI (0.00s)
|
||||||
|
--- PASS: TestRunPRDescribe/first_diff_succeeds_—_calls_AI (0.00s)
|
||||||
|
--- PASS: TestRunPRDescribe/first_diff_empty,_second_succeeds_—_calls_AI (0.00s)
|
||||||
|
--- PASS: TestRunPRDescribe/second_diff_error_—_skips_AI (0.00s)
|
||||||
|
=== RUN TestRunLintFileNotFound
|
||||||
|
❌ File not found: /nonexistent/path/file.go
|
||||||
|
--- PASS: TestRunLintFileNotFound (0.00s)
|
||||||
|
=== RUN TestProcessDocsFileNotFound
|
||||||
|
❌ File not found: /nonexistent/path/file.go
|
||||||
|
--- PASS: TestProcessDocsFileNotFound (0.00s)
|
||||||
|
=== RUN TestProcessDocsFileUnsupportedLanguage
|
||||||
|
⚠️ Skipping /tmp/test1496774039.xyz: unsupported file type: .xyz
|
||||||
|
--- PASS: TestProcessDocsFileUnsupportedLanguage (0.00s)
|
||||||
|
=== RUN TestProcessDocsFilePreviewAndCancel
|
||||||
|
📝 Generating Go docs for: /tmp/test2334651960.go
|
||||||
|
📋 Preview of documented code:
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
package main
|
||||||
|
// Foo does nothing.
|
||||||
|
func Foo() {}
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Apply documentation to /tmp/test2334651960.go? (y/N):
|
||||||
|
❌ Cancelled. No changes made to: /tmp/test2334651960.go
|
||||||
|
--- PASS: TestProcessDocsFilePreviewAndCancel (0.00s)
|
||||||
|
=== RUN TestProcessDocsFileAutoApply
|
||||||
|
📝 Generating Go docs for: /tmp/test2305422141.go
|
||||||
|
📋 Preview of documented code:
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
package main
|
||||||
|
// Bar does nothing.
|
||||||
|
func Bar() {}
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
✅ Documentation applied: /tmp/test2305422141.go
|
||||||
|
💾 Original saved to: /tmp/test2305422141.go.bak
|
||||||
|
--- PASS: TestProcessDocsFileAutoApply (0.00s)
|
||||||
|
=== RUN TestRunDocs
|
||||||
|
❌ File not found: /nonexistent/file.go
|
||||||
|
--- PASS: TestRunDocs (0.00s)
|
||||||
|
=== RUN TestRemoveSourceComments
|
||||||
|
=== PAUSE TestRemoveSourceComments
|
||||||
|
=== RUN TestGetTestPrompt
|
||||||
|
=== PAUSE TestGetTestPrompt
|
||||||
|
=== RUN TestGetTestFilePath
|
||||||
|
=== PAUSE TestGetTestFilePath
|
||||||
|
=== RUN TestGetCodeLang
|
||||||
|
=== PAUSE TestGetCodeLang
|
||||||
|
=== CONT TestRemoveSourceComments
|
||||||
|
=== RUN TestRemoveSourceComments/no_comments
|
||||||
|
=== CONT TestGetTestFilePath
|
||||||
|
=== RUN TestRemoveSourceComments/last_modified
|
||||||
|
=== CONT TestGetTestPrompt
|
||||||
|
=== RUN TestGetTestFilePath/foo.go_Go
|
||||||
|
=== RUN TestRemoveSourceComments/generated_by
|
||||||
|
=== CONT TestGetCodeLang
|
||||||
|
=== RUN TestRemoveSourceComments/multiple_removable_lines
|
||||||
|
=== RUN TestGetTestPrompt/Go
|
||||||
|
=== RUN TestGetTestFilePath/dir/foo.py_Python
|
||||||
|
=== RUN TestRemoveSourceComments/partial_match_no_remove
|
||||||
|
=== RUN TestGetCodeLang/Go
|
||||||
|
=== RUN TestRemoveSourceComments/python_testgen
|
||||||
|
=== RUN TestGetCodeLang/Python
|
||||||
|
=== RUN TestGetCodeLang/C
|
||||||
|
=== RUN TestGetTestFilePath/bar.c_C
|
||||||
|
=== RUN TestGetCodeLang/C++
|
||||||
|
--- PASS: TestGetCodeLang (0.00s)
|
||||||
|
--- PASS: TestGetCodeLang/Go (0.00s)
|
||||||
|
--- PASS: TestGetCodeLang/Python (0.00s)
|
||||||
|
--- PASS: TestGetCodeLang/C (0.00s)
|
||||||
|
--- PASS: TestGetCodeLang/C++ (0.00s)
|
||||||
|
=== RUN TestRemoveSourceComments/c_testgen
|
||||||
|
--- PASS: TestRemoveSourceComments (0.00s)
|
||||||
|
--- PASS: TestRemoveSourceComments/no_comments (0.00s)
|
||||||
|
--- PASS: TestRemoveSourceComments/last_modified (0.00s)
|
||||||
|
--- PASS: TestRemoveSourceComments/generated_by (0.00s)
|
||||||
|
--- PASS: TestRemoveSourceComments/multiple_removable_lines (0.00s)
|
||||||
|
--- PASS: TestRemoveSourceComments/partial_match_no_remove (0.00s)
|
||||||
|
--- PASS: TestRemoveSourceComments/python_testgen (0.00s)
|
||||||
|
--- PASS: TestRemoveSourceComments/c_testgen (0.00s)
|
||||||
|
=== RUN TestGetTestPrompt/Python
|
||||||
|
=== RUN TestGetTestFilePath/baz.cpp_C++
|
||||||
|
=== RUN TestGetTestPrompt/C
|
||||||
|
=== RUN TestGetTestPrompt/C++
|
||||||
|
--- PASS: TestGetTestFilePath (0.00s)
|
||||||
|
--- PASS: TestGetTestFilePath/foo.go_Go (0.00s)
|
||||||
|
--- PASS: TestGetTestFilePath/dir/foo.py_Python (0.00s)
|
||||||
|
--- PASS: TestGetTestFilePath/bar.c_C (0.00s)
|
||||||
|
--- PASS: TestGetTestFilePath/baz.cpp_C++ (0.00s)
|
||||||
|
=== RUN TestGetTestPrompt/Invalid
|
||||||
|
--- PASS: TestGetTestPrompt (0.00s)
|
||||||
|
--- PASS: TestGetTestPrompt/Go (0.00s)
|
||||||
|
--- PASS: TestGetTestPrompt/Python (0.00s)
|
||||||
|
--- PASS: TestGetTestPrompt/C (0.00s)
|
||||||
|
--- PASS: TestGetTestPrompt/C++ (0.00s)
|
||||||
|
--- PASS: TestGetTestPrompt/Invalid (0.00s)
|
||||||
|
FAIL
|
||||||
|
FAIL gmgauthier.com/grokkit/cmd 0.949s
|
||||||
|
FAIL
|
||||||
42
cmd/completion_test.go
Normal file
42
cmd/completion_test.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCompletionCmd(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
shell string
|
||||||
|
}{
|
||||||
|
{"bash"},
|
||||||
|
{"zsh"},
|
||||||
|
{"fish"},
|
||||||
|
{"powershell"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.shell, func(t *testing.T) {
|
||||||
|
oldStdout := os.Stdout
|
||||||
|
defer func() { os.Stdout = oldStdout }()
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
os.Stdout = w
|
||||||
|
defer w.Close()
|
||||||
|
cmd := &cobra.Command{}
|
||||||
|
completionCmd.Run(cmd, []string{tt.shell})
|
||||||
|
w.Close()
|
||||||
|
b, err := io.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(b) == 0 {
|
||||||
|
t.Error("expected non-empty completion script")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
52
cmd/root_test.go
Normal file
52
cmd/root_test.go
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func rootSetHomeForTest(t *testing.T, dir string) {
|
||||||
|
t.Helper()
|
||||||
|
if err := os.Setenv("HOME", dir); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExecute(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
exitCode int
|
||||||
|
wantLevel string
|
||||||
|
}{
|
||||||
|
{"version", []string{"version"}, 0, ""},
|
||||||
|
{"help", []string{}, 0, ""},
|
||||||
|
{"debug flag", []string{"version", "--debug"}, 0, "debug"},
|
||||||
|
{"verbose flag", []string{"version", "-v"}, 0, "info"},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
rootSetHomeForTest(t, tmpDir)
|
||||||
|
oldArgs := os.Args
|
||||||
|
os.Args = append([]string{"grokkit"}, tt.args...)
|
||||||
|
defer func() { os.Args = oldArgs }()
|
||||||
|
Execute()
|
||||||
|
if tt.wantLevel != "" {
|
||||||
|
logFile := filepath.Join(tmpDir, ".config", "grokkit", "grokkit.log")
|
||||||
|
content, err := os.ReadFile(logFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
str := string(content)
|
||||||
|
if !strings.Contains(str, fmt.Sprintf(`"log_level":"%s"`, tt.wantLevel)) {
|
||||||
|
t.Errorf("log level not %s:\n%s", tt.wantLevel, str)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -98,3 +98,56 @@ func TestLoad(t *testing.T) {
|
|||||||
// Just ensure Load doesn't panic
|
// Just ensure Load doesn't panic
|
||||||
Load()
|
Load()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetTemperature(t *testing.T) {
|
||||||
|
viper.Reset()
|
||||||
|
viper.SetDefault("temperature", 0.7)
|
||||||
|
got := GetTemperature()
|
||||||
|
if got != 0.7 {
|
||||||
|
t.Errorf("GetTemperature() default = %v, want 0.7", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
viper.Set("temperature", 0.8)
|
||||||
|
got = GetTemperature()
|
||||||
|
if got != 0.8 {
|
||||||
|
t.Errorf("GetTemperature() custom = %v, want 0.8", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetTimeout(t *testing.T) {
|
||||||
|
viper.Reset()
|
||||||
|
viper.SetDefault("timeout", 60)
|
||||||
|
|
||||||
|
got := GetTimeout()
|
||||||
|
if got != 60 {
|
||||||
|
t.Errorf("GetTimeout() default = %d, want 60", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
viper.Set("timeout", 30)
|
||||||
|
got = GetTimeout()
|
||||||
|
if got != 30 {
|
||||||
|
t.Errorf("GetTimeout() = %d, want 30", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
viper.Set("timeout", 0)
|
||||||
|
got = GetTimeout()
|
||||||
|
if got != 60 {
|
||||||
|
t.Errorf("GetTimeout() invalid = %d, want 60", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetLogLevel(t *testing.T) {
|
||||||
|
viper.Reset()
|
||||||
|
viper.SetDefault("log_level", "info")
|
||||||
|
|
||||||
|
got := GetLogLevel()
|
||||||
|
if got != "info" {
|
||||||
|
t.Errorf("GetLogLevel() default = %q, want info", got)
|
||||||
|
}
|
||||||
|
|
||||||
|
viper.Set("log_level", "debug")
|
||||||
|
got = GetLogLevel()
|
||||||
|
if got != "debug" {
|
||||||
|
t.Errorf("GetLogLevel() custom = %q, want debug", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -72,3 +72,15 @@ func TestFileError(t *testing.T) {
|
|||||||
t.Errorf("FileError.Unwrap() did not return base error")
|
t.Errorf("FileError.Unwrap() did not return base error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAPIErrorUnwrap(t *testing.T) {
|
||||||
|
baseErr := errors.New("base api err")
|
||||||
|
apiErr := &APIError{
|
||||||
|
StatusCode: 500,
|
||||||
|
Message: "internal error",
|
||||||
|
Err: baseErr,
|
||||||
|
}
|
||||||
|
if unwrap := apiErr.Unwrap(); unwrap != baseErr {
|
||||||
|
t.Errorf("APIError.Unwrap() = %v, want %v", unwrap, baseErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
package logger
|
package logger
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@ -118,3 +120,30 @@ func TestWith(t *testing.T) {
|
|||||||
t.Errorf("With() returned nil logger")
|
t.Errorf("With() returned nil logger")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestWithContext(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
oldHome := os.Getenv("HOME")
|
||||||
|
setHome(t, tmpDir)
|
||||||
|
defer func() { _ = os.Setenv("HOME", oldHome) }()
|
||||||
|
|
||||||
|
t.Run("without init", func(t *testing.T) {
|
||||||
|
logger = nil // ensure nil
|
||||||
|
ctx := context.Background()
|
||||||
|
l := WithContext(ctx)
|
||||||
|
if l != slog.Default() {
|
||||||
|
t.Errorf("WithContext without logger = %v, want slog.Default()", l)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("with init", func(t *testing.T) {
|
||||||
|
if err := Init("info"); err != nil {
|
||||||
|
t.Fatalf("Init() = %v", err)
|
||||||
|
}
|
||||||
|
ctx := context.Background()
|
||||||
|
l := WithContext(ctx)
|
||||||
|
if l == slog.Default() {
|
||||||
|
t.Errorf("WithContext with logger == slog.Default()")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user