1 // Copyright 2022 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 func TestValueEqual(t *testing.T) {
28 GroupValue(Bool("b", true), Int("i", 3)),
30 for i, v1 := range vals {
31 for j, v2 := range vals {
35 t.Errorf("%v.Equal(%v): got %t, want %t", v1, v2, got, want)
41 func panics(f func()) (b bool) {
43 if x := recover(); x != nil {
51 func TestValueString(t *testing.T) {
52 for _, test := range []struct {
56 {Int64Value(-3), "-3"},
57 {Float64Value(.15), "0.15"},
58 {BoolValue(true), "true"},
59 {StringValue("foo"), "foo"},
60 {TimeValue(testTime), "2000-01-02 03:04:05 +0000 UTC"},
61 {AnyValue(time.Duration(3 * time.Second)), "3s"},
63 if got := test.v.String(); got != test.want {
64 t.Errorf("%#v:\ngot %q\nwant %q", test.v, got, test.want)
69 func TestValueNoAlloc(t *testing.T) {
70 // Assign values just to make sure the compiler doesn't optimize away the statements.
82 a := int(testing.AllocsPerRun(5, func() {
83 i = Int64Value(1).Int64()
84 u = Uint64Value(1).Uint64()
85 f = Float64Value(1).Float64()
86 b = BoolValue(true).Bool()
87 s = StringValue("foo").String()
88 d = DurationValue(d).Duration()
89 tm = TimeValue(testTime).Time()
93 t.Errorf("got %d allocs, want zero", a)
103 func TestAnyLevelAlloc(t *testing.T) {
104 // Because typical Levels are small integers,
105 // they are zero-alloc.
107 x := LevelDebug + 100
108 wantAllocs(t, 0, func() { a = AnyValue(x) })
112 func TestAnyValue(t *testing.T) {
113 for _, test := range []struct {
118 {1.5, Float64Value(1.5)},
119 {"s", StringValue("s")},
120 {uint(2), Uint64Value(2)},
121 {true, BoolValue(true)},
122 {testTime, TimeValue(testTime)},
123 {time.Hour, DurationValue(time.Hour)},
124 {[]Attr{Int("i", 3)}, GroupValue(Int("i", 3))},
125 {IntValue(4), IntValue(4)},
127 got := AnyValue(test.in)
128 if !got.Equal(test.want) {
129 t.Errorf("%v (%[1]T): got %v (kind %s), want %v (kind %s)",
130 test.in, got, got.Kind(), test.want, test.want.Kind())
135 func TestValueAny(t *testing.T) {
136 for _, want := range []any{
139 time.UTC, // time.Locations treated specially...
140 KindBool, // ...as are Kinds
145 if !reflect.DeepEqual(got, want) {
146 t.Errorf("got %v, want %v", got, want)
151 func TestLogValue(t *testing.T) {
153 r := &replace{StringValue(want)}
155 if g, w := v.Kind(), KindLogValuer; g != w {
156 t.Errorf("got %s, want %s", g, w)
158 got := v.LogValuer().LogValue().Any()
160 t.Errorf("got %#v, want %#v", got, want)
164 got = v.Resolve().Any()
166 t.Errorf("got %#v, want %#v", got, want)
169 // Test Resolve max iteration.
170 r.v = AnyValue(r) // create a cycle
171 got = AnyValue(r).Resolve().Any()
172 if _, ok := got.(error); !ok {
173 t.Errorf("expected error, got %T", got)
176 // Test Resolve group.
177 r = &replace{GroupValue(
179 Group("b", Any("c", &replace{StringValue("d")})),
182 got2 := v.Resolve().Any().([]Attr)
183 want2 := []Attr{Int("a", 1), Group("b", String("c", "d"))}
184 if !attrsEqual(got2, want2) {
185 t.Errorf("got %v, want %v", got2, want2)
190 func TestZeroTime(t *testing.T) {
192 got := TimeValue(z).Time()
194 t.Errorf("got %s (%#[1]v), not zero time (%#v)", got, z)
198 type replace struct {
202 func (r *replace) LogValue() Value { return r.v }
204 // A Value with "unsafe" strings is significantly faster:
205 // safe: 1785 ns/op, 0 allocs
206 // unsafe: 690 ns/op, 0 allocs
208 // Run this with and without -tags unsafe_kvs to compare.
209 func BenchmarkUnsafeStrings(b *testing.B) {
211 dst := make([]Value, 100)
212 src := make([]Value, len(dst))
213 b.Logf("Value size = %d", unsafe.Sizeof(Value{}))
215 src[i] = StringValue(fmt.Sprintf("string#%d", i))
219 for i := 0; i < b.N; i++ {
221 for _, a := range dst {