code.cloudfoundry.org/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  })