github.com/jasonkeene/cli@v6.14.1-0.20160816203908-ca5715166dfb+incompatible/cf/terminal/ui_test.go (about)

     1  package terminal_test
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"strings"
     7  
     8  	"github.com/cloudfoundry/cli/cf"
     9  	"github.com/cloudfoundry/cli/cf/configuration/coreconfig"
    10  	"github.com/cloudfoundry/cli/cf/i18n"
    11  	"github.com/cloudfoundry/cli/cf/models"
    12  	"github.com/cloudfoundry/cli/cf/trace/tracefakes"
    13  	"github.com/cloudfoundry/cli/testhelpers/configuration"
    14  	testconfig "github.com/cloudfoundry/cli/testhelpers/configuration"
    15  	io_helpers "github.com/cloudfoundry/cli/testhelpers/io"
    16  	go_i18n "github.com/nicksnyder/go-i18n/i18n"
    17  
    18  	. "github.com/cloudfoundry/cli/cf/terminal"
    19  	"github.com/cloudfoundry/cli/cf/trace"
    20  	. "github.com/cloudfoundry/cli/testhelpers/matchers"
    21  	. "github.com/onsi/ginkgo"
    22  	. "github.com/onsi/gomega"
    23  	"github.com/onsi/gomega/gbytes"
    24  )
    25  
    26  var _ = Describe("UI", func() {
    27  	var fakeLogger *tracefakes.FakePrinter
    28  	BeforeEach(func() {
    29  		fakeLogger = new(tracefakes.FakePrinter)
    30  	})
    31  
    32  	Describe("Printing message to stdout with PrintCapturingNoOutput", func() {
    33  		It("prints strings without using the TeePrinter", func() {
    34  			bucket := gbytes.NewBuffer()
    35  
    36  			printer := NewTeePrinter(os.Stdout)
    37  			printer.SetOutputBucket(bucket)
    38  
    39  			io_helpers.SimulateStdin("", func(reader io.Reader) {
    40  				output := io_helpers.CaptureOutput(func() {
    41  					ui := NewUI(reader, os.Stdout, printer, fakeLogger)
    42  					ui.PrintCapturingNoOutput("Hello")
    43  				})
    44  
    45  				Expect("Hello").To(Equal(strings.Join(output, "")))
    46  				Expect(bucket.Contents()).To(HaveLen(0))
    47  			})
    48  		})
    49  	})
    50  
    51  	Describe("Printing message to stdout with Say", func() {
    52  		It("prints strings", func() {
    53  			io_helpers.SimulateStdin("", func(reader io.Reader) {
    54  				output := io_helpers.CaptureOutput(func() {
    55  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
    56  					ui.Say("Hello")
    57  				})
    58  
    59  				Expect("Hello").To(Equal(strings.Join(output, "")))
    60  			})
    61  		})
    62  
    63  		It("prints formatted strings", func() {
    64  			io_helpers.SimulateStdin("", func(reader io.Reader) {
    65  				output := io_helpers.CaptureOutput(func() {
    66  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
    67  					ui.Say("Hello %s", "World!")
    68  				})
    69  
    70  				Expect("Hello World!").To(Equal(strings.Join(output, "")))
    71  			})
    72  		})
    73  
    74  		It("does not format strings when provided no args", func() {
    75  			output := io_helpers.CaptureOutput(func() {
    76  				ui := NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
    77  				ui.Say("Hello %s World!") // whoops
    78  			})
    79  
    80  			Expect(strings.Join(output, "")).To(Equal("Hello %s World!"))
    81  		})
    82  	})
    83  
    84  	Describe("Asking user for input", func() {
    85  		It("allows string with whitespaces", func() {
    86  			_ = io_helpers.CaptureOutput(func() {
    87  				io_helpers.SimulateStdin("foo bar\n", func(reader io.Reader) {
    88  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
    89  					Expect(ui.Ask("?")).To(Equal("foo bar"))
    90  				})
    91  			})
    92  		})
    93  
    94  		It("returns empty string if an error occured while reading string", func() {
    95  			_ = io_helpers.CaptureOutput(func() {
    96  				io_helpers.SimulateStdin("string without expected delimiter", func(reader io.Reader) {
    97  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
    98  					Expect(ui.Ask("?")).To(Equal(""))
    99  				})
   100  			})
   101  		})
   102  
   103  		It("always outputs the prompt, even when output is disabled", func() {
   104  			output := io_helpers.CaptureOutput(func() {
   105  				io_helpers.SimulateStdin("things are great\n", func(reader io.Reader) {
   106  					printer := NewTeePrinter(os.Stdout)
   107  					printer.DisableTerminalOutput(true)
   108  					ui := NewUI(reader, os.Stdout, printer, fakeLogger)
   109  					ui.Ask("You like things?")
   110  				})
   111  			})
   112  			Expect(strings.Join(output, "")).To(ContainSubstring("You like things?"))
   113  		})
   114  	})
   115  
   116  	Describe("Confirming user input", func() {
   117  		It("treats 'y' as an affirmative confirmation", func() {
   118  			io_helpers.SimulateStdin("y\n", func(reader io.Reader) {
   119  				out := io_helpers.CaptureOutput(func() {
   120  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   121  					Expect(ui.Confirm("Hello World?")).To(BeTrue())
   122  				})
   123  
   124  				Expect(out).To(ContainSubstrings([]string{"Hello World?"}))
   125  			})
   126  		})
   127  
   128  		It("treats 'yes' as an affirmative confirmation when default language is not en_US", func() {
   129  			oldLang := os.Getenv("LC_ALL")
   130  			defer os.Setenv("LC_ALL", oldLang)
   131  
   132  			oldT := i18n.T
   133  			defer func() {
   134  				i18n.T = oldT
   135  			}()
   136  
   137  			os.Setenv("LC_ALL", "fr_FR")
   138  
   139  			config := configuration.NewRepositoryWithDefaults()
   140  			i18n.T = i18n.Init(config)
   141  
   142  			io_helpers.SimulateStdin("yes\n", func(reader io.Reader) {
   143  				out := io_helpers.CaptureOutput(func() {
   144  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   145  					Expect(ui.Confirm("Hello World?")).To(BeTrue())
   146  				})
   147  				Expect(out).To(ContainSubstrings([]string{"Hello World?"}))
   148  			})
   149  		})
   150  
   151  		It("treats 'yes' as an affirmative confirmation", func() {
   152  			io_helpers.SimulateStdin("yes\n", func(reader io.Reader) {
   153  				out := io_helpers.CaptureOutput(func() {
   154  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   155  					Expect(ui.Confirm("Hello World?")).To(BeTrue())
   156  				})
   157  
   158  				Expect(out).To(ContainSubstrings([]string{"Hello World?"}))
   159  			})
   160  		})
   161  
   162  		It("treats other input as a negative confirmation", func() {
   163  			io_helpers.SimulateStdin("wat\n", func(reader io.Reader) {
   164  				out := io_helpers.CaptureOutput(func() {
   165  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   166  					Expect(ui.Confirm("Hello World?")).To(BeFalse())
   167  				})
   168  
   169  				Expect(out).To(ContainSubstrings([]string{"Hello World?"}))
   170  			})
   171  		})
   172  	})
   173  
   174  	Describe("Confirming deletion", func() {
   175  		It("formats a nice output string with exactly one prompt", func() {
   176  			io_helpers.SimulateStdin("y\n", func(reader io.Reader) {
   177  				out := io_helpers.CaptureOutput(func() {
   178  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   179  					Expect(ui.ConfirmDelete("fizzbuzz", "bizzbump")).To(BeTrue())
   180  				})
   181  
   182  				Expect(out).To(ContainSubstrings([]string{
   183  					"Really delete the fizzbuzz",
   184  					"bizzbump",
   185  					"?> ",
   186  				}))
   187  			})
   188  		})
   189  
   190  		It("treats 'yes' as an affirmative confirmation", func() {
   191  			io_helpers.SimulateStdin("yes\n", func(reader io.Reader) {
   192  				out := io_helpers.CaptureOutput(func() {
   193  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   194  					Expect(ui.ConfirmDelete("modelType", "modelName")).To(BeTrue())
   195  				})
   196  
   197  				Expect(out).To(ContainSubstrings([]string{"modelType modelName"}))
   198  			})
   199  		})
   200  
   201  		It("treats other input as a negative confirmation and warns the user", func() {
   202  			io_helpers.SimulateStdin("wat\n", func(reader io.Reader) {
   203  				out := io_helpers.CaptureOutput(func() {
   204  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   205  					Expect(ui.ConfirmDelete("modelType", "modelName")).To(BeFalse())
   206  				})
   207  
   208  				Expect(out).To(ContainSubstrings([]string{"Delete cancelled"}))
   209  			})
   210  		})
   211  	})
   212  
   213  	Describe("Confirming deletion with associations", func() {
   214  		It("warns the user that associated objects will also be deleted", func() {
   215  			io_helpers.SimulateStdin("wat\n", func(reader io.Reader) {
   216  				out := io_helpers.CaptureOutput(func() {
   217  					ui := NewUI(reader, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   218  					Expect(ui.ConfirmDeleteWithAssociations("modelType", "modelName")).To(BeFalse())
   219  				})
   220  
   221  				Expect(out).To(ContainSubstrings([]string{"Delete cancelled"}))
   222  			})
   223  		})
   224  	})
   225  
   226  	Context("when user is not logged in", func() {
   227  		var config coreconfig.Reader
   228  
   229  		BeforeEach(func() {
   230  			config = testconfig.NewRepository()
   231  		})
   232  
   233  		It("prompts the user to login", func() {
   234  			output := io_helpers.CaptureOutput(func() {
   235  				ui := NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   236  				ui.ShowConfiguration(config)
   237  			})
   238  
   239  			Expect(output).ToNot(ContainSubstrings([]string{"API endpoint:"}))
   240  			Expect(output).To(ContainSubstrings([]string{"Not logged in", "Use", "log in"}))
   241  		})
   242  	})
   243  
   244  	Context("when an api endpoint is set and the user logged in", func() {
   245  		var config coreconfig.ReadWriter
   246  
   247  		BeforeEach(func() {
   248  			accessToken := coreconfig.TokenInfo{
   249  				UserGUID: "my-user-guid",
   250  				Username: "my-user",
   251  				Email:    "my-user-email",
   252  			}
   253  			config = testconfig.NewRepositoryWithAccessToken(accessToken)
   254  			config.SetAPIEndpoint("https://test.example.org")
   255  			config.SetAPIVersion("☃☃☃")
   256  		})
   257  
   258  		Describe("tells the user what is set in the config", func() {
   259  			var output []string
   260  
   261  			JustBeforeEach(func() {
   262  				output = io_helpers.CaptureOutput(func() {
   263  					ui := NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   264  					ui.ShowConfiguration(config)
   265  				})
   266  			})
   267  
   268  			It("tells the user which api endpoint is set", func() {
   269  				Expect(output).To(ContainSubstrings([]string{"API endpoint:", "https://test.example.org"}))
   270  			})
   271  
   272  			It("tells the user the api version", func() {
   273  				Expect(output).To(ContainSubstrings([]string{"API version:", "☃☃☃"}))
   274  			})
   275  
   276  			It("tells the user which user is logged in", func() {
   277  				Expect(output).To(ContainSubstrings([]string{"User:", "my-user-email"}))
   278  			})
   279  
   280  			Context("when an org is targeted", func() {
   281  				BeforeEach(func() {
   282  					config.SetOrganizationFields(models.OrganizationFields{
   283  						Name: "org-name",
   284  						GUID: "org-guid",
   285  					})
   286  				})
   287  
   288  				It("tells the user which org is targeted", func() {
   289  					Expect(output).To(ContainSubstrings([]string{"Org:", "org-name"}))
   290  				})
   291  			})
   292  
   293  			Context("when a space is targeted", func() {
   294  				BeforeEach(func() {
   295  					config.SetSpaceFields(models.SpaceFields{
   296  						Name: "my-space",
   297  						GUID: "space-guid",
   298  					})
   299  				})
   300  
   301  				It("tells the user which space is targeted", func() {
   302  					Expect(output).To(ContainSubstrings([]string{"Space:", "my-space"}))
   303  				})
   304  			})
   305  		})
   306  
   307  		It("prompts the user to target an org and space when no org or space is targeted", func() {
   308  			output := io_helpers.CaptureOutput(func() {
   309  				ui := NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   310  				ui.ShowConfiguration(config)
   311  			})
   312  
   313  			Expect(output).To(ContainSubstrings([]string{"No", "org", "space", "targeted", "-o ORG", "-s SPACE"}))
   314  		})
   315  
   316  		It("prompts the user to target an org when no org is targeted", func() {
   317  			sf := models.SpaceFields{}
   318  			sf.GUID = "guid"
   319  			sf.Name = "name"
   320  
   321  			output := io_helpers.CaptureOutput(func() {
   322  				ui := NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   323  				ui.ShowConfiguration(config)
   324  			})
   325  
   326  			Expect(output).To(ContainSubstrings([]string{"No", "org", "targeted", "-o ORG"}))
   327  		})
   328  
   329  		It("prompts the user to target a space when no space is targeted", func() {
   330  			of := models.OrganizationFields{}
   331  			of.GUID = "of-guid"
   332  			of.Name = "of-name"
   333  
   334  			output := io_helpers.CaptureOutput(func() {
   335  				ui := NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   336  				ui.ShowConfiguration(config)
   337  			})
   338  
   339  			Expect(output).To(ContainSubstrings([]string{"No", "space", "targeted", "-s SPACE"}))
   340  		})
   341  	})
   342  
   343  	Describe("failing", func() {
   344  		Context("when 'T' func is not initialized", func() {
   345  			var t go_i18n.TranslateFunc
   346  			BeforeEach(func() {
   347  				t = i18n.T
   348  				i18n.T = nil
   349  			})
   350  
   351  			AfterEach(func() {
   352  				i18n.T = t
   353  			})
   354  
   355  			It("does not duplicate output if logger is set to stdout", func() {
   356  				output := io_helpers.CaptureOutput(func() {
   357  					logger := trace.NewWriterPrinter(os.Stdout, true)
   358  					NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), logger).Failed("this should print only once")
   359  				})
   360  
   361  				Expect(output).To(HaveLen(3))
   362  				Expect(output[0]).To(Equal("FAILED"))
   363  				Expect(output[1]).To(Equal("this should print only once"))
   364  				Expect(output[2]).To(Equal(""))
   365  			})
   366  		})
   367  
   368  		Context("when 'T' func is initialized", func() {
   369  			It("does not duplicate output if logger is set to stdout", func() {
   370  				output := io_helpers.CaptureOutput(
   371  					func() {
   372  						logger := trace.NewWriterPrinter(os.Stdout, true)
   373  						NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), logger).Failed("this should print only once")
   374  					})
   375  
   376  				Expect(output).To(HaveLen(3))
   377  				Expect(output[0]).To(Equal("FAILED"))
   378  				Expect(output[1]).To(Equal("this should print only once"))
   379  				Expect(output[2]).To(Equal(""))
   380  			})
   381  		})
   382  	})
   383  
   384  	Describe("NotifyUpdateIfNeeded", func() {
   385  		var (
   386  			output []string
   387  			config coreconfig.ReadWriter
   388  		)
   389  
   390  		BeforeEach(func() {
   391  			config = testconfig.NewRepository()
   392  		})
   393  
   394  		It("Prints a notification to user if current version < min cli version", func() {
   395  			config.SetMinCLIVersion("6.0.0")
   396  			config.SetMinRecommendedCLIVersion("6.5.0")
   397  			config.SetAPIVersion("2.15.1")
   398  			cf.Version = "5.0.0"
   399  			output = io_helpers.CaptureOutput(func() {
   400  				ui := NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   401  				ui.NotifyUpdateIfNeeded(config)
   402  			})
   403  
   404  			Expect(output).To(ContainSubstrings([]string{"Cloud Foundry API version",
   405  				"requires CLI version 6.0.0",
   406  				"You are currently on version 5.0.0",
   407  				"To upgrade your CLI, please visit: https://github.com/cloudfoundry/cli#downloads",
   408  			}))
   409  		})
   410  
   411  		It("Doesn't print a notification to user if current version >= min cli version", func() {
   412  			config.SetMinCLIVersion("6.0.0")
   413  			config.SetMinRecommendedCLIVersion("6.5.0")
   414  			config.SetAPIVersion("2.15.1")
   415  			cf.Version = "6.0.0"
   416  			output = io_helpers.CaptureOutput(func() {
   417  				ui := NewUI(os.Stdin, os.Stdout, NewTeePrinter(os.Stdout), fakeLogger)
   418  				ui.NotifyUpdateIfNeeded(config)
   419  			})
   420  
   421  			Expect(output[0]).To(Equal(""))
   422  		})
   423  	})
   424  })