summaryrefslogtreecommitdiff
path: root/internal/shell/shell_internal_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-22 20:21:34 +0200
committerPaul Buetow <paul@buetow.org>2026-02-22 20:21:34 +0200
commit3373b7e90c4e1ff1abcebe0594316131f546dfa8 (patch)
tree8acc26309fce0048f156e5cec2acca9a5d891628 /internal/shell/shell_internal_test.go
parent528a9c0888f1db2449d30bf9c0c8b55fcd3c645c (diff)
Add unit tests to reach 63.3% coverage (task 335)
- internal/shell/shell_internal_test.go (new): tests prefixCompleter.Do with table-driven cases covering empty prefix, partial match, no match, and multi-word line (prefix after space) - internal/cli/cli_test.go (new): tests pure helpers (logMsg, warn, printHelp, shredFile), dispatch paths with real store (ls, search, cat, rm, shred, get, paste, export, pathexport, open, edit, unknown command, empty argv), error paths for cmdAdd/cmdImport/cmdImportR, readPIN env-var path, completionFn commands-only path, makeActionFn nil cases - internal/store/store_test.go: added TestSearchActionPathExport, TestSearchActionWithCallback, TestSearchActionNilCallback, TestFzfEmpty, TestRemoveInteractiveInvalidThenDecline, TestImportForceOverwrite Total coverage: 44.8% → 63.3% Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat (limited to 'internal/shell/shell_internal_test.go')
-rw-r--r--internal/shell/shell_internal_test.go106
1 files changed, 106 insertions, 0 deletions
diff --git a/internal/shell/shell_internal_test.go b/internal/shell/shell_internal_test.go
new file mode 100644
index 0000000..73284d7
--- /dev/null
+++ b/internal/shell/shell_internal_test.go
@@ -0,0 +1,106 @@
+// package shell (internal test) exercises unexported types that cannot be
+// reached from the external shell_test package.
+package shell
+
+import (
+ "strings"
+ "testing"
+)
+
+// TestPrefixCompleterDo exercises the Do method of prefixCompleter against a
+// fixed candidate list. No TTY is required because the method is pure logic.
+func TestPrefixCompleterDo(t *testing.T) {
+ candidates := []string{"add", "edit", "export", "ls", "search"}
+
+ p := &prefixCompleter{
+ fn: func(prefix string) []string {
+ var out []string
+ for _, c := range candidates {
+ if strings.HasPrefix(c, prefix) {
+ out = append(out, c)
+ }
+ }
+ return out
+ },
+ }
+
+ cases := []struct {
+ name string
+ line string // full line up to cursor
+ wantSuffix []string
+ wantLen int
+ }{
+ {
+ // Empty input: all candidates returned; each suffix is the full word + space.
+ name: "empty prefix",
+ line: "",
+ wantSuffix: []string{"add ", "edit ", "export ", "ls ", "search "},
+ wantLen: 0,
+ },
+ {
+ // "e" prefix: edit, export.
+ name: "single char prefix",
+ line: "e",
+ wantSuffix: []string{"dit ", "xport "},
+ wantLen: 1,
+ },
+ {
+ // "ex" prefix: only export.
+ name: "two char prefix",
+ line: "ex",
+ wantSuffix: []string{"port "},
+ wantLen: 2,
+ },
+ {
+ // "z" prefix: no matches.
+ name: "no match",
+ line: "z",
+ wantSuffix: nil,
+ wantLen: 1,
+ },
+ {
+ // Line has a space: prefix is the word after the last space.
+ // "cat e" → prefix is "e", completions for "e".
+ name: "prefix after space",
+ line: "cat e",
+ wantSuffix: []string{"dit ", "xport "},
+ wantLen: 1,
+ },
+ }
+
+ for _, tc := range cases {
+ t.Run(tc.name, func(t *testing.T) {
+ line := []rune(tc.line)
+ pos := len(line)
+ newLine, length := p.Do(line, pos)
+
+ if length != tc.wantLen {
+ t.Errorf("length = %d; want %d", length, tc.wantLen)
+ }
+ if len(newLine) != len(tc.wantSuffix) {
+ t.Errorf("len(newLine) = %d; want %d (%v vs %v)",
+ len(newLine), len(tc.wantSuffix), toStrings(newLine), tc.wantSuffix)
+ return
+ }
+ // Build a set for order-independent comparison.
+ got := make(map[string]bool, len(newLine))
+ for _, r := range newLine {
+ got[string(r)] = true
+ }
+ for _, want := range tc.wantSuffix {
+ if !got[want] {
+ t.Errorf("missing suffix %q in completions %v", want, toStrings(newLine))
+ }
+ }
+ })
+ }
+}
+
+// toStrings converts a [][]rune to []string for readable error output.
+func toStrings(runes [][]rune) []string {
+ out := make([]string, len(runes))
+ for i, r := range runes {
+ out[i] = string(r)
+ }
+ return out
+}