Skip to content

Commit

Permalink
Add tests for Value and KeyValue
Browse files Browse the repository at this point in the history
  • Loading branch information
MrAlias committed Feb 20, 2024
1 parent 4fea171 commit 755c523
Showing 1 changed file with 301 additions and 0 deletions.
301 changes: 301 additions & 0 deletions log/keyvalue_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
// Copyright The OpenTelemetry Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Copyright 2022 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package log_test

import (
golog "log"
"os"
"testing"

"github.com/go-logr/logr"
"github.com/go-logr/logr/testr"
"github.com/go-logr/stdr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.opentelemetry.io/otel/internal/global"
"go.opentelemetry.io/otel/log"
)

func TestKind(t *testing.T) {
testCases := []struct {
kind log.Kind
str string
value int
}{
{log.KindBool, "Bool", 1},
{log.KindBytes, "Bytes", 5},
{log.KindEmpty, "Empty", 0},
{log.KindFloat64, "Float64", 2},
{log.KindInt64, "Int64", 3},
{log.KindSlice, "Slice", 6},
{log.KindMap, "Map", 7},
{log.KindString, "String", 4},
}
for _, tc := range testCases {
t.Run(tc.str, func(t *testing.T) {
assert.Equal(t, tc.value, int(tc.kind), "Kind value")
assert.Equal(t, tc.str, tc.kind.String(), "Kind string")
})
}
}

func TestValueEqual(t *testing.T) {
vals := []log.Value{
{},
log.Int64Value(1),
log.Int64Value(2),
log.Float64Value(3.5),
log.Float64Value(3.7),
log.BoolValue(true),
log.BoolValue(false),
log.StringValue("hi"),
log.StringValue("bye"),
log.BytesValue([]byte{1, 3, 5}),
log.SliceValue(log.StringValue("foo")),
log.SliceValue(log.IntValue(3), log.StringValue("foo")),
log.MapValue(log.Bool("b", true), log.Int("i", 3)),
log.MapValue(
log.Slice("l", log.IntValue(3), log.StringValue("foo")),
log.Bytes("b", []byte{3, 5, 7}),
),
}
for i, v1 := range vals {
for j, v2 := range vals {
assert.Equal(t, i == j, v1.Equal(v2), "%v.Equal(%v)", v1, v2)
}
}
}

func TestEmpty(t *testing.T) {
v := log.Value{}
t.Run("Value.Empty", func(t *testing.T) {
assert.True(t, v.Empty())
})
t.Run("Value.AsAny", func(t *testing.T) {
assert.Nil(t, v.AsAny())
})

t.Run("Bytes", func(t *testing.T) {
assert.Nil(t, log.Bytes("b", nil).Value.AsBytes())
})
t.Run("Slice", func(t *testing.T) {
assert.Nil(t, log.Slice("s").Value.AsSlice())
})
t.Run("Map", func(t *testing.T) {
assert.Nil(t, log.Map("m").Value.AsMap())
})
}

func TestEmptyGroupsPreserved(t *testing.T) {
t.Run("Map", func(t *testing.T) {
assert.Equal(t, []log.KeyValue{
log.Int("a", 1),
log.Map("g1", log.Map("g2")),
log.Map("g3", log.Map("g4", log.Int("b", 2))),
}, log.MapValue(
log.Int("a", 1),
log.Map("g1", log.Map("g2")),
log.Map("g3", log.Map("g4", log.Int("b", 2))),
).AsMap())
})

t.Run("Slice", func(t *testing.T) {
assert.Equal(t, []log.Value{{}}, log.SliceValue(log.Value{}).AsSlice())
})
}

func TestBool(t *testing.T) {
const key, val = "key", true
kv := log.Bool(key, val)
testKV(t, key, val, kv)

v, k := kv.Value, log.KindBool
t.Run("AsBool", func(t *testing.T) {
assert.Equal(t, val, kv.Value.AsBool(), "AsBool")
})
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
}

