doing 2.0.18 → 2.0.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/Gemfile.lock +15 -5
  4. data/README.md +1 -1
  5. data/bin/doing +2 -18
  6. data/doing.gemspec +5 -4
  7. data/doing.rdoc +2 -2
  8. data/generate_completions.sh +3 -3
  9. data/lib/doing/cli_status.rb +6 -2
  10. data/lib/doing/completion/bash_completion.rb +185 -0
  11. data/lib/doing/completion/fish_completion.rb +175 -0
  12. data/lib/doing/completion/string.rb +17 -0
  13. data/lib/doing/completion/zsh_completion.rb +140 -0
  14. data/lib/doing/completion.rb +39 -0
  15. data/lib/doing/version.rb +1 -1
  16. data/lib/doing/wwid.rb +18 -6
  17. data/lib/doing.rb +1 -1
  18. data/lib/helpers/fzf/.goreleaser.yml +119 -0
  19. data/lib/helpers/fzf/.rubocop.yml +28 -0
  20. data/lib/helpers/fzf/ADVANCED.md +565 -0
  21. data/lib/helpers/fzf/BUILD.md +49 -0
  22. data/lib/helpers/fzf/CHANGELOG.md +1193 -0
  23. data/lib/helpers/fzf/Dockerfile +11 -0
  24. data/lib/helpers/fzf/LICENSE +21 -0
  25. data/lib/helpers/fzf/Makefile +166 -0
  26. data/lib/helpers/fzf/README-VIM.md +486 -0
  27. data/lib/helpers/fzf/README.md +712 -0
  28. data/lib/helpers/fzf/bin/fzf-tmux +233 -0
  29. data/lib/helpers/fzf/doc/fzf.txt +512 -0
  30. data/lib/helpers/fzf/go.mod +17 -0
  31. data/lib/helpers/fzf/go.sum +31 -0
  32. data/lib/helpers/fzf/install +382 -0
  33. data/lib/helpers/fzf/install.ps1 +65 -0
  34. data/lib/helpers/fzf/main.go +14 -0
  35. data/lib/helpers/fzf/man/man1/fzf-tmux.1 +68 -0
  36. data/lib/helpers/fzf/man/man1/fzf.1 +1001 -0
  37. data/lib/helpers/fzf/plugin/fzf.vim +1048 -0
  38. data/lib/helpers/fzf/shell/completion.bash +381 -0
  39. data/lib/helpers/fzf/shell/completion.zsh +329 -0
  40. data/lib/helpers/fzf/shell/key-bindings.bash +96 -0
  41. data/lib/helpers/fzf/shell/key-bindings.fish +172 -0
  42. data/lib/helpers/fzf/shell/key-bindings.zsh +114 -0
  43. data/lib/helpers/fzf/src/LICENSE +21 -0
  44. data/lib/helpers/fzf/src/algo/algo.go +884 -0
  45. data/lib/helpers/fzf/src/algo/algo_test.go +197 -0
  46. data/lib/helpers/fzf/src/algo/normalize.go +492 -0
  47. data/lib/helpers/fzf/src/ansi.go +409 -0
  48. data/lib/helpers/fzf/src/ansi_test.go +427 -0
  49. data/lib/helpers/fzf/src/cache.go +81 -0
  50. data/lib/helpers/fzf/src/cache_test.go +39 -0
  51. data/lib/helpers/fzf/src/chunklist.go +89 -0
  52. data/lib/helpers/fzf/src/chunklist_test.go +80 -0
  53. data/lib/helpers/fzf/src/constants.go +85 -0
  54. data/lib/helpers/fzf/src/core.go +351 -0
  55. data/lib/helpers/fzf/src/history.go +96 -0
  56. data/lib/helpers/fzf/src/history_test.go +68 -0
  57. data/lib/helpers/fzf/src/item.go +44 -0
  58. data/lib/helpers/fzf/src/item_test.go +23 -0
  59. data/lib/helpers/fzf/src/matcher.go +235 -0
  60. data/lib/helpers/fzf/src/merger.go +120 -0
  61. data/lib/helpers/fzf/src/merger_test.go +88 -0
  62. data/lib/helpers/fzf/src/options.go +1691 -0
  63. data/lib/helpers/fzf/src/options_test.go +457 -0
  64. data/lib/helpers/fzf/src/pattern.go +425 -0
  65. data/lib/helpers/fzf/src/pattern_test.go +209 -0
  66. data/lib/helpers/fzf/src/protector/protector.go +8 -0
  67. data/lib/helpers/fzf/src/protector/protector_openbsd.go +10 -0
  68. data/lib/helpers/fzf/src/reader.go +201 -0
  69. data/lib/helpers/fzf/src/reader_test.go +63 -0
  70. data/lib/helpers/fzf/src/result.go +243 -0
  71. data/lib/helpers/fzf/src/result_others.go +16 -0
  72. data/lib/helpers/fzf/src/result_test.go +159 -0
  73. data/lib/helpers/fzf/src/result_x86.go +16 -0
  74. data/lib/helpers/fzf/src/terminal.go +2832 -0
  75. data/lib/helpers/fzf/src/terminal_test.go +638 -0
  76. data/lib/helpers/fzf/src/terminal_unix.go +26 -0
  77. data/lib/helpers/fzf/src/terminal_windows.go +45 -0
  78. data/lib/helpers/fzf/src/tokenizer.go +253 -0
  79. data/lib/helpers/fzf/src/tokenizer_test.go +112 -0
  80. data/lib/helpers/fzf/src/tui/dummy.go +46 -0
  81. data/lib/helpers/fzf/src/tui/light.go +987 -0
  82. data/lib/helpers/fzf/src/tui/light_unix.go +110 -0
  83. data/lib/helpers/fzf/src/tui/light_windows.go +145 -0
  84. data/lib/helpers/fzf/src/tui/tcell.go +721 -0
  85. data/lib/helpers/fzf/src/tui/tcell_test.go +392 -0
  86. data/lib/helpers/fzf/src/tui/ttyname_unix.go +47 -0
  87. data/lib/helpers/fzf/src/tui/ttyname_windows.go +14 -0
  88. data/lib/helpers/fzf/src/tui/tui.go +625 -0
  89. data/lib/helpers/fzf/src/tui/tui_test.go +20 -0
  90. data/lib/helpers/fzf/src/util/atomicbool.go +34 -0
  91. data/lib/helpers/fzf/src/util/atomicbool_test.go +17 -0
  92. data/lib/helpers/fzf/src/util/chars.go +198 -0
  93. data/lib/helpers/fzf/src/util/chars_test.go +46 -0
  94. data/lib/helpers/fzf/src/util/eventbox.go +96 -0
  95. data/lib/helpers/fzf/src/util/eventbox_test.go +61 -0
  96. data/lib/helpers/fzf/src/util/slab.go +12 -0
  97. data/lib/helpers/fzf/src/util/util.go +138 -0
  98. data/lib/helpers/fzf/src/util/util_test.go +40 -0
  99. data/lib/helpers/fzf/src/util/util_unix.go +47 -0
  100. data/lib/helpers/fzf/src/util/util_windows.go +83 -0
  101. data/lib/helpers/fzf/test/fzf.vader +175 -0
  102. data/lib/helpers/fzf/test/test_go.rb +2626 -0
  103. data/lib/helpers/fzf/uninstall +117 -0
  104. data/scripts/generate_bash_completions.rb +6 -12
  105. data/scripts/generate_fish_completions.rb +7 -16
  106. data/scripts/generate_zsh_completions.rb +6 -15
  107. metadata +144 -9
