Implementing a new Stack type
This commit is contained in:
parent
73e322b845
commit
27e0615ec5
4 changed files with 262 additions and 12 deletions
|
@ -2,25 +2,39 @@ package server
|
|||
|
||||
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 {
|
||||
// The operation that caused the error.
|
||||
Op string
|
||||
Op string
|
||||
// The error that occurred during the operation.
|
||||
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
|
||||
var (
|
||||
UnknownError = errors.New("Unknown Error.")
|
||||
InvalidCommand = errors.New("Invalid command.")
|
||||
TooManyArguments = errors.New("Too many arguments.")
|
||||
TooFewArguments = errors.New("Too few arguments.")
|
||||
InputUnknownError = errors.New("Unknown Error.")
|
||||
InputInvalidCommand = errors.New("Invalid command.")
|
||||
InputTooManyArguments = errors.New("Too many arguments.")
|
||||
InputTooFewArguments = errors.New("Too few arguments.")
|
||||
)
|
||||
|
||||
// Command Errors
|
||||
// Command Errors represent errors that occur when the server is executing commands
|
||||
var (
|
||||
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!")}
|
||||
)
|
||||
|
|
|
@ -8,9 +8,9 @@ import (
|
|||
// checkArgumentsLength returns an error if length is not equal to expected.
|
||||
func checkArgumentsLength(length int, expected int) error {
|
||||
if length > expected {
|
||||
return TooManyArguments
|
||||
return InputTooManyArguments
|
||||
} else if length < expected {
|
||||
return TooFewArguments
|
||||
return InputTooFewArguments
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ func ProcessInput(c net.Conn, text string) error {
|
|||
|
||||
c.Close()
|
||||
default:
|
||||
return &InputError{thisCommand, InvalidCommand}
|
||||
return &InputError{thisCommand, InputInvalidCommand}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
77
server/server/stack.go
Normal file
77
server/server/stack.go
Normal 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
159
server/server/stack_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue