Files
SerialTerminalForWindowsTer…/config_test.go
T
JiXieShi 31dd9da490 refactor: extract internal/config and eliminate global config var
Move Config struct to internal/config with exported fields. Replace
global var config with package-level cfg pointer. Add OpenLogFile to
config package. Add type alias Config = appconfig.Config in main
package for backward compatibility.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 21:45:08 +08:00

242 lines
5.7 KiB
Go

package main
import (
"os"
"path/filepath"
"testing"
"github.com/spf13/pflag"
appconfig "github.com/jixishi/SerialTerminalForWindowsTerminal/internal/config"
"github.com/jixishi/SerialTerminalForWindowsTerminal/pkg/forward"
)
func TestForwardModeNetworkAndString(t *testing.T) {
tests := []struct {
mode forward.Mode
network string
name string
}{
{mode: forward.None, network: "", name: "none"},
{mode: forward.TCP, network: "tcp", name: "tcp"},
{mode: forward.UDP, network: "udp", name: "udp"},
}
for _, tt := range tests {
if got := tt.mode.Network(); got != tt.network {
t.Fatalf("Network() mode=%v got=%q want=%q", tt.mode, got, tt.network)
}
if got := tt.mode.String(); got != tt.name {
t.Fatalf("String() mode=%v got=%q want=%q", tt.mode, got, tt.name)
}
}
}
func TestParseForwardMode(t *testing.T) {
tests := []struct {
input string
mode forward.Mode
ok bool
}{
{input: "tcp", mode: forward.TCP, ok: true},
{input: "TCP-C", mode: forward.TCP, ok: true},
{input: "1", mode: forward.TCP, ok: true},
{input: "udp", mode: forward.UDP, ok: true},
{input: " 2 ", mode: forward.UDP, ok: true},
{input: "unknown", mode: forward.None, ok: false},
{input: "", mode: forward.None, ok: false},
}
for _, tt := range tests {
got, ok := forward.ParseMode(tt.input)
if ok != tt.ok || got != tt.mode {
t.Fatalf("forward.ParseMode(%q) got=(%v,%v) want=(%v,%v)", tt.input, got, ok, tt.mode, tt.ok)
}
}
}
func TestOpenLogFile(t *testing.T) {
old := *cfg
defer func() { *cfg = old }()
*cfg = Config{
EnableLog: true,
PortName: "COM1",
LogFilePath: filepath.Join(t.TempDir(), "%s-%s.log"),
}
f, err := appconfig.OpenLogFile(cfg)
if err != nil {
t.Fatalf("openLogFile() unexpected error: %v", err)
}
if f == nil {
t.Fatalf("openLogFile() got nil file when enableLog=true")
}
_ = f.Close()
cfg.EnableLog = false
f, err = appconfig.OpenLogFile(cfg)
if err != nil {
t.Fatalf("openLogFile() unexpected error with enableLog=false: %v", err)
}
if f != nil {
t.Fatalf("openLogFile() expected nil file when enableLog=false")
}
}
func TestFlagFindValue(t *testing.T) {
s := "str"
sl := []string{"a"}
n := 1
il := []int{1}
b := true
ext := "ext"
tests := []struct {
name string
v ptrVal
want ValType
}{
{name: "string", v: ptrVal{string: &s}, want: stringVal},
{name: "stringSlice", v: ptrVal{sl: &sl}, want: sliceStrVal},
{name: "bool", v: ptrVal{bool: &b}, want: boolVal},
{name: "int", v: ptrVal{int: &n}, want: intVal},
{name: "intSlice", v: ptrVal{il: &il}, want: sliceIntVal},
{name: "ext", v: ptrVal{ext: &ext}, want: extVal},
{name: "none", v: ptrVal{}, want: notVal},
}
for _, tt := range tests {
got := flagFindValue(tt.v)
if got != tt.want {
t.Fatalf("%s: flagFindValue got=%v want=%v", tt.name, got, tt.want)
}
}
}
func TestFlagExt(t *testing.T) {
old := *cfg
defer func() { *cfg = old }()
*cfg = Config{}
flagExt()
if cfg.EnableLog {
t.Fatalf("expected enableLog=false when logFilePath empty")
}
if cfg.TimesTamp {
t.Fatalf("expected timesTamp=false when timesFmt empty")
}
if cfg.HotkeyMod != "ctrl+alt" {
t.Fatalf("expected default hotkeyMod=ctrl+alt, got=%q", cfg.HotkeyMod)
}
*cfg = Config{LogFilePath: "/tmp/log.txt"}
flagExt()
if !cfg.EnableLog {
t.Fatalf("expected enableLog=true when logFilePath set")
}
*cfg = Config{TimesFmt: "2006-01-02"}
flagExt()
if !cfg.TimesTamp {
t.Fatalf("expected timesTamp=true when timesFmt set")
}
*cfg = Config{HotkeyMod: ""}
flagExt()
if cfg.HotkeyMod != "ctrl+alt" {
t.Fatalf("empty hotkeyMod should default to ctrl+alt")
}
*cfg = Config{HotkeyMod: "ctrl+shift"}
flagExt()
if cfg.HotkeyMod != "ctrl+shift" {
t.Fatalf("expected ctrl+shift preserved")
}
*cfg = Config{HotkeyMod: " CTRL+SHIFT "}
flagExt()
if cfg.HotkeyMod != "ctrl+shift" {
t.Fatalf("expected whitespace+case normalization, got=%q", cfg.HotkeyMod)
}
*cfg = Config{HotkeyMod: "invalid"}
flagExt()
if cfg.HotkeyMod != "ctrl+alt" {
t.Fatalf("invalid hotkeyMod should default to ctrl+alt, got=%q", cfg.HotkeyMod)
}
}
func TestFlagInit(t *testing.T) {
var testStr string
var testBool bool
var testInt int
var testExt string
var testSl []string
var testIl []int
f := Flag{
v: ptrVal{string: &testStr},
sStr: "X", lStr: "test-str", dv: Val{string: "hello"}, help: "test string",
}
flagInit(&f)
if pflag.Lookup("test-str") == nil {
t.Fatalf("string flag not registered")
}
boolF := Flag{
v: ptrVal{bool: &testBool},
sStr: "Y", lStr: "test-bool", dv: Val{bool: true}, help: "test bool",
}
flagInit(&boolF)
intF := Flag{
v: ptrVal{int: &testInt},
sStr: "Z", lStr: "test-int", dv: Val{int: 42}, help: "test int",
}
flagInit(&intF)
extF := Flag{
v: ptrVal{ext: &testExt},
sStr: "E", lStr: "test-ext", dv: Val{extdef: "default-val", string: ""}, help: "test ext",
}
flagInit(&extF)
slF := Flag{
v: ptrVal{sl: &testSl},
sStr: "1", lStr: "test-sl", dv: Val{string: "a"}, help: "test sl",
}
flagInit(&slF)
ilF := Flag{
v: ptrVal{il: &testIl},
sStr: "2", lStr: "test-il", dv: Val{int: 1}, help: "test il",
}
flagInit(&ilF)
}
func TestNormalizeFlags(t *testing.T) {
oldArgs := os.Args
defer func() { os.Args = oldArgs }()
os.Args = []string{"COM.exe", "-port", "COM17", "-baud", "9600", "-p", "COM1", "--gui", "COM17"}
normalizeFlags()
args := os.Args
if args[1] != "--port" {
t.Fatalf("expected -port -> --port, got %q", args[1])
}
if args[3] != "--baud" {
t.Fatalf("expected -baud -> --baud, got %q", args[3])
}
if args[5] != "-p" {
t.Fatalf("expected -p unchanged, got %q", args[5])
}
if args[7] != "--gui" {
t.Fatalf("expected --gui unchanged, got %q", args[7])
}
if args[8] != "COM17" {
t.Fatalf("expected value unchanged, got %q", args[8])
}
}