Commit 2c359fc1 authored by Kirill Smelkov's avatar Kirill Smelkov Committed by Kamil Kisiel

decoder: Remember protocol version as last seen in a PROTO opcode

In the next patch decoding a pickle will depend on whether current
protocol is <= 2 or >= 3. For this let's teach PROTO opcode handler to
recall last seen protocol version.

For testing - prepare tests infrastructure for cases where protocol
version affects decoding semantic: if a test pickle in tests table comes
with \x80\xff prefix, on decode tests this prefix will be changed to
concrete

	\x80 ver

with all versions protperly iterated as specified in TestPickle.protov.

We will also need this functionality in the next patch.
parent 514123d4
......@@ -142,6 +142,9 @@ type Decoder struct {
// reusable buffer for readLine
line []byte
// protocol version seen in last PROTO opcode; 0 by default.
protocol int
}
// DecoderConfig allows to tune Decoder.
......@@ -170,10 +173,11 @@ func NewDecoder(r io.Reader) *Decoder {
func NewDecoderWithConfig(r io.Reader, config *DecoderConfig) *Decoder {
reader := bufio.NewReader(r)
return &Decoder{
r: reader,
config: config,
stack: make([]interface{}, 0),
memo: make(map[string]interface{}),
r: reader,
config: config,
stack: make([]interface{}, 0),
memo: make(map[string]interface{}),
protocol: 0,
}
}
......@@ -311,6 +315,9 @@ loop:
// So we allow all supported versions as PROTO argument.
err = ErrInvalidPickleVersion
}
if err == nil {
d.protocol = int(v)
}
default:
return nil, OpcodeError{key, insn}
......
......@@ -9,6 +9,7 @@ import (
"math/big"
"reflect"
"strconv"
"strings"
"testing"
)
......@@ -61,7 +62,12 @@ const longLine = "28,34,30,55,100,130,87,169,194,202,232,252,267,274,286,315,308
// data. However the test data can still be used to feed ogórek decoder.
type TestPickle struct {
protov []int
data string // without `PROTO <ver>` prefix
// pickle data without `PROTO <ver>` prefix.
// optionally the prefix template (\x80\xff) could be given for cases
// where initial `PROTO <ver>` presence affects decoding semantic.
data string
err error // !nil if encoding should fail
}
......@@ -385,6 +391,11 @@ type foo struct {
Bar int32
}
// if test pickle starts from protoPrefixTemplate, this prefix is changed to
// concrete `PROTO ver` when checking decoding. When checking encoding the
// protocol prefix is always automatically prepended and is always concrete.
var protoPrefixTemplate = string([]byte{opProto, 0xff})
// TestDecode verifies ogórek decoder.
func TestDecode(t *testing.T) {
for _, test := range tests {
......@@ -393,9 +404,22 @@ func TestDecode(t *testing.T) {
continue
}
t.Run(fmt.Sprintf("%s/%q", test.name, pickle.data), func(t *testing.T) {
testDecode(t, test.objectOut, pickle.data)
})
if strings.HasPrefix(pickle.data, protoPrefixTemplate) {
// test case asked to have concrete `PROTO ver` prefix.
// let's range over all pickle's protocols.
for _, proto := range pickle.protov {
data := string([]byte{opProto, byte(proto)}) +
pickle.data[len(protoPrefixTemplate):]
t.Run(fmt.Sprintf("%s/%q/proto=%d", test.name, data, proto), func(t *testing.T) {
testDecode(t, test.objectOut, data)
})
}
} else {
t.Run(fmt.Sprintf("%s/%q", test.name, pickle.data), func(t *testing.T) {
testDecode(t, test.objectOut, pickle.data)
})
}
}
}
}
......@@ -406,7 +430,7 @@ func TestEncode(t *testing.T) {
alreadyTested := make(map[int]bool) // protocols we tested encode with so far
for _, pickle := range test.picklev {
for _, proto := range pickle.protov {
dataOk := pickle.data
dataOk := strings.TrimPrefix(pickle.data, protoPrefixTemplate)
// protocols >= 2 must include "PROTO <ver>" prefix
if proto >= 2 && pickle.err == nil {
dataOk = string([]byte{opProto, byte(proto)}) + dataOk
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment