github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/logging/prefix_writer_test.go (about) 1 package logging_test 2 3 import ( 4 "bytes" 5 "errors" 6 "io" 7 "testing" 8 9 "github.com/heroku/color" 10 "github.com/sclevine/spec" 11 "github.com/sclevine/spec/report" 12 13 "github.com/buildpacks/pack/pkg/logging" 14 h "github.com/buildpacks/pack/testhelpers" 15 ) 16 17 func TestPrefixWriter(t *testing.T) { 18 color.Disable(true) 19 defer color.Disable(false) 20 spec.Run(t, "PrefixWriter", testPrefixWriter, spec.Parallel(), spec.Report(report.Terminal{})) 21 } 22 23 func testPrefixWriter(t *testing.T, when spec.G, it spec.S) { 24 var ( 25 assert = h.NewAssertionManager(t) 26 ) 27 28 when("#Write", func() { 29 it("prepends prefix to string", func() { 30 var w bytes.Buffer 31 32 writer := logging.NewPrefixWriter(&w, "prefix") 33 _, err := writer.Write([]byte("test")) 34 assert.Nil(err) 35 err = writer.Close() 36 assert.Nil(err) 37 38 h.AssertEq(t, w.String(), "[prefix] test\n") 39 }) 40 41 it("prepends prefix to multi-line string", func() { 42 var w bytes.Buffer 43 44 writer := logging.NewPrefixWriter(&w, "prefix") 45 _, err := writer.Write([]byte("line 1\nline 2\nline 3")) 46 assert.Nil(err) 47 err = writer.Close() 48 assert.Nil(err) 49 50 h.AssertEq(t, w.String(), "[prefix] line 1\n[prefix] line 2\n[prefix] line 3\n") 51 }) 52 53 it("buffers mid-line calls", func() { 54 var buf bytes.Buffer 55 56 writer := logging.NewPrefixWriter(&buf, "prefix") 57 _, err := writer.Write([]byte("word 1, ")) 58 assert.Nil(err) 59 _, err = writer.Write([]byte("word 2, ")) 60 assert.Nil(err) 61 _, err = writer.Write([]byte("word 3.")) 62 assert.Nil(err) 63 err = writer.Close() 64 assert.Nil(err) 65 66 h.AssertEq(t, buf.String(), "[prefix] word 1, word 2, word 3.\n") 67 }) 68 69 it("handles empty lines", func() { 70 var buf bytes.Buffer 71 72 writer := logging.NewPrefixWriter(&buf, "prefix") 73 _, err := writer.Write([]byte("\n")) 74 assert.Nil(err) 75 err = writer.Close() 76 assert.Nil(err) 77 78 h.AssertEq(t, buf.String(), "[prefix] \n") 79 }) 80 81 it("handles empty input", func() { 82 var buf bytes.Buffer 83 84 writer := logging.NewPrefixWriter(&buf, "prefix") 85 _, err := writer.Write([]byte("")) 86 assert.Nil(err) 87 err = writer.Close() 88 assert.Nil(err) 89 90 assert.Equal(buf.String(), "") 91 }) 92 93 it("propagates reader errors", func() { 94 var buf bytes.Buffer 95 96 factory := &boobyTrapReaderFactory{failAtCallNumber: 2} 97 writer := logging.NewPrefixWriter(&buf, "prefix", logging.WithReaderFactory(factory.NewReader)) 98 _, err := writer.Write([]byte("word 1,")) 99 assert.Nil(err) 100 _, err = writer.Write([]byte("word 2.")) 101 assert.ErrorContains(err, "some error") 102 }) 103 104 it("handles requests to clear line", func() { 105 var buf bytes.Buffer 106 107 writer := logging.NewPrefixWriter(&buf, "prefix") 108 _, err := writer.Write([]byte("progress 1\rprogress 2\rprogress 3\rcomplete!")) 109 assert.Nil(err) 110 err = writer.Close() 111 assert.Nil(err) 112 113 h.AssertEq(t, buf.String(), "[prefix] complete!\n") 114 }) 115 116 it("handles requests clear line (amidst content)", func() { 117 var buf bytes.Buffer 118 119 writer := logging.NewPrefixWriter(&buf, "prefix") 120 _, err := writer.Write([]byte("downloading\rcompleted! \r\nall done!\nnevermind\r")) 121 assert.Nil(err) 122 err = writer.Close() 123 assert.Nil(err) 124 125 h.AssertEq(t, buf.String(), "[prefix] completed! \n[prefix] all done!\n[prefix] \n") 126 }) 127 }) 128 } 129 130 type boobyTrapReaderFactory struct { 131 numberOfCalls int 132 failAtCallNumber int 133 } 134 135 func (b *boobyTrapReaderFactory) NewReader(data []byte) io.Reader { 136 b.numberOfCalls++ 137 if b.numberOfCalls >= b.failAtCallNumber { 138 return &faultyReader{} 139 } 140 141 return bytes.NewReader(data) 142 } 143 144 type faultyReader struct { 145 } 146 147 func (f faultyReader) Read(b []byte) (n int, err error) { 148 return 0, errors.New("some error") 149 }