Repository: uber-go/zap
File: sugar_test.go (Go)

Code before:
		{
			desc:     "key-value pair and a dangling key",
			args:     []interface{}{"foo", 42, "dangling"},
			expected: []zapcore.Field{Int("foo", 42)},
			errLogs:  []observer.LoggedEntry{ignored("dangling")},
		},
		{
			desc:     "pairs, a structured field, and a dangling key",
			args:     []interface{}{"first", "field", Int("foo", 42), "baz", "quux", "dangling"},
			expected: []zapcore.Field{String("first", "field"), Int("foo", 42), String("baz", "quux")},
			errLogs:  []observer.LoggedEntry{ignored("dangling")},
		},
		{
			desc:     "one non-string key",
			args:     []interface{}{"foo", 42, true, "bar"},
			expected: []zapcore.Field{Int("foo", 42)},
			errLogs:  []observer.LoggedEntry{nonString(invalidPair{2, true, "bar"})},
		},
		{
			desc:     "pairs, structured fields, non-string keys, and a dangling key",
			args:     []interface{}{"foo", 42, true, "bar", Int("structure", 11), 42, "reversed", "dangling"},
			expected: []zapcore.Field{Int("foo", 42), Int("structure", 11)},
			errLogs: []observer.LoggedEntry{
				ignored("dangling"),
				nonString(invalidPair{2, true, "bar"}, invalidPair{5, 42, "reversed"}),
			},
		},
	}

	for _, tt := range tests {
		withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
			logger.With(tt.args...).Info("")
			output := logs.AllUntimed()
			if len(tt.errLogs) > 0 {
				for i := range tt.errLogs {
					assert.Equal(t, tt.errLogs[i], output[i], "Unexpected error log at position %d for scenario %s.", i, tt.desc)
				}
			}
			assert.Equal(t, len(tt.errLogs)+1, len(output), "Expected only one non-error message to be logged in scenario %s.", tt.desc)
			assert.Equal(t, tt.expected, output[len(tt.errLogs)].Context, "Unexpected message context in scenario %s.", tt.desc)
		})
	}
}

type stringerF func() string

func (f stringerF) String() string { return f() }

func TestSugarStructuredLogging(t *testing.T) {
	tests := []struct {
		msg       string

Review comment (suggestion):
other cases that occur to me:
- dangling non-string value
- other things that aren't strings as keys, like structs, interface values, etc
- more interleaving, like `pair(s), structured field(s), pair(s), structured field(s)`

I hesitate to suggest programmatically generating test cases, especially in a world where we still can't use sub-tests (I dearly look forward to a post go 1.6 support world ;-) ).

Code after:
		{
			desc:     "structured field and a dangling non-string key",
			args:     []interface{}{Int("foo", 42), 13},
			expected: []zapcore.Field{Int("foo", 42)},
			errLogs:  []observer.LoggedEntry{ignored(13)},
		},
		{
			desc:     "key-value pair and a dangling key",
			args:     []interface{}{"foo", 42, "dangling"},
			expected: []zapcore.Field{Int("foo", 42)},
			errLogs:  []observer.LoggedEntry{ignored("dangling")},
		},
		{
			desc:     "pairs, a structured field, and a dangling key",
			args:     []interface{}{"first", "field", Int("foo", 42), "baz", "quux", "dangling"},
			expected: []zapcore.Field{String("first", "field"), Int("foo", 42), String("baz", "quux")},
			errLogs:  []observer.LoggedEntry{ignored("dangling")},
		},
		{
			desc:     "one non-string key",
			args:     []interface{}{"foo", 42, true, "bar"},
			expected: []zapcore.Field{Int("foo", 42)},
			errLogs:  []observer.LoggedEntry{nonString(invalidPair{2, true, "bar"})},
		},
		{
			desc:     "pairs, structured fields, non-string keys, and a dangling key",
			args:     []interface{}{"foo", 42, true, "bar", Int("structure", 11), 42, "reversed", "baz", "quux", "dangling"},
			expected: []zapcore.Field{Int("foo", 42), Int("structure", 11), String("baz", "quux")},
			errLogs: []observer.LoggedEntry{
				ignored("dangling"),
				nonString(invalidPair{2, true, "bar"}, invalidPair{5, 42, "reversed"}),
			},
		},
	}

	for _, tt := range tests {
		withSugar(t, DebugLevel, nil, func(logger *SugaredLogger, logs *observer.ObservedLogs) {
			logger.With(tt.args...).Info("")
			output := logs.AllUntimed()
			if len(tt.errLogs) > 0 {
				for i := range tt.errLogs {
					assert.Equal(t, tt.errLogs[i], output[i], "Unexpected error log at position %d for scenario %s.", i, tt.desc)
				}
			}
			assert.Equal(t, len(tt.errLogs)+1, len(output), "Expected only one non-error message to be logged in scenario %s.", tt.desc)
			assert.Equal(t, tt.expected, output[len(tt.errLogs)].Context, "Unexpected message context in scenario %s.", tt.desc)
		})
	}
}

type stringerF func() string