// Copyright 2025 eat-pray-ai & OpenWaygate // SPDX-License-Identifier: Apache-2.0 package utils import ( "bytes" "errors" "fmt" "io" "os" "reflect" "strings" "testing" "github.com/spf13/cobra" "github.com/spf13/pflag" ) func TestStrToBoolPtr(t *testing.T) { type args struct { b *string } tests := []struct { name string args args want *bool }{ { name: "true", args: args{b: new("true")}, want: func() *bool { b := true return &b }(), }, { name: "false", args: args{b: new("false")}, want: func() *bool { b := false return &b }(), }, { name: "empty", args: args{b: new("")}, want: nil, }, { name: "null", args: args{b: new("null")}, want: nil, }, { name: "NULL", args: args{b: new("NULL")}, want: nil, }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { if got := StrToBoolPtr(tt.args.b); !reflect.DeepEqual(got, tt.want) { t.Errorf("BoolPtr() = %v, want %v", got, tt.want) } }, ) } } func TestGetFileName(t *testing.T) { type args struct { file string } tests := []struct { name string args args want string }{ { name: "with extension", args: args{file: "example.txt"}, want: "example", }, { name: "without extension", args: args{file: "example"}, want: "example", }, { name: "with path", args: args{file: "/foo/bar/example.txt"}, want: "example", }, { name: "double extension", args: args{file: "archive.tar.gz"}, want: "archive.tar", }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { if got := GetFileName(tt.args.file); got != tt.want { t.Errorf("GetFileName() = %v, want %v", got, tt.want) } }, ) } } func TestIsJson(t *testing.T) { type args struct { s string } tests := []struct { name string args args want bool }{ { name: "valid json", args: args{s: `{"key": "value"}`}, want: true, }, { name: "invalid json", args: args{s: `{"key": "value"`}, want: false, }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { if got := IsJson(tt.args.s); got != tt.want { t.Errorf("IsJson() = %v, want %v", got, tt.want) } }, ) } } func TestIsInteractive(t *testing.T) { devNull, _ := os.Open(os.DevNull) defer func() { _ = devNull.Close() }() tests := []struct { name string writer io.Writer ci string want bool }{ { name: "bytes.Buffer is non-interactive", writer: &bytes.Buffer{}, want: false, }, { name: "os.File without TTY is non-interactive", writer: devNull, want: false, }, { name: "CI env forces non-interactive", writer: os.Stdout, ci: "true", want: false, }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { if tt.ci != "" { t.Setenv("CI", tt.ci) } if got := IsInteractive(tt.writer); got != tt.want { t.Errorf("IsInteractive() = %v, want %v", got, tt.want) } }, ) } } func TestPrintJSON(t *testing.T) { tests := []struct { name string data any interactive bool wantWriter string }{ { name: "interactive indented json", data: map[string]string{"key": "value"}, interactive: true, wantWriter: "{\n \"key\": \"value\"\n}\n", }, { name: "non-interactive compact json", data: map[string]string{"key": "value"}, interactive: false, wantWriter: "{\"key\":\"value\"}\n", }, { name: "nil data interactive", data: nil, interactive: true, wantWriter: "null\n", }, { name: "nil data non-interactive", data: nil, interactive: false, wantWriter: "null\n", }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { orig := IsInteractive IsInteractive = func(any) bool { return tt.interactive } defer func() { IsInteractive = orig }() writer := &bytes.Buffer{} PrintJSON(tt.data, writer) if gotWriter := writer.String(); gotWriter != tt.wantWriter { t.Errorf("PrintJSON() = %v, want %v", gotWriter, tt.wantWriter) } }, ) } } func TestPrintYAML(t *testing.T) { tests := []struct { name string data any wantWriter string }{ { name: "simple yaml", data: map[string]string{"key": "value"}, wantWriter: "key: value\n\n", }, { name: "nil data", data: nil, wantWriter: "null\n\n", }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { writer := &bytes.Buffer{} PrintYAML(tt.data, writer) if gotWriter := writer.String(); gotWriter != tt.wantWriter { t.Errorf("PrintYAML() = %v, want %v", gotWriter, tt.wantWriter) } }, ) } } func TestResetBool(t *testing.T) { type args struct { m map[string]**bool flagSet *pflag.FlagSet } b := new(true) cmd := &cobra.Command{} cmd.Flags().BoolVar(b, "flag", false, "") tests := []struct { name string args args }{ { name: "reset bool flags", args: args{ m: map[string]**bool{ "flag": &b, }, flagSet: cmd.Flags(), }, }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { ResetBool(tt.args.m, tt.args.flagSet) if b != nil { t.Errorf("ResetBool() = %v, want nil", *b) } }, ) } } func TestExtractHl(t *testing.T) { type args struct { uri string } tests := []struct { name string args args want string }{ { name: "valid language uri with hl", args: args{uri: "i18n://language/zh-CN"}, want: "zh-CN", }, { name: "valid region uri with hl", args: args{uri: "i18n://region/zh-CN"}, want: "zh-CN", }, { name: "valid language uri without hl", args: args{uri: "i18n://language/"}, want: "", }, { name: "valid region uri without hl", args: args{uri: "i18n://region/"}, want: "", }, { name: "invalid uri", args: args{uri: "i18n://invalid/zh-CN"}, want: "", }, { name: "empty uri", args: args{uri: ""}, want: "", }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { if got := ExtractHl(tt.args.uri); got != tt.want { t.Errorf("ExtractHl() = %v, want %v", got, tt.want) } }, ) } } func TestBoolToStrPtr(t *testing.T) { bTrue := true bFalse := false type args struct { b *bool } tests := []struct { name string args args want *string }{ { name: "true", args: args{b: &bTrue}, want: new("true"), }, { name: "false", args: args{b: &bFalse}, want: new("false"), }, { name: "nil", args: args{b: nil}, want: new(""), }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { if got := BoolToStrPtr(tt.args.b); !reflect.DeepEqual(got, tt.want) { t.Errorf("BoolToStrPtr() = %v, want %v", got, tt.want) } }, ) } } func TestRandomStage(t *testing.T) { s1 := RandomStage() s2 := RandomStage() if s1 == "" { t.Error("RandomStage() returned empty string") } if s1 == s2 { t.Error("RandomStage() returned same value twice") } } func TestConfirmPreRun(t *testing.T) { tests := []struct { name string yes bool input string interactive bool wantErr error }{ { name: "yes flag bypasses prompt", yes: true, wantErr: nil, }, { name: "non-interactive without yes flag", yes: false, interactive: false, wantErr: ErrNotConfirmed, }, { name: "interactive confirm with y", yes: false, interactive: true, input: "y\n", wantErr: nil, }, { name: "interactive confirm with Y", yes: false, interactive: true, input: "Y\n", wantErr: nil, }, { name: "interactive deny with n", yes: false, interactive: true, input: "n\n", wantErr: ErrNotConfirmed, }, { name: "interactive deny with empty", yes: false, interactive: true, input: "\n", wantErr: ErrNotConfirmed, }, { name: "interactive deny with EOF", yes: false, interactive: true, input: "", wantErr: ErrNotConfirmed, }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { orig := IsInteractive IsInteractive = func(any) bool { return tt.interactive } defer func() { IsInteractive = orig }() cmd := &cobra.Command{Use: "test"} cmd.Flags().Bool("yes", false, "") if tt.yes { _ = cmd.Flags().Set("yes", "true") } var errBuf bytes.Buffer cmd.SetErr(&errBuf) cmd.SetIn(strings.NewReader(tt.input)) err := ConfirmPreRun(cmd, "Would do something") if !errors.Is(err, tt.wantErr) { t.Errorf("ConfirmPreRun() error = %v, want %v", err, tt.wantErr) } }, ) } } func TestHandleCmdError(t *testing.T) { tests := []struct { name string input error wantOut string wantErr string }{ { name: "with error", input: fmt.Errorf("some error"), wantOut: "help called", wantErr: "Error: some error\n", }, { name: "without error", input: nil, wantOut: "", wantErr: "", }, } for _, tt := range tests { t.Run( tt.name, func(t *testing.T) { cmd := &cobra.Command{Use: "test"} var outBuf, errBuf bytes.Buffer cmd.SetOut(&outBuf) cmd.SetErr(&errBuf) cmd.SetHelpFunc( func(c *cobra.Command, _ []string) { _, _ = fmt.Fprint(c.OutOrStdout(), "help called") }, ) HandleCmdError(tt.input, cmd) if gotOut := outBuf.String(); gotOut != tt.wantOut { t.Fatalf( "unexpected stdout output, got %q, want %q", gotOut, tt.wantOut, ) } if gotErr := errBuf.String(); gotErr != tt.wantErr { t.Fatalf( "unexpected stderr output, got %q, want %q", gotErr, tt.wantErr, ) } }, ) } }