File: eredis_parser_tests.erl

package info (click to toggle)
erlang-redis-client 1.2.0-8
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 244 kB
  • sloc: erlang: 1,568; makefile: 46
file content (325 lines) | stat: -rw-r--r-- 19,744 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
%%
%% Parser tests. In particular tests for partial responses. This would
%% probably be a very good candidate for testing with quickcheck or
%% properl.
%%

-module(eredis_parser_tests).

-include("eredis.hrl").
-include_lib("eunit/include/eunit.hrl").

-import(eredis_parser, [parse/2, init/0, parse_bulk/1, parse_bulk/2,
                        parse_multibulk/1, parse_multibulk/2, buffer_create/0, buffer_create/1]).


% parse a binary one byte at a time
one_byte_parse(B) ->
    one_byte_parse(init(), B).

one_byte_parse(S, <<>>) ->
    parse(S, <<>>);
one_byte_parse(S, <<Byte>>) ->
    parse(S, <<Byte>>);
one_byte_parse(S, <<Byte, B/binary>>) ->
    case parse(S, <<Byte>>) of
        {continue, NewState} ->
            one_byte_parse(NewState, B);
        {ok, Value, Rest, NewState} ->
            {ok, Value, <<Rest/binary, B/binary>>, NewState};
        {error, Err, Rest, NewState} ->
            {error, Err, <<Rest/binary, B/binary>>, NewState};
        Other ->
            Other
    end.


parse_bulk_test() ->
    B = <<"$3\r\nbar\r\n">>,
    ?assertEqual({ok, <<"bar">>, #pstate{}}, parse(#pstate{}, B)).

parse_split_bulk_test() ->
    State1 = init(),
    B1 = <<"$3\r\n">>,
    B2 = <<"bar\r\n">>,

    {continue, State2} = parse(State1, B1),
    Buffer = buffer_create(<<"\r\n">>),
    ?assertEqual(#pstate{state = bulk_continue, continuation_data = {3, Buffer}},
                 State2),

    ?assertMatch({ok, <<"bar">>, _}, parse(State2, B2)).


parse_very_split_bulk_test() ->
    State1 = init(),
    B1 = <<"$1">>,
    B2 = <<"3\r\n">>,
    B3 = <<"foobarbazquux\r\n">>, %% 13 bytes

    Buffer1 = buffer_create(<<"$1">>),
    ?assertEqual({continue,
                  #pstate{state = bulk_continue,
                          continuation_data = {incomplete_size, Buffer1}}},
                 parse(State1, B1)),
    {continue, State2} = parse(State1, B1),

    Buffer2 = buffer_create(<<"\r\n">>),
    ?assertEqual({continue,
                  #pstate{state = bulk_continue,
                          continuation_data = {13, Buffer2}}},
                 parse(State2, B2)),
    {continue, State3} = parse(State2, B2),

    ?assertMatch({ok, <<"foobarbazquux">>, _}, parse(State3, B3)).


too_much_data_test() ->
    B = <<"$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n">>,
    ?assertEqual({ok, <<"1">>, <<"$1\r\n2\r\n$1\r\n3\r\n">>}, parse_bulk(B)).

too_much_data_in_continuation_test() ->
    B1 = <<"$1\r\n">>,
    B2 = <<"1\r\n$1\r\n2\r\n$1\r\n3\r\n">>,

    Buffer = buffer_create(<<"\r\n">>),
    ?assertEqual({continue, {1, Buffer}}, parse_bulk(B1)),
    {continue, ContinuationData1} = parse_bulk(B1),

    ?assertEqual({ok, <<"1">>, <<"$1\r\n2\r\n$1\r\n3\r\n">>},
                 parse_bulk(ContinuationData1, B2)).

bulk_test_() ->
    B = <<"$3\r\nbar\r\n">>,
    ?_assertEqual({ok, <<"bar">>, <<>>}, parse_bulk(B)).

bulk_split_test() ->
    B1 = <<"$3\r\n">>,
    B2 = <<"bar\r\n">>,

    Buffer = buffer_create(<<"\r\n">>),
    ?assertEqual({continue, {3, Buffer}}, parse_bulk(B1)),
    {continue, Res} = parse_bulk(B1),
    ?assertEqual({ok, <<"bar">>, <<>>}, parse_bulk(Res, B2)).

