summaryrefslogtreecommitdiffstats
path: root/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest
diff options
context:
space:
mode:
Diffstat (limited to 'dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest')
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/doc.go22
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/logger.go140
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/logger_test.go193
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/logged_entry.go39
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/logged_entry_test.go88
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/observer.go196
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/observer_test.go258
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/testingt.go47
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/testingt_test.go29
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/timeout.go45
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/timeout_test.go43
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/writer.go44
-rw-r--r--dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/writer_test.go68
13 files changed, 1212 insertions, 0 deletions
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/doc.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/doc.go
new file mode 100644
index 0000000..b377859
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/doc.go
@@ -0,0 +1,22 @@
+// Copyright (c) 2016 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Package zaptest provides a variety of helpers for testing log output.
+package zaptest // import "go.uber.org/zap/zaptest"
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/logger.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/logger.go
new file mode 100644
index 0000000..6a4a354
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/logger.go
@@ -0,0 +1,140 @@
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zaptest
+
+import (
+ "bytes"
+
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+)
+
+// LoggerOption configures the test logger built by NewLogger.
+type LoggerOption interface {
+ applyLoggerOption(*loggerOptions)
+}
+
+type loggerOptions struct {
+ Level zapcore.LevelEnabler
+ zapOptions []zap.Option
+}
+
+type loggerOptionFunc func(*loggerOptions)
+
+func (f loggerOptionFunc) applyLoggerOption(opts *loggerOptions) {
+ f(opts)
+}
+
+// Level controls which messages are logged by a test Logger built by
+// NewLogger.
+func Level(enab zapcore.LevelEnabler) LoggerOption {
+ return loggerOptionFunc(func(opts *loggerOptions) {
+ opts.Level = enab
+ })
+}
+
+// WrapOptions adds zap.Option's to a test Logger built by NewLogger.
+func WrapOptions(zapOpts ...zap.Option) LoggerOption {
+ return loggerOptionFunc(func(opts *loggerOptions) {
+ opts.zapOptions = zapOpts
+ })
+}
+
+// NewLogger builds a new Logger that logs all messages to the given
+// testing.TB.
+//
+// logger := zaptest.NewLogger(t)
+//
+// Use this with a *testing.T or *testing.B to get logs which get printed only
+// if a test fails or if you ran go test -v.
+//
+// The returned logger defaults to logging debug level messages and above.
+// This may be changed by passing a zaptest.Level during construction.
+//
+// logger := zaptest.NewLogger(t, zaptest.Level(zap.WarnLevel))
+//
+// You may also pass zap.Option's to customize test logger.
+//
+// logger := zaptest.NewLogger(t, zaptest.WrapOptions(zap.AddCaller()))
+func NewLogger(t TestingT, opts ...LoggerOption) *zap.Logger {
+ cfg := loggerOptions{
+ Level: zapcore.DebugLevel,
+ }
+ for _, o := range opts {
+ o.applyLoggerOption(&cfg)
+ }
+
+ writer := newTestingWriter(t)
+ zapOptions := []zap.Option{
+ // Send zap errors to the same writer and mark the test as failed if
+ // that happens.
+ zap.ErrorOutput(writer.WithMarkFailed(true)),
+ }
+ zapOptions = append(zapOptions, cfg.zapOptions...)
+
+ return zap.New(
+ zapcore.NewCore(
+ zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()),
+ writer,
+ cfg.Level,
+ ),
+ zapOptions...,
+ )
+}
+
+// testingWriter is a WriteSyncer that writes to the given testing.TB.
+type testingWriter struct {
+ t TestingT
+
+ // If true, the test will be marked as failed if this testingWriter is
+ // ever used.
+ markFailed bool
+}
+
+func newTestingWriter(t TestingT) testingWriter {
+ return testingWriter{t: t}
+}
+
+// WithMarkFailed returns a copy of this testingWriter with markFailed set to
+// the provided value.
+func (w testingWriter) WithMarkFailed(v bool) testingWriter {
+ w.markFailed = v
+ return w
+}
+
+func (w testingWriter) Write(p []byte) (n int, err error) {
+ n = len(p)
+
+ // Strip trailing newline because t.Log always adds one.
+ p = bytes.TrimRight(p, "\n")
+
+ // Note: t.Log is safe for concurrent use.
+ w.t.Logf("%s", p)
+ if w.markFailed {
+ w.t.Fail()
+ }
+
+ return n, nil
+}
+
+func (w testingWriter) Sync() error {
+ return nil
+}
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/logger_test.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/logger_test.go
new file mode 100644
index 0000000..576f682
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/logger_test.go
@@ -0,0 +1,193 @@
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zaptest
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "strings"
+ "testing"
+
+ "go.uber.org/zap"
+ "go.uber.org/zap/internal/ztest"
+ "go.uber.org/zap/zapcore"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestTestLogger(t *testing.T) {
+ ts := newTestLogSpy(t)
+ defer ts.AssertPassed()
+
+ log := NewLogger(ts)
+
+ log.Info("received work order")
+ log.Debug("starting work")
+ log.Warn("work may fail")
+ log.Error("work failed", zap.Error(errors.New("great sadness")))
+
+ assert.Panics(t, func() {
+ log.Panic("failed to do work")
+ }, "log.Panic should panic")
+
+ ts.AssertMessages(
+ "INFO received work order",
+ "DEBUG starting work",
+ "WARN work may fail",
+ `ERROR work failed {"error": "great sadness"}`,
+ "PANIC failed to do work",
+ )
+}
+
+func TestTestLoggerSupportsLevels(t *testing.T) {
+ ts := newTestLogSpy(t)
+ defer ts.AssertPassed()
+
+ log := NewLogger(ts, Level(zap.WarnLevel))
+
+ log.Info("received work order")
+ log.Debug("starting work")
+ log.Warn("work may fail")
+ log.Error("work failed", zap.Error(errors.New("great sadness")))
+
+ assert.Panics(t, func() {
+ log.Panic("failed to do work")
+ }, "log.Panic should panic")
+
+ ts.AssertMessages(
+ "WARN work may fail",
+ `ERROR work failed {"error": "great sadness"}`,
+ "PANIC failed to do work",
+ )
+}
+
+func TestTestLoggerSupportsWrappedZapOptions(t *testing.T) {
+ ts := newTestLogSpy(t)
+ defer ts.AssertPassed()
+
+ log := NewLogger(ts, WrapOptions(zap.AddCaller(), zap.Fields(zap.String("k1", "v1"))))
+
+ log.Info("received work order")
+ log.Debug("starting work")
+ log.Warn("work may fail")
+ log.Error("work failed", zap.Error(errors.New("great sadness")))
+
+ assert.Panics(t, func() {
+ log.Panic("failed to do work")
+ }, "log.Panic should panic")
+
+ ts.AssertMessages(
+ `INFO zaptest/logger_test.go:89 received work order {"k1": "v1"}`,
+ `DEBUG zaptest/logger_test.go:90 starting work {"k1": "v1"}`,
+ `WARN zaptest/logger_test.go:91 work may fail {"k1": "v1"}`,
+ `ERROR zaptest/logger_test.go:92 work failed {"k1": "v1", "error": "great sadness"}`,
+ `PANIC zaptest/logger_test.go:95 failed to do work {"k1": "v1"}`,
+ )
+}
+
+func TestTestingWriter(t *testing.T) {
+ ts := newTestLogSpy(t)
+ w := newTestingWriter(ts)
+
+ n, err := io.WriteString(w, "hello\n\n")
+ assert.NoError(t, err, "WriteString must not fail")
+ assert.Equal(t, 7, n)
+}
+
+func TestTestLoggerErrorOutput(t *testing.T) {
+ // This test verifies that the test logger logs internal messages to the
+ // testing.T and marks the test as failed.
+
+ ts := newTestLogSpy(t)
+ defer ts.AssertFailed()
+
+ log := NewLogger(ts)
+
+ // Replace with a core that fails.
+ log = log.WithOptions(zap.WrapCore(func(zapcore.Core) zapcore.Core {
+ return zapcore.NewCore(
+ zapcore.NewConsoleEncoder(zap.NewDevelopmentEncoderConfig()),
+ zapcore.Lock(zapcore.AddSync(ztest.FailWriter{})),
+ zapcore.DebugLevel,
+ )
+ }))
+
+ log.Info("foo") // this fails
+
+ if assert.Len(t, ts.Messages, 1, "expected a log message") {
+ assert.Regexp(t, `write error: failed`, ts.Messages[0])
+ }
+}
+
+// testLogSpy is a testing.TB that captures logged messages.
+type testLogSpy struct {
+ testing.TB
+
+ failed bool
+ Messages []string
+}
+
+func newTestLogSpy(t testing.TB) *testLogSpy {
+ return &testLogSpy{TB: t}
+}
+
+func (t *testLogSpy) Fail() {
+ t.failed = true
+}
+
+func (t *testLogSpy) Failed() bool {
+ return t.failed
+}
+
+func (t *testLogSpy) FailNow() {
+ t.Fail()
+ t.TB.FailNow()
+}
+
+func (t *testLogSpy) Logf(format string, args ...interface{}) {
+ // Log messages are in the format,
+ //
+ // 2017-10-27T13:03:01.000-0700 DEBUG your message here {data here}
+ //
+ // We strip the first part of these messages because we can't really test
+ // for the timestamp from these tests.
+ m := fmt.Sprintf(format, args...)
+ m = m[strings.IndexByte(m, '\t')+1:]
+ t.Messages = append(t.Messages, m)
+ t.TB.Log(m)
+}
+
+func (t *testLogSpy) AssertMessages(msgs ...string) {
+ assert.Equal(t.TB, msgs, t.Messages, "logged messages did not match")
+}
+
+func (t *testLogSpy) AssertPassed() {
+ t.assertFailed(false, "expected test to pass")
+}
+
+func (t *testLogSpy) AssertFailed() {
+ t.assertFailed(true, "expected test to fail")
+}
+
+func (t *testLogSpy) assertFailed(v bool, msg string) {
+ assert.Equal(t.TB, v, t.failed, msg)
+}
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/logged_entry.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/logged_entry.go
new file mode 100644
index 0000000..a4ea7ec
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/logged_entry.go
@@ -0,0 +1,39 @@
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package observer
+
+import "go.uber.org/zap/zapcore"
+
+// An LoggedEntry is an encoding-agnostic representation of a log message.
+// Field availability is context dependant.
+type LoggedEntry struct {
+ zapcore.Entry
+ Context []zapcore.Field
+}
+
+// ContextMap returns a map for all fields in Context.
+func (e LoggedEntry) ContextMap() map[string]interface{} {
+ encoder := zapcore.NewMapObjectEncoder()
+ for _, f := range e.Context {
+ f.AddTo(encoder)
+ }
+ return encoder.Fields
+}
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/logged_entry_test.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/logged_entry_test.go
new file mode 100644
index 0000000..50f6123
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/logged_entry_test.go
@@ -0,0 +1,88 @@
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package observer
+
+import (
+ "testing"
+
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLoggedEntryContextMap(t *testing.T) {
+ tests := []struct {
+ msg string
+ fields []zapcore.Field
+ want map[string]interface{}
+ }{
+ {
+ msg: "no fields",
+ fields: nil,
+ want: map[string]interface{}{},
+ },
+ {
+ msg: "simple",
+ fields: []zapcore.Field{
+ zap.String("k1", "v"),
+ zap.Int64("k2", 10),
+ },
+ want: map[string]interface{}{
+ "k1": "v",
+ "k2": int64(10),
+ },
+ },
+ {
+ msg: "overwrite",
+ fields: []zapcore.Field{
+ zap.String("k1", "v1"),
+ zap.String("k1", "v2"),
+ },
+ want: map[string]interface{}{
+ "k1": "v2",
+ },
+ },
+ {
+ msg: "nested",
+ fields: []zapcore.Field{
+ zap.String("k1", "v1"),
+ zap.Namespace("nested"),
+ zap.String("k2", "v2"),
+ },
+ want: map[string]interface{}{
+ "k1": "v1",
+ "nested": map[string]interface{}{
+ "k2": "v2",
+ },
+ },
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.msg, func(t *testing.T) {
+ entry := LoggedEntry{
+ Context: tt.fields,
+ }
+ assert.Equal(t, tt.want, entry.ContextMap())
+ })
+ }
+}
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/observer.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/observer.go
new file mode 100644
index 0000000..f77f130
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/observer.go
@@ -0,0 +1,196 @@
+// Copyright (c) 2016-2022 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+// Package observer provides a zapcore.Core that keeps an in-memory,
+// encoding-agnostic representation of log entries. It's useful for
+// applications that want to unit test their log output without tying their
+// tests to a particular output encoding.
+package observer // import "go.uber.org/zap/zaptest/observer"
+
+import (
+ "strings"
+ "sync"
+ "time"
+
+ "go.uber.org/zap/internal"
+ "go.uber.org/zap/zapcore"
+)
+
+// ObservedLogs is a concurrency-safe, ordered collection of observed logs.
+type ObservedLogs struct {
+ mu sync.RWMutex
+ logs []LoggedEntry
+}
+
+// Len returns the number of items in the collection.
+func (o *ObservedLogs) Len() int {
+ o.mu.RLock()
+ n := len(o.logs)
+ o.mu.RUnlock()
+ return n
+}
+
+// All returns a copy of all the observed logs.
+func (o *ObservedLogs) All() []LoggedEntry {
+ o.mu.RLock()
+ ret := make([]LoggedEntry, len(o.logs))
+ copy(ret, o.logs)
+ o.mu.RUnlock()
+ return ret
+}
+
+// TakeAll returns a copy of all the observed logs, and truncates the observed
+// slice.
+func (o *ObservedLogs) TakeAll() []LoggedEntry {
+ o.mu.Lock()
+ ret := o.logs
+ o.logs = nil
+ o.mu.Unlock()
+ return ret
+}
+
+// AllUntimed returns a copy of all the observed logs, but overwrites the
+// observed timestamps with time.Time's zero value. This is useful when making
+// assertions in tests.
+func (o *ObservedLogs) AllUntimed() []LoggedEntry {
+ ret := o.All()
+ for i := range ret {
+ ret[i].Time = time.Time{}
+ }
+ return ret
+}
+
+// FilterLevelExact filters entries to those logged at exactly the given level.
+func (o *ObservedLogs) FilterLevelExact(level zapcore.Level) *ObservedLogs {
+ return o.Filter(func(e LoggedEntry) bool {
+ return e.Level == level
+ })
+}
+
+// FilterMessage filters entries to those that have the specified message.
+func (o *ObservedLogs) FilterMessage(msg string) *ObservedLogs {
+ return o.Filter(func(e LoggedEntry) bool {
+ return e.Message == msg
+ })
+}
+
+// FilterMessageSnippet filters entries to those that have a message containing the specified snippet.
+func (o *ObservedLogs) FilterMessageSnippet(snippet string) *ObservedLogs {
+ return o.Filter(func(e LoggedEntry) bool {
+ return strings.Contains(e.Message, snippet)
+ })
+}
+
+// FilterField filters entries to those that have the specified field.
+func (o *ObservedLogs) FilterField(field zapcore.Field) *ObservedLogs {
+ return o.Filter(func(e LoggedEntry) bool {
+ for _, ctxField := range e.Context {
+ if ctxField.Equals(field) {
+ return true
+ }
+ }
+ return false
+ })
+}
+
+// FilterFieldKey filters entries to those that have the specified key.
+func (o *ObservedLogs) FilterFieldKey(key string) *ObservedLogs {
+ return o.Filter(func(e LoggedEntry) bool {
+ for _, ctxField := range e.Context {
+ if ctxField.Key == key {
+ return true
+ }
+ }
+ return false
+ })
+}
+
+// Filter returns a copy of this ObservedLogs containing only those entries
+// for which the provided function returns true.
+func (o *ObservedLogs) Filter(keep func(LoggedEntry) bool) *ObservedLogs {
+ o.mu.RLock()
+ defer o.mu.RUnlock()
+
+ var filtered []LoggedEntry
+ for _, entry := range o.logs {
+ if keep(entry) {
+ filtered = append(filtered, entry)
+ }
+ }
+ return &ObservedLogs{logs: filtered}
+}
+
+func (o *ObservedLogs) add(log LoggedEntry) {
+ o.mu.Lock()
+ o.logs = append(o.logs, log)
+ o.mu.Unlock()
+}
+
+// New creates a new Core that buffers logs in memory (without any encoding).
+// It's particularly useful in tests.
+func New(enab zapcore.LevelEnabler) (zapcore.Core, *ObservedLogs) {
+ ol := &ObservedLogs{}
+ return &contextObserver{
+ LevelEnabler: enab,
+ logs: ol,
+ }, ol
+}
+
+type contextObserver struct {
+ zapcore.LevelEnabler
+ logs *ObservedLogs
+ context []zapcore.Field
+}
+
+var (
+ _ zapcore.Core = (*contextObserver)(nil)
+ _ internal.LeveledEnabler = (*contextObserver)(nil)
+)
+
+func (co *contextObserver) Level() zapcore.Level {
+ return zapcore.LevelOf(co.LevelEnabler)
+}
+
+func (co *contextObserver) Check(ent zapcore.Entry, ce *zapcore.CheckedEntry) *zapcore.CheckedEntry {
+ if co.Enabled(ent.Level) {
+ return ce.AddCore(ent, co)
+ }
+ return ce
+}
+
+func (co *contextObserver) With(fields []zapcore.Field) zapcore.Core {
+ return &contextObserver{
+ LevelEnabler: co.LevelEnabler,
+ logs: co.logs,
+ context: append(co.context[:len(co.context):len(co.context)], fields...),
+ }
+}
+
+func (co *contextObserver) Write(ent zapcore.Entry, fields []zapcore.Field) error {
+ all := make([]zapcore.Field, 0, len(fields)+len(co.context))
+ all = append(all, co.context...)
+ all = append(all, fields...)
+ co.logs.add(LoggedEntry{ent, all})
+ return nil
+}
+
+func (co *contextObserver) Sync() error {
+ return nil
+}
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/observer_test.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/observer_test.go
new file mode 100644
index 0000000..2a901b1
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/observer/observer_test.go
@@ -0,0 +1,258 @@
+// Copyright (c) 2016-2022 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package observer_test
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "go.uber.org/zap"
+ "go.uber.org/zap/zapcore"
+ . "go.uber.org/zap/zaptest/observer"
+)
+
+func assertEmpty(t testing.TB, logs *ObservedLogs) {
+ assert.Equal(t, 0, logs.Len(), "Expected empty ObservedLogs to have zero length.")
+ assert.Equal(t, []LoggedEntry{}, logs.All(), "Unexpected LoggedEntries in empty ObservedLogs.")
+}
+
+func TestObserver(t *testing.T) {
+ observer, logs := New(zap.InfoLevel)
+ assertEmpty(t, logs)
+
+ t.Run("LevelOf", func(t *testing.T) {
+ assert.Equal(t, zap.InfoLevel, zapcore.LevelOf(observer), "Observer reported the wrong log level.")
+ })
+
+ assert.NoError(t, observer.Sync(), "Unexpected failure in no-op Sync")
+
+ obs := zap.New(observer).With(zap.Int("i", 1))
+ obs.Info("foo")
+ obs.Debug("bar")
+ want := []LoggedEntry{{
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "foo"},
+ Context: []zapcore.Field{zap.Int("i", 1)},
+ }}
+
+ assert.Equal(t, 1, logs.Len(), "Unexpected observed logs Len.")
+ assert.Equal(t, want, logs.AllUntimed(), "Unexpected contents from AllUntimed.")
+
+ all := logs.All()
+ require.Equal(t, 1, len(all), "Unexpected number of LoggedEntries returned from All.")
+ assert.NotEqual(t, time.Time{}, all[0].Time, "Expected non-zero time on LoggedEntry.")
+
+ // copy & zero time for stable assertions
+ untimed := append([]LoggedEntry{}, all...)
+ untimed[0].Time = time.Time{}
+ assert.Equal(t, want, untimed, "Unexpected LoggedEntries from All.")
+
+ assert.Equal(t, all, logs.TakeAll(), "Expected All and TakeAll to return identical results.")
+ assertEmpty(t, logs)
+}
+
+func TestObserverWith(t *testing.T) {
+ sf1, logs := New(zap.InfoLevel)
+
+ // need to pad out enough initial fields so that the underlying slice cap()
+ // gets ahead of its len() so that the sf3/4 With append's could choose
+ // not to copy (if the implementation doesn't force them)
+ sf1 = sf1.With([]zapcore.Field{zap.Int("a", 1), zap.Int("b", 2)})
+
+ sf2 := sf1.With([]zapcore.Field{zap.Int("c", 3)})
+ sf3 := sf2.With([]zapcore.Field{zap.Int("d", 4)})
+ sf4 := sf2.With([]zapcore.Field{zap.Int("e", 5)})
+ ent := zapcore.Entry{Level: zap.InfoLevel, Message: "hello"}
+
+ for i, core := range []zapcore.Core{sf2, sf3, sf4} {
+ if ce := core.Check(ent, nil); ce != nil {
+ ce.Write(zap.Int("i", i))
+ }
+ }
+
+ assert.Equal(t, []LoggedEntry{
+ {
+ Entry: ent,
+ Context: []zapcore.Field{
+ zap.Int("a", 1),
+ zap.Int("b", 2),
+ zap.Int("c", 3),
+ zap.Int("i", 0),
+ },
+ },
+ {
+ Entry: ent,
+ Context: []zapcore.Field{
+ zap.Int("a", 1),
+ zap.Int("b", 2),
+ zap.Int("c", 3),
+ zap.Int("d", 4),
+ zap.Int("i", 1),
+ },
+ },
+ {
+ Entry: ent,
+ Context: []zapcore.Field{
+ zap.Int("a", 1),
+ zap.Int("b", 2),
+ zap.Int("c", 3),
+ zap.Int("e", 5),
+ zap.Int("i", 2),
+ },
+ },
+ }, logs.All(), "expected no field sharing between With siblings")
+}
+
+func TestFilters(t *testing.T) {
+ logs := []LoggedEntry{
+ {
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "log a"},
+ Context: []zapcore.Field{zap.String("fStr", "1"), zap.Int("a", 1)},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "log a"},
+ Context: []zapcore.Field{zap.String("fStr", "2"), zap.Int("b", 2)},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "log b"},
+ Context: []zapcore.Field{zap.Int("a", 1), zap.Int("b", 2)},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "log c"},
+ Context: []zapcore.Field{zap.Int("a", 1), zap.Namespace("ns"), zap.Int("a", 2)},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "msg 1"},
+ Context: []zapcore.Field{zap.Int("a", 1), zap.Namespace("ns")},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "any map"},
+ Context: []zapcore.Field{zap.Any("map", map[string]string{"a": "b"})},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "any slice"},
+ Context: []zapcore.Field{zap.Any("slice", []string{"a"})},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "msg 2"},
+ Context: []zapcore.Field{zap.Int("b", 2), zap.Namespace("filterMe")},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.InfoLevel, Message: "any slice"},
+ Context: []zapcore.Field{zap.Any("filterMe", []string{"b"})},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.WarnLevel, Message: "danger will robinson"},
+ Context: []zapcore.Field{zap.Int("b", 42)},
+ },
+ {
+ Entry: zapcore.Entry{Level: zap.ErrorLevel, Message: "warp core breach"},
+ Context: []zapcore.Field{zap.Int("b", 42)},
+ },
+ }
+
+ logger, sink := New(zap.InfoLevel)
+ for _, log := range logs {
+ logger.Write(log.Entry, log.Context)
+ }
+
+ tests := []struct {
+ msg string
+ filtered *ObservedLogs
+ want []LoggedEntry
+ }{
+ {
+ msg: "filter by message",
+ filtered: sink.FilterMessage("log a"),
+ want: logs[0:2],
+ },
+ {
+ msg: "filter by field",
+ filtered: sink.FilterField(zap.String("fStr", "1")),
+ want: logs[0:1],
+ },
+ {
+ msg: "filter by message and field",
+ filtered: sink.FilterMessage("log a").FilterField(zap.Int("b", 2)),
+ want: logs[1:2],
+ },
+ {
+ msg: "filter by field with duplicate fields",
+ filtered: sink.FilterField(zap.Int("a", 2)),
+ want: logs[3:4],
+ },
+ {
+ msg: "filter doesn't match any messages",
+ filtered: sink.FilterMessage("no match"),
+ want: []LoggedEntry{},
+ },
+ {
+ msg: "filter by snippet",
+ filtered: sink.FilterMessageSnippet("log"),
+ want: logs[0:4],
+ },
+ {
+ msg: "filter by snippet and field",
+ filtered: sink.FilterMessageSnippet("a").FilterField(zap.Int("b", 2)),
+ want: logs[1:2],
+ },
+ {
+ msg: "filter for map",
+ filtered: sink.FilterField(zap.Any("map", map[string]string{"a": "b"})),
+ want: logs[5:6],
+ },
+ {
+ msg: "filter for slice",
+ filtered: sink.FilterField(zap.Any("slice", []string{"a"})),
+ want: logs[6:7],
+ },
+ {
+ msg: "filter field key",
+ filtered: sink.FilterFieldKey("filterMe"),
+ want: logs[7:9],
+ },
+ {
+ msg: "filter by arbitrary function",
+ filtered: sink.Filter(func(e LoggedEntry) bool {
+ return len(e.Context) > 1
+ }),
+ want: func() []LoggedEntry {
+ // Do not modify logs slice.
+ w := make([]LoggedEntry, 0, len(logs))
+ w = append(w, logs[0:5]...)
+ w = append(w, logs[7])
+ return w
+ }(),
+ },
+ {
+ msg: "filter level",
+ filtered: sink.FilterLevelExact(zap.WarnLevel),
+ want: logs[9:10],
+ },
+ }
+
+ for _, tt := range tests {
+ got := tt.filtered.AllUntimed()
+ assert.Equal(t, tt.want, got, tt.msg)
+ }
+}
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/testingt.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/testingt.go
new file mode 100644
index 0000000..792463b
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/testingt.go
@@ -0,0 +1,47 @@
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zaptest
+
+// TestingT is a subset of the API provided by all *testing.T and *testing.B
+// objects.
+type TestingT interface {
+ // Logs the given message without failing the test.
+ Logf(string, ...interface{})
+
+ // Logs the given message and marks the test as failed.
+ Errorf(string, ...interface{})
+
+ // Marks the test as failed.
+ Fail()
+
+ // Returns true if the test has been marked as failed.
+ Failed() bool
+
+ // Returns the name of the test.
+ Name() string
+
+ // Marks the test as failed and stops execution of that test.
+ FailNow()
+}
+
+// Note: We currently only rely on Logf. We are including Errorf and FailNow
+// in the interface in anticipation of future need since we can't extend the
+// interface without a breaking change.
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/testingt_test.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/testingt_test.go
new file mode 100644
index 0000000..d847796
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/testingt_test.go
@@ -0,0 +1,29 @@
+// Copyright (c) 2017 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zaptest
+
+import "testing"
+
+// Just a compile-time test to ensure that TestingT matches the testing.TB
+// interface. We could do this in testingt.go but that would put a dependency
+// on the "testing" package from zaptest.
+
+var _ TestingT = (testing.TB)(nil)
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/timeout.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/timeout.go
new file mode 100644
index 0000000..f0be444
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/timeout.go
@@ -0,0 +1,45 @@
+// Copyright (c) 2016 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zaptest
+
+import (
+ "time"
+
+ "go.uber.org/zap/internal/ztest"
+)
+
+// Timeout scales the provided duration by $TEST_TIMEOUT_SCALE.
+//
+// Deprecated: This function is intended for internal testing and shouldn't be
+// used outside zap itself. It was introduced before Go supported internal
+// packages.
+func Timeout(base time.Duration) time.Duration {
+ return ztest.Timeout(base)
+}
+
+// Sleep scales the sleep duration by $TEST_TIMEOUT_SCALE.
+//
+// Deprecated: This function is intended for internal testing and shouldn't be
+// used outside zap itself. It was introduced before Go supported internal
+// packages.
+func Sleep(base time.Duration) {
+ ztest.Sleep(base)
+}
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/timeout_test.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/timeout_test.go
new file mode 100644
index 0000000..3962ecd
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/timeout_test.go
@@ -0,0 +1,43 @@
+// Copyright (c) 2016 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zaptest
+
+import (
+ "testing"
+ "time"
+
+ "github.com/stretchr/testify/assert"
+ "go.uber.org/zap/internal/ztest"
+)
+
+func TestTimeout(t *testing.T) {
+ defer ztest.Initialize("2")()
+ assert.Equal(t, time.Duration(100), Timeout(50), "Expected to scale up timeout.")
+}
+
+func TestSleep(t *testing.T) {
+ defer ztest.Initialize("2")()
+ const sleepFor = 50 * time.Millisecond
+ now := time.Now()
+ Sleep(sleepFor)
+ elapsed := time.Since(now)
+ assert.True(t, 2*sleepFor <= elapsed, "Expected to scale up timeout.")
+}
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/writer.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/writer.go
new file mode 100644
index 0000000..4b772f8
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/writer.go
@@ -0,0 +1,44 @@
+// Copyright (c) 2016 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zaptest
+
+import "go.uber.org/zap/internal/ztest"
+
+type (
+ // A Syncer is a spy for the Sync portion of zapcore.WriteSyncer.
+ Syncer = ztest.Syncer
+
+ // A Discarder sends all writes to io.Discard.
+ Discarder = ztest.Discarder
+
+ // FailWriter is a WriteSyncer that always returns an error on writes.
+ FailWriter = ztest.FailWriter
+
+ // ShortWriter is a WriteSyncer whose write method never returns an error,
+ // but always reports that it wrote one byte less than the input slice's
+ // length (thus, a "short write").
+ ShortWriter = ztest.ShortWriter
+
+ // Buffer is an implementation of zapcore.WriteSyncer that sends all writes to
+ // a bytes.Buffer. It has convenience methods to split the accumulated buffer
+ // on newlines.
+ Buffer = ztest.Buffer
+)
diff --git a/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/writer_test.go b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/writer_test.go
new file mode 100644
index 0000000..c18f18a
--- /dev/null
+++ b/dependencies/pkg/mod/go.uber.org/zap@v1.23.0/zaptest/writer_test.go
@@ -0,0 +1,68 @@
+// Copyright (c) 2016 Uber Technologies, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+
+package zaptest
+
+import (
+ "errors"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestSyncer(t *testing.T) {
+ err := errors.New("sentinel")
+ s := &Syncer{}
+ s.SetError(err)
+ assert.Equal(t, err, s.Sync(), "Expected Sync to fail with provided error.")
+ assert.True(t, s.Called(), "Expected to record that Sync was called.")
+}
+
+func TestDiscarder(t *testing.T) {
+ d := &Discarder{}
+ payload := []byte("foo")
+ n, err := d.Write(payload)
+ assert.NoError(t, err, "Unexpected error writing to Discarder.")
+ assert.Equal(t, len(payload), n, "Wrong number of bytes written.")
+}
+
+func TestFailWriter(t *testing.T) {
+ w := &FailWriter{}
+ payload := []byte("foo")
+ n, err := w.Write(payload)
+ assert.Error(t, err, "Expected an error writing to FailWriter.")
+ assert.Equal(t, len(payload), n, "Wrong number of bytes written.")
+}
+
+func TestShortWriter(t *testing.T) {
+ w := &ShortWriter{}
+ payload := []byte("foo")
+ n, err := w.Write(payload)
+ assert.NoError(t, err, "Unexpected error writing to ShortWriter.")
+ assert.Equal(t, len(payload)-1, n, "Wrong number of bytes written.")
+}
+
+func TestBuffer(t *testing.T) {
+ buf := &Buffer{}
+ buf.WriteString("foo\n")
+ buf.WriteString("bar\n")
+ assert.Equal(t, []string{"foo", "bar"}, buf.Lines(), "Unexpected output from Lines.")
+ assert.Equal(t, "foo\nbar", buf.Stripped(), "Unexpected output from Stripped.")
+}