@@ -0,0 +1,457 @@
1
+ package fzf
2
+
3
+ import (
4
+ "fmt"
5
+ "io/ioutil"
6
+ "testing"
7
+
8
+ "github.com/junegunn/fzf/src/tui"
9
+ )
10
+
11
+ func TestDelimiterRegex(t *testing.T) {
12
+ // Valid regex
13
+ delim := delimiterRegexp(".")
14
+ if delim.regex == nil || delim.str != nil {
15
+ t.Error(delim)
16
+ }
17
+ // Broken regex -> string
18
+ delim = delimiterRegexp("[0-9")
19
+ if delim.regex != nil || *delim.str != "[0-9" {
20
+ t.Error(delim)
21
+ }
22
+ // Valid regex
23
+ delim = delimiterRegexp("[0-9]")
24
+ if delim.regex.String() != "[0-9]" || delim.str != nil {
25
+ t.Error(delim)
26
+ }
27
+ // Tab character
28
+ delim = delimiterRegexp("\t")
29
+ if delim.regex != nil || *delim.str != "\t" {
30
+ t.Error(delim)
31
+ }
32
+ // Tab expression
33
+ delim = delimiterRegexp("\\t")
34
+ if delim.regex != nil || *delim.str != "\t" {
35
+ t.Error(delim)
36
+ }
37
+ // Tabs -> regex
38
+ delim = delimiterRegexp("\t+")
39
+ if delim.regex == nil || delim.str != nil {
40
+ t.Error(delim)
41
+ }
42
+ }
43
+
44
+ func TestDelimiterRegexString(t *testing.T) {
45
+ delim := delimiterRegexp("*")
46
+ tokens := Tokenize("-*--*---**---", delim)
47
+ if delim.regex != nil ||
48
+ tokens[0].text.ToString() != "-*" ||
49
+ tokens[1].text.ToString() != "--*" ||
50
+ tokens[2].text.ToString() != "---*" ||
51
+ tokens[3].text.ToString() != "*" ||
52
+ tokens[4].text.ToString() != "---" {
53
+ t.Errorf("%s %v %d", delim, tokens, len(tokens))
54
+ }
55
+ }
56
+
57
+ func TestDelimiterRegexRegex(t *testing.T) {
58
+ delim := delimiterRegexp("--\\*")
59
+ tokens := Tokenize("-*--*---**---", delim)
60
+ if delim.str != nil ||
61
+ tokens[0].text.ToString() != "-*--*" ||
62
+ tokens[1].text.ToString() != "---*" ||
63
+ tokens[2].text.ToString() != "*---" {
64
+ t.Errorf("%s %d", tokens, len(tokens))
65
+ }
66
+ }
67
+
68
+ func TestSplitNth(t *testing.T) {
69
+ {
70
+ ranges := splitNth("..")
71
+ if len(ranges) != 1 ||
72
+ ranges[0].begin != rangeEllipsis ||
73
+ ranges[0].end != rangeEllipsis {
74
+ t.Errorf("%v", ranges)
75
+ }
76
+ }
77
+ {
78
+ ranges := splitNth("..3,1..,2..3,4..-1,-3..-2,..,2,-2,2..-2,1..-1")
79
+ if len(ranges) != 10 ||
80
+ ranges[0].begin != rangeEllipsis || ranges[0].end != 3 ||
81
+ ranges[1].begin != rangeEllipsis || ranges[1].end != rangeEllipsis ||
82
+ ranges[2].begin != 2 || ranges[2].end != 3 ||
83
+ ranges[3].begin != 4 || ranges[3].end != rangeEllipsis ||
84
+ ranges[4].begin != -3 || ranges[4].end != -2 ||
85
+ ranges[5].begin != rangeEllipsis || ranges[5].end != rangeEllipsis ||
86
+ ranges[6].begin != 2 || ranges[6].end != 2 ||
87
+ ranges[7].begin != -2 || ranges[7].end != -2 ||
88
+ ranges[8].begin != 2 || ranges[8].end != -2 ||
89
+ ranges[9].begin != rangeEllipsis || ranges[9].end != rangeEllipsis {
90
+ t.Errorf("%v", ranges)
91
+ }
92
+ }
93
+ }
94
+
95
+ func TestIrrelevantNth(t *testing.T) {
96
+ {
97
+ opts := defaultOptions()
98
+ words := []string{"--nth", "..", "-x"}
99
+ parseOptions(opts, words)
100
+ postProcessOptions(opts)
101
+ if len(opts.Nth) != 0 {
102
+ t.Errorf("nth should be empty: %v", opts.Nth)
103
+ }
104
+ }
105
+ for _, words := range [][]string{{"--nth", "..,3", "+x"}, {"--nth", "3,1..", "+x"}, {"--nth", "..-1,1", "+x"}} {
106
+ {
107
+ opts := defaultOptions()
108
+ parseOptions(opts, words)
109
+ postProcessOptions(opts)
110
+ if len(opts.Nth) != 0 {
111
+ t.Errorf("nth should be empty: %v", opts.Nth)
112
+ }
113
+ }
114
+ {
115
+ opts := defaultOptions()
116
+ words = append(words, "-x")
117
+ parseOptions(opts, words)
118
+ postProcessOptions(opts)
119
+ if len(opts.Nth) != 2 {
120
+ t.Errorf("nth should not be empty: %v", opts.Nth)
121
+ }
122
+ }
123
+ }
124
+ }
125
+
126
+ func TestParseKeys(t *testing.T) {
127
+ pairs := parseKeyChords("ctrl-z,alt-z,f2,@,Alt-a,!,ctrl-G,J,g,ctrl-alt-a,ALT-enter,alt-SPACE", "")
128
+ checkEvent := func(e tui.Event, s string) {
129
+ if pairs[e] != s {
130
+ t.Errorf("%s != %s", pairs[e], s)
131
+ }
132
+ }
133
+ check := func(et tui.EventType, s string) {
134
+ checkEvent(et.AsEvent(), s)
135
+ }
136
+ if len(pairs) != 12 {
137
+ t.Error(12)
138
+ }
139
+ check(tui.CtrlZ, "ctrl-z")
140
+ check(tui.F2, "f2")
141
+ check(tui.CtrlG, "ctrl-G")
142
+ checkEvent(tui.AltKey('z'), "alt-z")
143
+ checkEvent(tui.Key('@'), "@")
144
+ checkEvent(tui.AltKey('a'), "Alt-a")
145
+ checkEvent(tui.Key('!'), "!")
146
+ checkEvent(tui.Key('J'), "J")
147
+ checkEvent(tui.Key('g'), "g")
148
+ checkEvent(tui.CtrlAltKey('a'), "ctrl-alt-a")
149
+ checkEvent(tui.CtrlAltKey('m'), "ALT-enter")
150
+ checkEvent(tui.AltKey(' '), "alt-SPACE")
151
+
152
+ // Synonyms
153
+ pairs = parseKeyChords("enter,Return,space,tab,btab,esc,up,down,left,right", "")
154
+ if len(pairs) != 9 {
155
+ t.Error(9)
156
+ }
157
+ check(tui.CtrlM, "Return")
158
+ checkEvent(tui.Key(' '), "space")
159
+ check(tui.Tab, "tab")
160
+ check(tui.BTab, "btab")
161
+ check(tui.ESC, "esc")
162
+ check(tui.Up, "up")
163
+ check(tui.Down, "down")
164
+ check(tui.Left, "left")
165
+ check(tui.Right, "right")
166
+
167
+ pairs = parseKeyChords("Tab,Ctrl-I,PgUp,page-up,pgdn,Page-Down,Home,End,Alt-BS,Alt-BSpace,shift-left,shift-right,btab,shift-tab,return,Enter,bspace", "")
168
+ if len(pairs) != 11 {
169
+ t.Error(11)
170
+ }
171
+ check(tui.Tab, "Ctrl-I")
172
+ check(tui.PgUp, "page-up")
173
+ check(tui.PgDn, "Page-Down")
174
+ check(tui.Home, "Home")
175
+ check(tui.End, "End")
176
+ check(tui.AltBS, "Alt-BSpace")
177
+ check(tui.SLeft, "shift-left")
178
+ check(tui.SRight, "shift-right")
179
+ check(tui.BTab, "shift-tab")
180
+ check(tui.CtrlM, "Enter")
181
+ check(tui.BSpace, "bspace")
182
+ }
183
+
184
+ func TestParseKeysWithComma(t *testing.T) {
185
+ checkN := func(a int, b int) {
186
+ if a != b {
187
+ t.Errorf("%d != %d", a, b)
188
+ }
189
+ }
190
+ check := func(pairs map[tui.Event]string, e tui.Event, s string) {
191
+ if pairs[e] != s {
192
+ t.Errorf("%s != %s", pairs[e], s)
193
+ }
194
+ }
195
+
196
+ pairs := parseKeyChords(",", "")
197
+ checkN(len(pairs), 1)
198
+ check(pairs, tui.Key(','), ",")
199
+
200
+ pairs = parseKeyChords(",,a,b", "")
201
+ checkN(len(pairs), 3)
202
+ check(pairs, tui.Key('a'), "a")
203
+ check(pairs, tui.Key('b'), "b")
204
+ check(pairs, tui.Key(','), ",")
205
+
206
+ pairs = parseKeyChords("a,b,,", "")
207
+ checkN(len(pairs), 3)
208
+ check(pairs, tui.Key('a'), "a")
209
+ check(pairs, tui.Key('b'), "b")
210
+ check(pairs, tui.Key(','), ",")
211
+
212
+ pairs = parseKeyChords("a,,,b", "")
213
+ checkN(len(pairs), 3)
214
+ check(pairs, tui.Key('a'), "a")
215
+ check(pairs, tui.Key('b'), "b")
216
+ check(pairs, tui.Key(','), ",")
217
+
218
+ pairs = parseKeyChords("a,,,b,c", "")
219
+ checkN(len(pairs), 4)
220
+ check(pairs, tui.Key('a'), "a")
221
+ check(pairs, tui.Key('b'), "b")
222
+ check(pairs, tui.Key('c'), "c")
223
+ check(pairs, tui.Key(','), ",")
224
+
225
+ pairs = parseKeyChords(",,,", "")
226
+ checkN(len(pairs), 1)
227
+ check(pairs, tui.Key(','), ",")
228
+
229
+ pairs = parseKeyChords(",ALT-,,", "")
230
+ checkN(len(pairs), 1)
231
+ check(pairs, tui.AltKey(','), "ALT-,")
232
+ }
233
+
234
+ func TestBind(t *testing.T) {
235
+ keymap := defaultKeymap()
236
+ check := func(event tui.Event, arg1 string, types ...actionType) {
237
+ if len(keymap[event]) != len(types) {
238
+ t.Errorf("invalid number of actions for %v (%d != %d)",
239
+ event, len(types), len(keymap[event]))
240
+ return
241
+ }
242
+ for idx, action := range keymap[event] {
243
+ if types[idx] != action.t {
244
+ t.Errorf("invalid action type (%d != %d)", types[idx], action.t)
245
+ }
246
+ }
247
+ if len(arg1) > 0 && keymap[event][0].a != arg1 {
248
+ t.Errorf("invalid action argument: (%s != %s)", arg1, keymap[event][0].a)
249
+ }
250
+ }
251
+ check(tui.CtrlA.AsEvent(), "", actBeginningOfLine)
252
+ parseKeymap(keymap,
253
+ "ctrl-a:kill-line,ctrl-b:toggle-sort+up+down,c:page-up,alt-z:page-down,"+
254
+ "f1:execute(ls {+})+abort+execute(echo {+})+select-all,f2:execute/echo {}, {}, {}/,f3:execute[echo '({})'],f4:execute;less {};,"+
255
+ "alt-a:execute-Multi@echo (,),[,],/,:,;,%,{}@,alt-b:execute;echo (,),[,],/,:,@,%,{};,"+
256
+ "x:Execute(foo+bar),X:execute/bar+baz/"+
257
+ ",f1:+first,f1:+top"+
258
+ ",,:abort,::accept,+:execute:++\nfoobar,Y:execute(baz)+up")
259
+ check(tui.CtrlA.AsEvent(), "", actKillLine)
260
+ check(tui.CtrlB.AsEvent(), "", actToggleSort, actUp, actDown)
261
+ check(tui.Key('c'), "", actPageUp)
262
+ check(tui.Key(','), "", actAbort)
263
+ check(tui.Key(':'), "", actAccept)
264
+ check(tui.AltKey('z'), "", actPageDown)
265
+ check(tui.F1.AsEvent(), "ls {+}", actExecute, actAbort, actExecute, actSelectAll, actFirst, actFirst)
266
+ check(tui.F2.AsEvent(), "echo {}, {}, {}", actExecute)
267
+ check(tui.F3.AsEvent(), "echo '({})'", actExecute)
268
+ check(tui.F4.AsEvent(), "less {}", actExecute)
269
+ check(tui.Key('x'), "foo+bar", actExecute)
270
+ check(tui.Key('X'), "bar+baz", actExecute)
271
+ check(tui.AltKey('a'), "echo (,),[,],/,:,;,%,{}", actExecuteMulti)
272
+ check(tui.AltKey('b'), "echo (,),[,],/,:,@,%,{}", actExecute)
273
+ check(tui.Key('+'), "++\nfoobar,Y:execute(baz)+up", actExecute)
274
+
275
+ for idx, char := range []rune{'~', '!', '@', '#', '$', '%', '^', '&', '*', '|', ';', '/'} {
276
+ parseKeymap(keymap, fmt.Sprintf("%d:execute%cfoobar%c", idx%10, char, char))
277
+ check(tui.Key([]rune(fmt.Sprintf("%d", idx%10))[0]), "foobar", actExecute)
278
+ }
279
+
280
+ parseKeymap(keymap, "f1:abort")
281
+ check(tui.F1.AsEvent(), "", actAbort)
282
+ }
283
+
284
+ func TestColorSpec(t *testing.T) {
285
+ theme := tui.Dark256
286
+ dark := parseTheme(theme, "dark")
287
+ if *dark != *theme {
288
+ t.Errorf("colors should be equivalent")
289
+ }
290
+ if dark == theme {
291
+ t.Errorf("point should not be equivalent")
292
+ }
293
+
294
+ light := parseTheme(theme, "dark,light")
295
+ if *light == *theme {
296
+ t.Errorf("should not be equivalent")
297
+ }
298
+ if *light != *tui.Light256 {
299
+ t.Errorf("colors should be equivalent")
300
+ }
301
+ if light == theme {
302
+ t.Errorf("point should not be equivalent")
303
+ }
304
+
305
+ customized := parseTheme(theme, "fg:231,bg:232")
306
+ if customized.Fg.Color != 231 || customized.Bg.Color != 232 {
307
+ t.Errorf("color not customized")
308
+ }
309
+ if *tui.Dark256 == *customized {
310
+ t.Errorf("colors should not be equivalent")
311
+ }
312
+ customized.Fg = tui.Dark256.Fg
313
+ customized.Bg = tui.Dark256.Bg
314
+ if *tui.Dark256 != *customized {
315
+ t.Errorf("colors should now be equivalent: %v, %v", tui.Dark256, customized)
316
+ }
317
+
318
+ customized = parseTheme(theme, "fg:231,dark,bg:232")
319
+ if customized.Fg != tui.Dark256.Fg || customized.Bg == tui.Dark256.Bg {
320
+ t.Errorf("color not customized")
321
+ }
322
+ }
323
+
324
+ func TestDefaultCtrlNP(t *testing.T) {
325
+ check := func(words []string, et tui.EventType, expected actionType) {
326
+ e := et.AsEvent()
327
+ opts := defaultOptions()
328
+ parseOptions(opts, words)
329
+ postProcessOptions(opts)
330
+ if opts.Keymap[e][0].t != expected {
331
+ t.Error()
332
+ }
333
+ }
334
+ check([]string{}, tui.CtrlN, actDown)
335
+ check([]string{}, tui.CtrlP, actUp)
336
+
337
+ check([]string{"--bind=ctrl-n:accept"}, tui.CtrlN, actAccept)
338
+ check([]string{"--bind=ctrl-p:accept"}, tui.CtrlP, actAccept)
339
+
340
+ f, _ := ioutil.TempFile("", "fzf-history")
341
+ f.Close()
342
+ hist := "--history=" + f.Name()
343
+ check([]string{hist}, tui.CtrlN, actNextHistory)
344
+ check([]string{hist}, tui.CtrlP, actPreviousHistory)
345
+
346
+ check([]string{hist, "--bind=ctrl-n:accept"}, tui.CtrlN, actAccept)
347
+ check([]string{hist, "--bind=ctrl-n:accept"}, tui.CtrlP, actPreviousHistory)
348
+
349
+ check([]string{hist, "--bind=ctrl-p:accept"}, tui.CtrlN, actNextHistory)
350
+ check([]string{hist, "--bind=ctrl-p:accept"}, tui.CtrlP, actAccept)
351
+ }
352
+
353
+ func optsFor(words ...string) *Options {
354
+ opts := defaultOptions()
355
+ parseOptions(opts, words)
356
+ postProcessOptions(opts)
357
+ return opts
358
+ }
359
+
360
+ func TestToggle(t *testing.T) {
361
+ opts := optsFor()
362
+ if opts.ToggleSort {
363
+ t.Error()
364
+ }
365
+
366
+ opts = optsFor("--bind=a:toggle-sort")
367
+ if !opts.ToggleSort {
368
+ t.Error()
369
+ }
370
+
371
+ opts = optsFor("--bind=a:toggle-sort", "--bind=a:up")
372
+ if opts.ToggleSort {
373
+ t.Error()
374
+ }
375
+ }
376
+
377
+ func TestPreviewOpts(t *testing.T) {
378
+ opts := optsFor()
379
+ if !(opts.Preview.command == "" &&
380
+ opts.Preview.hidden == false &&
381
+ opts.Preview.wrap == false &&
382
+ opts.Preview.position == posRight &&
383
+ opts.Preview.size.percent == true &&
384
+ opts.Preview.size.size == 50) {
385
+ t.Error()
386
+ }
387
+ opts = optsFor("--preview", "cat {}", "--preview-window=left:15,hidden,wrap:+{1}-/2")
388
+ if !(opts.Preview.command == "cat {}" &&
389
+ opts.Preview.hidden == true &&
390
+ opts.Preview.wrap == true &&
391
+ opts.Preview.position == posLeft &&
392
+ opts.Preview.scroll == "+{1}-/2" &&
393
+ opts.Preview.size.percent == false &&
394
+ opts.Preview.size.size == 15) {
395
+ t.Error(opts.Preview)
396
+ }
397
+ opts = optsFor("--preview-window=up,15,wrap,hidden,+{1}+3-1-2/2", "--preview-window=down", "--preview-window=cycle")
398
+ if !(opts.Preview.command == "" &&
399
+ opts.Preview.hidden == true &&
400
+ opts.Preview.wrap == true &&
401
+ opts.Preview.cycle == true &&
402
+ opts.Preview.position == posDown &&
403
+ opts.Preview.scroll == "+{1}+3-1-2/2" &&
404
+ opts.Preview.size.percent == false &&
405
+ opts.Preview.size.size == 15) {
406
+ t.Error(opts.Preview.size.size)
407
+ }
408
+ opts = optsFor("--preview-window=up:15:wrap:hidden")
409
+ if !(opts.Preview.command == "" &&
410
+ opts.Preview.hidden == true &&
411
+ opts.Preview.wrap == true &&
412
+ opts.Preview.position == posUp &&
413
+ opts.Preview.size.percent == false &&
414
+ opts.Preview.size.size == 15) {
415
+ t.Error(opts.Preview)
416
+ }
417
+ opts = optsFor("--preview=foo", "--preview-window=up", "--preview-window=default:70%")
418
+ if !(opts.Preview.command == "foo" &&
419
+ opts.Preview.position == posRight &&
420
+ opts.Preview.size.percent == true &&
421
+ opts.Preview.size.size == 70) {
422
+ t.Error(opts.Preview)
423
+ }
424
+ }
425
+
426
+ func TestAdditiveExpect(t *testing.T) {
427
+ opts := optsFor("--expect=a", "--expect", "b", "--expect=c")
428
+ if len(opts.Expect) != 3 {
429
+ t.Error(opts.Expect)
430
+ }
431
+ }
432
+
433
+ func TestValidateSign(t *testing.T) {
434
+ testCases := []struct {
435
+ inputSign string
436
+ isValid bool
437
+ }{
438
+ {"> ", true},
439
+ {"아", true},
440
+ {"😀", true},
441
+ {"", false},
442
+ {">>>", false},
443
+ {"\n", false},
444
+ {"\t", false},
445
+ }
446
+
447
+ for _, testCase := range testCases {
448
+ err := validateSign(testCase.inputSign, "")
449
+ if testCase.isValid && err != nil {
450
+ t.Errorf("Input sign `%s` caused error", testCase.inputSign)
451
+ }
452
+
453
+ if !testCase.isValid && err == nil {
454
+ t.Errorf("Input sign `%s` did not cause error", testCase.inputSign)
455
+ }
456
+ }
457
+ }