diff --git a/printer/printer.go b/printer/printer.go index a40477ead..9855e13cd 100644 --- a/printer/printer.go +++ b/printer/printer.go @@ -7,6 +7,7 @@ import ( "bytes" "encoding/json" "fmt" + "io" "os" "text/template" ) @@ -17,6 +18,9 @@ const ( ) type Printer struct { + writer io.Writer + eWriter io.Writer + Format string Single bool Lines []interface{} @@ -25,12 +29,17 @@ type Printer struct { var printer Printer -// Sets the format for the final output of the printer +func init() { + printer.writer = os.Stdout + printer.eWriter = os.Stderr +} + +// SetFormat sets the format for the final output of the printer func SetFormat(t string) { printer.Format = t } -// Sets the single flag on the printer. If this flag is set, the +// SetSingle sets the single flag on the printer. If this flag is set, the // printer will check the size of stored elements before printing, and // if there is only one, it will be printed on its own instead of // inside a list @@ -38,7 +47,7 @@ func SetSingle(single bool) { printer.Single = single } -// Prints an element. Depending on the format, the element can be +// PrintT prints an element. Depending on the format, the element can be // formatted and printed as a structure or used to populate the // template func PrintT(templateString string, v interface{}) { @@ -51,20 +60,20 @@ func PrintT(templateString string, v interface{}) { } tplString := tpl.String() printer.Lines = append(printer.Lines, tplString) - fmt.Println(tplString) + fmt.Fprintln(printer.writer, tplString) case FormatJSON: printer.Lines = append(printer.Lines, v) } } -// Prints an element. If the format requires a template, the element +// Print an element. If the format requires a template, the element // will be printed as a structure with field names using the print // verb %+v func Print(v interface{}) { PrintT("{{printf \"%+v\" .}}", v) } -// Prints the elements accumulated in the printer +// Flush writes the elements accumulated in the printer func Flush() { if printer.Format == FormatJSON { var b []byte @@ -74,29 +83,29 @@ func Flush() { b, _ = json.MarshalIndent(printer.Lines, "", " ") } - fmt.Println(string(b)) + fmt.Fprintln(printer.writer, string(b)) printer.Lines = []interface{}{} } } -// Resets the printer's accumulated lines +// Clean resets the printer's accumulated lines func Clean() { printer.Lines = []interface{}{} printer.ErrorLines = []interface{}{} } -// Returns the printer's accumulated lines +// GetLines returns the printer's accumulated lines func GetLines() []interface{} { return printer.Lines } -// Returns the printer's accumulated error lines +// GetErrorLines returns the printer's accumulated error lines func GetErrorLines() []interface{} { return printer.ErrorLines } -// Prints an error string to the stderr. +// PrintError prints to the stderr. func PrintError(msg string) { printer.ErrorLines = append(printer.ErrorLines, msg) - fmt.Fprintln(os.Stderr, msg) + fmt.Fprintln(printer.eWriter, msg) } diff --git a/printer/printer_test.go b/printer/printer_test.go new file mode 100644 index 000000000..03762b79b --- /dev/null +++ b/printer/printer_test.go @@ -0,0 +1,81 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +package printer + +import ( + "bufio" + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +type mockWriter []byte + +func (w *mockWriter) Write(b []byte) (n int, err error) { + *w = append(*w, b...) + return len(*w) - len(b), nil +} + +func TestPrintT(t *testing.T) { + w := bufio.NewWriter(&bytes.Buffer{}) + printer.writer = w + printer.Format = FormatPlain + + ts := struct { + ID int + }{ + ID: 123, + } + + t.Run("should execute template", func(t *testing.T) { + tpl := `testing template {{.ID}}` + PrintT(tpl, ts) + assert.Len(t, GetLines(), 1) + + Flush() + assert.Equal(t, "testing template 123", printer.Lines[0]) + }) + + t.Run("should fail to execute, no method or field", func(t *testing.T) { + Clean() + tpl := `testing template {{.Name}}` + PrintT(tpl, ts) + assert.Len(t, GetErrorLines(), 1) + + Flush() + assert.Equal(t, "Can't print the message using the provided template: "+tpl, printer.ErrorLines[0]) + }) +} + +func TestFlush(t *testing.T) { + printer.Format = FormatJSON + + t.Run("should print a line in JSON format", func(t *testing.T) { + mw := &mockWriter{} + printer.writer = mw + Clean() + + Print("test string") + assert.Len(t, GetLines(), 1) + + Flush() + assert.Equal(t, "[\n \"test string\"\n]\n", string(*mw)) + assert.Empty(t, GetLines(), 0) + }) + + t.Run("should print multi line in JSON format", func(t *testing.T) { + mw := &mockWriter{} + printer.writer = mw + + Clean() + Print("test string-1") + Print("test string-2") + assert.Len(t, GetLines(), 2) + + Flush() + assert.Equal(t, "[\n \"test string-1\",\n \"test string-2\"\n]\n", string(*mw)) + assert.Empty(t, GetLines(), 0) + }) +}