github.com/hashicorp/packer@v1.14.3/packer/ui_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package packer 5 6 import ( 7 "bytes" 8 "strings" 9 "testing" 10 11 packersdk "github.com/hashicorp/packer-plugin-sdk/packer" 12 ) 13 14 // This reads the output from the bytes.Buffer in our test object 15 // and then resets the buffer. 16 func readWriter(ui *packersdk.BasicUi) (result string) { 17 buffer := ui.Writer.(*bytes.Buffer) 18 result = buffer.String() 19 buffer.Reset() 20 return 21 } 22 23 // Reset the input Reader than add some input to it. 24 func writeReader(ui *packersdk.BasicUi, input string) { 25 buffer := ui.Reader.(*bytes.Buffer) 26 buffer.WriteString(input) 27 } 28 29 func readErrorWriter(ui *packersdk.BasicUi) (result string) { 30 buffer := ui.ErrorWriter.(*bytes.Buffer) 31 result = buffer.String() 32 buffer.Reset() 33 return 34 } 35 36 func testUi() *packersdk.BasicUi { 37 return &packersdk.BasicUi{ 38 Reader: new(bytes.Buffer), 39 Writer: new(bytes.Buffer), 40 ErrorWriter: new(bytes.Buffer), 41 TTY: new(testTTY), 42 } 43 } 44 45 type testTTY struct { 46 say string 47 } 48 49 func (tty *testTTY) Close() error { return nil } 50 func (tty *testTTY) ReadString() (string, error) { 51 return tty.say, nil 52 } 53 54 func TestColoredUi(t *testing.T) { 55 bufferUi := testUi() 56 ui := &ColoredUi{UiColorYellow, UiColorRed, bufferUi, &UiProgressBar{}} 57 58 if !ui.supportsColors() { 59 t.Skip("skipping for ui without color support") 60 } 61 62 ui.Say("foo") 63 result := readWriter(bufferUi) 64 if result != "\033[1;33mfoo\033[0m\n" { 65 t.Fatalf("invalid output: %s", result) 66 } 67 68 ui.Message("foo") 69 result = readWriter(bufferUi) 70 if result != "\033[1;33mfoo\033[0m\n" { 71 t.Fatalf("invalid output: %s", result) 72 } 73 74 ui.Error("foo") 75 result = readWriter(bufferUi) 76 if result != "" { 77 t.Fatalf("invalid output: %s", result) 78 } 79 80 result = readErrorWriter(bufferUi) 81 if result != "\033[1;31mfoo\033[0m\n" { 82 t.Fatalf("invalid output: %s", result) 83 } 84 } 85 86 func TestColoredUi_noColorEnv(t *testing.T) { 87 bufferUi := testUi() 88 ui := &ColoredUi{UiColorYellow, UiColorRed, bufferUi, &UiProgressBar{}} 89 90 // Set the env var to get rid of the color 91 t.Setenv("PACKER_NO_COLOR", "1") 92 93 ui.Say("foo") 94 result := readWriter(bufferUi) 95 if result != "foo\n" { 96 t.Fatalf("invalid output: %s", result) 97 } 98 99 ui.Message("foo") 100 result = readWriter(bufferUi) 101 if result != "foo\n" { 102 t.Fatalf("invalid output: %s", result) 103 } 104 105 ui.Error("foo") 106 result = readErrorWriter(bufferUi) 107 if result != "foo\n" { 108 t.Fatalf("invalid output: %s", result) 109 } 110 } 111 112 func TestTargetedUI(t *testing.T) { 113 bufferUi := testUi() 114 targetedUi := &TargetedUI{ 115 Target: "foo", 116 Ui: bufferUi, 117 } 118 119 var actual, expected string 120 targetedUi.Say("foo") 121 actual = readWriter(bufferUi) 122 expected = "==> foo: foo\n" 123 if actual != expected { 124 t.Fatalf("bad: %#v", actual) 125 } 126 127 targetedUi.Message("foo") 128 actual = readWriter(bufferUi) 129 expected = "==> foo: foo\n" 130 if actual != expected { 131 t.Fatalf("bad: %#v", actual) 132 } 133 134 targetedUi.Error("bar") 135 actual = readErrorWriter(bufferUi) 136 expected = "==> foo: bar\n" 137 if actual != expected { 138 t.Fatalf("bad: %#v", actual) 139 } 140 141 targetedUi.Say("foo\nbar") 142 actual = readWriter(bufferUi) 143 expected = "==> foo: foo\n==> foo: bar\n" 144 if actual != expected { 145 t.Fatalf("bad: %#v", actual) 146 } 147 } 148 149 func TestColoredUi_ImplUi(t *testing.T) { 150 var raw interface{} 151 raw = &ColoredUi{} 152 if _, ok := raw.(packersdk.Ui); !ok { 153 t.Fatalf("ColoredUi must implement Ui") 154 } 155 } 156 157 func TestTargetedUI_ImplUi(t *testing.T) { 158 var raw interface{} 159 raw = &TargetedUI{} 160 if _, ok := raw.(packersdk.Ui); !ok { 161 t.Fatalf("TargetedUI must implement Ui") 162 } 163 } 164 165 func TestBasicUi_ImplUi(t *testing.T) { 166 var raw interface{} 167 raw = &packersdk.BasicUi{} 168 if _, ok := raw.(packersdk.Ui); !ok { 169 t.Fatalf("BasicUi must implement Ui") 170 } 171 } 172 173 func TestBasicUi_Error(t *testing.T) { 174 bufferUi := testUi() 175 176 var actual, expected string 177 bufferUi.Error("foo") 178 actual = readErrorWriter(bufferUi) 179 expected = "foo\n" 180 if actual != expected { 181 t.Fatalf("bad: %#v", actual) 182 } 183 184 bufferUi.ErrorWriter = nil 185 bufferUi.Error("5") 186 actual = readWriter(bufferUi) 187 expected = "5\n" 188 if actual != expected { 189 t.Fatalf("bad: %#v", actual) 190 } 191 } 192 193 func TestBasicUi_Say(t *testing.T) { 194 bufferUi := testUi() 195 196 var actual, expected string 197 198 bufferUi.Say("foo") 199 actual = readWriter(bufferUi) 200 expected = "foo\n" 201 if actual != expected { 202 t.Fatalf("bad: %#v", actual) 203 } 204 205 bufferUi.Say("5") 206 actual = readWriter(bufferUi) 207 expected = "5\n" 208 if actual != expected { 209 t.Fatalf("bad: %#v", actual) 210 } 211 } 212 213 func TestBasicUi_Ask(t *testing.T) { 214 215 var actual, expected string 216 var err error 217 218 var testCases = []struct { 219 Prompt, Input, Answer string 220 }{ 221 {"[c]ontinue or [a]bort", "c\n", "c"}, 222 {"[c]ontinue or [a]bort", "c", "c"}, 223 // Empty input shouldn't give an error 224 {"Name", "Joe Bloggs\n", "Joe Bloggs"}, 225 {"Name", "Joe Bloggs", "Joe Bloggs"}, 226 {"Name", "\n", ""}, 227 } 228 229 for _, testCase := range testCases { 230 // Because of the internal bufio we can't easily reset the input, so create a new one each time 231 bufferUi := testUi() 232 bufferUi.TTY = &testTTY{testCase.Input} 233 234 actual, err = bufferUi.Ask(testCase.Prompt) 235 if err != nil { 236 t.Fatal(err) 237 } 238 239 if actual != testCase.Answer { 240 t.Fatalf("bad answer: %#v", actual) 241 } 242 243 actual = readWriter(bufferUi) 244 expected = testCase.Prompt + " " 245 if actual != expected { 246 t.Fatalf("bad prompt: %#v", actual) 247 } 248 } 249 250 } 251 252 func TestMachineReadableUi_ImplUi(t *testing.T) { 253 var raw interface{} 254 raw = &MachineReadableUi{} 255 if _, ok := raw.(packersdk.Ui); !ok { 256 t.Fatalf("MachineReadableUi must implement Ui") 257 } 258 } 259 260 func TestMachineReadableUi(t *testing.T) { 261 var data, expected string 262 263 buf := new(bytes.Buffer) 264 ui := &MachineReadableUi{Writer: buf} 265 266 // No target 267 ui.Machine("foo", "bar", "baz") 268 data = strings.SplitN(buf.String(), ",", 2)[1] 269 expected = ",foo,bar,baz\n" 270 if data != expected { 271 t.Fatalf("bad: %s", data) 272 } 273 274 // Target 275 buf.Reset() 276 ui.Machine("mitchellh,foo", "bar", "baz") 277 data = strings.SplitN(buf.String(), ",", 2)[1] 278 expected = "mitchellh,foo,bar,baz\n" 279 if data != expected { 280 t.Fatalf("bad: %s", data) 281 } 282 283 // Commas 284 buf.Reset() 285 ui.Machine("foo", "foo,bar") 286 data = strings.SplitN(buf.String(), ",", 2)[1] 287 expected = ",foo,foo%!(PACKER_COMMA)bar\n" 288 if data != expected { 289 t.Fatalf("bad: %s", data) 290 } 291 292 // New lines 293 buf.Reset() 294 ui.Machine("foo", "foo\n") 295 data = strings.SplitN(buf.String(), ",", 2)[1] 296 expected = ",foo,foo\\n\n" 297 if data != expected { 298 t.Fatalf("bad: %#v", data) 299 } 300 }