Skip to content

Commit

Permalink
Create error type for handling erros
Browse files Browse the repository at this point in the history
  • Loading branch information
hsy3418 committed Aug 25, 2019
1 parent 4f06d71 commit bd52411
Show file tree
Hide file tree
Showing 8 changed files with 353 additions and 0 deletions.
12 changes: 12 additions & 0 deletions 07_errors/hsy3418/error.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import "fmt"

type Error struct {
Message string
Code int
}

func (e *Error) Error() string {
return fmt.Sprintf("Error code:%d,Error:%s", e.Code, e.Message)
}
13 changes: 13 additions & 0 deletions 07_errors/hsy3418/error_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestError(t *testing.T) {
err := Error{Code: -1, Message: "Invalid Error"}
errMessage := err.Error()
assert.Equal(t, "Error code:-1,Error:Invalid Error", errMessage)
}
26 changes: 26 additions & 0 deletions 07_errors/hsy3418/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"fmt"
"io"
"os"
)

var out io.Writer = os.Stdout

func main() {
p1 := Puppy{ID: 101, Breed: "Poodle", Colour: "White", Value: 1280.5}
p2 := Puppy{ID: 102, Breed: "Poodle", Colour: "Grey", Value: 1340.5}

mapStore := NewMapStore()
syncStore := NewSyncStore()

_ = mapStore.CreatePuppy(p1)
_ = syncStore.CreatePuppy(p2)

puppy, _ := mapStore.ReadPuppy(101)
puppy2, _ := syncStore.ReadPuppy(102)
fmt.Fprintf(out, "Puppy ID %d is %v", puppy.ID, puppy.Value)
fmt.Fprintf(out, "Puppy ID %d is %v", puppy2.ID, puppy2.Value)

}
18 changes: 18 additions & 0 deletions 07_errors/hsy3418/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"bytes"
"testing"

"github.com/stretchr/testify/assert"
)

func TestMain(t *testing.T) {
assert := assert.New(t)
var buf bytes.Buffer
out = &buf
main()
expected := "Puppy ID 101 is 1280.5Puppy ID 102 is 1340.5"
actual := buf.String()
assert.Equal(expected, actual)
}
63 changes: 63 additions & 0 deletions 07_errors/hsy3418/mapStore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package main

import "fmt"

// MapStore is a implementation of storer for the storage of puppies
type MapStore struct {
puppies map[int32]Puppy
}

func NewMapStore() *MapStore {
return &MapStore{
puppies: map[int32]Puppy{},
}
}

// CreatePuppy adds a nuw puppy to the puppies store
func (m *MapStore) CreatePuppy(puppy Puppy) error {
if puppy.Value < 0 {
err := &Error{
Message: "The puppy value is invalidate",
Code: -1,
}
return err
}
if _, exists := m.puppies[puppy.ID]; !exists {
m.puppies[puppy.ID] = puppy
return nil
}
return fmt.Errorf("puppy with %d ID already exists", puppy.ID)
}

// ReadPuppy retrieves the puppy for a given id from puppies store
func (m *MapStore) ReadPuppy(id int32) (Puppy, error) {
if _, exists := m.puppies[id]; !exists {
return Puppy{}, &Error{Message: "puppy ID does not exist", Code: -2}
}
return m.puppies[id], nil
}

//UpdatePuppy updates the puppy for the given id
func (m *MapStore) UpdatePuppy(puppy Puppy) error {
if puppy.Value < 0 {
err := &Error{
Message: "The puppy value is invalidate",
Code: -1,
}
return err
}
if _, exists := m.puppies[puppy.ID]; !exists {
return &Error{Message: "puppy ID does not exist", Code: -2}
}
m.puppies[puppy.ID] = puppy
return nil
}

//DeletePuppy delete the puppy for the given id from puppies store
func (m *MapStore) DeletePuppy(id int32) error {
if _, exists := m.puppies[id]; exists {
delete(m.puppies, id)
return nil
}
return &Error{Message: "puppy ID does not exist", Code: -2}
}
133 changes: 133 additions & 0 deletions 07_errors/hsy3418/store_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package main

import (
"fmt"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/suite"
)

func (suite *storerTestSuite) SetupTest() {
suite.store = suite.makeStore()
suite.toBeCreatedPuppy = Puppy{ID: 101, Breed: "Poodle", Colour: "White", Value: 1000.5}
suite.existsPuppy = Puppy{ID: 102, Breed: "Poodle", Colour: "White", Value: 1280.5}
suite.toBeUpdatedPuppy = Puppy{ID: 102, Breed: "Poodle", Colour: "White", Value: 2000}
suite.invalidPuppy = Puppy{ID: 103, Breed: "Poodle", Colour: "White", Value: -1000}
suite.invaildError = &Error{
Message: "The puppy value is invalidate",
Code: -1,
}
suite.invalidIDError = &Error{Message: "puppy ID does not exist", Code: -2}
err := suite.store.CreatePuppy(suite.existsPuppy)
if err != nil {
suite.FailNow("Failed to setup test")
}
}

type storerTestSuite struct {
suite.Suite
store Storer
makeStore func() Storer
toBeCreatedPuppy Puppy
existsPuppy Puppy
toBeUpdatedPuppy Puppy
invalidPuppy Puppy
invaildError error
invalidIDError error
}

