Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/anti_cheat.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func antiCheatTest(stageHarness *test_case_harness.TestCaseHarness) error {
commandTestCase := test_cases.SendCommandTestCase{
Command: "MEMORY",
Args: []string{"DOCTOR"},
Assertion: resp_assertions.NewRegexStringAssertion("[sS]am"),
Assertion: resp_assertions.NewRegexBulkStringAssertion("[sS]am"),
ShouldSkipUnreadDataCheck: true,
}
err = commandTestCase.Run(client, logger)
Expand Down
6 changes: 4 additions & 2 deletions internal/resp_assertions/array_element_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ type ArrayElementAssertion struct {
}

func (a ArrayElementAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ARRAY {
return fmt.Errorf("Expected array, got %s", value.Type)
arrayTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ARRAY}

if err := arrayTypeAssertion.Run(value); err != nil {
return err
}

array := value.Array()
Expand Down
7 changes: 4 additions & 3 deletions internal/resp_assertions/array_elements_assertion.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package resp_assertions

import (
"fmt"
"slices"

resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value"
Expand All @@ -18,8 +17,10 @@ type ArrayElementsAssertion struct {
}

func (a ArrayElementsAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ARRAY {
return fmt.Errorf("Expected array, got %s", value.Type)
dataTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ARRAY}

if err := dataTypeAssertion.Run(value); err != nil {
return err
}

// Sort the indexes so the assertion runs serially
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ type BulkStringAbsentFromArrayAssertion struct {
}

func (a BulkStringAbsentFromArrayAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ARRAY {
return fmt.Errorf("Expected array, got %s", value.Type)
arrayTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ARRAY}

if err := arrayTypeAssertion.Run(value); err != nil {
return err
}

array := value.Array()
Expand Down
29 changes: 29 additions & 0 deletions internal/resp_assertions/bulk_string_assertion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package resp_assertions

import (
"fmt"

resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value"
)

type BulkStringAssertion struct {
ExpectedValue string
}

func NewBulkStringAssertion(expectedValue string) RESPAssertion {
return BulkStringAssertion{ExpectedValue: expectedValue}
}

func (a BulkStringAssertion) Run(value resp_value.Value) error {
bulkStringTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.BULK_STRING}

if err := bulkStringTypeAssertion.Run(value); err != nil {
return err
}

if value.String() != a.ExpectedValue {
return fmt.Errorf("Expected %q, got %q", a.ExpectedValue, value.String())
}

return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ type BulkStringPresentInArrayAssertion struct {
}

func (a BulkStringPresentInArrayAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ARRAY {
return fmt.Errorf("Expected array, got %s", value.Type)
arrayTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ARRAY}

if err := arrayTypeAssertion.Run(value); err != nil {
return err
}

array := value.Array()
Expand Down
14 changes: 8 additions & 6 deletions internal/resp_assertions/command_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ func NewCommandAssertion(expectedCommand string, expectedArgs ...string) RESPAss
}

func (a CommandAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ARRAY {
return fmt.Errorf("Expected array type, got %s", value.Type)
arrayTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ARRAY}

if err := arrayTypeAssertion.Run(value); err != nil {
return err
}

elements := value.Array()
Expand All @@ -30,8 +32,8 @@ func (a CommandAssertion) Run(value resp_value.Value) error {
return fmt.Errorf("Expected array with at least 1 element, got %d elements", len(elements))
}

if elements[0].Type != resp_value.SIMPLE_STRING && elements[0].Type != resp_value.BULK_STRING {
return fmt.Errorf("Expected first array element to be a string, got %s", elements[0].Type)
if elements[0].Type != resp_value.BULK_STRING {
return fmt.Errorf("Expected first array element to be a bulk string, got %s", elements[0].Type)
}

command := elements[0].String()
Expand All @@ -46,8 +48,8 @@ func (a CommandAssertion) Run(value resp_value.Value) error {

for i, expectedArg := range a.ExpectedArgs {
actualArg := elements[i+1]
if actualArg.Type != resp_value.SIMPLE_STRING && actualArg.Type != resp_value.BULK_STRING {
return fmt.Errorf("Expected argument %d to be a string, got %s", i+1, actualArg.Type)
if actualArg.Type != resp_value.BULK_STRING {
return fmt.Errorf("Expected argument %d to be a bulk string, got %s", i+1, actualArg.Type)
}

if actualArg.String() != expectedArg {
Expand Down
16 changes: 15 additions & 1 deletion internal/resp_assertions/data_type_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,22 @@ type DataTypeAssertion struct {
}

func (a DataTypeAssertion) Run(value resp_value.Value) error {
dataTypeHint := ""

switch a.ExpectedType {
case resp_value.NIL:
dataTypeHint = "$-1\r\n"
case resp_value.NIL_ARRAY:
dataTypeHint = "*-1\r\n"
}

// Spacing
if dataTypeHint != "" {
dataTypeHint = " " + dataTypeHint
}

if value.Type != a.ExpectedType {
return fmt.Errorf("Expected %s, found %s", a.ExpectedType, value.Type)
return fmt.Errorf("Expected %s%s, found %s", a.ExpectedType, dataTypeHint, value.Type)
}
return nil
}
6 changes: 4 additions & 2 deletions internal/resp_assertions/error_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ func NewErrorAssertion(expectedValue string) RESPAssertion {
}

func (a ErrorAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ERROR {
return fmt.Errorf("Expected error, got %s", value.Type)
respErrorTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ERROR}

if err := respErrorTypeAssertion.Run(value); err != nil {
return err
}

if value.Error() != a.ExpectedValue {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@ func NewFloatingPointBulkStringAssertion(expectedValue float64, tolerance float6
}

func (a FloatingPointBulkStringAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.BULK_STRING {
return fmt.Errorf("Expected bulk string, got %s", value.Type)
bulkStringTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.BULK_STRING}

if err := bulkStringTypeAssertion.Run(value); err != nil {
return err
}

stringValue := value.String()
Expand Down
6 changes: 4 additions & 2 deletions internal/resp_assertions/integer_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ func NewIntegerAssertion(expectedValue int) RESPAssertion {
}

func (a IntegerAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.INTEGER {
return fmt.Errorf("Expected integer, got %s", value.Type)
integerTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.INTEGER}

if err := integerTypeAssertion.Run(value); err != nil {
return err
}

if value.Integer() != a.ExpectedValue {
Expand Down
8 changes: 4 additions & 4 deletions internal/resp_assertions/nil_array_assertion.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package resp_assertions

import (
"fmt"

resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value"
)

Expand All @@ -13,8 +11,10 @@ func NewNilArrayAssertion() RESPAssertion {
}

func (a NilArrayAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.NIL_ARRAY {
return fmt.Errorf(`Expected null array ("*-1\r\n"), got %s`, value.Type)
nilArrayTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.NIL_ARRAY}

if err := nilArrayTypeAssertion.Run(value); err != nil {
return err
}

return nil
Expand Down
9 changes: 2 additions & 7 deletions internal/resp_assertions/nil_assertion.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package resp_assertions

import (
"fmt"

resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value"
)

Expand All @@ -13,9 +11,6 @@ func NewNilAssertion() RESPAssertion {
}

func (a NilAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.NIL {
return fmt.Errorf(`Expected null bulk string ("$-1\r\n"), got %s`, value.Type)
}

return nil
nullBulkStringTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.NIL}
return nullBulkStringTypeAssertion.Run(value)
}
10 changes: 6 additions & 4 deletions internal/resp_assertions/only_command_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@ func NewOnlyCommandAssertion(expectedCommand string) RESPAssertion {
}

func (a OnlyCommandAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ARRAY {
return fmt.Errorf("Expected array type, got %s", value.Type)
arrayTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ARRAY}

if err := arrayTypeAssertion.Run(value); err != nil {
return err
}

elements := value.Array()
Expand All @@ -28,8 +30,8 @@ func (a OnlyCommandAssertion) Run(value resp_value.Value) error {
return fmt.Errorf("Expected array with at least 1 element, got %d elements", len(elements))
}

if elements[0].Type != resp_value.SIMPLE_STRING && elements[0].Type != resp_value.BULK_STRING {
return fmt.Errorf("Expected first array element to be a string, got %s", elements[0].Type)
if elements[0].Type != resp_value.BULK_STRING {
return fmt.Errorf("Expected first array element to be a bulk string, got %s", elements[0].Type)
}

command := elements[0].String()
Expand Down
6 changes: 4 additions & 2 deletions internal/resp_assertions/ordered_array_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ func NewOrderedArrayAssertion(expectedValue []RESPAssertion) RESPAssertion {
}

func (a OrderedArrayAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ARRAY {
return fmt.Errorf("Expected an array, got %s", value.Type)
arrayTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ARRAY}

if err := arrayTypeAssertion.Run(value); err != nil {
return err
}

if len(value.Array()) != len(a.ExpectedValue) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@ import (
resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value"
)

// OrderedStringArrayAssertion : Order of the actual and expected values matters.
// OrderedBulkStringArrayAssertion : Order of the actual and expected values matters.
// We don't alter the ordering.
type OrderedStringArrayAssertion struct {
type OrderedBulkStringArrayAssertion struct {
ExpectedValue []string
}

func NewOrderedStringArrayAssertion(expectedValue []string) RESPAssertion {
return OrderedStringArrayAssertion{ExpectedValue: expectedValue}
func NewOrderedBulkStringArrayAssertion(expectedValue []string) RESPAssertion {
return OrderedBulkStringArrayAssertion{ExpectedValue: expectedValue}
}

func (a OrderedStringArrayAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ARRAY {
return fmt.Errorf("Expected an array, got %s", value.Type)
func (a OrderedBulkStringArrayAssertion) Run(value resp_value.Value) error {
arrayTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ARRAY}

if err := arrayTypeAssertion.Run(value); err != nil {
return err
}

if len(value.Array()) != len(a.ExpectedValue) {
Expand All @@ -28,7 +30,7 @@ func (a OrderedStringArrayAssertion) Run(value resp_value.Value) error {
for i, expectedValue := range a.ExpectedValue {
actualElement := value.Array()[i]

if actualElement.Type != resp_value.BULK_STRING && actualElement.Type != resp_value.SIMPLE_STRING {
if actualElement.Type != resp_value.BULK_STRING {
return fmt.Errorf("Expected element #%d to be a string, got %s", i+1, actualElement.Type)
}

Expand Down
2 changes: 1 addition & 1 deletion internal/resp_assertions/published_message_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ func NewPublishedMessageAssertion(channel string, message string) RESPAssertion
}

func (c PublishedMessageAssertion) Run(value resp_value.Value) error {
arrayAssertion := NewOrderedStringArrayAssertion([]string{"message", c.ExpectedChannel, c.ExpectedMessage})
arrayAssertion := NewOrderedBulkStringArrayAssertion([]string{"message", c.ExpectedChannel, c.ExpectedMessage})
return arrayAssertion.Run(value)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ import (
resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value"
)

type RegexStringAssertion struct {
type RegexBulkStringAssertion struct {
ExpectedPattern *regexp.Regexp
}

func NewRegexStringAssertion(expectedPattern string) RESPAssertion {
func NewRegexBulkStringAssertion(expectedPattern string) RESPAssertion {
pattern, err := regexp.Compile(expectedPattern)
if err != nil {
panic(err)
}

return RegexStringAssertion{ExpectedPattern: pattern}
return RegexBulkStringAssertion{ExpectedPattern: pattern}
}

func (a RegexStringAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.SIMPLE_STRING && value.Type != resp_value.BULK_STRING {
return fmt.Errorf("Expected simple string or bulk string, got %s", value.Type)
func (a RegexBulkStringAssertion) Run(value resp_value.Value) error {
bulkStringTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.BULK_STRING}

if err := bulkStringTypeAssertion.Run(value); err != nil {
return err
}

if !a.ExpectedPattern.MatchString(value.String()) {
Expand Down
6 changes: 4 additions & 2 deletions internal/resp_assertions/regex_error_assertion.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ func NewRegexErrorAssertion(expectedPattern string) RESPAssertion {
}

func (a RegexErrorAssertion) Run(value resp_value.Value) error {
if value.Type != resp_value.ERROR {
return fmt.Errorf("Expected error, got %s", value.Type)
respErrorTypeAssertion := DataTypeAssertion{ExpectedType: resp_value.ERROR}

if err := respErrorTypeAssertion.Run(value); err != nil {
return err
}

if !a.ExpectedPattern.MatchString(value.Error()) {
Expand Down
Loading