bulk_very_split_test() ->
    B1 = <<"$1">>,
    B2 = <<"3\r\n">>,
    B3 = <<"foobarbazquux\r\n">>, %% 13 bytes

    Buffer1 = buffer_create(<<"$1">>),
    ?assertEqual({continue, {incomplete_size, Buffer1}}, parse_bulk(B1)),
    {continue, ContinuationData1} = parse_bulk(B1),

    Buffer2 = buffer_create(<<"\r\n">>),
    ?assertEqual({continue, {13, Buffer2}}, parse_bulk(ContinuationData1, B2)),
    {continue, ContinuationData2} = parse_bulk(ContinuationData1, B2),

    ?assertEqual({ok, <<"foobarbazquux">>, <<>>}, parse_bulk(ContinuationData2, B3)).

bulk_split_on_newline_test() ->
    B1 = <<"$13\r\nfoobarbazquux">>,
    B2 = <<"\r\n">>, %% 13 bytes

    Buffer = buffer_create(<<"\r\nfoobarbazquux">>),
    ?assertEqual({continue, {13, Buffer}}, parse_bulk(B1)),
    {continue, ContinuationData1} = parse_bulk(B1),
    ?assertEqual({ok, <<"foobarbazquux">>, <<>>}, parse_bulk(ContinuationData1, B2)).


bulk_nil_test() ->
    B = <<"$-1\r\n">>,
    ?assertEqual({ok, undefined, init()}, parse(init(), B)).

bulk_nil_chunked_test() ->
    State1 = init(),
    B1 = <<"$-1">>,
    B2 = <<"\r\n">>,
    Buffer = buffer_create(<<"$-1">>),
    ?assertEqual({continue, #pstate{state = bulk_continue,
                                    continuation_data = {incomplete_size,Buffer}}},
                 parse(State1, B1)),

    {continue, State2} = parse(State1, B1),

    ?assertEqual({ok, undefined, init()}, parse(State2, B2)).

bulk_nil_with_extra_test() ->
    B = <<"$-1\r\n$3\r\nfoo\r\n">>,
    ?assertEqual({ok, undefined, <<"$3\r\nfoo\r\n">>, init()}, parse(init(), B)).

bulk_crap_test() ->
    B = <<"\r\n">>,
    ?assertEqual({error, unknown_response}, parse(init(), B)).




multibulk_test() ->
    %% [{1, 1}, {2, 2}, {3, 3}]
    B = <<"*3\r\n$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n">>,
    ?assertEqual({ok, [<<"1">>, <<"2">>, <<"3">>], <<>>}, parse_multibulk(B)).

