github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/cover/profile_test.go (about) 1 // Copyright 2019 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 cover 6 7 import ( 8 "fmt" 9 "io/ioutil" 10 "os" 11 "reflect" 12 "testing" 13 ) 14 15 func TestParseProfiles(t *testing.T) { 16 tests := []struct { 17 name string 18 input string 19 output []*Profile 20 expectErr bool 21 }{ 22 { 23 name: "parsing an empty file produces empty output", 24 input: `mode: set`, 25 output: []*Profile{}, 26 }, 27 { 28 name: "simple valid file produces expected output", 29 input: `mode: set 30 some/fancy/path:42.69,44.16 2 1`, 31 output: []*Profile{ 32 { 33 FileName: "some/fancy/path", 34 Mode: "set", 35 Blocks: []ProfileBlock{ 36 { 37 StartLine: 42, StartCol: 69, 38 EndLine: 44, EndCol: 16, 39 NumStmt: 2, Count: 1, 40 }, 41 }, 42 }, 43 }, 44 }, 45 { 46 name: "file with syntax characters in path produces expected output", 47 input: `mode: set 48 some fancy:path/some,file.go:42.69,44.16 2 1`, 49 output: []*Profile{ 50 { 51 FileName: "some fancy:path/some,file.go", 52 Mode: "set", 53 Blocks: []ProfileBlock{ 54 { 55 StartLine: 42, StartCol: 69, 56 EndLine: 44, EndCol: 16, 57 NumStmt: 2, Count: 1, 58 }, 59 }, 60 }, 61 }, 62 }, 63 { 64 name: "file with multiple blocks in one file produces expected output", 65 input: `mode: set 66 some/fancy/path:42.69,44.16 2 1 67 some/fancy/path:44.16,46.3 1 0`, 68 output: []*Profile{ 69 { 70 FileName: "some/fancy/path", 71 Mode: "set", 72 Blocks: []ProfileBlock{ 73 { 74 StartLine: 42, StartCol: 69, 75 EndLine: 44, EndCol: 16, 76 NumStmt: 2, Count: 1, 77 }, 78 { 79 StartLine: 44, StartCol: 16, 80 EndLine: 46, EndCol: 3, 81 NumStmt: 1, Count: 0, 82 }, 83 }, 84 }, 85 }, 86 }, 87 { 88 name: "file with multiple files produces expected output", 89 input: `mode: set 90 another/fancy/path:44.16,46.3 1 0 91 some/fancy/path:42.69,44.16 2 1`, 92 output: []*Profile{ 93 { 94 FileName: "another/fancy/path", 95 Mode: "set", 96 Blocks: []ProfileBlock{ 97 { 98 StartLine: 44, StartCol: 16, 99 EndLine: 46, EndCol: 3, 100 NumStmt: 1, Count: 0, 101 }, 102 }, 103 }, 104 { 105 FileName: "some/fancy/path", 106 Mode: "set", 107 Blocks: []ProfileBlock{ 108 { 109 StartLine: 42, StartCol: 69, 110 EndLine: 44, EndCol: 16, 111 NumStmt: 2, Count: 1, 112 }, 113 }, 114 }, 115 }, 116 }, 117 { 118 name: "intertwined files are merged correctly", 119 input: `mode: set 120 some/fancy/path:42.69,44.16 2 1 121 another/fancy/path:47.2,47.13 1 1 122 some/fancy/path:44.16,46.3 1 0`, 123 output: []*Profile{ 124 { 125 FileName: "another/fancy/path", 126 Mode: "set", 127 Blocks: []ProfileBlock{ 128 { 129 StartLine: 47, StartCol: 2, 130 EndLine: 47, EndCol: 13, 131 NumStmt: 1, Count: 1, 132 }, 133 }, 134 }, 135 { 136 FileName: "some/fancy/path", 137 Mode: "set", 138 Blocks: []ProfileBlock{ 139 { 140 StartLine: 42, StartCol: 69, 141 EndLine: 44, EndCol: 16, 142 NumStmt: 2, Count: 1, 143 }, 144 { 145 StartLine: 44, StartCol: 16, 146 EndLine: 46, EndCol: 3, 147 NumStmt: 1, Count: 0, 148 }, 149 }, 150 }, 151 }, 152 }, 153 { 154 name: "duplicate blocks are merged correctly", 155 input: `mode: count 156 some/fancy/path:42.69,44.16 2 4 157 some/fancy/path:42.69,44.16 2 3`, 158 output: []*Profile{ 159 { 160 FileName: "some/fancy/path", 161 Mode: "count", 162 Blocks: []ProfileBlock{ 163 { 164 StartLine: 42, StartCol: 69, 165 EndLine: 44, EndCol: 16, 166 NumStmt: 2, Count: 7, 167 }, 168 }, 169 }, 170 }, 171 }, 172 { 173 name: "an invalid mode line is an error", 174 input: `mode:count`, 175 expectErr: true, 176 }, 177 { 178 name: "a missing field is an error", 179 input: `mode: count 180 some/fancy/path:42.69,44.16 2`, 181 expectErr: true, 182 }, 183 { 184 name: "a missing path field is an error", 185 input: `mode: count 186 42.69,44.16 2 3`, 187 expectErr: true, 188 }, 189 { 190 name: "a non-numeric count is an error", 191 input: `mode: count 192 42.69,44.16 2 nope`, 193 expectErr: true, 194 }, 195 { 196 name: "an empty path is an error", 197 input: `mode: count 198 :42.69,44.16 2 3`, 199 expectErr: true, 200 }, 201 { 202 name: "a negative count is an error", 203 input: `mode: count 204 some/fancy/path:42.69,44.16 2 -1`, 205 expectErr: true, 206 }, 207 } 208 209 for _, tc := range tests { 210 t.Run(tc.name, func(t *testing.T) { 211 f, err := ioutil.TempFile("", "") 212 if err != nil { 213 t.Fatalf("Failed to create a temp file: %v.", err) 214 } 215 defer func() { 216 f.Close() 217 os.Remove(f.Name()) 218 }() 219 n, err := f.WriteString(tc.input) 220 if err != nil { 221 t.Fatalf("Failed to write to temp file: %v", err) 222 } 223 if n < len(tc.input) { 224 t.Fatalf("Didn't write enough bytes to temp file (wrote %d, expected %d).", n, len(tc.input)) 225 } 226 if err := f.Sync(); err != nil { 227 t.Fatalf("Failed to sync temp file: %v", err) 228 } 229 230 result, err := ParseProfiles(f.Name()) 231 if err != nil { 232 if !tc.expectErr { 233 t.Errorf("Unexpected error: %v", err) 234 } 235 return 236 } 237 if tc.expectErr { 238 t.Errorf("Expected an error, but got value %q", stringifyProfileArray(result)) 239 } 240 if !reflect.DeepEqual(result, tc.output) { 241 t.Errorf("Mismatched results.\nExpected: %s\nActual: %s", stringifyProfileArray(tc.output), stringifyProfileArray(result)) 242 } 243 }) 244 } 245 } 246 247 func stringifyProfileArray(profiles []*Profile) string { 248 deref := make([]Profile, 0, len(profiles)) 249 for _, p := range profiles { 250 deref = append(deref, *p) 251 } 252 return fmt.Sprintf("%#v", deref) 253 } 254 255 func BenchmarkParseLine(b *testing.B) { 256 const line = "k8s.io/kubernetes/cmd/kube-controller-manager/app/options/ttlafterfinishedcontroller.go:31.73,32.14 1 1" 257 b.SetBytes(int64(len(line))) 258 for n := 0; n < b.N; n++ { 259 parseLine(line) 260 } 261 }