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.
12 "golang.org/x/tools/go/packages/packagestest"
15 type Normalizer struct {
22 func CollectNormalizers(exported *packagestest.Exported) []Normalizer {
23 // build the path normalizing patterns
24 var normalizers []Normalizer
25 for _, m := range exported.Modules {
26 for fragment := range m.Files {
28 path: exported.File(m.Name, fragment),
31 if n.slashed = filepath.ToSlash(n.path); n.slashed == n.path {
34 quoted := strconv.Quote(n.path)
35 if n.escaped = quoted[1 : len(quoted)-1]; n.escaped == n.path {
38 normalizers = append(normalizers, n)
44 // NormalizePrefix normalizes a single path at the front of the input string.
45 func NormalizePrefix(s string, normalizers []Normalizer) string {
46 for _, n := range normalizers {
47 if t := strings.TrimPrefix(s, n.path); t != s {
50 if t := strings.TrimPrefix(s, n.slashed); t != s {
53 if t := strings.TrimPrefix(s, n.escaped); t != s {
60 // Normalize replaces all paths present in s with just the fragment portion
61 // this is used to make golden files not depend on the temporary paths of the files
62 func Normalize(s string, normalizers []Normalizer) string {
69 // collect the initial state of all the matchers
70 for _, n := range normalizers {
71 index := strings.Index(s, n.path)
73 match = append(match, entry{n.path, index, n.fragment})
76 index := strings.Index(s, n.slashed)
78 match = append(match, entry{n.slashed, index, n.fragment})
82 index := strings.Index(s, n.escaped)
84 match = append(match, entry{n.escaped, index, n.fragment})
88 // result should be the same or shorter than the input
92 // find the nearest path match to the start of the buffer
95 for i, c := range match {
96 if c.index >= 0 && nearest > c.index {
101 // if there are no matches, we copy the rest of the string and are done
103 b.WriteString(s[last:])
108 // copy up to the start of the match
109 b.WriteString(s[last:n.index])
110 // skip over the filename
111 last = n.index + len(n.path)
113 // Hack: In multi-module mode, we add a "testmodule/" prefix, so trim
114 // it from the fragment.
115 fragment := n.fragment
116 if strings.HasPrefix(fragment, "testmodule") {
117 split := strings.Split(filepath.ToSlash(fragment), "/")
118 fragment = filepath.FromSlash(strings.Join(split[1:], "/"))
121 // add in the fragment instead
122 b.WriteString(fragment)
123 // see what the next match for this path is
124 n.index = strings.Index(s[last:], n.path)