Implementing a new Stack type

This commit is contained in:
Denis-Cosmin Nutiu 2017-10-28 19:02:26 +03:00
parent 73e322b845
commit 27e0615ec5
4 changed files with 262 additions and 12 deletions

View file

@ -2,25 +2,39 @@ package server
import "errors" import "errors"
// InputError will be raised when the input is not right. // InputError will be raised when the input given to the parser by the client is not right.
type InputError struct { type InputError struct {
// The operation that caused the error. // The operation that caused the error.
Op string Op string
// The error that occurred during the operation. // The error that occurred during the operation.
Err error Err error
} }
func (e *InputError) Error() string { return "Error: " + e.Op + ": " + e.Err.Error() } func (e InputError) Error() string { return "Error: " + e.Op + ": " + e.Err.Error() }
// Input Errors // Input Errors
var ( var (
UnknownError = errors.New("Unknown Error.") InputUnknownError = errors.New("Unknown Error.")
InvalidCommand = errors.New("Invalid command.") InputInvalidCommand = errors.New("Invalid command.")
TooManyArguments = errors.New("Too many arguments.") InputTooManyArguments = errors.New("Too many arguments.")
TooFewArguments = errors.New("Too few arguments.") InputTooFewArguments = errors.New("Too few arguments.")
) )
// Command Errors // Command Errors represent errors that occur when the server is executing commands
var ( var (
GetNoBitsError = errors.New("The file/directory contains zero bits!") GetNoBitsError = errors.New("The file/directory contains zero bits!")
) )
type StackError struct {
ErrorName string
Err error
}
func (e StackError) Error() string { return e.ErrorName + ": " + e.Err.Error() }
// Stack Errors
var (
StackInvalidTypeError = StackError{"InvalidTypeError", errors.New("Invalid item type for the Stack")}
StackOverflowError = StackError{"StackOverflowError", errors.New("Stack capacity exceeded!")}
StackUnderflowError = StackError{"StackUnderflowError", errors.New("Stack is empty!")}
)

View file

@ -8,9 +8,9 @@ import (
// checkArgumentsLength returns an error if length is not equal to expected. // checkArgumentsLength returns an error if length is not equal to expected.
func checkArgumentsLength(length int, expected int) error { func checkArgumentsLength(length int, expected int) error {
if length > expected { if length > expected {
return TooManyArguments return InputTooManyArguments
} else if length < expected { } else if length < expected {
return TooFewArguments return InputTooFewArguments
} }
return nil return nil
} }
@ -81,7 +81,7 @@ func ProcessInput(c net.Conn, text string) error {
c.Close() c.Close()
default: default:
return &InputError{thisCommand, InvalidCommand} return &InputError{thisCommand, InputInvalidCommand}
} }
return nil return nil

77
server/server/stack.go Normal file
View file

@ -0,0 +1,77 @@
package server
// Stack interface
type Stack interface {
// Push pushes an item to the stack. Returns an error if it fails.
Push(item interface{})
// Pop retrieves an item from the stack and removes it.
Pop() interface{}
// Top peeks at an item from the stack.
Top() interface{}
// IsEmpty returns bool indicating if the stack is empty.
IsEmpty() bool
// Capacity returns the capacity of the stack.
Capacity() int
// Size returns the size of the stack
Size() int
}
// StringStack is a stack that holds string objects
type StringStack struct {
index int
capacity int
items []string
}
func MakeStringStack(capacity int) *StringStack {
st := StringStack{}
st.capacity = capacity
st.index = 0
st.items = make([]string, capacity, capacity)
return &st
}
func (st *StringStack) Push(item interface{}) {
if st.index == st.Capacity() {
panic(StackOverflowError)
}
value, ok := item.(string)
if ok == false {
panic(StackInvalidTypeError)
}
st.items[st.index] = value
st.index++
}
func (st *StringStack) Pop() interface{} {
if st.Size() == 0 {
panic(StackUnderflowError)
}
st.index--
return st.items[st.index]
}
func (st *StringStack) Top() interface{} {
if st.Size() == 0 {
panic(StackUnderflowError)
}
return st.items[st.index-1]
}
func (st *StringStack) IsEmpty() bool {
return st.Size() == 0
}
func (st *StringStack) Capacity() int {
return st.capacity
}
func (st *StringStack) Size() int {
return st.index
}

159
server/server/stack_test.go Normal file
View file

@ -0,0 +1,159 @@
package server
import (
"testing"
"math/rand"
)
func TestMakeStringStack(t *testing.T) {
st := MakeStringStack(10)
if st == nil {
t.Errorf("MakeStringStack returned null!")
}
if st.Capacity() != 10 {
t.Errorf("StringStack: Stack capacity is not ok! Want: 10 Got: %d", st.Capacity())
}
if st.IsEmpty() != true {
t.Errorf("StringStack: Newly created stack is not empty!")
}
}
func TestStringStack_CanPush(t *testing.T) {
var st Stack = MakeStringStack(10)
str := "Hello World"
st.Push(str)
if st.Top() != str {
t.Errorf("StringStack: Push() failed. Want: %s Got: %s", str, st.Top())
}
if st.Size() != 1 {
t.Errorf("StringStack: Size is not correct after one push. Want %d Got %d", 1, st.Size())
}
}
func TestStringStack_StackOverflows(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("StringStack: Capacity of 0 doesn't overflow on Push()!")
}
}()
st := MakeStringStack(0)
st.Push(".")
}
func TestStringStack_InvalidType(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("StringStack: Push() pushed a non-string type.")
}
}()
st := MakeStringStack(1)
st.Push(1)
}
func TestStringStack_Capacity(t *testing.T) {
stCap := rand.Intn(100)
st := MakeStringStack(stCap)
if st.Capacity() != stCap {
t.Errorf("StringStack: Invalid capacity! Want: %d Got: %d", stCap, st.Capacity())
}
}
func TestStringStack_Size(t *testing.T) {
pushes := rand.Intn(10)
st := MakeStringStack(15)
for i := 0; i < pushes; i++ {
st.Push("a")
}
if st.Size() != pushes {
t.Errorf("StringStack: Invalid size! Want: %d Got %d", pushes, st.Size())
}
}
func TestStringStack_IsEmpty(t *testing.T) {
st := MakeStringStack(10)
if st.IsEmpty() == false {
t.Errorf("StringStack: With no push, the stack is not empty!")
}
}
func TestStringStack_IsEmptyAfterPushAndPop(t *testing.T) {
st := MakeStringStack(10)
pushes := rand.Intn(5)
for i := 0; i < pushes; i++ {
st.Push("a")
}
for i := 0; i < pushes; i++ {
st.Pop()
}
if st.IsEmpty() == false {
t.Errorf("StringStack: After push and pop, the stack is not empty!")
}
}
func TestStringStack_Top(t *testing.T) {
st := MakeStringStack(1)
st.Push("A")
if st.Top() != "A" {
t.Errorf("StringStack: Top() returned invalid value!")
}
}
func TestStringStack_TopUnderflow(t *testing.T) {
defer func() {
if r := recover(); r == nil {
t.Errorf("StringStack: Top() on empty stack didn't underflow.")
}
}()
st := MakeStringStack(1)
st.Top()
}
func TestStringStack_Pop(t *testing.T) {
st := MakeStringStack(1)
st.Push("A")
if st.Pop() != "A" {
t.Errorf("StringStack: Pop() returned invalid value!")
}
}
func TestStringStack_Push(t *testing.T) {
st := MakeStringStack(1)
st.Push("A")
}
func TestStringStack_PushAndPop(t *testing.T) {
st := MakeStringStack(12)
characters := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k"}
pushes := rand.Intn(len(characters))
for i := 0; i < pushes; i++ {
st.Push(characters[i])
}
for i := pushes - 1; i >= 0; i-- {
if val := st.Pop(); val != characters[i] {
t.Errorf("StringStack: Pop() and Push() don't work correctly. Want %s Got %s", characters[i], val)
}
}
}