github.com/AndrienkoAleksandr/go@v0.0.19/src/log/slog/record_test.go (about) 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. 4 5 package slog 6 7 import ( 8 "slices" 9 "strconv" 10 "strings" 11 "testing" 12 "time" 13 ) 14 15 func TestRecordAttrs(t *testing.T) { 16 as := []Attr{Int("k1", 1), String("k2", "foo"), Int("k3", 3), 17 Int64("k4", -1), Float64("f", 3.1), Uint64("u", 999)} 18 r := newRecordWithAttrs(as) 19 if g, w := r.NumAttrs(), len(as); g != w { 20 t.Errorf("NumAttrs: got %d, want %d", g, w) 21 } 22 if got := attrsSlice(r); !attrsEqual(got, as) { 23 t.Errorf("got %v, want %v", got, as) 24 } 25 26 // Early return. 27 // Hit both loops in Record.Attrs: front and back. 28 for _, stop := range []int{2, 6} { 29 var got []Attr 30 r.Attrs(func(a Attr) bool { 31 got = append(got, a) 32 return len(got) < stop 33 }) 34 want := as[:stop] 35 if !attrsEqual(got, want) { 36 t.Errorf("got %v, want %v", got, want) 37 } 38 } 39 } 40 41 func TestRecordSource(t *testing.T) { 42 // Zero call depth => empty *Source. 43 for _, test := range []struct { 44 depth int 45 wantFunction string 46 wantFile string 47 wantLinePositive bool 48 }{ 49 {0, "", "", false}, 50 {-16, "", "", false}, 51 {1, "log/slog.TestRecordSource", "record_test.go", true}, // 1: caller of NewRecord 52 {2, "testing.tRunner", "testing.go", true}, 53 } { 54 var pc uintptr 55 if test.depth > 0 { 56 pc = callerPC(test.depth + 1) 57 } 58 r := NewRecord(time.Time{}, 0, "", pc) 59 got := r.source() 60 if i := strings.LastIndexByte(got.File, '/'); i >= 0 { 61 got.File = got.File[i+1:] 62 } 63 if got.Function != test.wantFunction || got.File != test.wantFile || (got.Line > 0) != test.wantLinePositive { 64 t.Errorf("depth %d: got (%q, %q, %d), want (%q, %q, %t)", 65 test.depth, 66 got.Function, got.File, got.Line, 67 test.wantFunction, test.wantFile, test.wantLinePositive) 68 } 69 } 70 } 71 72 func TestAliasingAndClone(t *testing.T) { 73 intAttrs := func(from, to int) []Attr { 74 var as []Attr 75 for i := from; i < to; i++ { 76 as = append(as, Int("k", i)) 77 } 78 return as 79 } 80 81 check := func(r Record, want []Attr) { 82 t.Helper() 83 got := attrsSlice(r) 84 if !attrsEqual(got, want) { 85 t.Errorf("got %v, want %v", got, want) 86 } 87 } 88 89 // Create a record whose Attrs overflow the inline array, 90 // creating a slice in r.back. 91 r1 := NewRecord(time.Time{}, 0, "", 0) 92 r1.AddAttrs(intAttrs(0, nAttrsInline+1)...) 93 // Ensure that r1.back's capacity exceeds its length. 94 b := make([]Attr, len(r1.back), len(r1.back)+1) 95 copy(b, r1.back) 96 r1.back = b 97 // Make a copy that shares state. 98 r2 := r1 99 // Adding to both should panic. 100 r1.AddAttrs(Int("p", 0)) 101 if !panics(func() { r2.AddAttrs(Int("p", 1)) }) { 102 t.Error("expected panic") 103 } 104 r1Attrs := attrsSlice(r1) 105 // Adding to a clone is fine. 106 r2 = r1.Clone() 107 check(r2, r1Attrs) 108 r2.AddAttrs(Int("p", 2)) 109 check(r1, r1Attrs) // r1 is unchanged 110 check(r2, append(slices.Clip(r1Attrs), Int("p", 2))) 111 } 112 113 func newRecordWithAttrs(as []Attr) Record { 114 r := NewRecord(time.Now(), LevelInfo, "", 0) 115 r.AddAttrs(as...) 116 return r 117 } 118 119 func attrsSlice(r Record) []Attr { 120 s := make([]Attr, 0, r.NumAttrs()) 121 r.Attrs(func(a Attr) bool { s = append(s, a); return true }) 122 return s 123 } 124 125 func attrsEqual(as1, as2 []Attr) bool { 126 return slices.EqualFunc(as1, as2, Attr.Equal) 127 } 128 129 // Currently, pc(2) takes over 400ns, which is too expensive 130 // to call it for every log message. 131 func BenchmarkPC(b *testing.B) { 132 for depth := 0; depth < 5; depth++ { 133 b.Run(strconv.Itoa(depth), func(b *testing.B) { 134 b.ReportAllocs() 135 var x uintptr 136 for i := 0; i < b.N; i++ { 137 x = callerPC(depth) 138 } 139 _ = x 140 }) 141 } 142 } 143 144 func BenchmarkRecord(b *testing.B) { 145 const nAttrs = nAttrsInline * 10 146 var a Attr 147 148 for i := 0; i < b.N; i++ { 149 r := NewRecord(time.Time{}, LevelInfo, "", 0) 150 for j := 0; j < nAttrs; j++ { 151 r.AddAttrs(Int("k", j)) 152 } 153 r.Attrs(func(b Attr) bool { a = b; return true }) 154 } 155 _ = a 156 }