Skip to content

Commit 2c3dd72

Browse files
authored
Merge pull request #175 from codecrafters-io/andy/fix
CC-1731: Fix Redis #xu1
2 parents 024884c + 9b8419a commit 2c3dd72

File tree

6 files changed

+667
-577
lines changed

6 files changed

+667
-577
lines changed

internal/resp/decoder/decode_array.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ func decodeArray(reader *bytes.Reader) (resp_value.Value, error) {
3131
}
3232
}
3333

34-
if length < 0 {
34+
if length == -1 {
35+
return resp_value.NewNilValue(), nil
36+
}
37+
38+
if length < -1 {
3539
// Ensure error points to the correct byte
3640
reader.Seek(int64(offsetBeforeLength), io.SeekStart)
3741

internal/resp/value/value.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,19 @@ func (v *Value) FormattedString() string {
125125

126126
return ""
127127
}
128+
129+
func (v Value) ToSerializable() interface{} {
130+
switch v.Type {
131+
case BULK_STRING:
132+
return v.String()
133+
case ARRAY:
134+
arr := v.Array()
135+
result := make([]interface{}, len(arr))
136+
for i, elem := range arr {
137+
result[i] = elem.ToSerializable()
138+
}
139+
return result
140+
default:
141+
return v.String()
142+
}
143+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package resp_assertions
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
resp_value "github.com/codecrafters-io/redis-tester/internal/resp/value"
8+
)
9+
10+
type StreamEntry struct {
11+
Id string
12+
FieldValuePairs [][]string
13+
}
14+
15+
type StreamResponse struct {
16+
Key string
17+
Entries []StreamEntry
18+
}
19+
20+
type XReadResponseAssertion struct {
21+
ExpectedStreamResponses []StreamResponse
22+
}
23+
24+
func NewXReadResponseAssertion(expectedValue []StreamResponse) RESPAssertion {
25+
return XReadResponseAssertion{ExpectedStreamResponses: expectedValue}
26+
}
27+
28+
func (a XReadResponseAssertion) Run(value resp_value.Value) error {
29+
if value.Type != resp_value.ARRAY {
30+
return fmt.Errorf("Expected array, got %s", value.Type)
31+
}
32+
33+
expected := a.buildExpected().ToSerializable()
34+
actual := value.ToSerializable()
35+
36+
expectedJSON, err := json.MarshalIndent(expected, "", " ")
37+
if err != nil {
38+
return fmt.Errorf("failed to marshal expected value: %w", err)
39+
}
40+
actualJSON, err := json.MarshalIndent(actual, "", " ")
41+
if err != nil {
42+
return fmt.Errorf("failed to marshal actual value: %w", err)
43+
}
44+
45+
if string(expectedJSON) != string(actualJSON) {
46+
return fmt.Errorf("XREAD response mismatch:\nExpected:\n%s\nGot:\n%s", expectedJSON, actualJSON)
47+
}
48+
49+
return nil
50+
}
51+
52+
func (a XReadResponseAssertion) buildExpected() resp_value.Value {
53+
streams := make([]resp_value.Value, len(a.ExpectedStreamResponses))
54+
for i, stream := range a.ExpectedStreamResponses {
55+
streams[i] = stream.toRESPValue()
56+
}
57+
return resp_value.NewArrayValue(streams)
58+
}
59+
60+
func (s StreamResponse) toRESPValue() resp_value.Value {
61+
entries := make([]resp_value.Value, len(s.Entries))
62+
for i, entry := range s.Entries {
63+
entries[i] = entry.toRESPValue()
64+
}
65+
return resp_value.NewArrayValue([]resp_value.Value{
66+
resp_value.NewBulkStringValue(s.Key),
67+
resp_value.NewArrayValue(entries),
68+
})
69+
}
70+
71+
func (e StreamEntry) toRESPValue() resp_value.Value {
72+
var fieldValues []resp_value.Value
73+
for _, pair := range e.FieldValuePairs {
74+
for _, v := range pair {
75+
fieldValues = append(fieldValues, resp_value.NewBulkStringValue(v))
76+
}
77+
}
78+
return resp_value.NewArrayValue([]resp_value.Value{
79+
resp_value.NewBulkStringValue(e.Id),
80+
resp_value.NewArrayValue(fieldValues),
81+
})
82+
}

0 commit comments

Comments
 (0)