Skip to content

Commit c88662b

Browse files
feat(printer): add Noticef and Noticeln methods to printer (#1675)
We were missing dedicated printer methods to display sth. to the user on StdErr regardless of output-format or verbosity. STACKITCLI-480
1 parent 1efac23 commit c88662b

2 files changed

Lines changed: 157 additions & 0 deletions

File tree

‎internal/pkg/print/print.go‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,16 @@ func (p *Printer) Outputln(msg string) {
9797
mustPrint(fmt.Fprintln(p.StdOut, msg))
9898
}
9999

100+
// Noticef prints a formatted notice to StdErr, regardless of verbosity or output format.
101+
func (p *Printer) Noticef(msg string, args ...any) {
102+
mustPrint(fmt.Fprintf(p.StdErr, msg, args...))
103+
}
104+
105+
// Noticeln prints a notice followed by a newline to StdErr, regardless of verbosity or output format.
106+
func (p *Printer) Noticeln(msg string) {
107+
mustPrint(fmt.Fprintln(p.StdErr, msg))
108+
}
109+
100110
// Print a Debug level log through the "slog" package.
101111
// If the verbosity level is not Debug, it does nothing
102112
func (p *Printer) Debug(level Level, msg string, args ...any) {

‎internal/pkg/print/print_test.go‎

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,153 @@ func TestOutputln(t *testing.T) {
152152
}
153153
}
154154

155+
func TestNoticef(t *testing.T) {
156+
tests := []struct {
157+
description string
158+
message string
159+
args []any
160+
verbosity Level
161+
outputFormatNone bool
162+
expectedOutput string
163+
}{
164+
{
165+
description: "debug verbosity",
166+
message: "Test message",
167+
verbosity: DebugLevel,
168+
expectedOutput: "Test message",
169+
},
170+
{
171+
description: "info verbosity",
172+
message: "Test message",
173+
verbosity: InfoLevel,
174+
expectedOutput: "Test message",
175+
},
176+
{
177+
description: "with args",
178+
message: "Test message with args: %s, %d\n",
179+
args: []any{"arg1", 2},
180+
verbosity: InfoLevel,
181+
expectedOutput: "Test message with args: arg1, 2\n",
182+
},
183+
{
184+
description: "warning verbosity",
185+
message: "Test message",
186+
verbosity: WarningLevel,
187+
expectedOutput: "Test message",
188+
},
189+
{
190+
description: "error verbosity",
191+
message: "Test message",
192+
verbosity: ErrorLevel,
193+
expectedOutput: "Test message",
194+
},
195+
{
196+
description: "output format none",
197+
message: "Test message: %s",
198+
args: []any{"arg1"},
199+
verbosity: ErrorLevel,
200+
outputFormatNone: true,
201+
expectedOutput: "Test message: arg1",
202+
},
203+
{
204+
description: "empty message",
205+
verbosity: InfoLevel,
206+
},
207+
}
208+
for _, tt := range tests {
209+
t.Run(tt.description, func(t *testing.T) {
210+
var stdout, stderr bytes.Buffer
211+
p := &Printer{
212+
StdOut: &stdout,
213+
StdErr: &stderr,
214+
Verbosity: tt.verbosity,
215+
}
216+
viper.Reset()
217+
if tt.outputFormatNone {
218+
viper.Set(outputFormatKey, NoneOutputFormat)
219+
}
220+
221+
p.Noticef(tt.message, tt.args...)
222+
223+
if output := stderr.String(); output != tt.expectedOutput {
224+
t.Errorf("unexpected stderr: got %q, want %q", output, tt.expectedOutput)
225+
}
226+
if output := stdout.String(); output != "" {
227+
t.Errorf("unexpected stdout: got %q, want %q", output, "")
228+
}
229+
})
230+
}
231+
}
232+
233+
func TestNoticeln(t *testing.T) {
234+
tests := []struct {
235+
description string
236+
message string
237+
verbosity Level
238+
outputFormatNone bool
239+
}{
240+
{
241+
description: "debug verbosity",
242+
message: "Test message",
243+
verbosity: DebugLevel,
244+
},
245+
{
246+
description: "info verbosity",
247+
message: "Test message",
248+
verbosity: InfoLevel,
249+
},
250+
{
251+
description: "warning verbosity",
252+
message: "Test message",
253+
verbosity: WarningLevel,
254+
},
255+
{
256+
description: "error verbosity",
257+
message: "Test message",
258+
verbosity: ErrorLevel,
259+
},
260+
{
261+
description: "output format none",
262+
message: "Test message",
263+
verbosity: ErrorLevel,
264+
outputFormatNone: true,
265+
},
266+
{
267+
description: "empty message",
268+
verbosity: InfoLevel,
269+
},
270+
{
271+
description: "literal format specifier",
272+
message: "Test message: %s",
273+
verbosity: InfoLevel,
274+
},
275+
}
276+
for _, tt := range tests {
277+
t.Run(tt.description, func(t *testing.T) {
278+
var stdout, stderr bytes.Buffer
279+
p := &Printer{
280+
StdOut: &stdout,
281+
StdErr: &stderr,
282+
Verbosity: tt.verbosity,
283+
}
284+
viper.Reset()
285+
if tt.outputFormatNone {
286+
viper.Set(outputFormatKey, NoneOutputFormat)
287+
}
288+
289+
p.Noticeln(tt.message)
290+
291+
expectedOutput := tt.message + "\n"
292+
if output := stderr.String(); output != expectedOutput {
293+
t.Errorf("unexpected stderr: got %q, want %q", output, expectedOutput)
294+
}
295+
if output := stdout.String(); output != "" {
296+
t.Errorf("unexpected stdout: got %q, want %q", output, "")
297+
}
298+
})
299+
}
300+
}
301+
155302
func TestPagerDisplay(t *testing.T) {
156303
tests := []struct {
157304
description string

0 commit comments

Comments
 (0)