summaryrefslogtreecommitdiff
path: root/cmd/hexai-tmux-action/main_test.go
blob: e1c02e18e036c515b334cca278b198a1f99dee49 (plain)
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
128
129
130
131
132
133
134
135
136
137
138
139
140
package main

import (
	"bytes"
	"context"
	"errors"
	"io"
	"strings"
	"testing"

	"codeberg.org/snonux/hexai/internal/hexaiaction"
)

func TestRun_DelegatesToRunCommand(t *testing.T) {
	old := runCommand
	t.Cleanup(func() { runCommand = old })

	var gotOpts hexaiaction.Options
	runCommand = func(_ context.Context, opts hexaiaction.Options, _ io.Reader, _, _ io.Writer) error {
		gotOpts = opts
		return nil
	}

	opts := actionOptions{
		infile: "in.txt", outfile: "out.txt",
		tmuxPopupWidth: "90%", tmuxPopupHeight: "70%",
	}
	if err := run(opts, nil, nil, nil); err != nil {
		t.Fatalf("run: %v", err)
	}
	if gotOpts.Infile != "in.txt" || gotOpts.Outfile != "out.txt" {
		t.Fatalf("unexpected opts: %+v", gotOpts)
	}
	if gotOpts.TmuxPopupWidth != "90%" || gotOpts.TmuxPopupHeight != "70%" {
		t.Fatalf("unexpected tmux opts: %+v", gotOpts)
	}
}

func TestRun_WithConfigPath(t *testing.T) {
	old := runCommand
	t.Cleanup(func() { runCommand = old })

	runCommand = func(_ context.Context, _ hexaiaction.Options, _ io.Reader, _, _ io.Writer) error {
		return nil
	}

	opts := actionOptions{configPath: "  /tmp/test.toml  "}
	if err := run(opts, nil, nil, nil); err != nil {
		t.Fatalf("run: %v", err)
	}
}

func TestRun_Error(t *testing.T) {
	old := runCommand
	t.Cleanup(func() { runCommand = old })

	wantErr := errors.New("action failed")
	runCommand = func(_ context.Context, _ hexaiaction.Options, _ io.Reader, _, _ io.Writer) error {
		return wantErr
	}

	if err := run(actionOptions{}, nil, nil, nil); !errors.Is(err, wantErr) {
		t.Fatalf("expected error, got: %v", err)
	}
}

// runMain happy path: every flag is forwarded into hexaiaction.Options and
// the stub returns 0. The captured Options confirm the field-by-field
// mapping that main relies on.
func TestRunMain_FlagsForwardedToHexaiaction(t *testing.T) {
	old := runCommand
	t.Cleanup(func() { runCommand = old })

	var got hexaiaction.Options
	runCommand = func(_ context.Context, opts hexaiaction.Options, _ io.Reader, _, _ io.Writer) error {
		got = opts
		return nil
	}

	args := []string{
		"-infile", "in.txt",
		"-outfile", "out.txt",
		"-tmux-target", "%2",
		"-tmux-popup-width", "70%",
		"-tmux-popup-height", "40%",
		"-ui-child",
	}
	var stderr bytes.Buffer
	code := runMain(args, nil, &bytes.Buffer{}, &stderr)
	if code != 0 {
		t.Fatalf("runMain code = %d, want 0; stderr=%q", code, stderr.String())
	}
	if got.Infile != "in.txt" || got.Outfile != "out.txt" {
		t.Fatalf("infile/outfile mismatch: %+v", got)
	}
	if got.TmuxTarget != "%2" || got.TmuxPopupWidth != "70%" || got.TmuxPopupHeight != "40%" {
		t.Fatalf("tmux flags mismatch: %+v", got)
	}
	if !got.UIChild {
		t.Fatal("expected UIChild=true")
	}
}

// On runCommand failure, runMain returns 1 (the production exit code) and
// writes the error message to stderr so users see what went wrong.
func TestRunMain_RuntimeErrorReturnsOne(t *testing.T) {
	old := runCommand
	t.Cleanup(func() { runCommand = old })
	runCommand = func(context.Context, hexaiaction.Options, io.Reader, io.Writer, io.Writer) error {
		return errors.New("action exploded")
	}

	var stderr bytes.Buffer
	code := runMain(nil, nil, &bytes.Buffer{}, &stderr)
	if code != 1 {
		t.Fatalf("runMain code = %d, want 1", code)
	}
	if !strings.Contains(stderr.String(), "action exploded") {
		t.Fatalf("stderr missing error: %q", stderr.String())
	}
}

// Bad flag must yield exit 2 without ever invoking runCommand.
func TestRunMain_BadFlagReturnsTwo(t *testing.T) {
	old := runCommand
	t.Cleanup(func() { runCommand = old })
	called := false
	runCommand = func(context.Context, hexaiaction.Options, io.Reader, io.Writer, io.Writer) error {
		called = true
		return nil
	}
	var stderr bytes.Buffer
	code := runMain([]string{"--bogus"}, nil, &bytes.Buffer{}, &stderr)
	if code != 2 {
		t.Fatalf("runMain code = %d, want 2", code)
	}
	if called {
		t.Fatal("runCommand must not be called on flag-parse failure")
	}
}