Codebase list golang-github-spf13-viper / a00caae
feat(encoding): Encoder/Decoder registry implementations Mark Sagi-Kazar authored 4 years ago Márk Sági-Kazár committed 2 years ago
5 changed file(s) with 275 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 package encoding
1
2 import (
3 "sync"
4 )
5
6 // Decoder decodes the contents of b into a v representation.
7 // It's primarily used for decoding contents of a file into a map[string]interface{}.
8 type Decoder interface {
9 Decode(b []byte, v interface{}) error
10 }
11
12 const (
13 // ErrDecoderNotFound is returned when there is no decoder registered for a format.
14 ErrDecoderNotFound = encodingError("decoder not found for this format")
15
16 // ErrDecoderFormatAlreadyRegistered is returned when an decoder is already registered for a format.
17 ErrDecoderFormatAlreadyRegistered = encodingError("decoder already registered for this format")
18 )
19
20 // DecoderRegistry can choose an appropriate Decoder based on the provided format.
21 type DecoderRegistry struct {
22 decoders map[string]Decoder
23
24 mu sync.RWMutex
25 }
26
27 // NewDecoderRegistry returns a new, initialized DecoderRegistry.
28 func NewDecoderRegistry() *DecoderRegistry {
29 return &DecoderRegistry{
30 decoders: make(map[string]Decoder),
31 }
32 }
33
34 // RegisterDecoder registers a Decoder for a format.
35 // Registering a Decoder for an already existing format is not supported.
36 func (e *DecoderRegistry) RegisterDecoder(format string, enc Decoder) error {
37 e.mu.Lock()
38 defer e.mu.Unlock()
39
40 if _, ok := e.decoders[format]; ok {
41 return ErrDecoderFormatAlreadyRegistered
42 }
43
44 e.decoders[format] = enc
45
46 return nil
47 }
48
49 // Decode calls the underlying Decoder based on the format.
50 func (e *DecoderRegistry) Decode(format string, b []byte, v interface{}) error {
51 e.mu.RLock()
52 decoder, ok := e.decoders[format]
53 e.mu.RUnlock()
54
55 if !ok {
56 return ErrDecoderNotFound
57 }
58
59 return decoder.Decode(b, v)
60 }
0 package encoding
1
2 import (
3 "testing"
4 )
5
6 type decoder struct {
7 v interface{}
8 }
9
10 func (d decoder) Decode(_ []byte, v interface{}) error {
11 rv := v.(*string)
12 *rv = d.v.(string)
13
14 return nil
15 }
16
17 func TestDecoderRegistry_RegisterDecoder(t *testing.T) {
18 t.Run("OK", func(t *testing.T) {
19 registry := NewDecoderRegistry()
20
21 err := registry.RegisterDecoder("myformat", decoder{})
22 if err != nil {
23 t.Fatal(err)
24 }
25 })
26
27 t.Run("AlreadyRegistered", func(t *testing.T) {
28 registry := NewDecoderRegistry()
29
30 err := registry.RegisterDecoder("myformat", decoder{})
31 if err != nil {
32 t.Fatal(err)
33 }
34
35 err = registry.RegisterDecoder("myformat", decoder{})
36 if err != ErrDecoderFormatAlreadyRegistered {
37 t.Fatalf("expected ErrDecoderFormatAlreadyRegistered, got: %v", err)
38 }
39 })
40 }
41
42 func TestDecoderRegistry_Decode(t *testing.T) {
43 t.Run("OK", func(t *testing.T) {
44 registry := NewDecoderRegistry()
45 decoder := decoder{
46 v: "decoded value",
47 }
48
49 err := registry.RegisterDecoder("myformat", decoder)
50 if err != nil {
51 t.Fatal(err)
52 }
53
54 var v string
55
56 err = registry.Decode("myformat", []byte("some value"), &v)
57 if err != nil {
58 t.Fatal(err)
59 }
60
61 if v != "decoded value" {
62 t.Fatalf("expected 'decoded value', got: %#v", v)
63 }
64 })
65
66 t.Run("DecoderNotFound", func(t *testing.T) {
67 registry := NewDecoderRegistry()
68
69 var v string
70
71 err := registry.Decode("myformat", []byte("some value"), &v)
72 if err != ErrDecoderNotFound {
73 t.Fatalf("expected ErrDecoderNotFound, got: %v", err)
74 }
75 })
76 }
0 package encoding
1
2 import (
3 "sync"
4 )
5
6 // Encoder encodes the contents of v into a byte representation.
7 // It's primarily used for encoding a map[string]interface{} into a file format.
8 type Encoder interface {
9 Encode(v interface{}) ([]byte, error)
10 }
11
12 const (
13 // ErrEncoderNotFound is returned when there is no encoder registered for a format.
14 ErrEncoderNotFound = encodingError("encoder not found for this format")
15
16 // ErrEncoderFormatAlreadyRegistered is returned when an encoder is already registered for a format.
17 ErrEncoderFormatAlreadyRegistered = encodingError("encoder already registered for this format")
18 )
19
20 // EncoderRegistry can choose an appropriate Encoder based on the provided format.
21 type EncoderRegistry struct {
22 encoders map[string]Encoder
23
24 mu sync.RWMutex
25 }
26
27 // NewEncoderRegistry returns a new, initialized EncoderRegistry.
28 func NewEncoderRegistry() *EncoderRegistry {
29 return &EncoderRegistry{
30 encoders: make(map[string]Encoder),
31 }
32 }
33
34 // RegisterEncoder registers an Encoder for a format.
35 // Registering a Encoder for an already existing format is not supported.
36 func (e *EncoderRegistry) RegisterEncoder(format string, enc Encoder) error {
37 e.mu.Lock()
38 defer e.mu.Unlock()
39
40 if _, ok := e.encoders[format]; ok {
41 return ErrEncoderFormatAlreadyRegistered
42 }
43
44 e.encoders[format] = enc
45
46 return nil
47 }
48
49 func (e *EncoderRegistry) Encode(format string, v interface{}) ([]byte, error) {
50 e.mu.RLock()
51 encoder, ok := e.encoders[format]
52 e.mu.RUnlock()
53
54 if !ok {
55 return nil, ErrEncoderNotFound
56 }
57
58 return encoder.Encode(v)
59 }
0 package encoding
1
2 import (
3 "testing"
4 )
5
6 type encoder struct {
7 b []byte
8 }
9
10 func (e encoder) Encode(_ interface{}) ([]byte, error) {
11 return e.b, nil
12 }
13
14 func TestEncoderRegistry_RegisterEncoder(t *testing.T) {
15 t.Run("OK", func(t *testing.T) {
16 registry := NewEncoderRegistry()
17
18 err := registry.RegisterEncoder("myformat", encoder{})
19 if err != nil {
20 t.Fatal(err)
21 }
22 })
23
24 t.Run("AlreadyRegistered", func(t *testing.T) {
25 registry := NewEncoderRegistry()
26
27 err := registry.RegisterEncoder("myformat", encoder{})
28 if err != nil {
29 t.Fatal(err)
30 }
31
32 err = registry.RegisterEncoder("myformat", encoder{})
33 if err != ErrEncoderFormatAlreadyRegistered {
34 t.Fatalf("expected ErrEncoderFormatAlreadyRegistered, got: %v", err)
35 }
36 })
37 }
38
39 func TestEncoderRegistry_Decode(t *testing.T) {
40 t.Run("OK", func(t *testing.T) {
41 registry := NewEncoderRegistry()
42 encoder := encoder{
43 b: []byte("encoded value"),
44 }
45
46 err := registry.RegisterEncoder("myformat", encoder)
47 if err != nil {
48 t.Fatal(err)
49 }
50
51 b, err := registry.Encode("myformat", "some value")
52 if err != nil {
53 t.Fatal(err)
54 }
55
56 if string(b) != "encoded value" {
57 t.Fatalf("expected 'encoded value', got: %#v", string(b))
58 }
59 })
60
61 t.Run("EncoderNotFound", func(t *testing.T) {
62 registry := NewEncoderRegistry()
63
64 _, err := registry.Encode("myformat", "some value")
65 if err != ErrEncoderNotFound {
66 t.Fatalf("expected ErrEncoderNotFound, got: %v", err)
67 }
68 })
69 }
0 package encoding
1
2 type encodingError string
3
4 func (e encodingError) Error() string {
5 return string(e)
6 }