Fix escaping for `Matcher.String()`

Now the string created will correctly parse back.

Signed-off-by: beorn7 <beorn@grafana.com>
This commit is contained in:
beorn7 2021-01-13 13:21:30 +01:00
parent f7742393ae
commit e1ab2477c0
2 changed files with 84 additions and 1 deletions

View File

@ -16,6 +16,7 @@ package labels
import ( import (
"fmt" "fmt"
"regexp" "regexp"
"strings"
) )
// MatchType is an enum for label matching types. // MatchType is an enum for label matching types.
@ -69,7 +70,7 @@ func NewMatcher(t MatchType, n, v string) (*Matcher, error) {
} }
func (m *Matcher) String() string { func (m *Matcher) String() string {
return fmt.Sprintf("%s%s%q", m.Name, m.Type, m.Value) return fmt.Sprintf(`%s%s"%s"`, m.Name, m.Type, openMetricsEscape(m.Value))
} }
// Matches returns whether the matcher matches the given string value. // Matches returns whether the matcher matches the given string value.
@ -86,3 +87,16 @@ func (m *Matcher) Matches(s string) bool {
} }
panic("labels.Matcher.Matches: invalid match type") panic("labels.Matcher.Matches: invalid match type")
} }
// openMetricsEscape is similar to the usual string escaping, but more
// restricted. It merely replaces a new-line character with '\n', a double-quote
// character with '\"', and a backslack with '\\', which is the escaping used by
// OpenMetrics.
func openMetricsEscape(s string) string {
r := strings.NewReplacer(
`\`, `\\`,
"\n", `\n`,
`"`, `\"`,
)
return r.Replace(s)
}

View File

@ -122,3 +122,72 @@ func TestMatcher(t *testing.T) {
} }
} }
} }
func TestMatcherString(t *testing.T) {
tests := []struct {
name string
op MatchType
value string
want string
}{
{
name: `foo`,
op: MatchEqual,
value: `bar`,
want: `foo="bar"`,
},
{
name: `foo`,
op: MatchNotEqual,
value: `bar`,
want: `foo!="bar"`,
},
{
name: `foo`,
op: MatchRegexp,
value: `bar`,
want: `foo=~"bar"`,
},
{
name: `foo`,
op: MatchNotRegexp,
value: `bar`,
want: `foo!~"bar"`,
},
{
name: `foo`,
op: MatchEqual,
value: `back\slash`,
want: `foo="back\\slash"`,
},
{
name: `foo`,
op: MatchEqual,
value: `double"quote`,
want: `foo="double\"quote"`,
},
{
name: `foo`,
op: MatchEqual,
value: `new
line`,
want: `foo="new\nline"`,
},
{
name: `foo`,
op: MatchEqual,
value: `tab stop`,
want: `foo="tab stop"`,
},
}
for _, test := range tests {
m, err := NewMatcher(test.op, test.name, test.value)
if err != nil {
t.Fatal(err)
}
if got := m.String(); got != test.want {
t.Errorf("Unexpected string representation of matcher; want %v, got %v", test.want, got)
}
}
}