1// Copyright The OpenTelemetry Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package label_test
16
17import (
18	"strings"
19	"testing"
20
21	"github.com/google/go-cmp/cmp"
22
23	"go.opentelemetry.io/otel/label"
24)
25
26func TestKeyValueConstructors(t *testing.T) {
27	tt := []struct {
28		name     string
29		actual   label.KeyValue
30		expected label.KeyValue
31	}{
32		{
33			name:   "Bool",
34			actual: label.Bool("k1", true),
35			expected: label.KeyValue{
36				Key:   "k1",
37				Value: label.BoolValue(true),
38			},
39		},
40		{
41			name:   "Int64",
42			actual: label.Int64("k1", 123),
43			expected: label.KeyValue{
44				Key:   "k1",
45				Value: label.Int64Value(123),
46			},
47		},
48		{
49			name:   "Uint64",
50			actual: label.Uint64("k1", 1),
51			expected: label.KeyValue{
52				Key:   "k1",
53				Value: label.Uint64Value(1),
54			},
55		},
56		{
57			name:   "Float64",
58			actual: label.Float64("k1", 123.5),
59			expected: label.KeyValue{
60				Key:   "k1",
61				Value: label.Float64Value(123.5),
62			},
63		},
64		{
65			name:   "Int32",
66			actual: label.Int32("k1", 123),
67			expected: label.KeyValue{
68				Key:   "k1",
69				Value: label.Int32Value(123),
70			},
71		},
72		{
73			name:   "Uint32",
74			actual: label.Uint32("k1", 123),
75			expected: label.KeyValue{
76				Key:   "k1",
77				Value: label.Uint32Value(123),
78			},
79		},
80		{
81			name:   "Float32",
82			actual: label.Float32("k1", 123.5),
83			expected: label.KeyValue{
84				Key:   "k1",
85				Value: label.Float32Value(123.5),
86			},
87		},
88		{
89			name:   "String",
90			actual: label.String("k1", "123.5"),
91			expected: label.KeyValue{
92				Key:   "k1",
93				Value: label.StringValue("123.5"),
94			},
95		},
96		{
97			name:   "Int",
98			actual: label.Int("k1", 123),
99			expected: label.KeyValue{
100				Key:   "k1",
101				Value: label.IntValue(123),
102			},
103		},
104		{
105			name:   "Uint",
106			actual: label.Uint("k1", 123),
107			expected: label.KeyValue{
108				Key:   "k1",
109				Value: label.UintValue(123),
110			},
111		},
112	}
113
114	for _, test := range tt {
115		t.Run(test.name, func(t *testing.T) {
116			if diff := cmp.Diff(test.actual, test.expected, cmp.AllowUnexported(label.Value{})); diff != "" {
117				t.Fatal(diff)
118			}
119		})
120	}
121}
122
123func TestAny(t *testing.T) {
124	builder := &strings.Builder{}
125	builder.WriteString("foo")
126	jsonifyStruct := struct {
127		Public    string
128		private   string
129		Tagged    string `json:"tagName"`
130		Empty     string
131		OmitEmpty string `json:",omitempty"`
132		Omit      string `json:"-"`
133	}{"foo", "bar", "baz", "", "", "omitted"}
134	invalidStruct := struct {
135		N complex64
136	}{complex(0, 0)}
137	for _, testcase := range []struct {
138		key       string
139		value     interface{}
140		wantType  label.Type
141		wantValue interface{}
142	}{
143		{
144			key:       "bool type inferred",
145			value:     true,
146			wantType:  label.BOOL,
147			wantValue: true,
148		},
149		{
150			key:       "int64 type inferred",
151			value:     int64(42),
152			wantType:  label.INT64,
153			wantValue: int64(42),
154		},
155		{
156			key:       "uint64 type inferred",
157			value:     uint64(42),
158			wantType:  label.UINT64,
159			wantValue: uint64(42),
160		},
161		{
162			key:       "float64 type inferred",
163			value:     float64(42.1),
164			wantType:  label.FLOAT64,
165			wantValue: 42.1,
166		},
167		{
168			key:       "int32 type inferred",
169			value:     int32(42),
170			wantType:  label.INT32,
171			wantValue: int32(42),
172		},
173		{
174			key:       "uint32 type inferred",
175			value:     uint32(42),
176			wantType:  label.UINT32,
177			wantValue: uint32(42),
178		},
179		{
180			key:       "float32 type inferred",
181			value:     float32(42.1),
182			wantType:  label.FLOAT32,
183			wantValue: float32(42.1),
184		},
185		{
186			key:       "string type inferred",
187			value:     "foo",
188			wantType:  label.STRING,
189			wantValue: "foo",
190		},
191		{
192			key:       "stringer type inferred",
193			value:     builder,
194			wantType:  label.STRING,
195			wantValue: "foo",
196		},
197		{
198			key:       "unknown value serialized as %v",
199			value:     nil,
200			wantType:  label.STRING,
201			wantValue: "<nil>",
202		},
203		{
204			key:       "JSON struct serialized correctly",
205			value:     &jsonifyStruct,
206			wantType:  label.STRING,
207			wantValue: `{"Public":"foo","tagName":"baz","Empty":""}`,
208		},
209		{
210			key:       "Invalid JSON struct falls back to string",
211			value:     &invalidStruct,
212			wantType:  label.STRING,
213			wantValue: "&{(0+0i)}",
214		},
215	} {
216		t.Logf("Running test case %s", testcase.key)
217		keyValue := label.Any(testcase.key, testcase.value)
218		if keyValue.Value.Type() != testcase.wantType {
219			t.Errorf("wrong value type, got %#v, expected %#v", keyValue.Value.Type(), testcase.wantType)
220		}
221		got := keyValue.Value.AsInterface()
222		if diff := cmp.Diff(testcase.wantValue, got); diff != "" {
223			t.Errorf("+got, -want: %s", diff)
224		}
225	}
226}
227