Skip to content

Commit d558d08

Browse files
committedAug 20, 2019
Copy from upstream/07_errors/patrickmarabeas
Lab 08 (anz-bank#592)
1 parent a0f8dbd commit d558d08

File tree

8 files changed

+355
-0
lines changed

8 files changed

+355
-0
lines changed
 

‎08_project/patrickmarabeas/errors.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package main
2+
3+
import "fmt"
4+
5+
type ErrorCode int
6+
7+
type Error struct {
8+
Code ErrorCode
9+
Message string
10+
}
11+
12+
const (
13+
NegativeValue ErrorCode = iota + 1001
14+
IDNotFound
15+
Unknown = 1999
16+
)
17+
18+
func (e *Error) Error() string {
19+
return fmt.Sprintf("[%d] %s", e.Code, e.Message)
20+
}
21+
22+
// NewError creates a new error with the given enum
23+
func NewError(code ErrorCode) error {
24+
switch code {
25+
case NegativeValue:
26+
return &Error{code, "Puppy value must be greater than 0"}
27+
case IDNotFound:
28+
return &Error{code, "Nonexistent Puppy ID"}
29+
default:
30+
return &Error{Unknown, "Unknown error"}
31+
}
32+
}
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestUnknownError(t *testing.T) {
10+
a := assert.New(t)
11+
12+
error := NewError(123)
13+
a.Equal(error, NewError(Unknown))
14+
}
15+
16+
func TestError(t *testing.T) {
17+
a := assert.New(t)
18+
19+
error := Error{1, "message"}
20+
formattedError := error.Error()
21+
a.Equal(formattedError, "[1] message")
22+
}

‎08_project/patrickmarabeas/main.go

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"os"
7+
)
8+
9+
var out io.Writer = os.Stdout
10+
11+
func main() {
12+
fmt.Fprint(out, "hello")
13+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"testing"
6+
)
7+
8+
func TestMainOutput(t *testing.T) {
9+
var buf bytes.Buffer
10+
out = &buf
11+
12+
main()
13+
14+
expected := "hello"
15+
16+
got := buf.String()
17+
18+
if expected != got {
19+
t.Errorf("\nExpected: %s\nGot: %s", expected, got)
20+
}
21+
}
+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package main
2+
3+
// NewMapStore returns a pointer to a new instance of the MapStore struct which implements the Storer interface.
4+
func NewMapStore() Storer {
5+
return &MapStore{
6+
uuid: 0,
7+
store: map[int]Puppy{},
8+
}
9+
}
10+
11+
// Create increments the uuid and adds the provided Puppy struct to the store with this identifier.
12+
func (store *MapStore) Create(puppy Puppy) (int, error) {
13+
if puppy.Value < 0 {
14+
return -1, NewError(NegativeValue)
15+
}
16+
17+
puppy.ID = store.uuid
18+
store.store[puppy.ID] = puppy
19+
store.uuid++
20+
21+
return puppy.ID, nil
22+
}
23+
24+
// Read returns the puppy matching the provided uuid.
25+
// An empty Puppy struct is returned if the identifier does not exist.
26+
func (store *MapStore) Read(id int) (Puppy, error) {
27+
if _, ok := store.store[id]; ok {
28+
return store.store[id], nil
29+
}
30+
31+
return Puppy{}, NewError(IDNotFound)
32+
}
33+
34+
// Update modifies the puppy matching the provided uuid in the store with the provided Puppy struct.
35+
// It returns a bool whether a matching identifier was modified or not.
36+
func (store *MapStore) Update(id int, puppy Puppy) (bool, error) {
37+
if _, ok := store.store[id]; !ok {
38+
return false, NewError(IDNotFound)
39+
}
40+
if puppy.Value < 0 {
41+
return false, NewError(NegativeValue)
42+
}
43+
44+
puppy.ID = id
45+
store.store[id] = puppy
46+
return true, nil
47+
}
48+
49+
// Destroy removes the puppy matching the provided uuid from the store.
50+
// It returns a bool whether a matching identifier was deleted or not.
51+
func (store *MapStore) Destroy(id int) (bool, error) {
52+
if _, ok := store.store[id]; !ok {
53+
return false, NewError(IDNotFound)
54+
}
55+
56+
delete(store.store, id)
57+
return true, nil
58+
}
+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package main
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
"github.com/stretchr/testify/suite"
8+
)
9+
10+
type StoreSuite struct {
11+
suite.Suite
12+
store Storer
13+
}
14+
15+
func (suite *StoreSuite) TestCreate() {
16+
a := assert.New(suite.T())
17+
18+
id, error := suite.store.Create(Puppy{Breed: "Wolf", Color: "Grey", Value: 450})
19+
a.Equal(id, 0)
20+
a.Equal(error, nil)
21+
}
22+
23+
func (suite *StoreSuite) TestCreateSecond() {
24+
a := assert.New(suite.T())
25+
26+
id, error := suite.store.Create(Puppy{Breed: "Boxer", Color: "Brown", Value: 300})
27+
a.Equal(id, 1)
28+
a.Equal(error, nil)
29+
}
30+
31+
func (suite *StoreSuite) TestCreateNegativeNumber() {
32+
a := assert.New(suite.T())
33+
34+
id, error := suite.store.Create(Puppy{Breed: "Wolf", Color: "Grey", Value: -100})
35+
a.Equal(id, -1)
36+
a.Equal(error, NewError(NegativeValue))
37+
}
38+
39+
func (suite *StoreSuite) TestRead() {
40+
a := assert.New(suite.T())
41+
42+
data, error := suite.store.Read(0)
43+
a.Equal(data, Puppy{ID: 0, Breed: "Wolf", Color: "Grey", Value: 450})
44+
a.Equal(error, nil)
45+
}
46+
47+
func (suite *StoreSuite) TestReadNonExistent() {
48+
a := assert.New(suite.T())
49+
50+
success, error := suite.store.Read(100)
51+
a.Equal(success, Puppy{})
52+
a.Equal(error, NewError(IDNotFound))
53+
}
54+
55+
func (suite *StoreSuite) TestUpdate() {
56+
a := assert.New(suite.T())
57+
58+
success, error := suite.store.Update(0, Puppy{Breed: "Doberman", Color: "Black", Value: 500})
59+
a.Equal(success, true)
60+
a.Equal(error, nil)
61+
62+
data, error := suite.store.Read(0)
63+
a.Equal(data, Puppy{ID: 0, Breed: "Doberman", Color: "Black", Value: 500})
64+
a.Equal(error, nil)
65+
}
66+
67+
func (suite *StoreSuite) TestUpdateNonExistent() {
68+
a := assert.New(suite.T())
69+
70+
success, error := suite.store.Update(100, Puppy{Breed: "Doberman", Color: "Black", Value: 500})
71+
a.Equal(success, false)
72+
a.Equal(error, NewError(IDNotFound))
73+
}
74+
75+
func (suite *StoreSuite) TestUpdateNegativeNumber() {
76+
a := assert.New(suite.T())
77+
78+
success, error := suite.store.Update(0, Puppy{Breed: "Doberman", Color: "Black", Value: -500})
79+
a.Equal(success, false)
80+
a.Equal(error, NewError(NegativeValue))
81+
}
82+
83+
func (suite *StoreSuite) TestDestroy() {
84+
a := assert.New(suite.T())
85+
86+
success, error := suite.store.Destroy(1)
87+
a.Equal(success, true)
88+
a.Equal(error, nil)
89+
90+
data, error := suite.store.Read(1)
91+
a.Equal(data, Puppy{})
92+
a.Equal(error, NewError(IDNotFound))
93+
}
94+
95+
func (suite *StoreSuite) TestDestroyNonExistent() {
96+
a := assert.New(suite.T())
97+
98+
success, error := suite.store.Destroy(100)
99+
a.Equal(success, false)
100+
a.Equal(error, NewError(IDNotFound))
101+
}
102+
103+
func (suite *StoreSuite) TestIdIncrementOnDelete() {
104+
a := assert.New(suite.T())
105+
id, _ := suite.store.Create(Puppy{Breed: "Greyhound", Color: "Light Brown", Value: 700})
106+
success, _ := suite.store.Destroy(id)
107+
a.Equal(success, true)
108+
109+
newID, _ := suite.store.Create(Puppy{Breed: "Greyhound", Color: "Light Brown", Value: 700})
110+
a.Equal(newID, 3)
111+
}
112+
113+
func TestStore(t *testing.T) {
114+
suite.Run(t, &StoreSuite{store: NewMapStore()})
115+
suite.Run(t, &StoreSuite{store: NewSyncStore()})
116+
}
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package main
2+
3+
// NewSyncStore returns a pointer to a new instance of the SyncStore struct which implements the Storer interface.
4+
func NewSyncStore() Storer {
5+
return &SyncStore{
6+
uuid: 0,
7+
}
8+
}
9+
10+
// Create increments the uuid and adds the provided Puppy struct to the store with this identifier.
11+
func (store *SyncStore) Create(puppy Puppy) (int, error) {
12+
if puppy.Value < 0 {
13+
return -1, NewError(NegativeValue)
14+
}
15+
16+
store.Lock()
17+
puppy.ID = store.uuid
18+
store.Store(puppy.ID, puppy)
19+
store.uuid++
20+
store.Unlock()
21+
22+
return puppy.ID, nil
23+
}
24+
25+
// Read returns the puppy matching the provided uuid.
26+
// An empty Puppy struct is returned if the identifier does not exist.
27+
func (store *SyncStore) Read(id int) (Puppy, error) {
28+
store.RLock()
29+
if value, ok := store.Load(id); ok {
30+
return value.(Puppy), nil
31+
}
32+
store.RUnlock()
33+
34+
return Puppy{}, NewError(IDNotFound)
35+
}
36+
37+
// Update modifies the puppy matching the provided uuid in the store with the provided Puppy struct.
38+
// It returns a bool whether a matching identifier was modified or not.
39+
func (store *SyncStore) Update(id int, puppy Puppy) (bool, error) {
40+
if _, ok := store.Load(id); !ok {
41+
return false, NewError(IDNotFound)
42+
}
43+
if puppy.Value < 0 {
44+
return false, NewError(NegativeValue)
45+
}
46+
47+
puppy.ID = id
48+
store.Store(id, puppy)
49+
50+
return true, nil
51+
}
52+
53+
// Destroy removes the puppy matching the provided uuid from the store.
54+
// It returns a bool whether a matching identifier was deleted or not.
55+
func (store *SyncStore) Destroy(id int) (bool, error) {
56+
if _, ok := store.Load(id); !ok {
57+
return false, NewError(IDNotFound)
58+
}
59+
60+
store.Lock()
61+
store.Delete(id)
62+
store.Unlock()
63+
64+
return true, nil
65+
}

‎08_project/patrickmarabeas/types.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package main
2+
3+
import "sync"
4+
5+
type Puppy struct {
6+
ID int
7+
Breed string
8+
Color string
9+
Value int // cents
10+
}
11+
12+
type Storer interface {
13+
Create(puppy Puppy) (int, error)
14+
Read(ID int) (Puppy, error)
15+
Update(ID int, puppy Puppy) (bool, error)
16+
Destroy(ID int) (bool, error)
17+
}
18+
19+
type MapStore struct {
20+
uuid int
21+
store map[int]Puppy
22+
}
23+
24+
type SyncStore struct {
25+
uuid int
26+
sync.Map
27+
sync.RWMutex
28+
}

0 commit comments

Comments
 (0)
Please sign in to comment.