-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Snapshots allow for storing and retreiving of commits. This is a preliminary stage to allow for saving incomplete or failed commits. The author field uses the repository user. Adding tags was necessary to allow empty authors to be omitted from the snapshot file.
- Loading branch information
1 parent
d392cd9
commit 00f37de
Showing
3 changed files
with
268 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package snapshot | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"io" | ||
|
||
"github.com/mikelorant/committed/internal/repository" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
type Snapshot struct { | ||
Emoji string `yaml:"emoji,omitempty"` | ||
Summary string `yaml:"summary,omitempty"` | ||
Body string `yaml:"body,omitempty"` | ||
Footer string `yaml:"footer,omitempty"` | ||
Author repository.User `yaml:"author,omitempty"` | ||
Amend bool `yaml:"amend,omitempty"` | ||
} | ||
|
||
var ( | ||
errReader = errors.New("empty reader") | ||
errWriter = errors.New("empty writer") | ||
) | ||
|
||
func (s *Snapshot) Load(fh io.Reader) (Snapshot, error) { | ||
var snap Snapshot | ||
|
||
if fh == nil { | ||
return snap, errReader | ||
} | ||
|
||
err := yaml.NewDecoder(fh).Decode(&snap) | ||
switch { | ||
case err == nil: | ||
case errors.Is(err, io.EOF): | ||
default: | ||
return snap, fmt.Errorf("unable to decode snapshot: %w", err) | ||
} | ||
|
||
return snap, nil | ||
} | ||
|
||
func (s *Snapshot) Save(fh io.WriteCloser, snap Snapshot) error { | ||
if fh == nil { | ||
return errWriter | ||
} | ||
|
||
err := yaml.NewEncoder(fh).Encode(&snap) | ||
if err != nil { | ||
return fmt.Errorf("unable to encode snapshot: %w", err) | ||
} | ||
defer fh.Close() | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
package snapshot_test | ||
|
||
import ( | ||
"bytes" | ||
"errors" | ||
"io" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/MakeNowJust/heredoc/v2" | ||
"github.com/mikelorant/committed/internal/repository" | ||
"github.com/mikelorant/committed/internal/snapshot" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
type readWriteCloser struct { | ||
bytes.Buffer | ||
} | ||
|
||
func (wc *readWriteCloser) Close() error { | ||
return nil | ||
} | ||
|
||
type errorReadWriteCloser struct { | ||
readWriteCloser | ||
} | ||
|
||
func (t *errorReadWriteCloser) Write(p []byte) (n int, err error) { | ||
return 0, errMock | ||
} | ||
|
||
var errMock = errors.New("error") | ||
|
||
func TestLoad(t *testing.T) { | ||
type args struct { | ||
reader io.Reader | ||
} | ||
type want struct { | ||
snapshot snapshot.Snapshot | ||
err string | ||
} | ||
|
||
tests := []struct { | ||
name string | ||
args args | ||
want want | ||
}{ | ||
{ | ||
name: "data", | ||
args: args{ | ||
reader: strings.NewReader(heredoc.Doc(` | ||
emoji: ":art:" | ||
summary: summary | ||
body: body | ||
footer: footer | ||
author: | ||
name: John Doe | ||
email: [email protected] | ||
amend: true | ||
`)), | ||
}, | ||
want: want{ | ||
snapshot: snapshot.Snapshot{ | ||
Emoji: ":art:", | ||
Summary: "summary", | ||
Body: "body", | ||
Footer: "footer", | ||
Author: repository.User{ | ||
Name: "John Doe", | ||
Email: "[email protected]", | ||
}, | ||
Amend: true, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "empty", | ||
args: args{ | ||
reader: strings.NewReader(""), | ||
}, | ||
}, | ||
{ | ||
name: "error_reader", | ||
want: want{ | ||
err: "empty reader", | ||
}, | ||
}, | ||
{ | ||
name: "error_eof", | ||
args: args{ | ||
reader: io.LimitReader(strings.NewReader("summary: summary"), 0), | ||
}, | ||
}, | ||
{ | ||
name: "error_decode", | ||
args: args{ | ||
reader: io.LimitReader(strings.NewReader("summary: summary"), 1), | ||
}, | ||
want: want{ | ||
err: "unable to decode snapshot", | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
var s snapshot.Snapshot | ||
|
||
snap, err := s.Load(tt.args.reader) | ||
|
||
if tt.want.err != "" { | ||
assert.Error(t, err) | ||
assert.ErrorContains(t, err, tt.want.err) | ||
return | ||
} | ||
assert.NoError(t, err) | ||
assert.Equal(t, tt.want.snapshot, snap) | ||
}) | ||
} | ||
} | ||
|
||
func TestSave(t *testing.T) { | ||
type args struct { | ||
writer io.ReadWriteCloser | ||
snapshot snapshot.Snapshot | ||
} | ||
|
||
type want struct { | ||
data string | ||
err string | ||
} | ||
|
||
tests := []struct { | ||
name string | ||
args args | ||
want want | ||
}{ | ||
{ | ||
name: "data", | ||
args: args{ | ||
writer: new(readWriteCloser), | ||
snapshot: snapshot.Snapshot{ | ||
Emoji: ":art:", | ||
Summary: "summary", | ||
Body: "body", | ||
Footer: "footer", | ||
Author: repository.User{ | ||
Name: "John Doe", | ||
Email: "[email protected]", | ||
}, | ||
Amend: true, | ||
}, | ||
}, | ||
want: want{ | ||
data: heredoc.Doc(` | ||
emoji: ':art:' | ||
summary: summary | ||
body: body | ||
footer: footer | ||
author: | ||
name: John Doe | ||
email: [email protected] | ||
amend: true | ||
`), | ||
}, | ||
}, | ||
{ | ||
name: "empty", | ||
args: args{ | ||
writer: new(readWriteCloser), | ||
}, | ||
want: want{ | ||
data: "{}\n", | ||
}, | ||
}, | ||
{ | ||
name: "error_encode", | ||
args: args{ | ||
writer: new(errorReadWriteCloser), | ||
}, | ||
want: want{ | ||
err: "unable to encode snapshot", | ||
}, | ||
}, | ||
{ | ||
name: "error_writer", | ||
want: want{ | ||
err: "empty writer", | ||
}, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
var s snapshot.Snapshot | ||
|
||
err := s.Save(tt.args.writer, tt.args.snapshot) | ||
if tt.want.err != "" { | ||
assert.Error(t, err) | ||
assert.ErrorContains(t, err, tt.want.err) | ||
return | ||
} | ||
assert.NoError(t, err) | ||
|
||
got, _ := io.ReadAll(tt.args.writer) | ||
assert.Equal(t, tt.want.data, string(got)) | ||
}) | ||
} | ||
} |