//successfully create puppy, new puppy, existing puppy, value <0
func (suite *storerTestSuite) TestCreatePuppy() {
assert := assert.New(suite.T())
testCases := []struct {
title string
input Puppy
expected error
}{
{"Create new puppy", suite.toBeCreatedPuppy, nil},
{"Create existing puppy", suite.toBeCreatedPuppy, fmt.Errorf("puppy with 101 ID already exists")},
{"Create a invalid puppy", suite.invalidPuppy, suite.invaildError},
}
for _, tc := range testCases {
tc := tc
suite.T().Run(tc.title, func(t *testing.T) {
err := suite.store.CreatePuppy(tc.input)
assert.Equal(tc.expected, err)
})
}

}

//
func (suite *storerTestSuite) TestUpdatePuppy() {
assert := assert.New(suite.T())
testCases := []struct {
title string
inputPuppy Puppy
expectedError error
}{
{"Update puppy successfully", suite.toBeUpdatedPuppy, nil},
{"Update a invalid puppy", suite.invalidPuppy, suite.invaildError},
{"Update non-existing puppy", Puppy{}, suite.invalidIDError},
}
for _, tc := range testCases {
tc := tc
suite.T().Run(tc.title, func(t *testing.T) {
err := suite.store.UpdatePuppy(tc.inputPuppy)
assert.Equal(tc.expectedError, err)
})
}

}

func (suite *storerTestSuite) TestReadPuppy() {
assert := assert.New(suite.T())
testCases := []struct {
title string
input int32
expected Puppy
expectedError error
}{
{"Read puppy successfully", suite.existsPuppy.ID, suite.existsPuppy, nil},
{"Read non-existing puppy", suite.toBeCreatedPuppy.ID, Puppy{}, suite.invalidIDError},
}
for _, tc := range testCases {
tc := tc
suite.T().Run(tc.title, func(t *testing.T) {
readPuppy, err := suite.store.ReadPuppy(tc.input)
assert.Equal(tc.expected, readPuppy)
assert.Equal(tc.expectedError, err)
})
}

}

func (suite *storerTestSuite) TestDeletePuppy() {
assert := assert.New(suite.T())
testCases := []struct {
title string
input int32
expectedError error
}{
{"Delete puppy successfully", suite.existsPuppy.ID, nil},
{"Delete non-existing puppy", suite.toBeCreatedPuppy.ID, suite.invalidIDError},
}
for _, tc := range testCases {
tc := tc
suite.T().Run(tc.title, func(t *testing.T) {
err := suite.store.DeletePuppy(tc.input)
assert.Equal(tc.expectedError, err)
})
}

}

func TestStorers(t *testing.T) {
suite.Run(t, &storerTestSuite{
makeStore: func() Storer { return NewMapStore() },
})
suite.Run(t, &storerTestSuite{
makeStore: func() Storer { return NewSyncStore() },
})
}
71 changes: 71 additions & 0 deletions 07_errors/hsy3418/syncStore.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package main

import (
"fmt"
"sync"
)

type SyncStore struct {
sync.Mutex
sync.Map
}

func NewSyncStore() *SyncStore {
return &SyncStore{}
}

// CreatePuppy adds a nuw puppy to the puppies store
func (m *SyncStore) CreatePuppy(puppy Puppy) error {
m.Lock()
defer m.Unlock()
if puppy.Value < 0 {
err := &Error{
Message: "The puppy value is invalidate",
Code: -1,
}
return err
}
if _, exists := m.Load(puppy.ID); exists {
return fmt.Errorf("puppy with %d ID already exists", puppy.ID)
}
m.Store(puppy.ID, puppy)
return nil
}

// ReadPuppy retrieves the puppy for a given id from puppies store
func (m *SyncStore) ReadPuppy(id int32) (Puppy, error) {
if p, exists := m.Load(id); exists {
puppy, _ := p.(Puppy)
return puppy, nil
}
return Puppy{}, &Error{Message: "puppy ID does not exist", Code: -2}
}

//UpdatePuppy updates the puppy for the given id
func (m *SyncStore) UpdatePuppy(puppy Puppy) error {
m.Lock()
defer m.Unlock()
if puppy.Value < 0 {
err := &Error{
Message: "The puppy value is invalidate",
Code: -1,
}
return err
}
if _, exists := m.Load(puppy.ID); !exists {
return &Error{Message: "puppy ID does not exist", Code: -2}
}
m.Store(puppy.ID, puppy)
return nil
}

//DeletePuppy delete the puppy for the given id from puppies store
func (m *SyncStore) DeletePuppy(id int32) error {
m.Lock()
defer m.Unlock()
if _, exists := m.Load(id); exists {
m.Delete(id)
return nil
}
return &Error{Message: "puppy ID does not exist", Code: -2}
}
17 changes: 17 additions & 0 deletions 07_errors/hsy3418/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package main

// Puppy defines the data structure corresponding to a pet
type Puppy struct {
ID int32 `json:"id"`
Value float32 `json:"value"`
Breed string `json:"breed"`
Colour string `json:"colour"`
}

//Storer define standard CRUD operations for puppys
type Storer interface {
CreatePuppy(Puppy) error
ReadPuppy(ID int32) (Puppy, error)
UpdatePuppy(puppy Puppy) error
DeletePuppy(ID int32) error
}

0 comments on commit bd52411

Please sign in to comment.