github.com/cloudfoundry/cli@v7.1.0+incompatible/util/ui/prompt_test.go (about) 1 package ui_test 2 3 import ( 4 "regexp" 5 6 "code.cloudfoundry.org/cli/util/configv3" 7 . "code.cloudfoundry.org/cli/util/ui" 8 "code.cloudfoundry.org/cli/util/ui/uifakes" 9 . "github.com/onsi/ginkgo" 10 . "github.com/onsi/gomega" 11 . "github.com/onsi/gomega/gbytes" 12 "github.com/vito/go-interact/interact" 13 ) 14 15 var _ = Describe("Prompts", func() { 16 var ( 17 ui *UI 18 fakeConfig *uifakes.FakeConfig 19 out *Buffer 20 errBuff *Buffer 21 inBuffer *Buffer 22 ) 23 24 BeforeEach(func() { 25 fakeConfig = new(uifakes.FakeConfig) 26 fakeConfig.ColorEnabledReturns(configv3.ColorEnabled) 27 28 var err error 29 ui, err = NewUI(fakeConfig) 30 Expect(err).NotTo(HaveOccurred()) 31 32 out = NewBuffer() 33 ui.Out = out 34 ui.OutForInteration = out 35 errBuff = NewBuffer() 36 ui.Err = errBuff 37 38 inBuffer = NewBuffer() 39 ui.In = inBuffer 40 }) 41 42 Describe("DisplayBoolPrompt", func() { 43 Describe("display text", func() { 44 BeforeEach(func() { 45 _, err := inBuffer.Write([]byte("\n")) 46 Expect(err).ToNot(HaveOccurred()) 47 }) 48 49 It("displays the passed in string", func() { 50 _, err := ui.DisplayBoolPrompt(false, "some-prompt", nil) 51 Expect(err).NotTo(HaveOccurred()) 52 Expect(out).To(Say(`some-prompt \[yN\]:`)) 53 }) 54 }) 55 56 When("the user chooses yes", func() { 57 BeforeEach(func() { 58 _, err := inBuffer.Write([]byte("y\n")) 59 Expect(err).ToNot(HaveOccurred()) 60 }) 61 62 It("returns true", func() { 63 response, err := ui.DisplayBoolPrompt(false, "some-prompt", nil) 64 Expect(err).ToNot(HaveOccurred()) 65 Expect(response).To(BeTrue()) 66 }) 67 }) 68 69 When("the user chooses no", func() { 70 BeforeEach(func() { 71 _, err := inBuffer.Write([]byte("n\n")) 72 Expect(err).ToNot(HaveOccurred()) 73 }) 74 75 It("returns false", func() { 76 response, err := ui.DisplayBoolPrompt(false, "some-prompt", nil) 77 Expect(err).ToNot(HaveOccurred()) 78 Expect(response).To(BeFalse()) 79 }) 80 }) 81 82 When("the user chooses the default", func() { 83 BeforeEach(func() { 84 _, err := inBuffer.Write([]byte("\n")) 85 Expect(err).ToNot(HaveOccurred()) 86 }) 87 88 When("the default is true", func() { 89 It("returns true", func() { 90 response, err := ui.DisplayBoolPrompt(true, "some-prompt", nil) 91 Expect(err).ToNot(HaveOccurred()) 92 Expect(response).To(BeTrue()) 93 }) 94 }) 95 96 When("the default is false", func() { 97 It("returns false", func() { 98 response, err := ui.DisplayBoolPrompt(false, "some-prompt", nil) 99 Expect(err).ToNot(HaveOccurred()) 100 Expect(response).To(BeFalse()) 101 }) 102 }) 103 }) 104 105 When("the interact library returns an error", func() { 106 It("returns the error", func() { 107 _, err := inBuffer.Write([]byte("invalid\n")) 108 Expect(err).ToNot(HaveOccurred()) 109 _, err = ui.DisplayBoolPrompt(false, "some-prompt", nil) 110 Expect(err).To(HaveOccurred()) 111 }) 112 }) 113 }) 114 115 Describe("DisplayPasswordPrompt", func() { 116 BeforeEach(func() { 117 _, err := inBuffer.Write([]byte("some-input\n")) 118 Expect(err).ToNot(HaveOccurred()) 119 }) 120 121 It("displays the passed in string", func() { 122 _, err := ui.DisplayPasswordPrompt("App {{.AppName}} does not exist.", map[string]interface{}{ 123 "AppName": "some-app", 124 }) 125 Expect(err).NotTo(HaveOccurred()) 126 Expect(out).To(Say("App some-app does not exist.")) 127 }) 128 129 It("returns the user input", func() { 130 userInput, err := ui.DisplayPasswordPrompt("App {{.AppName}} does not exist.", map[string]interface{}{ 131 "AppName": "some-app", 132 }) 133 134 Expect(err).ToNot(HaveOccurred()) 135 Expect(userInput).To(Equal("some-input")) 136 Expect(out).ToNot(Say("some-input")) 137 }) 138 139 When("the locale is not set to English", func() { 140 BeforeEach(func() { 141 fakeConfig.LocaleReturns("fr-FR") 142 143 var err error 144 ui, err = NewUI(fakeConfig) 145 Expect(err).NotTo(HaveOccurred()) 146 147 ui.Out = out 148 ui.OutForInteration = out 149 150 inBuffer = NewBuffer() 151 ui.In = inBuffer 152 153 _, err = inBuffer.Write([]byte("ffffff\n")) 154 Expect(err).ToNot(HaveOccurred()) 155 }) 156 157 It("translates and displays the prompt", func() { 158 _, err := ui.DisplayPasswordPrompt("App {{.AppName}} does not exist.", map[string]interface{}{ 159 "AppName": "some-app", 160 }) 161 Expect(err).NotTo(HaveOccurred()) 162 Expect(out).To(Say("L'application some-app n'existe pas.\n")) 163 }) 164 }) 165 }) 166 167 Describe("DisplayTextPrompt", func() { 168 BeforeEach(func() { 169 _, err := inBuffer.Write([]byte("some-input\n")) 170 Expect(err).ToNot(HaveOccurred()) 171 }) 172 173 It("displays the passed in string and returns the user input string", func() { 174 userInput, err := ui.DisplayTextPrompt("App {{.AppName}} does not exist.", map[string]interface{}{ 175 "AppName": "some-app", 176 }) 177 178 Expect(err).ToNot(HaveOccurred()) 179 Expect(out).To(Say("App some-app does not exist.")) 180 Expect(userInput).To(Equal("some-input")) 181 Expect(out).To(Say("some-input")) 182 }) 183 184 When("the local is not set to English", func() { 185 BeforeEach(func() { 186 fakeConfig.LocaleReturns("fr-FR") 187 188 var err error 189 ui, err = NewUI(fakeConfig) 190 Expect(err).NotTo(HaveOccurred()) 191 192 ui.Out = out 193 ui.OutForInteration = out 194 195 inBuffer = NewBuffer() 196 ui.In = inBuffer 197 198 _, err = inBuffer.Write([]byte("ffffff\n")) 199 Expect(err).ToNot(HaveOccurred()) 200 }) 201 202 It("translates and displays the prompt", func() { 203 _, err := ui.DisplayTextPrompt("App {{.AppName}} does not exist.", map[string]interface{}{ 204 "AppName": "some-app", 205 }) 206 Expect(err).NotTo(HaveOccurred()) 207 Expect(out).To(Say("L'application some-app n'existe pas.\n")) 208 }) 209 }) 210 }) 211 212 Describe("DisplayOptionalTextPrompt", func() { 213 When("the user enters a value", func() { 214 BeforeEach(func() { 215 _, err := inBuffer.Write([]byte("some-input\n")) 216 Expect(err).ToNot(HaveOccurred()) 217 }) 218 219 It("displays the passed in string and returns the user input string", func() { 220 userInput, err := ui.DisplayOptionalTextPrompt("default", "App {{.AppName}} does not exist.", map[string]interface{}{ 221 "AppName": "some-app", 222 }) 223 224 Expect(err).ToNot(HaveOccurred()) 225 Expect(out).To(Say(regexp.QuoteMeta("App some-app does not exist. (default):"))) 226 Expect(userInput).To(Equal("some-input")) 227 Expect(out).To(Say("some-input")) 228 }) 229 }) 230 231 When("the user presses enter to accept the default", func() { 232 BeforeEach(func() { 233 _, err := inBuffer.Write([]byte("\n")) 234 Expect(err).ToNot(HaveOccurred()) 235 }) 236 237 It("displays the passed in string and returns the default value", func() { 238 userInput, err := ui.DisplayOptionalTextPrompt("default", "App {{.AppName}} does not exist.", map[string]interface{}{ 239 "AppName": "some-app", 240 }) 241 242 Expect(err).ToNot(HaveOccurred()) 243 Expect(out).To(Say(regexp.QuoteMeta("App some-app does not exist. (default):"))) 244 Expect(userInput).To(Equal("default")) 245 }) 246 }) 247 }) 248 249 Describe("DisplayTextMenu", func() { 250 var ( 251 choices []string 252 prompt string 253 values map[string]interface{} 254 menuErr error 255 choice string 256 ) 257 BeforeEach(func() { 258 choices = []string{ 259 "choice-1", 260 "choice-2", 261 "choice-3", 262 "choice-4", 263 } 264 265 prompt = "some-{{.prompt}}" 266 values = map[string]interface{}{ 267 "prompt": "org", 268 } 269 }) 270 271 JustBeforeEach(func() { 272 choice, menuErr = ui.DisplayTextMenu(choices, prompt, values) 273 }) 274 275 It("displays the templated prompt correctly", func() { 276 Expect(ui.Out).To(Say("some-org \\(enter to skip\\):")) 277 }) 278 279 It("displays the choices correctly", func() { 280 Expect(ui.Out).To(Say("1. choice-1")) 281 Expect(ui.Out).To(Say("2. choice-2")) 282 Expect(ui.Out).To(Say("3. choice-3")) 283 Expect(ui.Out).To(Say("4. choice-4")) 284 }) 285 286 When("the user enters a valid list index", func() { 287 BeforeEach(func() { 288 _, err := inBuffer.Write([]byte("2\n")) 289 Expect(err).ToNot(HaveOccurred()) 290 }) 291 292 It("returns the value at that list position", func() { 293 Expect(choice).To(Equal("choice-2")) 294 }) 295 }) 296 297 When("the user enters the last list index", func() { 298 BeforeEach(func() { 299 _, err := inBuffer.Write([]byte("4\n")) 300 Expect(err).ToNot(HaveOccurred()) 301 }) 302 303 It("returns the value at that list position", func() { 304 Expect(choice).To(Equal("choice-4")) 305 }) 306 }) 307 308 When("the user enters a valid list display value", func() { 309 BeforeEach(func() { 310 _, err := inBuffer.Write([]byte("choice-3\n")) 311 Expect(err).ToNot(HaveOccurred()) 312 }) 313 314 It("returns that value", func() { 315 Expect(choice).To(Equal("choice-3")) 316 }) 317 }) 318 319 When("the user enters a list index which is too high", func() { 320 BeforeEach(func() { 321 _, err := inBuffer.Write([]byte("47\n")) 322 Expect(err).ToNot(HaveOccurred()) 323 }) 324 325 It("returns an invalid choice error", func() { 326 Expect(choice).To(Equal("")) 327 Expect(menuErr).To(Equal(ErrInvalidIndex)) 328 }) 329 }) 330 331 When("the user enters a list index which is too low", func() { 332 BeforeEach(func() { 333 _, err := inBuffer.Write([]byte("0\n")) 334 Expect(err).ToNot(HaveOccurred()) 335 }) 336 337 It("returns an invalid choice error", func() { 338 Expect(choice).To(Equal("")) 339 Expect(menuErr).To(Equal(ErrInvalidIndex)) 340 }) 341 }) 342 343 When("the user enters an invalid list display value", func() { 344 BeforeEach(func() { 345 _, err := inBuffer.Write([]byte("choice-94\n")) 346 Expect(err).ToNot(HaveOccurred()) 347 }) 348 349 It("returns an invalid choice error", func() { 350 Expect(choice).To(Equal("")) 351 Expect(menuErr).To(MatchError(InvalidChoiceError{Choice: "choice-94"})) 352 }) 353 }) 354 355 When("the user enters a blank line to decline to choose", func() { 356 BeforeEach(func() { 357 _, err := inBuffer.Write([]byte("\n")) 358 Expect(err).ToNot(HaveOccurred()) 359 }) 360 361 It("returns an empty string and no error", func() { 362 Expect(menuErr).ToNot(HaveOccurred()) 363 Expect(choice).To(Equal("")) 364 }) 365 }) 366 367 When("the user presses CTRL+C or CTRL+D", func() { 368 369 }) 370 }) 371 372 Describe("interrupt handling", func() { 373 When("the prompt is canceled by a keyboard interrupt (e.g. CTRL-C)", func() { 374 var ( 375 fakeResolver *uifakes.FakeResolver 376 fakeExiter *uifakes.FakeExiter 377 fakeInteractor *uifakes.FakeInteractor 378 ) 379 380 BeforeEach(func() { 381 fakeResolver = new(uifakes.FakeResolver) 382 fakeResolver.ResolveReturns(interact.ErrKeyboardInterrupt) 383 fakeExiter = new(uifakes.FakeExiter) 384 fakeInteractor = new(uifakes.FakeInteractor) 385 fakeInteractor.NewInteractionReturns(fakeResolver) 386 ui.Interactor = fakeInteractor 387 ui.Exiter = fakeExiter 388 }) 389 390 It("exits immediately from password prompt", func() { 391 _, err := ui.DisplayPasswordPrompt("App {{.AppName}} does not exist.", map[string]interface{}{ 392 "AppName": "some-app", 393 }) 394 Expect(err).To(MatchError("keyboard interrupt")) 395 Expect(fakeExiter.ExitCallCount()).To(Equal(1)) 396 Expect(fakeExiter.ExitArgsForCall(0)).To(Equal(130)) 397 }) 398 399 It("exits immediately from text prompt", func() { 400 _, err := ui.DisplayTextPrompt("App {{.AppName}} does not exist.", map[string]interface{}{ 401 "AppName": "some-app", 402 }) 403 Expect(err).To(MatchError("keyboard interrupt")) 404 Expect(fakeExiter.ExitCallCount()).To(Equal(1)) 405 Expect(fakeExiter.ExitArgsForCall(0)).To(Equal(130)) 406 }) 407 408 It("exits immediately from optional text prompt", func() { 409 _, err := ui.DisplayOptionalTextPrompt("some-default-value", "App {{.AppName}} does not exist.", map[string]interface{}{ 410 "AppName": "some-app", 411 }) 412 Expect(err).To(MatchError("keyboard interrupt")) 413 Expect(fakeExiter.ExitCallCount()).To(Equal(1)) 414 Expect(fakeExiter.ExitArgsForCall(0)).To(Equal(130)) 415 }) 416 417 It("exits immediately from bool prompt", func() { 418 _, err := ui.DisplayBoolPrompt(false, "some-prompt", nil) 419 Expect(err).To(MatchError("keyboard interrupt")) 420 Expect(fakeExiter.ExitCallCount()).To(Equal(1)) 421 Expect(fakeExiter.ExitArgsForCall(0)).To(Equal(130)) 422 }) 423 424 It("exits immediately from multiple choice prompt", func() { 425 choices := []string{"foo", "bar"} 426 choice, err := ui.DisplayTextMenu(choices, "choose!") 427 Expect(choice).To(Equal("")) 428 Expect(err).To(MatchError("keyboard interrupt")) 429 Expect(fakeExiter.ExitCallCount()).To(Equal(1)) 430 Expect(fakeExiter.ExitArgsForCall(0)).To(Equal(130)) 431 }) 432 }) 433 }) 434 })