github.com/haraldrudell/parl@v0.4.176/log_test.go (about) 1 /* 2 © 2020–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package parl 7 8 import ( 9 "fmt" 10 "strings" 11 "sync" 12 "testing" 13 14 "github.com/haraldrudell/parl/perrors" 15 "github.com/haraldrudell/parl/plog" 16 "github.com/haraldrudell/parl/pruntime" 17 ) 18 19 func TestLogLog(t *testing.T) { 20 // reset of static loggings logInstance object 21 defer func(stderrLogger0 *plog.LogInstance) { 22 stderrLogger = stderrLogger0 23 }(stderrLogger) 24 defer SetDebug(false) 25 26 text1, textNewline, expectedLocation, _, writer, _ := mocksLogStat() 27 stderrLogger = plog.NewLogFrames(writer, 1) 28 29 var actualSlice []string 30 var actual string 31 32 // Log 33 Log(text1) 34 actualSlice = writer.getData() 35 if len(actualSlice) != 1 || actualSlice[0] != textNewline { 36 t.Logf(".Log failed: expected: %q actual: %s", textNewline, quoteSliceLogStat(actualSlice)) 37 t.Fail() 38 } 39 40 // Log with Location 41 SetDebug(true) 42 Log(text1 + "\n") 43 actualSlice = writer.getData() 44 if len(actualSlice) != 1 { 45 t.Logf("Log SetDebug: invocations not 1: %d", len(actualSlice)) 46 } else { 47 actual = actualSlice[0] 48 } 49 if !strings.HasPrefix(actual, text1) { 50 t.Logf("Log SetDebug: no text1 prefix: %q", actual) 51 t.Fail() 52 } 53 if !strings.Contains(actual, expectedLocation) { 54 t.Logf("Log SetDebug: no location: actual: %q expected: %q", actual, expectedLocation) 55 t.Fail() 56 } 57 if strings.Index(actual, "\n") != len(actual)-1 { 58 t.Logf("Log SetDebug: newline not at end: actual: %q expected: %q", actual, expectedLocation) 59 t.Fail() 60 } 61 } 62 63 func TestInfoLog(t *testing.T) { 64 defer func(stderrLogger0 *plog.LogInstance) { 65 stderrLogger = stderrLogger0 66 }(stderrLogger) 67 defer SetSilent(false) 68 69 text1, textNewline, _, _, writer, _ := mocksLogStat() 70 stderrLogger = plog.NewLogFrames(writer, 1) 71 72 var actualSlice []string 73 74 // Info 75 Info(text1) 76 actualSlice = writer.getData() 77 if len(actualSlice) != 1 || actualSlice[0] != textNewline { 78 t.Logf(".Log failed: expected:\n%q actual:\n%+v", textNewline, quoteSliceLogStat(actualSlice)) 79 t.Fail() 80 } 81 if IsSilent() { 82 t.Logf("SetSilent default true") 83 t.Fail() 84 } 85 86 // SetSilent 87 SetSilent(true) 88 if !IsSilent() { 89 t.Logf("SetSilent ineffective") 90 t.Fail() 91 } 92 Info(text1) 93 actualSlice = writer.getData() 94 if len(actualSlice) != 0 { 95 t.Logf("SetSilent true: Info still prints") 96 t.Fail() 97 } 98 } 99 100 func TestDebugLog(t *testing.T) { 101 defer func(stderrLogger0 *plog.LogInstance) { 102 stderrLogger = stderrLogger0 103 }(stderrLogger) 104 defer SetDebug(false) 105 106 text1, textNewline, expectedLocation, _, writer, _ := mocksLogStat() 107 stderrLogger = plog.NewLogFrames(writer, 1) 108 109 var actualSlice []string 110 var actual string 111 112 // Debug off 113 if IsThisDebug() { 114 t.Logf("IsThisDebug default true") 115 t.Fail() 116 } 117 Debug(text1) 118 actualSlice = writer.getData() 119 if len(actualSlice) != 0 { 120 t.Logf("Debug prints as default") 121 t.Fail() 122 } 123 124 // Debug on 125 SetDebug(true) 126 if !IsThisDebug() { 127 t.Logf("IsThisDebug ineffective") 128 t.Fail() 129 } 130 Debug(textNewline) 131 actualSlice = writer.getData() 132 if len(actualSlice) != 1 { 133 t.Logf("Log SetDebug: invocations not 1: %d", len(actualSlice)) 134 t.FailNow() 135 } 136 actual = actualSlice[0] 137 if !strings.HasPrefix(actual, text1) { 138 t.Logf("Log SetDebug: no text1 prefix: %q", actual) 139 t.Fail() 140 } 141 if !strings.Contains(actual, expectedLocation) { 142 t.Logf("Log SetDebug: no location: actual: %q expected: %q", actual, expectedLocation) 143 t.Fail() 144 } 145 } 146 147 func TestRegexpLog(t *testing.T) { 148 defer func(stderrLogger0 *plog.LogInstance) { 149 stderrLogger = stderrLogger0 150 }(stderrLogger) 151 defer SetRegexp("") 152 153 text1, textNewline, expectedLocation, regexpLocation, writer, _ := mocksLogStat() 154 stderrLogger = plog.NewLogFrames(writer, 1) 155 156 matchingRegexp := regexpLocation 157 nonMatchingRegexp := "aaa" 158 159 var actualSlice []string 160 var actual string 161 162 // matching regexp 163 if err := SetRegexp(matchingRegexp); err != nil { 164 t.Logf("SetRegexp failed: input: %q err: %+v", matchingRegexp, err) 165 t.Fail() 166 } 167 Debug(textNewline) 168 actualSlice = writer.getData() 169 if len(actualSlice) != 1 { 170 t.Logf("matching regexp did not print 1: %d regexp input:\n%q", 171 len(actualSlice), 172 matchingRegexp) 173 t.Fail() 174 } 175 actual = actualSlice[0] 176 if !strings.HasPrefix(actual, text1) { 177 t.Logf("matching regexp: missing prefix: %q text: %q", text1, actual) 178 t.Fail() 179 } 180 if !strings.Contains(actual, expectedLocation) { 181 t.Logf("matching regexp: no location: actual:\n%q expected:\n%q", 182 actual, 183 expectedLocation) 184 t.Fail() 185 } 186 if strings.Index(actual, "\n") != len(actual)-1 { 187 t.Logf("matching regexp: newline not at end: actual: %q expected: %q", actual, expectedLocation) 188 t.Fail() 189 } 190 191 // non-matching regexp 192 if err := SetRegexp(nonMatchingRegexp); err != nil { 193 panic(err) 194 } 195 Debug(text1) 196 actualSlice = writer.getData() 197 if len(actualSlice) > 0 { 198 t.Logf("non-matching regexp did print: %d", len(actualSlice)) 199 t.Fail() 200 } 201 } 202 203 type mockWriterLogStat struct { 204 lock sync.Mutex 205 buf []string 206 } 207 208 func (w *mockWriterLogStat) Write(p []byte) (n int, err error) { 209 n = len(p) 210 w.lock.Lock() 211 defer w.lock.Unlock() 212 w.buf = append(w.buf, string(p)) 213 return 214 } 215 216 func (w *mockWriterLogStat) getData() (sList []string) { 217 w.lock.Lock() 218 defer w.lock.Unlock() 219 sList = w.buf 220 w.buf = nil 221 return 222 } 223 224 func quoteSliceLogStat(sList []string) (s string) { 225 var s2 []string 226 for _, sx := range sList { 227 s2 = append(s2, fmt.Sprintf("%q", sx)) 228 } 229 return strings.Join(s2, "\x20") 230 } 231 232 func mocksLogStat() (text1, textNewline, expectedLocation, regexpLocation string, writer *mockWriterLogStat, mockOutput func(n int, s string) (err error)) { 233 text1 = "abc" 234 textNewline = text1 + "\n" 235 236 // location text for this file 237 location := pruntime.NewCodeLocation(1) 238 expectedLocation = location.Short() 239 // remove line number since this changes 240 if index := strings.Index(expectedLocation, ":"); index == -1 { 241 panic(perrors.Errorf("error116.NewCodeLocation failed: %q", expectedLocation)) 242 } else { 243 expectedLocation = expectedLocation[0:index] 244 } 245 regexpLocation = location.FuncName 246 writer = &mockWriterLogStat{} 247 mockOutput = func(n int, s string) (err error) { 248 _ = n 249 if !strings.HasSuffix(s, "\n") { 250 s += "\n" 251 } 252 _, err = writer.Write([]byte(s)) 253 return 254 } 255 return 256 } 257 258 func TestIsThisDebugN(t *testing.T) { 259 SetDebug(false) 260 261 // matching Regexp should… 262 SetRegexp("TestIsThisDebugN") 263 if !IsThisDebug() { 264 t.Error("IsThisDebug false") 265 } 266 if !IsThisDebugN(0) { 267 t.Error("IsThisDebugN(0) false") 268 } 269 if IsThisDebugN(1) { 270 t.Error("IsThisDebugN(1) true") 271 } 272 273 // no debug should… 274 SetRegexp("") 275 if IsThisDebug() { 276 t.Error("IsThisDebug true") 277 } 278 if IsThisDebugN(0) { 279 t.Error("IsThisDebugN(0) true") 280 } 281 if IsThisDebugN(1) { 282 t.Error("IsThisDebugN(1) true") 283 } 284 }