github.com/liamawhite/cli-with-i18n@v6.32.1-0.20171122084555-dede0a5c3448+incompatible/cf/terminal/ui_test.go (about)

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