multibulk_parse_test() ->
    %% [{1, 1}, {2, 2}, {3, 3}]
    B = <<"*3\r\n$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n">>,
    ?assertEqual({ok, [<<"1">>, <<"2">>, <<"3">>], #pstate{}}, parse(init(), B)).

multibulk_one_byte_parse_test() ->
    %% [{1, 1}, {2, 2}, {3, 3}]
    B = <<"*3\r\n$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n">>,
    ?assertEqual({ok, [<<"1">>, <<"2">>, <<"3">>], #pstate{}},
                 one_byte_parse(B)).

nested_multibulk_test() ->
    %% [[1, 2], [3, 4]]
    B = <<"*2\r\n*2\r\n$1\r\n1\r\n$1\r\n2\r\n*2\r\n$1\r\n3\r\n$1\r\n4\r\n">>,
    ?assertEqual({ok, [[<<"1">>, <<"2">>], [<<"3">>, <<"4">>]], <<>>},
                 parse_multibulk(B)).

nested_multibulk_parse_test() ->
    %% [[1, 2], [3, 4]]
    B = <<"*2\r\n*2\r\n$1\r\n1\r\n$1\r\n2\r\n*2\r\n$1\r\n3\r\n$1\r\n4\r\n">>,
    ?assertEqual({ok, [[<<"1">>, <<"2">>], [<<"3">>, <<"4">>]], #pstate{}},
                 parse(init(), B)).

nested_multibulk_one_byte_parse_test() ->
    %% [[1, 2], [3, 4]]
    B = <<"*2\r\n*2\r\n$1\r\n1\r\n$1\r\n2\r\n*2\r\n$1\r\n3\r\n$1\r\n4\r\n">>,
    ?assertEqual({ok, [[<<"1">>, <<"2">>], [<<"3">>, <<"4">>]], #pstate{}},
                 one_byte_parse(B)).

multibulk_split_parse_test() ->
    %% [{1, 1}, {2, 2}, {3, 3}]
    B1 = <<"*3\r\n$1\r\n1\r\n$1">>,
    B2 = <<"\r\n2\r\n$1\r\n3\r\n">>,

    State1 = init(),

    Buffer = buffer_create(<<"$1">>),
    ?assertEqual({continue,
                  #pstate{state = multibulk_continue,
                          continuation_data =
                              {in_parsing_bulks,2,Buffer,[<<"1">>]}}},
                 parse(State1, B1)),

    {continue, State2} = parse(State1, B1),

    ?assertMatch({ok, [<<"1">>, <<"2">>, <<"3">>], _}, parse(State2, B2)).

multibulk_split_test() ->
    %% Split into 2 parts: <<"*3\r\n$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n">>
    B1 = <<"*3\r\n$1\r\n1\r\n$1">>,
    B2 = <<"\r\n2\r\n$1\r\n3\r\n">>,

    {continue, ContinuationData1} = parse_multibulk(B1),
    Result = parse_multibulk(ContinuationData1, B2),
    ?assertEqual({ok, [<<"1">>, <<"2">>, <<"3">>], <<>>}, Result).

multibulk_very_split_test() ->
    %% Split into 4 parts: <<"*3\r\n$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n">>
    B1 = <<"*">>,
    B2 = <<"3\r\n$1\r">>,
    B3 = <<"\n1\r\n$1\r\n2\r\n$1">>,
    B4 = <<"\r\n3\r\n">>,

    Buffer = buffer_create(<<"*">>),
    ?assertEqual({continue, {incomplete_size, Buffer}}, parse_multibulk(B1)),
    {continue, ContinuationData1} = parse_multibulk(B1),
    {continue, ContinuationData2} = parse_multibulk(ContinuationData1, B2),
    {continue, ContinuationData3} = parse_multibulk(ContinuationData2, B3),

    Result = parse_multibulk(ContinuationData3, B4),
    ?assertEqual({ok, [<<"1">>, <<"2">>, <<"3">>], <<>>}, Result).

multibulk_newline_split_test() ->
    %% Split into 4 parts: <<"*3\r\n$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n">>
    B1 = <<"*2\r\n$1\r\n1">>,
    B2 = <<"\r\n$1\r\n2\r\n">>,
    Buffer = buffer_create(<<"$1\r\n1">>),
    ?assertEqual({continue, {in_parsing_bulks, 2, Buffer, []}},
                 parse_multibulk(B1)),

    {continue, ContinuationData1} = parse_multibulk(B1),

    ?assertEqual({ok, [<<"1">>, <<"2">>], <<>>}, parse_multibulk(ContinuationData1, B2)).

multibulk_nil_test() ->
    B = <<"*-1\r\n">>,
    ?assertEqual({ok, undefined, <<>>}, parse_multibulk(B)).

multibulk_nil_parse_test() ->
    B = <<"*-1\r\n">>,
    ?assertEqual({ok, undefined, #pstate{}}, parse(init(), B)).

big_chunks_test() ->
    %% Real-world example, MGET 1..200
    B1 = <<"*200\r\n$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n$1\r\n4\r\n$1\r\n5\r\n$1\r\n6\r\n$1\r\n7\r\n$1\r\n8\r\n$1\r\n9\r\n$2\r\n10\r\n$2\r\n11\r\n$2\r\n12\r\n$2\r\n13\r\n$2\r\n14\r\n$2\r\n15\r\n$2\r\n16\r\n$2\r\n17\r\n$2\r\n18\r\n$2\r\n19\r\n$2\r\n20\r\n$2\r\n21\r\n$2\r\n22\r\n$2\r\n23\r\n$2\r\n24\r\n$2\r\n25\r\n$2\r\n26\r\n$2\r\n27\r\n$2\r\n28\r\n$2\r\n29\r\n$2\r\n30\r\n$2\r\n31\r\n$2\r\n32\r\n$2\r\n33\r\n$2\r\n34\r\n$2\r\n35\r\n$2\r\n36\r\n$2\r\n37\r\n$2\r\n38\r\n$2\r\n39\r\n$2\r\n40\r\n$2\r\n41\r\n$2\r\n42\r\n$2\r\n43\r\n$2\r\n44\r\n$2\r\n45\r\n$2\r\n46\r\n$2\r\n47\r\n$2\r\n48\r\n$2\r\n49\r\n$2\r\n50\r\n$2\r\n51\r\n$2\r\n52\r\n$2\r\n53\r\n$2\r\n54\r\n$2\r\n55\r\n$2\r\n56\r\n$2\r\n57\r\n$2\r\n58\r\n$2\r\n59\r\n$2\r\n60\r\n$2\r\n61\r\n$2\r\n62\r\n$2\r\n63\r\n$2\r\n64\r\n$2\r\n65\r\n$2\r\n66\r\n$2\r\n67\r\n$2\r\n68\r\n$2\r\n69\r\n$2\r\n70\r\n$2\r\n71\r\n$2\r\n72\r\n$2\r\n73\r\n$2\r\n74\r\n$2\r\n75\r\n$2\r\n76\r\n$2\r\n77\r\n$2\r\n78\r\n$2\r\n79\r\n$2\r\n80\r\n$2\r\n81\r\n$2\r\n82\r\n$2\r\n83\r\n$2\r\n84\r\n$2\r\n85\r\n$2\r\n86\r\n$2\r\n87\r\n$2\r\n88\r\n$2\r\n89\r\n$2\r\n90\r\n$2\r\n91\r\n$2\r\n92\r\n$2\r\n93\r\n$2\r\n94\r\n$2\r\n95\r\n$2\r\n96\r\n$2\r\n97\r\n$2\r\n98\r\n$2\r\n99\r\n$3\r\n100\r\n$3\r\n101\r\n$3\r\n102\r\n$3\r\n103\r\n$3\r\n104\r\n$3\r\n105\r\n$3\r\n106\r\n$3\r\n107\r\n$3\r\n108\r\n$3\r\n109\r\n$3\r\n110\r\n$3\r\n111\r\n$3\r\n112\r\n$3\r\n113\r\n$3\r\n114\r\n$3\r\n115\r\n$3\r\n116\r\n$3\r\n117\r\n$3\r\n118\r\n$3\r\n119\r\n$3\r\n120\r\n$3\r\n121\r\n$3\r\n122\r\n$3\r\n123\r\n$3\r\n124\r\n$3\r\n125\r\n$3\r\n126\r\n$3\r\n127\r\n$3\r\n128\r\n$3\r\n129\r\n$3\r\n130\r\n$3\r\n131\r\n$3\r\n132\r\n$3\r\n133\r\n$3\r\n134\r\n$3\r\n135\r\n$3\r\n136\r\n$3\r\n137\r\n$3\r\n138\r\n$3\r\n139\r\n$3\r\n140\r\n$3\r\n141\r\n$3\r\n142\r\n$3\r\n143\r\n$3\r\n144\r\n$3\r\n145\r\n$3\r\n146\r\n$3\r\n147\r\n$3\r\n148\r\n$3\r\n149\r\n$3\r\n150\r\n$3\r\n151\r\n$3\r\n152\r\n$3\r\n153\r\n$3\r\n154\r\n$3\r\n155\r\n$3\r\n156\r\n$3\r\n157\r\n$3\r\n158\r\n$3\r\n159\r\n$3\r\n160\r\n$3\r\n161\r\n$3\r\n162\r\n$3\r\n163\r\n$3\r\n164\r\n$3\r\n165\r\n$3\r\n166\r\n$3\r\n167\r\n$3\r\n168\r\n$3\r\n169\r\n$3\r\n170\r\n$3\r\n171\r\n$3\r\n172\r\n$3\r\n173\r\n$3\r\n1">>,
    B2 = <<"74\r\n$3\r\n175\r\n$3\r\n176\r\n$3\r\n177\r\n$3\r\n178\r\n$3\r\n179\r\n$3\r\n180\r\n$3\r\n181\r\n$3\r\n182\r\n$3\r\n183\r\n$3\r\n184\r\n$3\r\n185\r\n$3\r\n186\r\n$3\r\n187\r\n$3\r\n188\r\n$3\r\n189\r\n$3\r\n190\r\n$3\r\n191\r\n$3\r\n192\r\n$3\r\n193\r\n$3\r\n194\r\n$3\r\n195\r\n$3\r\n196\r\n$3\r\n197\r\n$3\r\n198\r\n$3\r\n199\r\n$3\r\n200\r\n">>,
    ExpectedValues = [list_to_binary(integer_to_list(N)) || N <- lists:seq(1, 200)],
    State1 = init(),

    ?assertMatch({continue,
                  #pstate{state = multibulk_continue,
                          continuation_data = {in_parsing_bulks, 27, _, _}}},
                 parse(State1, B1)),
    {continue, State2} = parse(State1, B1),

    ?assertMatch({ok, ExpectedValues, #pstate{state = undefined,
                                              continuation_data = undefined}},
                 parse(State2, B2)).


chunk_test() ->
    B1 = <<"*500\r\n$1\r\n1\r\n$1\r\n2\r\n$1\r\n3\r\n$1\r\n4\r\n$1\r\n5\r\n$1\r\n6\r\n$1\r\n7\r\n$1\r\n8\r\n$1\r\n9\r\n$2\r\n10\r\n$2\r\n11\r\n$2\r\n12\r\n$2\r\n13\r\n$2\r\n14\r\n$2\r\n15\r\n$2\r\n16\r\n$2\r\n17\r\n$2\r\n18\r\n$2\r\n19\r\n$2\r\n20\r\n$2\r\n21\r\n$2\r\n22\r\n$2\r\n23\r\n$2\r\n24\r\n$2\r\n25\r\n$2\r\n26\r\n$2\r\n27\r\n$2\r\n28\r\n$2\r\n29\r\n$2\r\n30\r\n$2\r\n31\r\n$2\r\n32\r\n$2\r\n33\r\n$2\r\n34\r\n$2\r\n35\r\n$2\r\n36\r\n$2\r\n37\r\n$2\r\n38\r\n$2\r\n39\r\n$2\r\n40\r\n$2\r\n41\r\n$2\r\n42\r\n$2\r\n43\r\n$2\r\n44\r\n$2\r\n45\r\n$2\r\n46\r\n$2\r\n47\r\n$2\r\n48\r\n$2\r\n49\r\n$2\r\n50\r\n$2\r\n51\r\n$2\r\n52\r\n$2\r\n53\r\n$2\r\n54\r\n$2\r\n55\r\n$2\r\n56\r\n$2\r\n57\r\n$2\r\n58\r\n$2\r\n59\r\n$2\r\n60\r\n$2\r\n61\r\n$2\r\n62\r\n$2\r\n63\r\n$2\r\n64\r\n$2\r\n65\r\n$2\r\n66\r\n$2\r\n67\r\n$2\r\n68\r\n$2\r\n69\r\n$2\r\n70\r\n$2\r\n71\r\n$2\r\n72\r\n$2\r\n73\r\n$2\r\n74\r\n$2\r\n75\r\n$2\r\n76\r\n$2\r\n77\r\n$2\r\n78\r\n$2\r\n79\r\n$2\r\n80\r\n$2\r\n81\r\n$2\r\n82\r\n$2\r\n83\r\n$2\r\n84\r\n$2\r\n85\r\n$2\r\n86\r\n$2\r\n87\r\n$2\r\n88\r\n$2\r\n89\r\n$2\r\n90\r\n$2\r\n91\r\n$2\r\n92\r\n$2\r\n93\r\n$2\r\n94\r\n$2\r\n95\r\n$2\r\n96\r\n$2\r\n97\r\n$2\r\n98\r\n$2\r\n99\r\n$3\r\n100\r\n$3\r\n101\r\n$3\r\n102\r\n$3\r\n103\r\n$3\r\n104\r\n$3\r\n105\r\n$3\r\n106\r\n$3\r\n107\r\n$3\r\n108\r\n$3\r\n109\r\n$3\r\n110\r\n$3\r\n111\r\n$3\r\n112\r\n$3\r\n113\r\n$3\r\n114\r\n$3\r\n115\r\n$3\r\n116\r\n$3\r\n117\r\n$3\r\n118\r\n$3\r\n119\r\n$3\r\n120\r\n$3\r\n121\r\n$3\r\n122\r\n$3\r\n123\r\n$3\r\n124\r\n$3\r\n125\r\n$3\r\n126\r\n$3\r\n127\r\n$3\r\n128\r\n$3\r\n129\r\n$3\r\n130\r\n$3\r\n131\r\n$3\r\n132\r\n$3\r\n133\r\n$3\r\n134\r\n$3\r\n135\r\n$3\r\n136\r\n$3\r\n137\r\n$3\r\n138\r\n$3\r\n139\r\n$3\r\n140\r\n$3\r\n141\r\n$3\r\n142\r\n$3\r\n143\r\n$3\r\n144\r\n$3\r\n145\r\n$3\r\n146\r\n$3\r\n147\r\n$3\r\n148\r\n$3\r\n149\r\n$3\r\n150\r\n$3\r\n151\r\n$3\r\n152\r\n$3\r\n153\r\n$3\r\n154\r\n$3\r\n155\r\n$3\r\n156\r\n$3\r\n157\r\n$3\r\n158\r\n$3\r\n159\r\n$3\r\n160\r\n$3\r\n161\r\n$3\r\n162\r\n$3\r\n163\r\n$3\r\n164\r\n$3\r\n165\r\n$3\r\n166\r\n$3\r\n167\r\n$3\r\n168\r\n$3\r\n169\r\n$3\r\n170\r\n$3\r\n171\r\n$3\r\n172\r\n$3\r\n173\r\n$3\r\n1">>,
    B2 = <<"74\r\n$3\r\n175\r\n$3\r\n176\r\n$3\r\n177\r\n$3\r\n178\r\n$3\r\n179\r\n$3\r\n180\r\n$3\r\n181\r\n$3\r\n182\r\n$3\r\n183\r\n$3\r\n184\r\n$3\r\n185\r\n$3\r\n186\r\n$3\r\n187\r\n$3\r\n188\r\n$3\r\n189\r\n$3\r\n190\r\n$3\r\n191\r\n$3\r\n192\r\n$3\r\n193\r\n$3\r\n194\r\n$3\r\n195\r\n$3\r\n196\r\n$3\r\n197\r\n$3\r\n198\r\n$3\r\n199\r\n$3\r\n200\r\n$3\r\n201\r\n$3\r\n202\r\n$3\r\n203\r\n$3\r\n204\r\n$3\r\n205\r\n$3\r\n206\r\n$3\r\n207\r\n$3\r\n208\r\n$3\r\n209\r\n$3\r\n210\r\n$3\r\n211\r\n$3\r\n212\r\n$3\r\n213\r\n$3\r\n214\r\n$3\r\n215\r\n$3\r\n216\r\n$3\r\n217\r\n$3\r\n218\r\n$3\r\n219\r\n$3\r\n220\r\n$3\r\n221\r\n$3\r\n222\r\n$3\r\n223\r\n$3\r\n224\r\n$3\r\n225\r\n$3\r\n226\r\n$3\r\n227\r\n$3\r\n228\r\n$3\r\n229\r\n$3\r\n230\r\n$3\r\n231\r\n$3\r\n232\r\n$3\r\n233\r\n$3\r\n234\r\n$3\r\n235\r\n$3\r\n236\r\n$3\r\n237\r\n$3\r\n238\r\n$3\r\n239\r\n$3\r\n240\r\n$3\r\n241\r\n$3\r\n242\r\n$3\r\n243\r\n$3\r\n244\r\n$3\r\n245\r\n$3\r\n246\r\n$3\r\n247\r\n$3\r\n248\r\n$3\r\n249\r\n$3\r\n250\r\n$3\r\n251\r\n$3\r\n252\r\n$3\r\n253\r\n$3\r\n254\r\n$3\r\n255\r\n$3\r\n256\r\n$3\r\n257\r\n$3\r\n258\r\n$3\r\n259\r\n$3\r\n260\r\n$3\r\n261\r\n$3\r\n262\r\n$3\r\n263\r\n$3\r\n264\r\n$3\r\n265\r\n$3\r\n266\r\n$3\r\n267\r\n$3\r\n268\r\n$3\r\n269\r\n$3\r\n270\r\n$3\r\n271\r\n$3\r\n272\r\n$3\r\n273\r\n$3\r\n274\r\n$3\r\n275\r\n$3\r\n276\r\n$3\r\n277\r\n$3\r\n278\r\n$3\r\n279\r\n$3\r\n280\r\n$3\r\n281\r\n$3\r\n282\r\n$3\r\n283\r\n$3\r\n284\r\n$3\r\n285\r\n$3\r\n286\r\n$3\r\n287\r\n$3\r\n288\r\n$3\r\n289\r\n$3\r\n290\r\n$3\r\n291\r\n$3\r\n292\r\n$3\r\n293\r\n$3\r\n294\r\n$3\r\n295\r\n$3\r\n296\r\n$3\r\n297\r\n$3\r\n298\r\n$3\r\n299\r\n$3\r\n300\r\n$3\r\n301\r\n$3\r\n302\r\n$3\r\n303\r\n$3\r\n304\r\n$3\r\n305\r\n$3\r\n306\r\n$3\r\n307\r\n$3\r\n308\r\n$3\r\n309\r\n$3\r\n310\r\n$3\r\n311\r\n$3\r\n312\r\n$3\r\n313\r\n$3\r\n314\r\n$3\r\n315\r\n$3\r\n316\r\n$3\r\n317\r\n$3\r\n318\r\n$3\r\n319\r\n$3\r\n320\r\n$3\r\n321\r\n$3\r\n322\r\n$3\r\n323\r\n$3\r\n324\r\n$3\r\n325\r\n$3\r\n326\r\n$3\r\n327\r\n$3\r\n328\r\n$3\r\n329\r\n$3\r\n330\r\n$3\r\n331\r\n$3\r\n332\r\n$3\r\n333\r\n$3\r\n334\r\n$3\r\n335\r\n$3\r\n336">>,
    B3 = <<"\r\n$3\r\n337\r\n$3\r\n338\r\n$3\r\n339\r\n$3\r\n340\r\n$3\r\n341\r\n$3\r\n342\r\n$3\r\n343\r\n$3\r\n344\r\n$3\r\n345\r\n$3\r\n346\r\n$3\r\n347\r\n$3\r\n348\r\n$3\r\n349\r\n$3\r\n350\r\n$3\r\n351\r\n$3\r\n352\r\n$3\r\n353\r\n$3\r\n354\r\n$3\r\n355\r\n$3\r\n356\r\n$3\r\n357\r\n$3\r\n358\r\n$3\r\n359\r\n$3\r\n360\r\n$3\r\n361\r\n$3\r\n362\r\n$3\r\n363\r\n$3\r\n364\r\n$3\r\n365\r\n$3\r\n366\r\n$3\r\n367\r\n$3\r\n368\r\n$3\r\n369\r\n$3\r\n370\r\n$3\r\n371\r\n$3\r\n372\r\n$3\r\n373\r\n$3\r\n374\r\n$3\r\n375\r\n$3\r\n376\r\n$3\r\n377\r\n$3\r\n378\r\n$3\r\n379\r\n$3\r\n380\r\n$3\r\n381\r\n$3\r\n382\r\n$3\r\n383\r\n$3\r\n384\r\n$3\r\n385\r\n$3\r\n386\r\n$3\r\n387\r\n$3\r\n388\r\n$3\r\n389\r\n$3\r\n390\r\n$3\r\n391\r\n$3\r\n392\r\n$3\r\n393\r\n$3\r\n394\r\n$3\r\n395\r\n$3\r\n396\r\n$3\r\n397\r\n$3\r\n398\r\n$3\r\n399\r\n$3\r\n400\r\n$3\r\n401\r\n$3\r\n402\r\n$3\r\n403\r\n$3\r\n404\r\n$3\r\n405\r\n$3\r\n406\r\n$3\r\n407\r\n$3\r\n408\r\n$3\r\n409\r\n$3\r\n410\r\n$3\r\n411\r\n$3\r\n412\r\n$3\r\n413\r\n$3\r\n414\r\n$3\r\n415\r\n$3\r\n416\r\n$3\r\n417\r\n$3\r\n418\r\n$3\r\n419\r\n$3\r\n420\r\n$3\r\n421\r\n$3\r\n422\r\n$3\r\n423\r\n$3\r\n424\r\n$3\r\n425\r\n$3\r\n426\r\n$3\r\n427\r\n$3\r\n428\r\n$3\r\n429\r\n$3\r\n430\r\n$3\r\n431\r\n$3\r\n432\r\n$3\r\n433\r\n$3\r\n434\r\n$3\r\n435\r\n$3\r\n436\r\n$3\r\n437\r\n$3\r\n438\r\n$3\r\n439\r\n$3\r\n440\r\n$3\r\n441\r\n$3\r\n442\r\n$3\r\n443\r\n$3\r\n444\r\n$3\r\n445\r\n$3\r\n446\r\n$3\r\n447\r\n$3\r\n448\r\n$3\r\n449\r\n$3\r\n450\r\n$3\r\n451\r\n$3\r\n452\r\n$3\r\n453\r\n$3\r\n454\r\n$3\r\n455\r\n$3\r\n456\r\n$3\r\n457\r\n$3\r\n458\r\n$3\r\n459\r\n$3\r\n460\r\n$3\r\n461\r\n$3\r\n462\r\n$3\r\n463\r\n$3\r\n464\r\n$3\r\n465\r\n$3\r\n466\r\n$3\r\n467\r\n$3\r\n468\r\n$3\r\n469\r\n$3\r\n470\r\n$3\r\n471\r\n$3\r\n472\r\n$3\r\n473\r\n$3\r\n474\r\n$3\r\n475\r\n$3\r\n476\r\n$3\r\n477\r\n$3\r\n478\r\n$3\r\n479\r\n$3\r\n480\r\n$3\r\n481\r\n$3\r\n482\r\n$3\r\n483\r\n$3\r\n484\r\n$3\r\n485\r\n$3\r\n486\r\n$3\r\n487\r\n$3\r\n488\r\n$3\r\n489\r\n$3\r\n490\r\n$3\r\n491\r\n$3\r\n492\r\n$3\r\n493\r\n$3\r\n494\r\n$3\r\n495\r\n$3\r\n496\r\n$3\r\n497\r\n$3\r\n498\r\n">>,

    {continue, ContinuationData1} = parse_multibulk(B1),
    {continue, ContinuationData2} = parse_multibulk(ContinuationData1, B2),

    EmptyBuffer = buffer_create(),
    ?assertMatch({continue, {in_parsing_bulks, 2, EmptyBuffer, _}},
                 parse_multibulk(ContinuationData2, B3)).

%% @doc: Test a binary string which contains \r\n inside it's data
binary_safe_test() ->
    B = <<"$14\r\nfoobar\r\nbarbaz\r\n">>,
    ?assertEqual({ok, <<"foobar\r\nbarbaz">>, init()}, parse(init(), B)).


status_test() ->
    B = <<"+OK\r\n">>,
    ?assertEqual({ok, <<"OK">>, init()}, parse(init(), B)).

status_chunked_test() ->
    B1 = <<"+O">>,
    B2 = <<"K\r\n">>,
    State1 = init(),

    ?assertEqual({continue, #pstate{state = status_continue,
                                    continuation_data = {incomplete_simple, buffer_create(<<"O">>)}}},
                 parse(State1, B1)),
    {continue, State2} = parse(State1, B1),
    ?assertEqual({ok, <<"OK">>, init()}, parse(State2, B2)).

error_test() ->
    B = <<"-ERR wrong number of arguments for 'get' command\r\n">>,
    ?assertEqual({error, <<"ERR wrong number of arguments for 'get' command">>, init()},
                 parse(init(), B)).

integer_test() ->
    B = <<":2\r\n">>,
    ?assertEqual({ok, <<"2">>, init()}, parse(init(), B)).

integer_reply_inside_multibulk_test() ->
    B = <<"*2\r\n:1\r\n:1\r\n">>,
    ?assertEqual({ok, [<<"1">>, <<"1">>], init()}, parse(init(), B)).

status_inside_multibulk_test() ->
    B = <<"*2\r\n+OK\r\n:1\r\n">>,
    ?assertEqual({ok, [<<"OK">>, <<"1">>], init()}, parse(init(), B)).

error_inside_multibulk_test() ->
    B = <<"*2\r\n-ERR foobar\r\n:1\r\n">>,
    ?assertEqual({ok, [<<"ERR foobar">>, <<"1">>], init()}, parse(init(), B)).