Source file
src/log/slog/value_test.go
1
2
3
4
5 package slog
6
7 import (
8 "fmt"
9 "reflect"
10 "strings"
11 "testing"
12 "time"
13 "unsafe"
14 )
15
16 func TestKindString(t *testing.T) {
17 if got, want := KindGroup.String(), "Group"; got != want {
18 t.Errorf("got %q, want %q", got, want)
19 }
20 }
21
22 func TestValueEqual(t *testing.T) {
23 var x, y int
24 vals := []Value{
25 {},
26 Int64Value(1),
27 Int64Value(2),
28 Float64Value(3.5),
29 Float64Value(3.7),
30 BoolValue(true),
31 BoolValue(false),
32 TimeValue(testTime),
33 TimeValue(time.Time{}),
34 TimeValue(time.Date(2001, 1, 2, 3, 4, 5, 0, time.UTC)),
35 TimeValue(time.Date(2300, 1, 1, 0, 0, 0, 0, time.UTC)),
36 TimeValue(time.Date(1715, 6, 13, 0, 25, 26, 290448384, time.UTC)),
37 AnyValue(&x),
38 AnyValue(&y),
39 GroupValue(Bool("b", true), Int("i", 3)),
40 GroupValue(Bool("b", true), Int("i", 4)),
41 GroupValue(Bool("b", true), Int("j", 4)),
42 DurationValue(3 * time.Second),
43 DurationValue(2 * time.Second),
44 StringValue("foo"),
45 StringValue("fuu"),
46 }
47 for i, v1 := range vals {
48 for j, v2 := range vals {
49 got := v1.Equal(v2)
50 want := i == j
51 if got != want {
52 t.Errorf("%v.Equal(%v): got %t, want %t", v1, v2, got, want)
53 }
54 }
55 }
56 }
57
58 func panics(f func()) (b bool) {
59 defer func() {
60 if x := recover(); x != nil {
61 b = true
62 }
63 }()
64 f()
65 return false
66 }
67
68 func TestValueString(t *testing.T) {
69 for _, test := range []struct {
70 v Value
71 want string
72 }{
73 {Int64Value(-3), "-3"},
74 {Uint64Value(1), "1"},
75 {Float64Value(.15), "0.15"},
76 {BoolValue(true), "true"},
77 {StringValue("foo"), "foo"},
78 {TimeValue(testTime), "2000-01-02 03:04:05 +0000 UTC"},
79 {AnyValue(time.Duration(3 * time.Second)), "3s"},
80 {GroupValue(Int("a", 1), Bool("b", true)), "[a=1 b=true]"},
81 } {
82 if got := test.v.String(); got != test.want {
83 t.Errorf("%#v:\ngot %q\nwant %q", test.v, got, test.want)
84 }
85 }
86 }
87
88 func TestValueNoAlloc(t *testing.T) {
89
90 var (
91 i int64
92 u uint64
93 f float64
94 b bool
95 s string
96 x any
97 p = &i
98 d time.Duration
99 tm time.Time
100 )
101 a := int(testing.AllocsPerRun(5, func() {
102 i = Int64Value(1).Int64()
103 u = Uint64Value(1).Uint64()
104 f = Float64Value(1).Float64()
105 b = BoolValue(true).Bool()
106 s = StringValue("foo").String()
107 d = DurationValue(d).Duration()
108 tm = TimeValue(testTime).Time()
109 x = AnyValue(p).Any()
110 }))
111 if a != 0 {
112 t.Errorf("got %d allocs, want zero", a)
113 }
114 _ = u
115 _ = f
116 _ = b
117 _ = s
118 _ = x
119 _ = tm
120 }
121
122 func TestAnyLevelAlloc(t *testing.T) {
123
124
125 var a Value
126 x := LevelDebug + 100
127 wantAllocs(t, 0, func() { a = AnyValue(x) })
128 _ = a
129 }
130
131 func TestAnyValue(t *testing.T) {
132 for _, test := range []struct {
133 in any
134 want Value
135 }{
136 {1, IntValue(1)},
137 {1.5, Float64Value(1.5)},
138 {float32(2.5), Float64Value(2.5)},
139 {"s", StringValue("s")},
140 {true, BoolValue(true)},
141 {testTime, TimeValue(testTime)},
142 {time.Hour, DurationValue(time.Hour)},
143 {[]Attr{Int("i", 3)}, GroupValue(Int("i", 3))},
144 {IntValue(4), IntValue(4)},
145 {uint(2), Uint64Value(2)},
146 {uint8(3), Uint64Value(3)},
147 {uint16(4), Uint64Value(4)},
148 {uint32(5), Uint64Value(5)},
149 {uint64(6), Uint64Value(6)},
150 {uintptr(7), Uint64Value(7)},
151 {int8(8), Int64Value(8)},
152 {int16(9), Int64Value(9)},
153 {int32(10), Int64Value(10)},
154 {int64(11), Int64Value(11)},
155 } {
156 got := AnyValue(test.in)
157 if !got.Equal(test.want) {
158 t.Errorf("%v (%[1]T): got %v (kind %s), want %v (kind %s)",
159 test.in, got, got.Kind(), test.want, test.want.Kind())
160 }
161 }
162 }
163
164 func TestValueAny(t *testing.T) {
165 for _, want := range []any{
166 nil,
167 LevelDebug + 100,
168 time.UTC,
169 KindBool,
170 []Attr{Int("a", 1)},
171 int64(2),
172 uint64(3),
173 true,
174 time.Minute,
175 time.Time{},
176 3.14,
177 "foo",
178 } {
179 v := AnyValue(want)
180 got := v.Any()
181 if !reflect.DeepEqual(got, want) {
182 t.Errorf("got %v, want %v", got, want)
183 }
184 }
185 }
186
187 func TestLogValue(t *testing.T) {
188 want := "replaced"
189 r := &replace{StringValue(want)}
190 v := AnyValue(r)
191 if g, w := v.Kind(), KindLogValuer; g != w {
192 t.Errorf("got %s, want %s", g, w)
193 }
194 got := v.LogValuer().LogValue().Any()
195 if got != want {
196 t.Errorf("got %#v, want %#v", got, want)
197 }
198
199
200 got = v.Resolve().Any()
201 if got != want {
202 t.Errorf("got %#v, want %#v", got, want)
203 }
204
205
206 r.v = AnyValue(r)
207 got = AnyValue(r).Resolve().Any()
208 if _, ok := got.(error); !ok {
209 t.Errorf("expected error, got %T", got)
210 }
211
212
213 c := Any("c", &replace{StringValue("d")})
214 v = AnyValue(&replace{GroupValue(Int("a", 1), Group("b", c))})
215 got2 := v.Resolve().Any().([]Attr)
216 want2 := []Attr{Int("a", 1), Group("b", c)}
217 if !attrsEqual(got2, want2) {
218 t.Errorf("got %v, want %v", got2, want2)
219 }
220
221
222 v = AnyValue(panickingLogValue{})
223 got = v.Resolve().Any()
224 gotErr, ok := got.(error)
225 if !ok {
226 t.Errorf("expected error, got %T", got)
227 }
228
229
230 if got, want := gotErr.Error(), "TestLogValue"; !strings.Contains(got, want) {
231 t.Errorf("got %q, want substring %q", got, want)
232 }
233 }
234
235 func TestValueTime(t *testing.T) {
236
237 for _, tm := range []time.Time{
238 time.Time{},
239 time.Unix(0, 1e15),
240 time.Date(2300, 1, 1, 0, 0, 0, 0, time.UTC),
241 } {
242 got := TimeValue(tm).Time()
243 if !got.Equal(tm) {
244 t.Errorf("got %s (%#[1]v), want %s (%#[2]v)", got, tm)
245 }
246 if g, w := got.Location(), tm.Location(); g != w {
247 t.Errorf("%s: location: got %v, want %v", tm, g, w)
248 }
249 }
250 }
251
252 func TestEmptyGroup(t *testing.T) {
253 g := GroupValue(
254 Int("a", 1),
255 Group("g1", Group("g2")),
256 Group("g3", Group("g4", Int("b", 2))))
257 got := g.Group()
258 want := []Attr{Int("a", 1), Group("g3", Group("g4", Int("b", 2)))}
259 if !attrsEqual(got, want) {
260 t.Errorf("\ngot %v\nwant %v", got, want)
261 }
262 }
263
264 type replace struct {
265 v Value
266 }
267
268 func (r *replace) LogValue() Value { return r.v }
269
270 type panickingLogValue struct{}
271
272 func (panickingLogValue) LogValue() Value { panic("bad") }
273
274
275
276
277
278
279 func BenchmarkUnsafeStrings(b *testing.B) {
280 b.ReportAllocs()
281 dst := make([]Value, 100)
282 src := make([]Value, len(dst))
283 b.Logf("Value size = %d", unsafe.Sizeof(Value{}))
284 for i := range src {
285 src[i] = StringValue(fmt.Sprintf("string#%d", i))
286 }
287 b.ResetTimer()
288 var d string
289 for i := 0; i < b.N; i++ {
290 copy(dst, src)
291 for _, a := range dst {
292 d = a.String()
293 }
294 }
295 _ = d
296 }
297
View as plain text