Implementing a new Stack type
This commit is contained in:
parent
73e322b845
commit
27e0615ec5
4 changed files with 262 additions and 12 deletions
|
@ -2,7 +2,7 @@ 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
|
||||||
|
@ -10,17 +10,31 @@ type InputError struct {
|
||||||
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!")}
|
||||||
|
)
|
||||||
|
|
|
@ -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
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