-
Notifications
You must be signed in to change notification settings - Fork 164
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create puupy struct Implement Init to initialize a puppy and assign a random id Implement String method to print a puppy struct At this point there is no check for collision ids Implement a map backed storer only at this time Implement ReadStore Error checking hasnt been implemented. At this stage nil will be returned if the item cant be found. This will be addressed in a later lab Implement DeletePuppy Fix boolean logic in ReadPuppy Implement UpdatePuppy Implement clone method on puppy Resolve problem with usage of pointers and references Separate MapStore into its own file Create a basic main_test Integrate linter feedback Rename ID to id where used as parameter Change mapstore test to use a test suite using the Storer interface Begin implementing a syncstore version of the Storer interface Implement all methids for syncstore Implement all cases for store_tests Ensure 100% test coverqge Fix linter errors Capitals and newlines in error messages Not assign table tests when ranging across them Misalignment of structs Verified lint and code cov passed Separate types into their own file
- Loading branch information
Bucknell, Andrew
committed
Jul 3, 2019
1 parent
25cd3bf
commit cca9118
Showing
7 changed files
with
338 additions
and
0 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,48 @@ | ||
package main | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
type MapStore map[uint32]*Puppy | ||
|
||
func (msp *MapStore) CreatePuppy(p *Puppy) error { | ||
if _, exist := (*msp)[p.ID]; exist { | ||
return fmt.Errorf("puppy %d already exists", p.ID) | ||
} | ||
(*msp)[p.ID] = p.Clone() | ||
return nil | ||
} | ||
|
||
func (msp *MapStore) ReadPuppy(id uint32) (*Puppy, error) { | ||
p, err := (*msp)[id] | ||
if !err { | ||
return nil, errors.New("no such puppy") | ||
} | ||
return p, nil | ||
} | ||
|
||
func (msp *MapStore) DeletePuppy(id uint32) (bool, error) { | ||
p, exist := (*msp)[id] | ||
if !exist { | ||
return false, errors.New("no such puppy") | ||
} | ||
delete(*msp, p.ID) | ||
return true, nil | ||
} | ||
|
||
func (msp *MapStore) UpdatePuppy(id uint32, puppy *Puppy) error { | ||
if puppy == nil { | ||
return fmt.Errorf("cant update to a nil puppy") | ||
} | ||
p, exist := (*msp)[id] | ||
if !exist { | ||
return errors.New("no such puppy") | ||
} | ||
if p.ID != puppy.ID { | ||
return errors.New("bad puppy") | ||
} | ||
(*msp)[id] = puppy.Clone() | ||
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,47 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"sync" | ||
) | ||
|
||
type SyncStore struct { | ||
sync.Map | ||
} | ||
|
||
func (store *SyncStore) CreatePuppy(p *Puppy) error { | ||
if _, ok := store.Load(p.ID); !ok { | ||
store.Store(p.ID, p) | ||
return nil | ||
} | ||
return fmt.Errorf("store already has a puppy with id : %d", p.ID) | ||
} | ||
|
||
func (store *SyncStore) ReadPuppy(id uint32) (*Puppy, error) { | ||
if p, ok := store.Load(id); ok { | ||
return p.(*Puppy), nil | ||
} | ||
return nil, fmt.Errorf("could not load puppy %d", id) | ||
} | ||
|
||
func (store *SyncStore) UpdatePuppy(id uint32, puppy *Puppy) error { | ||
if puppy == nil { | ||
return fmt.Errorf("cant update to a nil puppy") | ||
} | ||
if p, ok := store.Load(id); ok { | ||
if p.(*Puppy).ID == puppy.ID { | ||
store.Store(id, puppy.Clone()) | ||
return nil | ||
} | ||
return fmt.Errorf("bad puppy : %d != %d", p.(*Puppy).ID, id) | ||
} | ||
return fmt.Errorf("could not find puppy id = %d", id) | ||
} | ||
|
||
func (store *SyncStore) DeletePuppy(id uint32) (bool, error) { | ||
if _, ok := store.Load(id); ok { | ||
store.Delete(id) | ||
return true, nil | ||
} | ||
return false, fmt.Errorf("could not find puppy id = %d", id) | ||
} |
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,16 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
) | ||
|
||
var out io.Writer = os.Stdout | ||
|
||
func main() { | ||
|
||
store := new(MapStore) | ||
fmt.Fprintln(out, store) | ||
|
||
} |
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,21 @@ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"strconv" | ||
"testing" | ||
) | ||
|
||
func TestMainOutput(t *testing.T) { | ||
var buf bytes.Buffer | ||
out = &buf | ||
|
||
main() | ||
|
||
expected := strconv.Quote("&map[]\n") | ||
actual := strconv.Quote(buf.String()) | ||
|
||
if expected != actual { | ||
t.Errorf("unexpected result in main() : expected = %s, actual = %s\n", expected, actual) | ||
} | ||
} |
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,177 @@ | ||
package main | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/suite" | ||
) | ||
|
||
type storerSuite struct { | ||
suite.Suite | ||
store Storer | ||
storerType func() Storer | ||
} | ||
|
||
func TestStorers(t *testing.T) { | ||
suite.Run(t, &storerSuite{ | ||
storerType: func() Storer { return &MapStore{} }, | ||
}) | ||
suite.Run(t, &storerSuite{ | ||
storerType: func() Storer { return &SyncStore{} }, | ||
}) | ||
} | ||
|
||
func (s *storerSuite) SetupTest() { | ||
s.store = s.storerType() | ||
|
||
corgi := &Puppy{1000, "corgi", "orange and white", "$$$$$$$"} | ||
_ = s.store.CreatePuppy(corgi) | ||
spaniel := &Puppy{2000, "spaniel", "brown", "$$$$$$"} | ||
_ = s.store.CreatePuppy(spaniel) | ||
cujo := &Puppy{2500, "cujo", "tan", "$"} | ||
_ = s.store.CreatePuppy(cujo) | ||
terrier := &Puppy{3000, "terrier", "black", "$$$"} | ||
_ = s.store.CreatePuppy(terrier) | ||
bulldog := &Puppy{4000, "bulldog", "white", "$$"} | ||
_ = s.store.CreatePuppy(bulldog) | ||
} | ||
|
||
func (s *storerSuite) TestMapStore_CreatePuppy() { | ||
|
||
corgi := &Puppy{10000, "new corgi", "even brighter orange and white", "$$$$$$$"} | ||
|
||
tests := []struct { | ||
name string | ||
puppy *Puppy | ||
wantErr bool | ||
}{ | ||
{name: "New corgi", | ||
puppy: corgi, | ||
wantErr: false}, | ||
{name: "Existing corgi", | ||
puppy: corgi, | ||
wantErr: true}, | ||
} | ||
for _, tt := range tests { | ||
tt := tt | ||
s.T().Run(tt.name, func(t *testing.T) { | ||
if err := s.store.CreatePuppy(tt.puppy); (err != nil) != tt.wantErr { | ||
t.Errorf("CreatePuppy() error = %v, wantErr %v", err, tt.wantErr) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func (s *storerSuite) TestMapStore_ReadPuppy() { | ||
|
||
corgi := &Puppy{1000, "corgi", "orange and white", "$$$$$$$"} | ||
_ = s.store.CreatePuppy(corgi) | ||
|
||
tests := []struct { | ||
name string | ||
id uint32 | ||
wantErr bool | ||
want *Puppy | ||
}{ | ||
{name: "lookup existing puppy", | ||
id: 1000, | ||
want: corgi, | ||
wantErr: false, | ||
}, | ||
{name: "lookup non-existing puppy", | ||
id: 1001, | ||
want: nil, | ||
wantErr: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
tt := tt | ||
s.T().Run(tt.name, func(t *testing.T) { | ||
got, err := s.store.ReadPuppy(tt.id) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("ReadPuppy() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if !reflect.DeepEqual(got, tt.want) { | ||
t.Errorf("ReadPuppy() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func (s *storerSuite) TestMapStore_DeletePuppy() { | ||
tests := []struct { | ||
name string | ||
id uint32 | ||
want bool | ||
wantErr bool | ||
}{ | ||
{name: "delete existing corgi", | ||
id: 1000, | ||
want: true, | ||
wantErr: false, | ||
}, | ||
{name: "delete non-existent corgi", | ||
id: 1000, | ||
want: false, | ||
wantErr: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
tt := tt | ||
s.T().Run(tt.name, func(t *testing.T) { | ||
got, err := s.store.DeletePuppy(tt.id) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("DeletePuppy() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if got != tt.want { | ||
t.Errorf("DeletePuppy() = %v, want %v", got, tt.want) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func (s *storerSuite) TestMapStore_UpdatePuppy() { | ||
albinoCorgi := &Puppy{1000, "corgi", "white", "$$$$$$$"} | ||
corruptCorgi := &Puppy{1009, "corgi", "white", "$$$$$$$"} | ||
// _ = s.store.CreatePuppy(albinoCorgi) | ||
|
||
tests := []struct { | ||
name string | ||
id uint32 | ||
wantErr bool | ||
puppy *Puppy | ||
}{ | ||
{name: "update existing puppy", | ||
id: 1000, | ||
puppy: albinoCorgi, | ||
wantErr: false, | ||
}, | ||
{name: "update non-existing puppy", | ||
id: 1001, | ||
puppy: albinoCorgi, | ||
wantErr: true, | ||
}, | ||
{name: "update with an empty puppy", | ||
id: 1000, | ||
puppy: nil, | ||
wantErr: true, | ||
}, | ||
{name: "update with a corrupt puppy", | ||
id: 1000, | ||
puppy: corruptCorgi, | ||
wantErr: true, | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
tt := tt | ||
s.T().Run(tt.name, func(t *testing.T) { | ||
if err := s.store.UpdatePuppy(tt.id, tt.puppy); (err != nil) != tt.wantErr { | ||
t.Errorf("UpdatePuppy() error = %v, wantErr %v", err, tt.wantErr) | ||
} | ||
}) | ||
} | ||
} |
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,28 @@ | ||
package main | ||
|
||
import( | ||
|
||
) | ||
|
||
type Puppy struct { | ||
ID uint32 `json:"ID"` | ||
Breed string `json:"breed"` | ||
Colour string `json:"colour"` | ||
Value string `json:"value"` | ||
} | ||
|
||
func (p *Puppy) Clone() *Puppy { | ||
puppy := new(Puppy) | ||
puppy.ID = p.ID | ||
puppy.Breed = p.Breed | ||
puppy.Colour = p.Colour | ||
puppy.Value = p.Value | ||
return puppy | ||
} | ||
|
||
type Storer interface { | ||
CreatePuppy(*Puppy) error | ||
ReadPuppy(id uint32) (*Puppy, error) | ||
UpdatePuppy(id uint32, puppy *Puppy) error | ||
DeletePuppy(id uint32) (bool, error) | ||
} |