Skip to content

Commit

Permalink
added unit tests, standard errors, added constants and edge cases
Browse files Browse the repository at this point in the history
  • Loading branch information
ayadav16 committed Sep 26, 2024
1 parent c84f55b commit ebabd5c
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 99 deletions.
86 changes: 59 additions & 27 deletions integration_tests/commands/async/bitfield_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,66 +5,109 @@ import (
"time"

testifyAssert "github.com/stretchr/testify/assert"
"gotest.tools/v3/assert"
)

func TestBitfield(t *testing.T) {
conn := getLocalConnection()
defer conn.Close()

defer FireCommand(conn, "FLUSHDB") // clean up after all test cases
syntaxErrMsg := "ERR syntax error"
bitFieldTypeErrMsg := "ERR Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is."
integerErrMsg := "ERR value is not an integer or out of range"
overflowErrMsg := "ERR Invalid OVERFLOW type specified"

testCases := []struct {
Name string
Setup []string
Commands []string
Expected []interface{}
Delay []time.Duration
CleanUp []string
}{
{
Name: "BITFIELD Arity Check",
Commands: []string{"bitfield"},
Expected: []interface{}{"ERR wrong number of arguments for 'bitfield' command"},
Delay: []time.Duration{0},
CleanUp: []string{},
},
{
Name: "BITFIELD on unsupported type of SET",
Commands: []string{"SADD bits a b c", "bitfield bits"},
Expected: []interface{}{int64(3), "WRONGTYPE Operation against a key holding the wrong kind of value"},
Delay: []time.Duration{0, 0},
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD on unsupported type of JSON",
Commands: []string{"json.set bits $ 1", "bitfield bits"},
Expected: []interface{}{"OK", "WRONGTYPE Operation against a key holding the wrong kind of value"},
Delay: []time.Duration{0, 0},
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD on unsupported type of HSET",
Commands: []string{"HSET bits a 1", "bitfield bits"},
Expected: []interface{}{int64(1), "WRONGTYPE Operation against a key holding the wrong kind of value"},
Delay: []time.Duration{0, 0},
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD with syntax errors",
Commands: []string{
"bitfield bits set u8 0 255 incrby u8 0 100 get u8",
"bitfield bits set a8 0 255 incrby u8 0 100 get u8",
"bitfield bits set u8 a 255 incrby u8 0 100 get u8",
"bitfield bits set u8 0 255 incrby u8 0 100 overflow wraap",
"bitfield bits set u8 0 incrby u8 0 100 get u8 288",
},
Expected: []interface{}{
syntaxErrMsg,
bitFieldTypeErrMsg,
"ERR bit offset is not an integer or out of range",
overflowErrMsg,
integerErrMsg,
},
Delay: []time.Duration{0, 0, 0, 0, 0},
CleanUp: []string{"Del bit"},
},
{
Name: "BITFIELD signed SET and GET basics",
Setup: []string{},
Commands: []string{"bitfield bits set i8 0 -100", "bitfield bits set i8 0 101", "bitfield bits get i8 0"},
Expected: []interface{}{[]interface{}{int64(0)}, []interface{}{int64(-100)}, []interface{}{int64(101)}},
Delay: []time.Duration{0, 0, 0},
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD unsigned SET and GET basics",
Setup: []string{},
Commands: []string{"bitfield bits set u8 0 255", "bitfield bits set u8 0 100", "bitfield bits get u8 0"},
Expected: []interface{}{[]interface{}{int64(0)}, []interface{}{int64(255)}, []interface{}{int64(100)}},
Delay: []time.Duration{0, 0, 0},
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD signed SET and GET together",
Setup: []string{},
Commands: []string{"bitfield bits set i8 0 255 set i8 0 100 get i8 0"},
Expected: []interface{}{[]interface{}{int64(0), int64(-1), int64(100)}},
Delay: []time.Duration{0},
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD unsigned with SET, GET and INCRBY arguments",
Setup: []string{},
Commands: []string{"bitfield bits set u8 0 255 incrby u8 0 100 get u8 0"},
Expected: []interface{}{[]interface{}{int64(0), int64(99), int64(99)}},
Delay: []time.Duration{0},
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD with only key as argument",
Setup: []string{},
Commands: []string{"bitfield bits"},
Expected: []interface{}{[]interface{}{}},
Delay: []time.Duration{0},
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD #<idx> form",
Setup: []string{},
Name: "BITFIELD #<idx> form",
Commands: []string{
"bitfield bits set u8 #0 65",
"bitfield bits set u8 #1 66",
Expand All @@ -76,8 +119,7 @@ func TestBitfield(t *testing.T) {
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD basic INCRBY form",
Setup: []string{},
Name: "BITFIELD basic INCRBY form",
Commands: []string{
"bitfield bits set u8 #0 10",
"bitfield bits incrby u8 #0 100",
Expand All @@ -88,8 +130,7 @@ func TestBitfield(t *testing.T) {
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD chaining of multiple commands",
Setup: []string{},
Name: "BITFIELD chaining of multiple commands",
Commands: []string{
"bitfield bits set u8 #0 10",
"bitfield bits incrby u8 #0 100 incrby u8 #0 100",
Expand All @@ -99,8 +140,7 @@ func TestBitfield(t *testing.T) {
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD unsigned overflow wrap",
Setup: []string{},
Name: "BITFIELD unsigned overflow wrap",
Commands: []string{
"bitfield bits set u8 #0 100",
"bitfield bits overflow wrap incrby u8 #0 257",
Expand All @@ -119,8 +159,7 @@ func TestBitfield(t *testing.T) {
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD unsigned overflow sat",
Setup: []string{},
Name: "BITFIELD unsigned overflow sat",
Commands: []string{
"bitfield bits set u8 #0 100",
"bitfield bits overflow sat incrby u8 #0 257",
Expand All @@ -139,8 +178,7 @@ func TestBitfield(t *testing.T) {
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD signed overflow wrap",
Setup: []string{},
Name: "BITFIELD signed overflow wrap",
Commands: []string{
"bitfield bits set i8 #0 100",
"bitfield bits overflow wrap incrby i8 #0 257",
Expand All @@ -159,8 +197,7 @@ func TestBitfield(t *testing.T) {
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD signed overflow sat",
Setup: []string{},
Name: "BITFIELD signed overflow sat",
Commands: []string{
"bitfield bits set u8 #0 100",
"bitfield bits overflow sat incrby i8 #0 257",
Expand All @@ -180,15 +217,13 @@ func TestBitfield(t *testing.T) {
},
{
Name: "BITFIELD regression 1",
Setup: []string{},
Commands: []string{"set bits 1", "bitfield bits get u1 0"},
Expected: []interface{}{"OK", []interface{}{int64(0)}},
Delay: []time.Duration{0, 0},
CleanUp: []string{"DEL bits"},
},
{
Name: "BITFIELD regression 2",
Setup: []string{},
Name: "BITFIELD regression 2",
Commands: []string{
"bitfield mystring set i8 0 10",
"bitfield mystring set i8 64 10",
Expand All @@ -202,9 +237,6 @@ func TestBitfield(t *testing.T) {

for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
for _, cmd := range tc.Setup {
assert.Equal(t, FireCommand(conn, cmd), "OK")
}

for i := 0; i < len(tc.Commands); i++ {
if tc.Delay[i] > 0 {
Expand Down
41 changes: 22 additions & 19 deletions internal/errors/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,29 @@ import (
)

const (
ArityErr = "wrong number of arguments for '%s' command"
SyntaxErr = "syntax error"
ExpiryErr = "invalid expire time in '%s' command"
AuthErr = "AUTH failed"
IntOrOutOfRangeErr = "value is not an integer or out of range"
IntOrFloatErr = "value is not an integer or a float"
ValOutOfRangeErr = "value is out of range"
IncrDecrOverflowErr = "increment or decrement would overflow"
ElementPeekErr = "number of elements to peek should be a positive number less than %d"
NoKeyErr = "no such key"
ErrDefault = "-ERR %s"
WrongTypeErr = "-WRONGTYPE Operation against a key holding the wrong kind of value"
WrongTypeHllErr = "-WRONGTYPE Key is not a valid HyperLogLog string value."
InvalidHllErr = "-INVALIDOBJ Corrupted HLL object detected"
WorkerNotFoundErr = "worker with ID %s not found"
JSONPathNotExistErr = "-ERR Path '%s' does not exist"
JSONPathValueTypeErr = "-WRONGTYPE wrong type of path value - expected string but found integer"
InvalidExpireTime = "-ERR invalid expire time"
ArityErr = "wrong number of arguments for '%s' command"
SyntaxErr = "syntax error"
ExpiryErr = "invalid expire time in '%s' command"
AuthErr = "AUTH failed"
IntOrOutOfRangeErr = "value is not an integer or out of range"
IntOrFloatErr = "value is not an integer or a float"
ValOutOfRangeErr = "value is out of range"
IncrDecrOverflowErr = "increment or decrement would overflow"
ElementPeekErr = "number of elements to peek should be a positive number less than %d"
NoKeyErr = "no such key"
ErrDefault = "-ERR %s"
WrongTypeErr = "-WRONGTYPE Operation against a key holding the wrong kind of value"
WrongTypeHllErr = "-WRONGTYPE Key is not a valid HyperLogLog string value."
InvalidHllErr = "-INVALIDOBJ Corrupted HLL object detected"
WorkerNotFoundErr = "worker with ID %s not found"
JSONPathNotExistErr = "-ERR Path '%s' does not exist"
JSONPathValueTypeErr = "-WRONGTYPE wrong type of path value - expected string but found integer"
InvalidExpireTime = "-ERR invalid expire time"
HashValueNotIntegerErr = "hash value is not an integer"
InternalServerError = "-ERR: Internal server error, unable to process command"
InternalServerError = "-ERR: Internal server error, unable to process command"
InvalidBitfieldType = "-ERR Invalid bitfield type. Use something like i16 u8. Note that u64 is not supported but i64 is."
BitfieldOffsetErr = "-ERR bit offset is not an integer or out of range"
OverflowTypeErr = "-ERR Invalid OVERFLOW type specified"
)

var (
Expand Down
6 changes: 3 additions & 3 deletions internal/eval/bytearray.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,21 +268,21 @@ func (b *ByteArray) incrByBits(offset, width int, increment int64, overflow stri
}

switch overflow {
case "WRAP":
case WRAP:
if signed {
rangeSize := maxVal - minVal + 1
newValue = ((newValue-minVal)%rangeSize+rangeSize)%rangeSize + minVal
} else {
newValue %= maxVal + 1
}
case "SAT":
case SAT:
// Handle saturation
if newValue > maxVal {
newValue = maxVal
} else if newValue < minVal {
newValue = minVal
}
case "FAIL":
case FAIL:
// Handle failure on overflow
if newValue > maxVal || newValue < minVal {
return value, errors.New("overflow detected")
Expand Down
53 changes: 30 additions & 23 deletions internal/eval/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,35 @@ const (
XOR string = "XOR"
NOT string = "NOT"

Ex string = "EX"
Px string = "PX"
Pxat string = "PXAT"
Exat string = "EXAT"
XX string = "XX"
NX string = "NX"
Xx string = "xx"
Nx string = "nx"
GT string = "GT"
LT string = "LT"
KEEPTTL string = "KEEPTTL"
Keepttl string = "keepttl"
Sync string = "SYNC"
Async string = "ASYNC"
Help string = "HELP"
Memory string = "MEMORY"
Count string = "COUNT"
GetKeys string = "GETKEYS"
List string = "LIST"
Info string = "INFO"
Null string = "null"
null string = "null"
NULL string = "null"
Ex string = "EX"
Px string = "PX"
Pxat string = "PXAT"
Exat string = "EXAT"
XX string = "XX"
NX string = "NX"
Xx string = "xx"
Nx string = "nx"
GT string = "GT"
LT string = "LT"
KEEPTTL string = "KEEPTTL"
Keepttl string = "keepttl"
Sync string = "SYNC"
Async string = "ASYNC"
Help string = "HELP"
Memory string = "MEMORY"
Count string = "COUNT"
GetKeys string = "GETKEYS"
List string = "LIST"
Info string = "INFO"
Null string = "null"
null string = "null"
NULL string = "null"
WITHVALUES string = "WITHVALUES"
GET string = "GET"
SET string = "SET"
INCRBY string = "INCRBY"
OVERFLOW string = "OVERFLOW"
WRAP string = "WRAP"
SAT string = "SAT"
FAIL string = "FAIL"
)
Loading

0 comments on commit ebabd5c

Please sign in to comment.