Skip to content

Commit

Permalink
Use json.Marshaler over TextMarshaler if it's present (#8)
Browse files Browse the repository at this point in the history
## Summary

<!-- Describe your changes in detail here, if it closes an open issue,
include "Closes #<issue>" -->
  • Loading branch information
FollowTheProcess authored Nov 19, 2024
1 parent 57de294 commit 3622259
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 2 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ The files will be named automatically after the test:
Because of this, it needs to know how to serialise your value (which could be basically any valid construct in Go) to plain text, so we follow a few basic rules in priority order:

- **`snapshot.Snapper`:** If your type implements the `Snapper` interface, this is preferred over all other potential serialisation, this allows you to have total control over how your type is snapshotted, do whatever you like in the `Snap` method, just return a `[]byte` that you'd like to look at in the snapshot and thats it!
- **[json.Marshaler]:** If your type implements [json.Marshaler], this will be used and the snapshot will be a valid JSON file
- **[encoding.TextMarshaler]:** If your type implements [encoding.TextMarshaler], this will be used to render your value to the snapshot
- **[fmt.Stringer]:** If your type implements the [fmt.Stringer] interface, this is then used instead
- **Primitive Types:** Any primitive type in Go (`bool`, `int`, `string` etc.) is serialised according to the `%v` verb in the [fmt] package
Expand All @@ -155,5 +156,6 @@ This package was created with [copier] and the [FollowTheProcess/go_copier] proj
[copier]: https://copier.readthedocs.io/en/stable/
[FollowTheProcess/go_copier]: https://github.com/FollowTheProcess/go_copier
[fmt]: https://pkg.go.dev/fmt
[json.Marshaler]: https://pkg.go.dev/encoding/json#Marshaler
[encoding.TextMarshaler]: https://pkg.go.dev/encoding#TextMarshaler
[fmt.Stringer]: https://pkg.go.dev/fmt#Stringer
8 changes: 8 additions & 0 deletions snapshot.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package snapshot
import (
"bytes"
"encoding"
"encoding/json"
"errors"
"fmt"
"io/fs"
Expand Down Expand Up @@ -75,6 +76,13 @@ func (s *Shotter) Snap(value any) {
return
}
current.Write(content)
case json.Marshaler:
content, err := val.MarshalJSON()
if err != nil {
s.tb.Fatalf("%T implements json.Marshaler but MarshalJSON() returned an error: %v", val, err)
return
}
current.Write(content)
case encoding.TextMarshaler:
content, err := val.MarshalText()
if err != nil {
Expand Down
29 changes: 27 additions & 2 deletions snapshot_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,14 @@ func (e explosion) Snap() ([]byte, error) {
// nosnap has no Snap implementation.
type nosnap struct{}

// textMarshaler is a struct that implements encoding.TextMarshaller.
// textMarshaler is a struct that implements encoding.TextMarshaler.
type textMarshaler struct{}

func (t textMarshaler) MarshalText() (text []byte, err error) {
return []byte("MarshalText() called\n"), nil
}

// errMarshaler is a struct that implements encoding.TextMarshaller, but always returns an error.
// errMarshaler is a struct that implements encoding.TextMarshaler, but always returns an error.
type errMarshaler struct{}

func (t errMarshaler) MarshalText() (text []byte, err error) {
Expand All @@ -88,6 +88,20 @@ func (s stringer) String() string {
return "String() called\n"
}

// jsonMarshaler is a struct that implements json.Marshaler.
type jsonMarshaler struct{}

func (j jsonMarshaler) MarshalJSON() ([]byte, error) {
return []byte(`{"key": "value"}`), nil
}

// errJSONMarshaler is a struct that implements json.Marshaler, but always returns an error.
type errJSONMarshaler struct{}

func (e errJSONMarshaler) MarshalJSON() ([]byte, error) {
return nil, errors.New("MarshalJSON error")
}

func TestSnap(t *testing.T) {
tests := []struct {
value any // Value to snap
Expand Down Expand Up @@ -165,6 +179,17 @@ func TestSnap(t *testing.T) {
wantFail: false,
existingSnap: "String() called\n",
},
{
name: "json marshaler",
value: jsonMarshaler{},
wantFail: false,
existingSnap: `{"key": "value"}`,
},
{
name: "json marshaler error",
value: errJSONMarshaler{},
wantFail: true,
},
}

for _, tt := range tests {
Expand Down
1 change: 1 addition & 0 deletions testdata/snapshots/TestSnap/json_marshaler.snap.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"key": "value"}

0 comments on commit 3622259

Please sign in to comment.