Skip to content

Commit 39b9d5c

Browse files
Merge pull request #229 from codecrafters-io/array-len-early-assertion
Early Assertion on array length in `ArrayElementsAssertion`
2 parents af107fc + ec169bc commit 39b9d5c

14 files changed

+69
-53
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ require (
1414

1515
require (
1616
github.com/davecgh/go-spew v1.1.1 // indirect
17+
github.com/dustin/go-humanize v1.0.1 // indirect
1718
github.com/fatih/color v1.18.0 // indirect
1819
github.com/mattn/go-colorable v0.1.14 // indirect
1920
github.com/mattn/go-isatty v0.0.20 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ github.com/codecrafters-io/tester-utils v0.4.9/go.mod h1:Fyrv4IebzjWtvKfpYf8ooYD
1111
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1212
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1313
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
14+
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
15+
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
1416
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
1517
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
1618
github.com/hdt3213/rdb v1.2.0 h1:wJgSW3A0Q28k/RuSKg7shvSj6+F9YsRAviMUDOuTSyI=

internal/resp_assertions/array_elements_assertion.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package resp_assertions
22

33
import (
4+
"fmt"
45
"slices"
56

67
resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value"
8+
"github.com/dustin/go-humanize/english"
79
)
810

911
type ArrayElementAssertionSpecification struct {
@@ -23,6 +25,24 @@ func (a ArrayElementsAssertion) Run(value resp_value.Value) error {
2325
return err
2426
}
2527

28+
array := value.Array()
29+
30+
if len(array) == 0 {
31+
panic("Codecrafters Internal Error - ArrayElementsAssertion called with empty specifications")
32+
}
33+
34+
largestIndex := slices.MaxFunc(a.ArrayElementAssertionSpecification, func(a, b ArrayElementAssertionSpecification) int {
35+
return a.ArrayElementAssertion.Index - b.ArrayElementAssertion.Index
36+
}).ArrayElementAssertion.Index
37+
38+
if largestIndex >= len(array) {
39+
return fmt.Errorf(
40+
"Expected at least %s to be present in the array, got only %d",
41+
english.Plural((largestIndex+1), "element", "elements"),
42+
len(array),
43+
)
44+
}
45+
2646
// Sort the indexes so the assertion runs serially
2747
slices.SortFunc(a.ArrayElementAssertionSpecification, func(aea1, aea2 ArrayElementAssertionSpecification) int {
2848
return aea1.ArrayElementAssertion.Index - aea2.ArrayElementAssertion.Index

internal/resp_assertions/bulk_string_absent_from_array_assertion.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func (a BulkStringAbsentFromArrayAssertion) Run(value resp_value.Value) error {
2121

2222
for _, element := range array {
2323
if element.Type == resp_value.BULK_STRING && element.String() == a.StringExpectedToBeAbsent {
24-
return fmt.Errorf("Expected string '%s' to be absent from the array, but is present", a.StringExpectedToBeAbsent)
24+
return fmt.Errorf("Expected bulk string '%s' to be absent from the array, but is present", a.StringExpectedToBeAbsent)
2525
}
2626
}
2727

internal/resp_assertions/ordered_bulk_string_array_assertion.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (a OrderedBulkStringArrayAssertion) Run(value resp_value.Value) error {
3131
actualElement := value.Array()[i]
3232

3333
if actualElement.Type != resp_value.BULK_STRING {
34-
return fmt.Errorf("Expected element #%d to be a string, got %s", i+1, actualElement.Type)
34+
return fmt.Errorf("Expected element #%d to be a bulk string, got %s", i+1, actualElement.Type)
3535
}
3636

3737
if actualElement.String() != expectedValue {

internal/resp_assertions/unordered_bulk_string_array_assertion.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func (a UnorderedBulkStringArrayAssertion) Run(value resp_value.Value) error {
3434
actualElement := value.Array()[i]
3535

3636
if actualElement.Type != resp_value.BULK_STRING {
37-
return fmt.Errorf("Expected element #%d to be a string, got %s", i+1, actualElement.Type)
37+
return fmt.Errorf("Expected element #%d to be a bulk string, got %s", i+1, actualElement.Type)
3838
}
3939

4040
actualElementStringArray[i] = value.Array()[i].String()

internal/test_cases/acl_getuser_test_case.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ func (t *AclGetuserTestCase) RunForFlagsTemplateOnly(client *instrumented_resp_c
3434
Assertion: resp_assertions.NewBulkStringAssertion("flags"),
3535
},
3636
PreAssertionHook: func() {
37-
clientLogger.Infof("Checking if the first element is \"flags\"")
37+
clientLogger.Infof("Checking if the first element is the bulk string \"flags\"")
3838
},
3939
AssertionSuccessHook: func() {
40-
clientLogger.Successf("✔ First element is \"flags\"")
40+
clientLogger.Successf("✔ First element is the bulk string \"flags\"")
4141
},
4242
},
4343
{
@@ -92,10 +92,10 @@ func (t *AclGetuserTestCase) addAssertionForFlags(assertion *resp_assertions.Arr
9292
{
9393
Assertion: resp_assertions.NewBulkStringAssertion("flags"),
9494
PreAssertionHook: func() {
95-
logger.Infof("Checking if the first element is \"flags\"")
95+
logger.Infof("Checking if the first element is the bulk string \"flags\"")
9696
},
9797
AssertionSuccessHook: func() {
98-
logger.Successf("✔ First element is \"flags\"")
98+
logger.Successf("✔ First element is the bulk string \"flags\"")
9999
},
100100
},
101101
},
@@ -177,10 +177,10 @@ func (t *AclGetuserTestCase) addAssertionForPasswords(assertion *resp_assertions
177177
{
178178
Assertion: resp_assertions.NewBulkStringAssertion("passwords"),
179179
PreAssertionHook: func() {
180-
logger.Infof("Checking if the third element of the array is \"passwords\"")
180+
logger.Infof("Checking if the third element of the array is the bulk string \"passwords\"")
181181
},
182182
AssertionSuccessHook: func() {
183-
logger.Successf("✔ Third element is \"passwords\"")
183+
logger.Successf("✔ Third element is the bulk string \"passwords\"")
184184
},
185185
},
186186
},

internal/test_cases/blocking_client_group_test_case.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/codecrafters-io/redis-tester/internal/instrumented_resp_connection"
99
"github.com/codecrafters-io/redis-tester/internal/resp_assertions"
1010
"github.com/codecrafters-io/tester-utils/logger"
11+
"github.com/dustin/go-humanize/english"
1112
)
1213

1314
type BlockingClientGroupTestCase struct {
@@ -40,7 +41,7 @@ func (t *BlockingClientGroupTestCase) AssertResponses(logger *logger.Logger) err
4041
logger.Infof(
4142
"Expecting %d %s to receive response of %s command",
4243
t.ResponseExpectingClientsCount,
43-
pluralize(t.ResponseExpectingClientsCount, "client", "clients"),
44+
english.PluralWord(t.ResponseExpectingClientsCount, "client", "clients"),
4445
t.CommandToSend[0],
4546
)
4647

internal/test_cases/receive_replication_handshake_test_case.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ func (t ReceiveReplicationHandshakeTestCase) RunReplconfStep2(client *instrument
9999

100100
if len(elements) == 5 {
101101
if elements[3].Type != resp_value.BULK_STRING {
102-
return fmt.Errorf("Expected third replconf argument to be a string, got %s", elements[3].Type)
102+
return fmt.Errorf("Expected third replconf argument to be a bulk string, got %s", elements[3].Type)
103103
}
104104

105105
secondCapaArg := elements[3].String()

internal/test_cases/utils.go

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)