Skip to content

Commit 8454829

Browse files
committed
feat(model): ValidationScheme implements pflag.Value and json.Marshaler/Unmarshaler interfaces
Signed-off-by: Julius Hinze <julius.hinze@grafana.com>
1 parent 0e1982f commit 8454829

2 files changed

Lines changed: 132 additions & 8 deletions

File tree

model/metric.go

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package model
1515

1616
import (
17+
"encoding/json"
1718
"errors"
1819
"fmt"
1920
"regexp"
@@ -77,10 +78,13 @@ const (
7778
UTF8Validation
7879
)
7980

80-
var (
81-
_ yaml.Marshaler = UnsetValidation
82-
_ fmt.Stringer = UnsetValidation
83-
)
81+
var _ interface {
82+
yaml.Marshaler
83+
yaml.Unmarshaler
84+
json.Marshaler
85+
json.Unmarshaler
86+
fmt.Stringer
87+
} = new(ValidationScheme)
8488

8589
// String returns the string representation of s.
8690
func (s ValidationScheme) String() string {
@@ -114,19 +118,50 @@ func (s *ValidationScheme) UnmarshalYAML(unmarshal func(any) error) error {
114118
if err := unmarshal(&scheme); err != nil {
115119
return err
116120
}
117-
switch scheme {
121+
return s.Set(scheme)
122+
}
123+
124+
// MarshalJSON implements the json.Marshaler interface.
125+
func (s ValidationScheme) MarshalJSON() ([]byte, error) {
126+
switch s {
127+
case UnsetValidation:
128+
return json.Marshal("")
129+
case UTF8Validation, LegacyValidation:
130+
return json.Marshal(s.String())
131+
default:
132+
return nil, fmt.Errorf("unhandled ValidationScheme: %d", s)
133+
}
134+
}
135+
136+
// UnmarshalJSON implements the json.Unmarshaler interface.
137+
func (s *ValidationScheme) UnmarshalJSON(bytes []byte) error {
138+
var repr string
139+
if err := json.Unmarshal(bytes, &repr); err != nil {
140+
return err
141+
}
142+
return s.Set(repr)
143+
}
144+
145+
// Set implements the pflag.Value interface.
146+
func (s *ValidationScheme) Set(text string) error {
147+
switch text {
118148
case "":
119149
// Don't change the value.
120-
case "legacy":
150+
case LegacyValidation.String():
121151
*s = LegacyValidation
122-
case "utf8":
152+
case UTF8Validation.String():
123153
*s = UTF8Validation
124154
default:
125-
return fmt.Errorf("unrecognized ValidationScheme: %q", scheme)
155+
return fmt.Errorf("unrecognized ValidationScheme: %q", text)
126156
}
127157
return nil
128158
}
129159

160+
// Type implements the pflag.Value interface.
161+
func (s ValidationScheme) Type() string {
162+
return "validationScheme"
163+
}
164+
130165
type EscapingScheme int
131166

132167
const (

model/metric_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package model
1515

1616
import (
17+
"encoding/json"
1718
"errors"
1819
"strings"
1920
"testing"
@@ -202,6 +203,94 @@ func TestValidationScheme_UnmarshalYAML(t *testing.T) {
202203
}
203204
}
204205

206+
func TestValidationScheme_UnmarshalJSON(t *testing.T) {
207+
testCases := []struct {
208+
name string
209+
input string
210+
want ValidationScheme
211+
wantErr bool
212+
}{
213+
{
214+
name: "invalid",
215+
input: `invalid`,
216+
wantErr: true,
217+
},
218+
{
219+
name: "empty",
220+
input: `""`,
221+
want: UnsetValidation,
222+
},
223+
{
224+
name: "legacy validation",
225+
input: `"legacy"`,
226+
want: LegacyValidation,
227+
},
228+
{
229+
name: "utf8 validation",
230+
input: `"utf8"`,
231+
want: UTF8Validation,
232+
},
233+
}
234+
for _, tc := range testCases {
235+
t.Run(tc.name, func(t *testing.T) {
236+
var got ValidationScheme
237+
err := json.Unmarshal([]byte(tc.input), &got)
238+
if tc.wantErr {
239+
require.Error(t, err)
240+
return
241+
}
242+
require.NoError(t, err)
243+
require.Equal(t, tc.want, ValidationScheme(got))
244+
245+
output, err := json.Marshal(got)
246+
require.NoError(t, err)
247+
require.Equal(t, tc.input, string(output))
248+
})
249+
}
250+
}
251+
252+
func TestValidationScheme_Set(t *testing.T) {
253+
testCases := []struct {
254+
name string
255+
input string
256+
want ValidationScheme
257+
wantErr bool
258+
}{
259+
{
260+
name: "invalid",
261+
input: `invalid`,
262+
wantErr: true,
263+
},
264+
{
265+
name: "empty",
266+
input: ``,
267+
want: UnsetValidation,
268+
},
269+
{
270+
name: "legacy validation",
271+
input: `legacy`,
272+
want: LegacyValidation,
273+
},
274+
{
275+
name: "utf8 validation",
276+
input: `utf8`,
277+
want: UTF8Validation,
278+
},
279+
}
280+
for _, tc := range testCases {
281+
t.Run(tc.name, func(t *testing.T) {
282+
var got ValidationScheme
283+
err := got.Set(tc.input)
284+
if tc.wantErr {
285+
require.Error(t, err)
286+
return
287+
}
288+
require.NoError(t, err)
289+
require.Equal(t, tc.want, ValidationScheme(got))
290+
})
291+
}
292+
}
293+
205294
func TestMetricNameIsLegacyValid(t *testing.T) {
206295
scenarios := []struct {
207296
mn LabelValue

0 commit comments

Comments
 (0)