-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathgcli_test.go
More file actions
267 lines (223 loc) · 6.67 KB
/
Copy pathgcli_test.go
File metadata and controls
267 lines (223 loc) · 6.67 KB
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
package gcli_test
import (
"runtime"
"testing"
"github.com/gookit/gcli/v3"
"github.com/gookit/goutil/x/assert"
)
func TestGcliBasic(t *testing.T) {
is := assert.New(t)
is.NotEmpty(gcli.Version())
is.NotEmpty(gcli.CommitID())
}
func TestVerbose(t *testing.T) {
is := assert.New(t)
old := gcli.Verbose()
is.Eq(gcli.VerbError, old)
is.False(gcli.GOpts().NoColor)
gcli.SetDebugMode()
is.Eq(gcli.VerbDebug, gcli.Verbose())
gcli.SetQuietMode()
is.Eq(gcli.VerbQuiet, gcli.Verbose())
info := gcli.VerbInfo
gcli.SetVerbose(info)
is.Eq(info, gcli.Verbose())
is.Eq(3, info.Int())
is.Eq("info", info.Name())
is.Eq("INFO", info.Upper())
gcli.SetVerbose(old)
is.Eq(gcli.VerbError, gcli.Verbose())
}
func TestVerbLevel(t *testing.T) {
is := assert.New(t)
verb := gcli.VerbLevel(23)
is.Eq("unknown", verb.Name())
is.Eq(23, verb.Int())
err := verb.Set("2")
is.NoErr(err)
is.Eq(gcli.VerbWarn, verb)
is.Eq("warn", verb.Name())
err = verb.Set("debug")
is.NoErr(err)
is.Eq(gcli.VerbDebug, verb)
is.Eq("debug", verb.Name())
err = verb.Set("30")
is.NoErr(err)
is.Eq(gcli.VerbCrazy, verb)
is.Eq("crazy", verb.Name())
}
func TestStrictMode(t *testing.T) {
is := assert.New(t)
old := gcli.StrictMode()
defer func() {
gcli.SetStrictMode(old)
}()
gcli.SetStrictMode(false)
is.False(gcli.StrictMode())
gcli.SetStrictMode(true)
is.True(gcli.StrictMode())
}
func TestNewCtx(t *testing.T) {
is := assert.New(t)
ctx := gcli.NewCtx()
ctx.InitCtx()
is.True(ctx.PID() > 0)
is.Eq(runtime.GOOS, ctx.OsName())
is.NotEmpty(ctx.BinName())
is.NotEmpty(ctx.WorkDir())
args := ctx.OsArgs()
is.NotEmpty(args)
if len(args) > 1 {
is.NotEmpty(ctx.ArgLine())
} else {
is.Empty(ctx.ArgLine())
}
}
func TestSetStrictMode(t *testing.T) {
stm := gcli.StrictMode()
defer gcli.SetStrictMode(stm)
opts := struct {
name string
ok, bl bool
}{}
// gcli.SetVerbose(gcli.VerbDebug)
app := gcli.NewApp(gcli.NotExitOnEnd())
app.Add(&gcli.Command{
Name: "test",
Config: func(c *gcli.Command) {
c.StrOpt(&opts.name, "name", "n", "", "1")
c.BoolOpt(&opts.ok, "ok", "o", true, "2")
c.BoolOpt(&opts.bl, "bl", "b", false, "3")
},
Func: func(c *gcli.Command, _ []string) error {
return nil
},
})
app.Run([]string{"test", "-o", "-n", "inhere"})
assert.Eq(t, "inhere", opts.name)
assert.True(t, opts.ok)
app.Run([]string{"test", "-o=false", "-n=inhere"})
assert.Eq(t, "inhere", opts.name)
assert.False(t, opts.ok)
app.Run([]string{"test", "-ob"})
// assert.StrContains(t, errMsg, "ddd")
gcli.SetStrictMode(true)
app.Run([]string{"test", "-ob"})
assert.True(t, opts.ok)
assert.True(t, opts.bl)
}
// TestStrictMode_safeShortSplit 验证 strictMode 收敛为驱动 gflag EnhanceShort 后,
// 取值型短选项不再被旧的"盲拆"逻辑错误拆分(回归 B4+B5)。
func TestStrictMode_safeShortSplit(t *testing.T) {
stm := gcli.StrictMode()
defer gcli.SetStrictMode(stm)
// 每个用例独立构建 app/opts,避免上一次 Run 的状态干扰
build := func() (*gcli.App, *struct {
out string
verbose bool
}) {
opts := &struct {
out string
verbose bool
}{}
app := gcli.NewApp(gcli.NotExitOnEnd())
app.Add(&gcli.Command{
Name: "test",
Config: func(c *gcli.Command) {
c.StrOpt(&opts.out, "out", "O", "", "out file") // 取值型短选项
c.BoolOpt(&opts.verbose, "verbose", "V", false, "v") // bool 短选项
},
Func: func(c *gcli.Command, _ []string) error { return nil },
})
return app, opts
}
gcli.SetStrictMode(true)
// 混合写法: -VO 含取值型短选项 O,非全 bool。
// 旧盲拆会错拆为 -V -O 并把后续 "val" 吞作 O 的值(verbose=true,out="val");
// 新方案下 -VO 不拆,整体作为未知长选项解析失败,opt 值不被污染(保持零值)。
t.Run("mixed value-short not blindly split", func(t *testing.T) {
app, opts := build()
app.Run([]string{"test", "-VO", "val"})
assert.False(t, opts.verbose) // 未被盲拆污染
assert.Eq(t, "", opts.out) // "val" 未被错误吞为 O 的值
})
// 纯 bool 组合: 拆分仍正常工作。
t.Run("all-bool short still split", func(t *testing.T) {
app, opts := build()
app.Run([]string{"test", "-VV"})
assert.True(t, opts.verbose)
})
// 单个 bool 短选项正常。
t.Run("single bool short", func(t *testing.T) {
app, opts := build()
app.Run([]string{"test", "-V"})
assert.True(t, opts.verbose)
})
// 取值型短选项分开写正常取值,未受影响。
t.Run("value-short with separate value", func(t *testing.T) {
app, opts := build()
app.Run([]string{"test", "-V", "-O", "val"})
assert.True(t, opts.verbose)
assert.Eq(t, "val", opts.out)
})
}
// TestSetEnhanceShort 验证全局 EnhanceShort 设置:一次设置作用于所有命令,
// 且命令自身的 Config.EnhanceShort 优先于全局设置。
func TestSetEnhanceShort(t *testing.T) {
defer gcli.SetEnhanceShort(gcli.EnhanceShortNone) // 还原全局状态
type testOpts struct {
a, u, x bool
output string
}
build := func(cfgFn func(*gcli.Command)) (*gcli.App, *testOpts) {
opts := &testOpts{}
app := gcli.NewApp(gcli.NotExitOnEnd())
app.Add(&gcli.Command{
Name: "test",
Config: func(c *gcli.Command) {
c.BoolOpt(&opts.a, "all", "a", false, "a")
c.BoolOpt(&opts.u, "upload", "u", false, "u")
c.BoolOpt(&opts.x, "extract", "x", false, "x")
c.StrOpt(&opts.output, "output", "O", "", "O")
if cfgFn != nil {
cfgFn(c)
}
},
Func: func(c *gcli.Command, _ []string) error { return nil },
})
return app, opts
}
// 全局 Merge 作用于未单独设置的命令
t.Run("global merge applies", func(t *testing.T) {
gcli.SetEnhanceShort(gcli.EnhanceShortMerge)
assert.Eq(t, gcli.EnhanceShortMerge, gcli.EnhanceShort())
app, opts := build(nil)
app.Run([]string{"test", "-aux"})
assert.True(t, opts.a)
assert.True(t, opts.u)
assert.True(t, opts.x)
})
// 默认 None: -aux 不拆(未定义选项), 均保持 false
t.Run("default none not split", func(t *testing.T) {
gcli.SetEnhanceShort(gcli.EnhanceShortNone)
app, opts := build(nil)
app.Run([]string{"test", "-aux"})
assert.False(t, opts.a)
assert.False(t, opts.u)
assert.False(t, opts.x)
})
// 命令级设置优先: 全局 Merge, 但命令设 Attach -> -Ostdout 被拆(全局 Merge 不支持紧贴取值)
t.Run("command-level overrides global", func(t *testing.T) {
gcli.SetEnhanceShort(gcli.EnhanceShortMerge)
app, opts := build(func(c *gcli.Command) {
c.ParserCfg().EnhanceShort = gcli.EnhanceShortAttach
})
app.Run([]string{"test", "-Ostdout"})
assert.Eq(t, "stdout", opts.output)
})
}
func TestString(t *testing.T) {
s := gcli.String("ab,cd")
assert.Eq(t, "ab,cd", s.String())
assert.Eq(t, []string{"ab", "cd"}, s.Split(","))
}