github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/util/ui/ui_test.go (about)

     1  package ui_test
     2  
     3  import (
     4  	"errors"
     5  	"time"
     6  
     7  	"code.cloudfoundry.org/cli/command/translatableerror/translatableerrorfakes"
     8  	"code.cloudfoundry.org/cli/util/configv3"
     9  	. "code.cloudfoundry.org/cli/util/ui"
    10  	"code.cloudfoundry.org/cli/util/ui/uifakes"
    11  	. "github.com/onsi/ginkgo"
    12  	. "github.com/onsi/gomega"
    13  	. "github.com/onsi/gomega/gbytes"
    14  )
    15  
    16  var _ = Describe("UI", func() {
    17  	var (
    18  		ui         *UI
    19  		fakeConfig *uifakes.FakeConfig
    20  		out        *Buffer
    21  		errBuff    *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.OutForInteraction = out
    35  		errBuff = NewBuffer()
    36  		ui.Err = errBuff
    37  	})
    38  
    39  	Describe("DisplayDeprecationWarning", func() {
    40  		It("displays the deprecation warning to ui.Err", func() {
    41  			ui.DisplayDeprecationWarning()
    42  			Expect(ui.Err).To(Say("Deprecation warning: This command has been deprecated. This feature will be removed in the future.\n"))
    43  		})
    44  
    45  		When("the locale is not set to English", func() {
    46  			BeforeEach(func() {
    47  				fakeConfig.LocaleReturns("fr-FR")
    48  
    49  				var err error
    50  				ui, err = NewUI(fakeConfig)
    51  				Expect(err).NotTo(HaveOccurred())
    52  
    53  				ui.Err = NewBuffer()
    54  			})
    55  
    56  			PIt("displays the translated deprecation warning to ui.Err", func() {
    57  				// TODO: Test implementation awaits translated version of deprecation warning string literal #164098152.
    58  			})
    59  		})
    60  	})
    61  
    62  	Describe("DisplayFileDeprecationWarning", func() {
    63  		It("displays the `cf files` deprecation warning to ui.Err", func() {
    64  			ui.DisplayFileDeprecationWarning()
    65  			Expect(ui.Err).To(Say("Deprecation warning: This command has been deprecated and will be removed in the future. For similar functionality, please use the `cf ssh` command instead.\n"))
    66  		})
    67  
    68  		When("the locale is not set to English", func() {
    69  			BeforeEach(func() {
    70  				fakeConfig.LocaleReturns("fr-FR")
    71  
    72  				var err error
    73  				ui, err = NewUI(fakeConfig)
    74  				Expect(err).NotTo(HaveOccurred())
    75  
    76  				ui.Err = NewBuffer()
    77  			})
    78  
    79  			PIt("displays the translated deprecation warning to ui.Err", func() {
    80  				// TODO: Test implementation awaits translated version of deprecation warning string literal #164098103.
    81  			})
    82  		})
    83  	})
    84  
    85  	Describe("DisplayError", func() {
    86  		When("passed a TranslatableError", func() {
    87  			var fakeTranslateErr *translatableerrorfakes.FakeTranslatableError
    88  
    89  			BeforeEach(func() {
    90  				fakeTranslateErr = new(translatableerrorfakes.FakeTranslatableError)
    91  				fakeTranslateErr.TranslateReturns("I am an error")
    92  
    93  				ui.DisplayError(fakeTranslateErr)
    94  			})
    95  
    96  			It("displays the error to ui.Err and displays FAILED in bold red to ui.Out", func() {
    97  				Expect(ui.Err).To(Say("I am an error\n"))
    98  				Expect(out).To(Say("\x1b\\[31;1mFAILED\x1b\\[0m\n"))
    99  			})
   100  
   101  			When("the locale is not set to english", func() {
   102  				It("translates the error text", func() {
   103  					Expect(fakeTranslateErr.TranslateCallCount()).To(Equal(1))
   104  					Expect(fakeTranslateErr.TranslateArgsForCall(0)).NotTo(BeNil())
   105  				})
   106  			})
   107  		})
   108  
   109  		When("passed a generic error", func() {
   110  			It("displays the error text to ui.Err and displays FAILED in bold red to ui.Out", func() {
   111  				ui.DisplayError(errors.New("I am a BANANA!"))
   112  				Expect(ui.Err).To(Say("I am a BANANA!\n"))
   113  				Expect(out).To(Say("\x1b\\[31;1mFAILED\x1b\\[0m\n"))
   114  			})
   115  		})
   116  	})
   117  
   118  	Describe("DisplayHeader", func() {
   119  		It("displays the header colorized and bolded to ui.Out", func() {
   120  			ui.DisplayHeader("some-header")
   121  			Expect(out).To(Say("\x1b\\[1msome-header\x1b\\[0m"))
   122  		})
   123  
   124  		When("the locale is not set to English", func() {
   125  			BeforeEach(func() {
   126  				fakeConfig.LocaleReturns("fr-FR")
   127  
   128  				var err error
   129  				ui, err = NewUI(fakeConfig)
   130  				Expect(err).NotTo(HaveOccurred())
   131  
   132  				ui.Out = out
   133  			})
   134  
   135  			It("displays the translated header colorized and bolded to ui.Out", func() {
   136  				ui.DisplayHeader("FEATURE FLAGS")
   137  				Expect(out).To(Say("\x1b\\[1mINDICATEURS DE FONCTION\x1b\\[0m"))
   138  			})
   139  		})
   140  	})
   141  
   142  	Describe("DisplayNewline", func() {
   143  		It("displays a new line", func() {
   144  			ui.DisplayNewline()
   145  			Expect(out).To(Say("\n"))
   146  		})
   147  	})
   148  
   149  	Describe("DisplayOK", func() {
   150  		It("displays 'OK' in green and bold", func() {
   151  			ui.DisplayOK()
   152  			Expect(out).To(Say("\x1b\\[32;1mOK\x1b\\[0m"))
   153  		})
   154  	})
   155  
   156  	// Covers the happy paths, additional cases are tested in TranslateText
   157  	Describe("DisplayText", func() {
   158  		It("displays the template with map values substituted into ui.Out with a newline", func() {
   159  			ui.DisplayText(
   160  				"template with {{.SomeMapValue}}",
   161  				map[string]interface{}{
   162  					"SomeMapValue": "map-value",
   163  				})
   164  			Expect(out).To(Say("template with map-value\n"))
   165  		})
   166  
   167  		When("the locale is not set to english", func() {
   168  			BeforeEach(func() {
   169  				fakeConfig.LocaleReturns("fr-FR")
   170  
   171  				var err error
   172  				ui, err = NewUI(fakeConfig)
   173  				Expect(err).NotTo(HaveOccurred())
   174  
   175  				ui.Out = out
   176  			})
   177  
   178  			It("displays the translated template with map values substituted into ui.Out", func() {
   179  				ui.DisplayText(
   180  					"\nTIP: Use '{{.Command}}' to target new org",
   181  					map[string]interface{}{
   182  						"Command": "foo",
   183  					})
   184  				Expect(out).To(Say("\nASTUCE : utilisez 'foo' pour cibler une nouvelle organisation"))
   185  			})
   186  		})
   187  	})
   188  
   189  	Describe("Display JSON", func() {
   190  		It("displays the indented JSON object", func() {
   191  			obj := map[string]interface{}{
   192  				"str":  "hello",
   193  				"bool": true,
   194  				"int":  42,
   195  				"pass": "abc>&gd!f",
   196  				"map":  map[string]interface{}{"float": 123.03},
   197  				"arr":  []string{"a", "b"},
   198  			}
   199  
   200  			_ = ui.DisplayJSON("named_json", obj)
   201  
   202  			Expect(out).To(SatisfyAll(
   203  				Say("named_json: {\n"),
   204  				Say("  \"arr\": \\[\n"),
   205  				Say("    \"a\","),
   206  				Say("    \"b\"\n"),
   207  				Say("  \\],\n"),
   208  				Say("  \"bool\": true,\n"),
   209  				Say("  \"int\": 42,\n"),
   210  				Say("  \"map\": {\n"),
   211  				Say("    \"float\": 123.03\n"),
   212  				Say("  },\n"),
   213  				Say("  \"pass\": \"abc>&gd!f\",\n"),
   214  				Say("  \"str\": \"hello\"\n"),
   215  				Say("}\n"),
   216  				Say("\n"),
   217  			))
   218  		})
   219  	})
   220  
   221  	Describe("DeferText", func() {
   222  		It("defers the template with map values substituted into ui.Out with a newline", func() {
   223  			ui.DeferText(
   224  				"template with {{.SomeMapValue}}",
   225  				map[string]interface{}{
   226  					"SomeMapValue": "map-value",
   227  				})
   228  			Expect(out).NotTo(Say("template with map-value\n"))
   229  			ui.FlushDeferred()
   230  			Expect(out).To(Say("template with map-value\n"))
   231  		})
   232  
   233  		When("the locale is not set to english", func() {
   234  			BeforeEach(func() {
   235  				fakeConfig.LocaleReturns("fr-FR")
   236  
   237  				var err error
   238  				ui, err = NewUI(fakeConfig)
   239  				Expect(err).NotTo(HaveOccurred())
   240  
   241  				ui.Out = out
   242  			})
   243  
   244  			It("defers the translated template with map values substituted into ui.Out", func() {
   245  				ui.DeferText(
   246  					"\nTIP: Use '{{.Command}}' to target new org",
   247  					map[string]interface{}{
   248  						"Command": "foo",
   249  					})
   250  				Expect(out).NotTo(Say("\nASTUCE : utilisez 'foo' pour cibler une nouvelle organisation"))
   251  				ui.FlushDeferred()
   252  				Expect(out).To(Say("\nASTUCE : utilisez 'foo' pour cibler une nouvelle organisation"))
   253  				ui.FlushDeferred()
   254  				Expect(out).NotTo(Say("\nASTUCE : utilisez 'foo' pour cibler une nouvelle organisation"))
   255  			})
   256  		})
   257  	})
   258  
   259  	Describe("DisplayTextWithBold", func() {
   260  		It("displays the template to ui.Out", func() {
   261  			ui.DisplayTextWithBold("some-template")
   262  			Expect(out).To(Say("some-template"))
   263  		})
   264  
   265  		When("an optional map is passed in", func() {
   266  			It("displays the template with map values bolded and substituted into ui.Out", func() {
   267  				ui.DisplayTextWithBold(
   268  					"template with {{.SomeMapValue}}",
   269  					map[string]interface{}{
   270  						"SomeMapValue": "map-value",
   271  					})
   272  				Expect(out).To(Say("template with \x1b\\[1mmap-value\x1b\\[0m"))
   273  			})
   274  		})
   275  
   276  		When("multiple optional maps are passed in", func() {
   277  			It("displays the template with only the first map values bolded and substituted into ui.Out", func() {
   278  				ui.DisplayTextWithBold(
   279  					"template with {{.SomeMapValue}} and {{.SomeOtherMapValue}}",
   280  					map[string]interface{}{
   281  						"SomeMapValue": "map-value",
   282  					},
   283  					map[string]interface{}{
   284  						"SomeOtherMapValue": "other-map-value",
   285  					})
   286  				Expect(out).To(Say("template with \x1b\\[1mmap-value\x1b\\[0m and <no value>"))
   287  			})
   288  		})
   289  
   290  		When("the locale is not set to english", func() {
   291  			BeforeEach(func() {
   292  				fakeConfig.LocaleReturns("fr-FR")
   293  
   294  				var err error
   295  				ui, err = NewUI(fakeConfig)
   296  				Expect(err).NotTo(HaveOccurred())
   297  
   298  				ui.Out = out
   299  			})
   300  
   301  			It("displays the translated template with map values bolded and substituted into ui.Out", func() {
   302  				ui.DisplayTextWithBold(
   303  					"App {{.AppName}} does not exist.",
   304  					map[string]interface{}{
   305  						"AppName": "some-app-name",
   306  					})
   307  				Expect(out).To(Say("L'application \x1b\\[1msome-app-name\x1b\\[0m n'existe pas.\n"))
   308  			})
   309  		})
   310  	})
   311  
   312  	Describe("DisplayTextWithFlavor", func() {
   313  		It("displays the template to ui.Out", func() {
   314  			ui.DisplayTextWithFlavor("some-template")
   315  			Expect(out).To(Say("some-template"))
   316  		})
   317  
   318  		When("an optional map is passed in", func() {
   319  			It("displays the template with map values colorized, bolded, and substituted into ui.Out", func() {
   320  				ui.DisplayTextWithFlavor(
   321  					"template with {{.SomeMapValue}}",
   322  					map[string]interface{}{
   323  						"SomeMapValue": "map-value",
   324  					})
   325  				Expect(out).To(Say("template with \x1b\\[36;1mmap-value\x1b\\[0m"))
   326  			})
   327  		})
   328  
   329  		When("multiple optional maps are passed in", func() {
   330  			It("displays the template with only the first map values colorized, bolded, and substituted into ui.Out", func() {
   331  				ui.DisplayTextWithFlavor(
   332  					"template with {{.SomeMapValue}} and {{.SomeOtherMapValue}}",
   333  					map[string]interface{}{
   334  						"SomeMapValue": "map-value",
   335  					},
   336  					map[string]interface{}{
   337  						"SomeOtherMapValue": "other-map-value",
   338  					})
   339  				Expect(out).To(Say("template with \x1b\\[36;1mmap-value\x1b\\[0m and <no value>"))
   340  			})
   341  		})
   342  
   343  		When("the locale is not set to english", func() {
   344  			BeforeEach(func() {
   345  				fakeConfig.LocaleReturns("fr-FR")
   346  
   347  				var err error
   348  				ui, err = NewUI(fakeConfig)
   349  				Expect(err).NotTo(HaveOccurred())
   350  
   351  				ui.Out = out
   352  			})
   353  
   354  			It("displays the translated template with map values colorized, bolded and substituted into ui.Out", func() {
   355  				ui.DisplayTextWithFlavor(
   356  					"App {{.AppName}} does not exist.",
   357  					map[string]interface{}{
   358  						"AppName": "some-app-name",
   359  					})
   360  				Expect(out).To(Say("L'application \x1b\\[36;1msome-app-name\x1b\\[0m n'existe pas.\n"))
   361  			})
   362  		})
   363  	})
   364  
   365  	Describe("DisplayDiffAddition", func() {
   366  		It("displays a green indented line with a +", func() {
   367  			ui.DisplayDiffAddition("added", 3, false)
   368  			Expect(out).To(Say(`\x1b\[32m\+       added\x1b\[0m`))
   369  		})
   370  		It("displays a hyphen when the addHyphen is true", func() {
   371  			ui.DisplayDiffAddition("added", 3, true)
   372  			Expect(out).To(Say(`\x1b\[32m\+     - added\x1b\[0m`))
   373  		})
   374  
   375  	})
   376  
   377  	Describe("DisplayDiffRemoval", func() {
   378  		It("displays a red indented line with a -", func() {
   379  			ui.DisplayDiffRemoval("removed", 3, false)
   380  			Expect(out).To(Say(`\x1b\[31m\-       removed\x1b\[0m`))
   381  		})
   382  		It("displays a a hyphen when addHyphen is true", func() {
   383  			ui.DisplayDiffRemoval("removed", 3, true)
   384  			Expect(out).To(Say(`\x1b\[31m\-     - removed\x1b\[0m`))
   385  		})
   386  	})
   387  
   388  	Describe("DisplayDiffUnchanged", func() {
   389  		It("displays a plain indented line with no prefix", func() {
   390  			ui.DisplayDiffUnchanged("unchanged", 3, false)
   391  			Expect(out).To(Say("        unchanged"))
   392  		})
   393  		It("displays a a hyphen when addHyphen is true", func() {
   394  			ui.DisplayDiffUnchanged("unchanged", 3, true)
   395  			Expect(out).To(Say("      - unchanged"))
   396  		})
   397  	})
   398  
   399  	Describe("TranslateText", func() {
   400  		It("returns the template", func() {
   401  			Expect(ui.TranslateText("some-template")).To(Equal("some-template"))
   402  		})
   403  
   404  		When("an optional map is passed in", func() {
   405  			It("returns the template with map values substituted in", func() {
   406  				expected := ui.TranslateText(
   407  					"template {{.SomeMapValue}}",
   408  					map[string]interface{}{
   409  						"SomeMapValue": "map-value",
   410  					})
   411  				Expect(expected).To(Equal("template map-value"))
   412  			})
   413  		})
   414  
   415  		When("multiple optional maps are passed in", func() {
   416  			It("returns the template with only the first map values substituted in", func() {
   417  				expected := ui.TranslateText(
   418  					"template with {{.SomeMapValue}} and {{.SomeOtherMapValue}}",
   419  					map[string]interface{}{
   420  						"SomeMapValue": "map-value",
   421  					},
   422  					map[string]interface{}{
   423  						"SomeOtherMapValue": "other-map-value",
   424  					})
   425  				Expect(expected).To(Equal("template with map-value and <no value>"))
   426  			})
   427  		})
   428  
   429  		When("the locale is not set to english", func() {
   430  			BeforeEach(func() {
   431  				fakeConfig.LocaleReturns("fr-FR")
   432  
   433  				var err error
   434  				ui, err = NewUI(fakeConfig)
   435  				Expect(err).NotTo(HaveOccurred())
   436  			})
   437  
   438  			It("returns the translated template", func() {
   439  				expected := ui.TranslateText("   View allowable quotas with 'CF_NAME quotas'")
   440  				Expect(expected).To(Equal("   Affichez les quotas pouvant être alloués avec 'CF_NAME quotas'"))
   441  			})
   442  		})
   443  	})
   444  
   445  	Describe("UserFriendlyDate", func() {
   446  		It("formats a time into an ISO8601 string", func() {
   447  			Expect(ui.UserFriendlyDate(time.Unix(0, 0))).To(MatchRegexp(`\w{3} [0-3]\d \w{3} [0-2]\d:[0-5]\d:[0-5]\d \w+ \d{4}`))
   448  		})
   449  	})
   450  })