Skip to content
This repository was archived by the owner on Apr 2, 2021. It is now read-only.

Commit 6585325

Browse files
chyrockasvith
authored andcommittedAug 27, 2018
add resp3 protocol part 4(protocol-string and render-string) (#82)
1 parent 91f7cd8 commit 6585325

File tree

2 files changed

+183
-59
lines changed

2 files changed

+183
-59
lines changed
 

‎internal/protcl/resp3.go

+48-4
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,55 @@ type Resp3 struct {
3939
Elems []*Resp3
4040
}
4141

42-
func (r *Resp3) String() string {
43-
return r.string("")
42+
// RenderString convert resp3 to show-message on client
43+
func (r *Resp3) RenderString() string {
44+
return r.renderString("")
4445
}
4546

46-
func (r *Resp3) string(pre string) string {
47+
// ProtocolString convert resp3 to protocol raw string
48+
func (r *Resp3) ProtocolString() string {
49+
buf := new(strings.Builder)
50+
buf.WriteByte(r.Type)
51+
r.protocolString(buf)
52+
return buf.String()
53+
}
54+
55+
func (r *Resp3) protocolString(buf *strings.Builder) {
56+
switch r.Type {
57+
case RepSimpleString, Resp3SimpleError:
58+
buf.WriteString(r.Str)
59+
case Resp3BlobString, Resp3BolbError:
60+
buf.WriteString(strconv.Itoa(len(r.Str)))
61+
buf.WriteByte('\n')
62+
buf.WriteString(r.Str)
63+
case Resp3Number:
64+
buf.WriteString(strconv.Itoa(r.Integer))
65+
case Resp3Double:
66+
buf.WriteString(strconv.FormatFloat(r.Double, 'f', -1, 64))
67+
case Resp3BigNumber:
68+
buf.WriteString(r.BigInt.String())
69+
case Resp3Null:
70+
case Resp3Boolean:
71+
if r.Boolean {
72+
buf.WriteByte('t')
73+
} else {
74+
buf.WriteByte('f')
75+
}
76+
case Resp3Array, Resp3Set:
77+
buf.WriteString(strconv.Itoa(len(r.Elems)))
78+
buf.WriteByte('\n')
79+
80+
for _, v := range r.Elems {
81+
buf.WriteByte(v.Type)
82+
v.protocolString(buf)
83+
}
84+
return
85+
}
86+
87+
buf.WriteByte('\n')
88+
}
89+
90+
func (r *Resp3) renderString(pre string) string {
4791
switch r.Type {
4892
case RepSimpleString, Resp3BlobString:
4993
return fmt.Sprintf("%s%q", pre, r.Str)
@@ -72,7 +116,7 @@ func (r *Resp3) string(pre string) string {
72116
}
73117
for _, elem := range r.Elems {
74118
str.WriteString("\n")
75-
str.WriteString(elem.string(pre + "\t"))
119+
str.WriteString(elem.renderString(pre + "\t"))
76120
}
77121
return str.String()
78122
}

‎internal/protcl/resp3_test.go

+135-55
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package protcl
22

33
import (
44
"bufio"
5+
"math/big"
56
"strings"
67
"testing"
78

@@ -14,7 +15,7 @@ func testResp3Parser(t *testing.T, input, expect string) {
1415
parser := NewResp3Parser(bufio.NewReader(strings.NewReader(input)))
1516
result, err := parser.Parse()
1617
assert.Nil(err)
17-
assert.Equal(expect, result.String())
18+
assert.Equal(expect, result.RenderString())
1819
}
1920

2021
func testResp3Error(t *testing.T, input, e string) {
@@ -27,59 +28,138 @@ func testResp3Error(t *testing.T, input, e string) {
2728
assert.Equal(e, err.Error())
2829
}
2930

31+
type TestResp3 struct {
32+
resp3 *Resp3
33+
protocol string
34+
render string
35+
err string
36+
}
37+
3038
func TestResp3Parser(t *testing.T) {
31-
// simple string
32-
testResp3Error(t, "+string", `EOF`)
33-
testResp3Parser(t, "+string\n", `"string"`)
34-
35-
// blob string
36-
testResp3Parser(t, "$0\n\n", `""`)
37-
testResp3Error(t, "$1\n\n", `unexpected line end`)
38-
testResp3Error(t, "$1\naa\n", `unexpected line end`)
39-
testResp3Parser(t, "$10\n1234567890\n", `"1234567890"`)
40-
41-
// simple error
42-
testResp3Parser(t, "-error\n", `(error) error`)
43-
testResp3Parser(t, "-Err error\n", `(error) Err error`)
44-
45-
// blob error
46-
testResp3Parser(t, "!3\nerr\n", `(error) err`)
47-
testResp3Parser(t, "!17\nErr this is error\n", `(error) Err this is error`)
48-
49-
// number
50-
testResp3Parser(t, ":-1\n", `(integer) -1`)
51-
testResp3Parser(t, ":0\n", `(integer) 0`)
52-
testResp3Parser(t, ":100\n", `(integer) 100`)
53-
54-
// double
55-
testResp3Parser(t, ",-1\n", `(double) -1`)
56-
testResp3Parser(t, ",0\n", `(double) 0`)
57-
testResp3Parser(t, ",10\n", `(double) 10`)
58-
testResp3Parser(t, ",.1\n", `(double) 0.1`)
59-
testResp3Parser(t, ",1.23\n", `(double) 1.23`)
60-
testResp3Parser(t, ",1.\n", `(double) 1`)
61-
testResp3Error(t, ",invalid\n", `convert invalid to double fail, because of strconv.ParseFloat: parsing "invalid": invalid syntax`)
62-
63-
// big number
64-
testResp3Parser(t, "(3492890328409238509324850943850943825024385\n", `(big number) 3492890328409238509324850943850943825024385`)
65-
testResp3Error(t, "(invalid string\n", `convert invalid string to Big Number fail`)
66-
67-
// null
68-
testResp3Parser(t, "_\n", "(null)")
69-
70-
// boolean
71-
testResp3Parser(t, "#t\n", `(boolean) true`)
72-
testResp3Parser(t, "#f\n", `(boolean) false`)
73-
testResp3Error(t, "#x\n", `unexpect string: t/f`)
74-
testResp3Error(t, "#\n", `unexpected line end`)
75-
76-
// array
77-
testResp3Error(t, "*3\n:1\n:2\n", "EOF")
78-
testResp3Parser(t, "*3\n:1\n:2\n:3\n", "(array)\n\t(integer) 1\n\t(integer) 2\n\t(integer) 3")
79-
testResp3Parser(t, "*2\n*3\n:1\n$5\nhello\n:2\n#f\n", "(array)\n\t(array)\n\t\t(integer) 1\n\t\t\"hello\"\n\t\t(integer) 2\n\t(boolean) false")
80-
81-
// set
82-
testResp3Error(t, "~3\n:1\n:2\n", "EOF")
83-
testResp3Parser(t, "~3\n:1\n:2\n:3\n", "(set)\n\t(integer) 1\n\t(integer) 2\n\t(integer) 3")
84-
testResp3Parser(t, "~2\n*3\n:1\n$5\nhello\n:2\n#f\n", "(set)\n\t(array)\n\t\t(integer) 1\n\t\t\"hello\"\n\t\t(integer) 2\n\t(boolean) false")
39+
assert := testifyAssert.New(t)
40+
41+
bigNumber, _ := big.NewInt(0).SetString("3492890328409238509324850943850943825024385", 10)
42+
testCases := []TestResp3{
43+
// simple renderString
44+
{protocol: "+renderString", err: "EOF"},
45+
{resp3: &Resp3{Type: Resp3SimpleString, Str: ""}, protocol: "+\n", render: `""`},
46+
{resp3: &Resp3{Type: Resp3SimpleString, Str: "hello"}, protocol: "+hello\n", render: `"hello"`},
47+
{resp3: &Resp3{Type: Resp3SimpleString, Str: "hello world"}, protocol: "+hello world\n", render: `"hello world"`},
48+
49+
// blob renderString
50+
{protocol: "$1\n\n", err: "unexpected line end"},
51+
{protocol: "$1\naa\n", err: "unexpected line end"},
52+
{resp3: &Resp3{Type: Resp3BlobString, Str: ""}, protocol: "$0\n\n", render: `""`},
53+
{resp3: &Resp3{Type: Resp3BlobString, Str: "hello"}, protocol: "$5\nhello\n", render: `"hello"`},
54+
{resp3: &Resp3{Type: Resp3BlobString, Str: "hello\nworld"}, protocol: "$11\nhello\nworld\n", render: "\"hello\\nworld\""},
55+
56+
// simple error
57+
{protocol: "-renderString", err: "EOF"},
58+
{resp3: &Resp3{Type: Resp3SimpleError, Str: ""}, protocol: "-\n", render: `(error) `},
59+
{resp3: &Resp3{Type: Resp3SimpleError, Str: "hello"}, protocol: "-hello\n", render: `(error) hello`},
60+
{resp3: &Resp3{Type: Resp3SimpleError, Str: "hello world"}, protocol: "-hello world\n", render: `(error) hello world`},
61+
62+
// blob error
63+
{protocol: "!1\n\n", err: "unexpected line end"},
64+
{protocol: "!1\naa\n", err: "unexpected line end"},
65+
{resp3: &Resp3{Type: Resp3BolbError, Str: ""}, protocol: "!0\n\n", render: `(error) `},
66+
{resp3: &Resp3{Type: Resp3BolbError, Str: "hello"}, protocol: "!5\nhello\n", render: `(error) hello`},
67+
{resp3: &Resp3{Type: Resp3BolbError, Str: "hello\nworld"}, protocol: "!11\nhello\nworld\n", render: "(error) hello\nworld"},
68+
69+
// number
70+
{protocol: ":invalid", err: "EOF"},
71+
{protocol: ":invalid\n", err: "ERR: error casting invalid to int"},
72+
{resp3: &Resp3{Type: Resp3Number, Integer: -1}, protocol: ":-1\n", render: `(integer) -1`},
73+
{resp3: &Resp3{Type: Resp3Number, Integer: 0}, protocol: ":0\n", render: `(integer) 0`},
74+
{resp3: &Resp3{Type: Resp3Number, Integer: 100}, protocol: ":100\n", render: `(integer) 100`},
75+
76+
// double
77+
{protocol: ",invalid", err: "EOF"},
78+
{protocol: ",invalid\n", err: "convert invalid to double fail, because of strconv.ParseFloat: parsing \"invalid\": invalid syntax"},
79+
{resp3: &Resp3{Type: Resp3Double, Double: -1}, protocol: ",-1\n", render: "(double) -1"},
80+
{resp3: &Resp3{Type: Resp3Double, Double: 0}, protocol: ",0\n", render: "(double) 0"},
81+
{resp3: &Resp3{Type: Resp3Double, Double: 10}, protocol: ",10\n", render: "(double) 10"},
82+
{resp3: &Resp3{Type: Resp3Double, Double: 1.23}, protocol: ",1.23\n", render: "(double) 1.23"},
83+
{protocol: ",.1\n", render: "(double) 0.1"},
84+
{protocol: ",1.\n", render: "(double) 1"},
85+
86+
// big number
87+
{protocol: "(invalid", err: "EOF"},
88+
{protocol: "(invalid\n", err: "convert invalid to Big Number fail"},
89+
{resp3: &Resp3{Type: Resp3BigNumber, BigInt: bigNumber}, protocol: "(3492890328409238509324850943850943825024385\n", render: "(big number) 3492890328409238509324850943850943825024385"},
90+
91+
// null
92+
{protocol: "_invalid", err: "unexpect string: <LF>"},
93+
{protocol: "_invalid\n", err: "unexpect string: <LF>"},
94+
{resp3: &Resp3{Type: Resp3Null}, protocol: "_\n", render: "(null)"},
95+
96+
// boolean
97+
{protocol: "#", err: "EOF"},
98+
{protocol: "#\n", err: "unexpected line end"},
99+
{protocol: "#x\n", err: "unexpect string: t/f"},
100+
{protocol: "#invalid", err: "unexpected line end"},
101+
{protocol: "#invalid\n", err: "unexpected line end"},
102+
{resp3: &Resp3{Type: Resp3Boolean, Boolean: true}, protocol: "#t\n", render: "(boolean) true"},
103+
{resp3: &Resp3{Type: Resp3Boolean, Boolean: false}, protocol: "#f\n", render: "(boolean) false"},
104+
105+
// array
106+
{protocol: "*", err: "EOF"},
107+
{protocol: "*\n", err: "ERR: error casting to int"},
108+
{protocol: "*invalid", err: "EOF"},
109+
{protocol: "*invalid\n", err: "ERR: error casting invalid to int"},
110+
{protocol: "*1\n\n", err: "unknown protocol type: \n"},
111+
{protocol: "*1\ninvalid\n", err: "unknown protocol type: i"},
112+
{protocol: "*3\n:1\n:2\n", err: "EOF"},
113+
{resp3: &Resp3{Type: Resp3Array, Elems: []*Resp3{
114+
{Type: Resp3Number, Integer: 1},
115+
{Type: Resp3Number, Integer: 2},
116+
{Type: Resp3Number, Integer: 3},
117+
}}, protocol: "*3\n:1\n:2\n:3\n", render: "(array)\n\t(integer) 1\n\t(integer) 2\n\t(integer) 3"},
118+
{resp3: &Resp3{Type: Resp3Array, Elems: []*Resp3{
119+
{Type: Resp3Array, Elems: []*Resp3{
120+
{Type: Resp3Number, Integer: 1},
121+
{Type: Resp3BlobString, Str: "hello"},
122+
{Type: Resp3Number, Integer: 2},
123+
}},
124+
{Type: Resp3Boolean, Boolean: false},
125+
}}, protocol: "*2\n*3\n:1\n$5\nhello\n:2\n#f\n", render: "(array)\n\t(array)\n\t\t(integer) 1\n\t\t\"hello\"\n\t\t(integer) 2\n\t(boolean) false"},
126+
127+
// set
128+
{protocol: "~", err: "EOF"},
129+
{protocol: "~\n", err: "ERR: error casting to int"},
130+
{protocol: "~invalid", err: "EOF"},
131+
{protocol: "~invalid\n", err: "ERR: error casting invalid to int"},
132+
{protocol: "~1\n\n", err: "unknown protocol type: \n"},
133+
{protocol: "~1\ninvalid\n", err: "unknown protocol type: i"},
134+
{protocol: "~3\n:1\n:2\n", err: "EOF"},
135+
{resp3: &Resp3{Type: Resp3Set, Elems: []*Resp3{
136+
{Type: Resp3Number, Integer: 1},
137+
{Type: Resp3Number, Integer: 2},
138+
{Type: Resp3Number, Integer: 3},
139+
}}, protocol: "~3\n:1\n:2\n:3\n", render: "(set)\n\t(integer) 1\n\t(integer) 2\n\t(integer) 3"},
140+
{resp3: &Resp3{Type: Resp3Set, Elems: []*Resp3{
141+
{Type: Resp3Array, Elems: []*Resp3{
142+
{Type: Resp3Number, Integer: 1},
143+
{Type: Resp3BlobString, Str: "hello"},
144+
{Type: Resp3Number, Integer: 2},
145+
}},
146+
{Type: Resp3Boolean, Boolean: false},
147+
}}, protocol: "~2\n*3\n:1\n$5\nhello\n:2\n#f\n", render: "(set)\n\t(array)\n\t\t(integer) 1\n\t\t\"hello\"\n\t\t(integer) 2\n\t(boolean) false"},
148+
}
149+
150+
for _, testCase := range testCases {
151+
if testCase.resp3 == nil {
152+
if testCase.render != "" {
153+
// protocol renderString -> render renderString
154+
testResp3Parser(t, testCase.protocol, testCase.render)
155+
} else {
156+
// err test
157+
testResp3Error(t, testCase.protocol, testCase.err)
158+
}
159+
} else {
160+
// resp3 -> protocol renderString -> render renderString
161+
assert.Equal(testCase.protocol, testCase.resp3.ProtocolString())
162+
testResp3Parser(t, testCase.protocol, testCase.render)
163+
}
164+
}
85165
}

0 commit comments

Comments
 (0)
This repository has been archived.