github.com/haraldrudell/parl@v0.4.176/closer_test.go (about) 1 /* 2 © 2022–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package parl 7 8 import ( 9 "errors" 10 "strconv" 11 "strings" 12 "testing" 13 14 "github.com/haraldrudell/parl/perrors" 15 ) 16 17 func TestCloser(t *testing.T) { 18 message := "close of closed channel" 19 messageNil := "close of nil channel" 20 21 var ch chan struct{} 22 var err error 23 var c chan struct{} 24 25 ch = make(chan struct{}) 26 Closer(ch, &err) 27 if err != nil { 28 t.Errorf("Closer err: %v exp nil", err) 29 } 30 31 err = nil 32 Closer(ch, &err) 33 if err == nil || !strings.Contains(err.Error(), message) { 34 t.Errorf("Closer closed err: %v exp %q", err, message) 35 } 36 37 ch = c 38 err = nil 39 Closer(ch, &err) 40 if err == nil || !strings.Contains(err.Error(), messageNil) { 41 t.Errorf("Closer nil err: %v exp %q", err, messageNil) 42 } 43 } 44 45 func TestCloserSend(t *testing.T) { 46 message := "close of closed channel" 47 messageNil := "close of nil channel" 48 49 var ch chan<- struct{} 50 var err error 51 var c chan<- struct{} 52 53 ch = make(chan<- struct{}) 54 CloserSend(ch, &err) 55 if err != nil { 56 t.Errorf("Closer err: %v exp nil", err) 57 } 58 59 err = nil 60 CloserSend(ch, &err) 61 if err == nil || !strings.Contains(err.Error(), message) { 62 t.Errorf("Closer closed err: %v exp %q", err, message) 63 } 64 65 ch = c 66 err = nil 67 CloserSend(ch, &err) 68 if err == nil || !strings.Contains(err.Error(), messageNil) { 69 t.Errorf("Closer nil err: %v exp %q", err, messageNil) 70 } 71 } 72 73 func TestClose(t *testing.T) { 74 // “nil pointer” 75 // - part of panic message: 76 // - “runtime error: invalid memory address or nil pointer dereference” 77 var message = "nil pointer" 78 // “x” 79 var messageX = "x" 80 // “y” 81 var messageY = "y" 82 83 var err error 84 85 // a successful Close should not return error 86 Close(newTestClosable(nil), &err) 87 if err != nil { 88 t.Errorf("Close err: %v", err) 89 } 90 91 // Close of nil io.Closable should return error, not panic 92 err = nil 93 Close(nil, &err) 94 95 // err: panic detected in parl.Close: 96 // “runtime error: invalid memory address or nil pointer dereference” 97 // at parl.Close()-closer.go:40 98 //t.Logf("err: %s", perrors.Short(err)) 99 //t.Fail() 100 101 if err == nil || !strings.Contains(err.Error(), message) { 102 t.Errorf("Close err: %v exp %q", err, message) 103 } 104 105 // a failed Close should append to err 106 // - err should become X with Y appended 107 err = errors.New(messageX) 108 Close(newTestClosable(errors.New(messageY)), &err) 109 // errs is a list of associated errors, oldest first 110 // - first X, then Y 111 var errs = perrors.ErrorList(err) 112 if len(errs) != 2 || errs[0].Error() != messageX || !strings.HasSuffix(errs[1].Error(), messageY) { 113 var quoteList = make([]string, len(errs)) 114 for i, err := range errs { 115 quoteList[i] = strconv.Quote(err.Error()) 116 } 117 // erss bad: ["x" "parl.Close y"] 118 t.Errorf("erss bad: %v", quoteList) 119 } 120 } 121 122 // testClosable is an [io.Closable] with configurable fail error 123 type testClosable struct{ err error } 124 125 // newTestClosable returns a closable whose Close always fails with err 126 func newTestClosable(err error) (closable *testClosable) { return &testClosable{err: err} } 127 128 // Close returns a configured error 129 func (tc *testClosable) Close() (err error) { return tc.err }