func TestFloat64(t *testing.T) {
const key, val = "key", 3.0
kv := log.Float64(key, val)
testKV(t, key, val, kv)

v, k := kv.Value, log.KindFloat64
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
t.Run("AsFloat64", func(t *testing.T) {
assert.Equal(t, val, v.AsFloat64(), "AsFloat64")
})
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
}

func TestInt(t *testing.T) {
const key, val = "key", 1
kv := log.Int(key, val)
testKV[int64](t, key, val, kv)

v, k := kv.Value, log.KindInt64
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
t.Run("AsInt64", func(t *testing.T) {
assert.Equal(t, int64(val), v.AsInt64(), "AsInt64")
})
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
}

func TestInt64(t *testing.T) {
const key, val = "key", 1
kv := log.Int64(key, val)
testKV[int64](t, key, val, kv)

v, k := kv.Value, log.KindInt64
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
t.Run("AsInt64", func(t *testing.T) {
assert.Equal(t, int64(val), v.AsInt64(), "AsInt64")
})
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
}

func TestString(t *testing.T) {
const key, val = "key", "test string value"
kv := log.String(key, val)
testKV(t, key, val, kv)

v, k := kv.Value, log.KindString
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
t.Run("AsString", func(t *testing.T) {
assert.Equal(t, val, v.AsString(), "AsString")
})
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
}

func TestBytes(t *testing.T) {
const key = "key"
val := []byte{3, 2, 1}
kv := log.Bytes(key, val)
testKV(t, key, val, kv)

v, k := kv.Value, log.KindBytes
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
t.Run("AsBytes", func(t *testing.T) {
assert.Equal(t, val, v.AsBytes(), "AsBytes")
})
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
}

func TestSlice(t *testing.T) {
const key = "key"
val := []log.Value{log.IntValue(3), log.StringValue("foo")}
kv := log.Slice(key, val...)
testKV(t, key, val, kv)

v, k := kv.Value, log.KindSlice
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
t.Run("AsSlice", func(t *testing.T) {
assert.Equal(t, val, v.AsSlice(), "AsSlice")
})
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
}

func TestMap(t *testing.T) {
const key = "key"
val := []log.KeyValue{
log.Slice("l", log.IntValue(3), log.StringValue("foo")),
log.Bytes("b", []byte{3, 5, 7}),
}
kv := log.Map(key, val...)
testKV(t, key, val, kv)

v, k := kv.Value, log.KindMap
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
t.Run("AsMap", func(t *testing.T) {
assert.Equal(t, val, v.AsMap(), "AsMap")
})
}

type logSink struct {
logr.LogSink

err error
msg string
keysAndValues []interface{}
}

func (l *logSink) Error(err error, msg string, keysAndValues ...interface{}) {
l.err, l.msg, l.keysAndValues = err, msg, keysAndValues
l.LogSink.Error(err, msg, keysAndValues)
}

var stdLogger = stdr.New(golog.New(os.Stderr, "", golog.LstdFlags|golog.Lshortfile))

func testErrKind[T any](f func() T, msg string, k log.Kind) func(*testing.T) {
return func(t *testing.T) {
l := &logSink{LogSink: testr.New(t).GetSink()}
global.SetLogger(logr.New(l))
t.Cleanup(func() { global.SetLogger(stdLogger) })

assert.Zero(t, f())

assert.ErrorContains(t, l.err, "invalid Kind")
assert.Equal(t, msg, l.msg)
require.Len(t, l.keysAndValues, 2, "logged attributes")
assert.Equal(t, l.keysAndValues[1], k)
}
}

func testKV[T any](t *testing.T, key string, val T, kv log.KeyValue) {
t.Helper()

assert.Equal(t, key, kv.Key, "incorrect key")
assert.False(t, kv.Value.Empty(), "value empty")
assert.Equal(t, kv.Value.AsAny(), T(val), "AsAny wrong value")
}

0 comments on commit 755c523

Please sign in to comment.