nim-libp2p/tests/testminprotobuf.nim

678 lines
22 KiB
Nim

## Nim-Libp2p
## Copyright (c) 2018 Status Research & Development GmbH
## Licensed under either of
## * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
## * MIT license ([LICENSE-MIT](LICENSE-MIT))
## at your option.
## This file may not be copied, modified, or distributed except according to
## those terms.
import unittest
import ../libp2p/protobuf/minprotobuf
import stew/byteutils, strutils
when defined(nimHasUsed): {.used.}
suite "MinProtobuf test suite":
const VarintVectors = [
"0800", "0801", "08ffffffff07", "08ffffffff0f", "08ffffffffffffffff7f",
"08ffffffffffffffffff01"
]
const VarintValues = [
0x0'u64, 0x1'u64, 0x7FFF_FFFF'u64, 0xFFFF_FFFF'u64,
0x7FFF_FFFF_FFFF_FFFF'u64, 0xFFFF_FFFF_FFFF_FFFF'u64
]
const Fixed32Vectors = [
"0d00000000", "0d01000000", "0dffffff7f", "0dddccbbaa", "0dffffffff"
]
const Fixed32Values = [
0x0'u32, 0x1'u32, 0x7FFF_FFFF'u32, 0xAABB_CCDD'u32, 0xFFFF_FFFF'u32
]
const Fixed64Vectors = [
"090000000000000000", "090100000000000000", "09ffffff7f00000000",
"09ddccbbaa00000000", "09ffffffff00000000", "09ffffffffffffff7f",
"099988ffeeddccbbaa", "09ffffffffffffffff"
]
const Fixed64Values = [
0x0'u64, 0x1'u64, 0x7FFF_FFFF'u64, 0xAABB_CCDD'u64, 0xFFFF_FFFF'u64,
0x7FFF_FFFF_FFFF_FFFF'u64, 0xAABB_CCDD_EEFF_8899'u64,
0xFFFF_FFFF_FFFF_FFFF'u64
]
const LengthVectors = [
"0a00", "0a0161", "0a026162", "0a0461626364", "0a086162636465666768"
]
const LengthValues = [
"", "a", "ab", "abcd", "abcdefgh"
]
## This vector values was tested with `protoc` and related proto file.
## syntax = "proto2";
## message testmsg {
## repeated uint64 d = 1 [packed=true];
## repeated uint64 d = 2 [packed=true];
## }
const PackedVarintVector =
"0a1f0001ffffffff07ffffffff0fffffffffffffffff7fffffffffffffffffff0112020001"
## syntax = "proto2";
## message testmsg {
## repeated sfixed32 d = 1 [packed=true];
## repeated sfixed32 d = 2 [packed=true];
## }
const PackedFixed32Vector =
"0a140000000001000000ffffff7fddccbbaaffffffff12080000000001000000"
## syntax = "proto2";
## message testmsg {
## repeated sfixed64 d = 1 [packed=true];
## repeated sfixed64 d = 2 [packed=true];
## }
const PackedFixed64Vector =
"""0a4000000000000000000100000000000000ffffff7f00000000ddccbbaa00000000
ffffffff00000000ffffffffffffff7f9988ffeeddccbbaaffffffffffffffff1210
00000000000000000100000000000000"""
proc getVarintEncodedValue(value: uint64): seq[byte] =
var pb = initProtoBuffer()
pb.write(1, value)
pb.finish()
return pb.buffer
proc getVarintDecodedValue(data: openarray[byte]): uint64 =
var value: uint64
var pb = initProtoBuffer(data)
let res = pb.getField(1, value)
doAssert(res)
value
proc getFixed32EncodedValue(value: float32): seq[byte] =
var pb = initProtoBuffer()
pb.write(1, value)
pb.finish()
return pb.buffer
proc getFixed32DecodedValue(data: openarray[byte]): uint32 =
var value: float32
var pb = initProtoBuffer(data)
let res = pb.getField(1, value)
doAssert(res)
cast[uint32](value)
proc getFixed64EncodedValue(value: float64): seq[byte] =
var pb = initProtoBuffer()
pb.write(1, value)
pb.finish()
return pb.buffer
proc getFixed64DecodedValue(data: openarray[byte]): uint64 =
var value: float64
var pb = initProtoBuffer(data)
let res = pb.getField(1, value)
doAssert(res)
cast[uint64](value)
proc getLengthEncodedValue(value: string): seq[byte] =
var pb = initProtoBuffer()
pb.write(1, value)
pb.finish()
return pb.buffer
proc getLengthEncodedValue(value: seq[byte]): seq[byte] =
var pb = initProtoBuffer()
pb.write(1, value)
pb.finish()
return pb.buffer
proc getLengthDecodedValue(data: openarray[byte]): string =
var value = newString(len(data))
var valueLen = 0
var pb = initProtoBuffer(data)
let res = pb.getField(1, value, valueLen)
doAssert(res)
value.setLen(valueLen)
value
proc isFullZero[T: byte|char](data: openarray[T]): bool =
for ch in data:
if int(ch) != 0:
return false
return true
proc corruptHeader(data: var openarray[byte], index: int) =
var values = [3, 4, 6]
data[0] = data[0] and 0xF8'u8
data[0] = data[0] or byte(values[index mod len(values)])
test "[varint] edge values test":
for i in 0 ..< len(VarintValues):
let data = getVarintEncodedValue(VarintValues[i])
check:
toHex(data) == VarintVectors[i]
getVarintDecodedValue(data) == VarintValues[i]
test "[varint] mixing many values with same field number test":
for i in 0 ..< len(VarintValues):
var pb = initProtoBuffer()
for k in 0 ..< len(VarintValues):
let index = (i + k + 1) mod len(VarintValues)
pb.write(1, VarintValues[index])
pb.finish()
check getVarintDecodedValue(pb.buffer) == VarintValues[i]
test "[varint] incorrect values test":
for i in 0 ..< len(VarintValues):
var value: uint64
var data = getVarintEncodedValue(VarintValues[i])
# corrupting
data.setLen(len(data) - 1)
var pb = initProtoBuffer(data)
check:
pb.getField(1, value) == false
test "[varint] non-existent field test":
for i in 0 ..< len(VarintValues):
var value: uint64
var data = getVarintEncodedValue(VarintValues[i])
var pb = initProtoBuffer(data)
check:
pb.getField(2, value) == false
value == 0'u64
test "[varint] corrupted header test":
for i in 0 ..< len(VarintValues):
for k in 0 ..< 3:
var value: uint64
var data = getVarintEncodedValue(VarintValues[i])
data.corruptHeader(k)
var pb = initProtoBuffer(data)
check:
pb.getField(1, value) == false
test "[varint] empty buffer test":
var value: uint64
var pb = initProtoBuffer()
check:
pb.getField(1, value) == false
value == 0'u64
test "[varint] Repeated field test":
var pb1 = initProtoBuffer()
pb1.write(1, VarintValues[1])
pb1.write(1, VarintValues[2])
pb1.write(2, VarintValues[3])
pb1.write(1, VarintValues[4])
pb1.write(1, VarintValues[5])
pb1.finish()
var pb2 = initProtoBuffer(pb1.buffer)
var fieldarr1: seq[uint64]
var fieldarr2: seq[uint64]
var fieldarr3: seq[uint64]
let r1 = pb2.getRepeatedField(1, fieldarr1)
let r2 = pb2.getRepeatedField(2, fieldarr2)
let r3 = pb2.getRepeatedField(3, fieldarr3)
check:
r1 == true
r2 == true
r3 == false
len(fieldarr3) == 0
len(fieldarr2) == 1
len(fieldarr1) == 4
fieldarr1[0] == VarintValues[1]
fieldarr1[1] == VarintValues[2]
fieldarr1[2] == VarintValues[4]
fieldarr1[3] == VarintValues[5]
fieldarr2[0] == VarintValues[3]
test "[varint] Repeated packed field test":
var pb1 = initProtoBuffer()
pb1.writePacked(1, VarintValues)
pb1.writePacked(2, VarintValues[0 .. 1])
pb1.finish()
check:
toHex(pb1.buffer) == PackedVarintVector
var pb2 = initProtoBuffer(pb1.buffer)
var fieldarr1: seq[uint64]
var fieldarr2: seq[uint64]
var fieldarr3: seq[uint64]
let r1 = pb2.getPackedRepeatedField(1, fieldarr1)
let r2 = pb2.getPackedRepeatedField(2, fieldarr2)
let r3 = pb2.getPackedRepeatedField(3, fieldarr3)
check:
r1 == true
r2 == true
r3 == false
len(fieldarr3) == 0
len(fieldarr2) == 2
len(fieldarr1) == 6
fieldarr1[0] == VarintValues[0]
fieldarr1[1] == VarintValues[1]
fieldarr1[2] == VarintValues[2]
fieldarr1[3] == VarintValues[3]
fieldarr1[4] == VarintValues[4]
fieldarr1[5] == VarintValues[5]
fieldarr2[0] == VarintValues[0]
fieldarr2[1] == VarintValues[1]
test "[fixed32] edge values test":
for i in 0 ..< len(Fixed32Values):
let data = getFixed32EncodedValue(cast[float32](Fixed32Values[i]))
check:
toHex(data) == Fixed32Vectors[i]
getFixed32DecodedValue(data) == Fixed32Values[i]
test "[fixed32] mixing many values with same field number test":
for i in 0 ..< len(Fixed32Values):
var pb = initProtoBuffer()
for k in 0 ..< len(Fixed32Values):
let index = (i + k + 1) mod len(Fixed32Values)
pb.write(1, cast[float32](Fixed32Values[index]))
pb.finish()
check getFixed32DecodedValue(pb.buffer) == Fixed32Values[i]
test "[fixed32] incorrect values test":
for i in 0 ..< len(Fixed32Values):
var value: float32
var data = getFixed32EncodedValue(float32(Fixed32Values[i]))
# corrupting
data.setLen(len(data) - 1)
var pb = initProtoBuffer(data)
check:
pb.getField(1, value) == false
test "[fixed32] non-existent field test":
for i in 0 ..< len(Fixed32Values):
var value: float32
var data = getFixed32EncodedValue(float32(Fixed32Values[i]))
var pb = initProtoBuffer(data)
check:
pb.getField(2, value) == false
value == float32(0)
test "[fixed32] corrupted header test":
for i in 0 ..< len(Fixed32Values):
for k in 0 ..< 3:
var value: float32
var data = getFixed32EncodedValue(float32(Fixed32Values[i]))
data.corruptHeader(k)
var pb = initProtoBuffer(data)
check:
pb.getField(1, value) == false
test "[fixed32] empty buffer test":
var value: float32
var pb = initProtoBuffer()
check:
pb.getField(1, value) == false
value == float32(0)
test "[fixed32] Repeated field test":
var pb1 = initProtoBuffer()
pb1.write(1, cast[float32](Fixed32Values[0]))
pb1.write(1, cast[float32](Fixed32Values[1]))
pb1.write(2, cast[float32](Fixed32Values[2]))
pb1.write(1, cast[float32](Fixed32Values[3]))
pb1.write(1, cast[float32](Fixed32Values[4]))
pb1.finish()
var pb2 = initProtoBuffer(pb1.buffer)
var fieldarr1: seq[float32]
var fieldarr2: seq[float32]
var fieldarr3: seq[float32]
let r1 = pb2.getRepeatedField(1, fieldarr1)
let r2 = pb2.getRepeatedField(2, fieldarr2)
let r3 = pb2.getRepeatedField(3, fieldarr3)
check:
r1 == true
r2 == true
r3 == false
len(fieldarr3) == 0
len(fieldarr2) == 1
len(fieldarr1) == 4
cast[uint32](fieldarr1[0]) == Fixed64Values[0]
cast[uint32](fieldarr1[1]) == Fixed64Values[1]
cast[uint32](fieldarr1[2]) == Fixed64Values[3]
cast[uint32](fieldarr1[3]) == Fixed64Values[4]
cast[uint32](fieldarr2[0]) == Fixed64Values[2]
test "[fixed32] Repeated packed field test":
var pb1 = initProtoBuffer()
var values = newSeq[float32](len(Fixed32Values))
for i in 0 ..< len(values):
values[i] = cast[float32](Fixed32Values[i])
pb1.writePacked(1, values)
pb1.writePacked(2, values[0 .. 1])
pb1.finish()
check:
toHex(pb1.buffer) == PackedFixed32Vector
var pb2 = initProtoBuffer(pb1.buffer)
var fieldarr1: seq[float32]
var fieldarr2: seq[float32]
var fieldarr3: seq[float32]
let r1 = pb2.getPackedRepeatedField(1, fieldarr1)
let r2 = pb2.getPackedRepeatedField(2, fieldarr2)
let r3 = pb2.getPackedRepeatedField(3, fieldarr3)
check:
r1 == true
r2 == true
r3 == false
len(fieldarr3) == 0
len(fieldarr2) == 2
len(fieldarr1) == 5
cast[uint32](fieldarr1[0]) == Fixed32Values[0]
cast[uint32](fieldarr1[1]) == Fixed32Values[1]
cast[uint32](fieldarr1[2]) == Fixed32Values[2]
cast[uint32](fieldarr1[3]) == Fixed32Values[3]
cast[uint32](fieldarr1[4]) == Fixed32Values[4]
cast[uint32](fieldarr2[0]) == Fixed32Values[0]
cast[uint32](fieldarr2[1]) == Fixed32Values[1]
test "[fixed64] edge values test":
for i in 0 ..< len(Fixed64Values):
let data = getFixed64EncodedValue(cast[float64](Fixed64Values[i]))
check:
toHex(data) == Fixed64Vectors[i]
getFixed64DecodedValue(data) == Fixed64Values[i]
test "[fixed64] mixing many values with same field number test":
for i in 0 ..< len(Fixed64Values):
var pb = initProtoBuffer()
for k in 0 ..< len(Fixed64Values):
let index = (i + k + 1) mod len(Fixed64Values)
pb.write(1, cast[float64](Fixed64Values[index]))
pb.finish()
check getFixed64DecodedValue(pb.buffer) == Fixed64Values[i]
test "[fixed64] incorrect values test":
for i in 0 ..< len(Fixed64Values):
var value: float32
var data = getFixed64EncodedValue(cast[float64](Fixed64Values[i]))
# corrupting
data.setLen(len(data) - 1)
var pb = initProtoBuffer(data)
check:
pb.getField(1, value) == false
test "[fixed64] non-existent field test":
for i in 0 ..< len(Fixed64Values):
var value: float64
var data = getFixed64EncodedValue(cast[float64](Fixed64Values[i]))
var pb = initProtoBuffer(data)
check:
pb.getField(2, value) == false
value == float64(0)
test "[fixed64] corrupted header test":
for i in 0 ..< len(Fixed64Values):
for k in 0 ..< 3:
var value: float64
var data = getFixed64EncodedValue(cast[float64](Fixed64Values[i]))
data.corruptHeader(k)
var pb = initProtoBuffer(data)
check:
pb.getField(1, value) == false
test "[fixed64] empty buffer test":
var value: float64
var pb = initProtoBuffer()
check:
pb.getField(1, value) == false
value == float64(0)
test "[fixed64] Repeated field test":
var pb1 = initProtoBuffer()
pb1.write(1, cast[float64](Fixed64Values[2]))
pb1.write(1, cast[float64](Fixed64Values[3]))
pb1.write(2, cast[float64](Fixed64Values[4]))
pb1.write(1, cast[float64](Fixed64Values[5]))
pb1.write(1, cast[float64](Fixed64Values[6]))
pb1.finish()
var pb2 = initProtoBuffer(pb1.buffer)
var fieldarr1: seq[float64]
var fieldarr2: seq[float64]
var fieldarr3: seq[float64]
let r1 = pb2.getRepeatedField(1, fieldarr1)
let r2 = pb2.getRepeatedField(2, fieldarr2)
let r3 = pb2.getRepeatedField(3, fieldarr3)
check:
r1 == true
r2 == true
r3 == false
len(fieldarr3) == 0
len(fieldarr2) == 1
len(fieldarr1) == 4
cast[uint64](fieldarr1[0]) == Fixed64Values[2]
cast[uint64](fieldarr1[1]) == Fixed64Values[3]
cast[uint64](fieldarr1[2]) == Fixed64Values[5]
cast[uint64](fieldarr1[3]) == Fixed64Values[6]
cast[uint64](fieldarr2[0]) == Fixed64Values[4]
test "[fixed64] Repeated packed field test":
var pb1 = initProtoBuffer()
var values = newSeq[float64](len(Fixed64Values))
for i in 0 ..< len(values):
values[i] = cast[float64](Fixed64Values[i])
pb1.writePacked(1, values)
pb1.writePacked(2, values[0 .. 1])
pb1.finish()
let expect = PackedFixed64Vector.multiReplace(("\n", ""), (" ", ""))
check:
toHex(pb1.buffer) == expect
var pb2 = initProtoBuffer(pb1.buffer)
var fieldarr1: seq[float64]
var fieldarr2: seq[float64]
var fieldarr3: seq[float64]
let r1 = pb2.getPackedRepeatedField(1, fieldarr1)
let r2 = pb2.getPackedRepeatedField(2, fieldarr2)
let r3 = pb2.getPackedRepeatedField(3, fieldarr3)
check:
r1 == true
r2 == true
r3 == false
len(fieldarr3) == 0
len(fieldarr2) == 2
len(fieldarr1) == 8
cast[uint64](fieldarr1[0]) == Fixed64Values[0]
cast[uint64](fieldarr1[1]) == Fixed64Values[1]
cast[uint64](fieldarr1[2]) == Fixed64Values[2]
cast[uint64](fieldarr1[3]) == Fixed64Values[3]
cast[uint64](fieldarr1[4]) == Fixed64Values[4]
cast[uint64](fieldarr1[5]) == Fixed64Values[5]
cast[uint64](fieldarr1[6]) == Fixed64Values[6]
cast[uint64](fieldarr1[7]) == Fixed64Values[7]
cast[uint64](fieldarr2[0]) == Fixed64Values[0]
cast[uint64](fieldarr2[1]) == Fixed64Values[1]
test "[length] edge values test":
for i in 0 ..< len(LengthValues):
let data1 = getLengthEncodedValue(LengthValues[i])
let data2 = getLengthEncodedValue(cast[seq[byte]](LengthValues[i]))
check:
toHex(data1) == LengthVectors[i]
toHex(data2) == LengthVectors[i]
check:
getLengthDecodedValue(data1) == LengthValues[i]
getLengthDecodedValue(data2) == LengthValues[i]
test "[length] mixing many values with same field number test":
for i in 0 ..< len(LengthValues):
var pb1 = initProtoBuffer()
var pb2 = initProtoBuffer()
for k in 0 ..< len(LengthValues):
let index = (i + k + 1) mod len(LengthValues)
pb1.write(1, LengthValues[index])
pb2.write(1, cast[seq[byte]](LengthValues[index]))
pb1.finish()
pb2.finish()
check getLengthDecodedValue(pb1.buffer) == LengthValues[i]
check getLengthDecodedValue(pb2.buffer) == LengthValues[i]
test "[length] incorrect values test":
for i in 0 ..< len(LengthValues):
var value = newSeq[byte](len(LengthValues[i]))
var valueLen = 0
var data = getLengthEncodedValue(LengthValues[i])
# corrupting
data.setLen(len(data) - 1)
var pb = initProtoBuffer(data)
check:
pb.getField(1, value, valueLen) == false
test "[length] non-existent field test":
for i in 0 ..< len(LengthValues):
var value = newSeq[byte](len(LengthValues[i]))
var valueLen = 0
var data = getLengthEncodedValue(LengthValues[i])
var pb = initProtoBuffer(data)
check:
pb.getField(2, value, valueLen) == false
valueLen == 0
test "[length] corrupted header test":
for i in 0 ..< len(LengthValues):
for k in 0 ..< 3:
var value = newSeq[byte](len(LengthValues[i]))
var valueLen = 0
var data = getLengthEncodedValue(LengthValues[i])
data.corruptHeader(k)
var pb = initProtoBuffer(data)
check:
pb.getField(1, value, valueLen) == false
test "[length] empty buffer test":
var value = newSeq[byte](len(LengthValues[0]))
var valueLen = 0
var pb = initProtoBuffer()
check:
pb.getField(1, value, valueLen) == false
valueLen == 0
test "[length] buffer overflow test":
for i in 1 ..< len(LengthValues):
let data = getLengthEncodedValue(LengthValues[i])
var value = newString(len(LengthValues[i]) - 1)
var valueLen = 0
var pb = initProtoBuffer(data)
check:
pb.getField(1, value, valueLen) == false
valueLen == len(LengthValues[i])
isFullZero(value) == true
test "[length] mix of buffer overflow and normal fields test":
var pb1 = initProtoBuffer()
pb1.write(1, "TEST10")
pb1.write(1, "TEST20")
pb1.write(1, "TEST")
pb1.write(1, "TEST30")
pb1.write(1, "SOME")
pb1.finish()
var pb2 = initProtoBuffer(pb1.buffer)
var value = newString(4)
var valueLen = 0
check:
pb2.getField(1, value, valueLen) == true
value == "SOME"
test "[length] too big message test":
var pb1 = initProtoBuffer()
var bigString = newString(MaxMessageSize + 1)
for i in 0 ..< len(bigString):
bigString[i] = 'A'
pb1.write(1, bigString)
pb1.finish()
var pb2 = initProtoBuffer(pb1.buffer)
var value = newString(MaxMessageSize + 1)
var valueLen = 0
check:
pb2.getField(1, value, valueLen) == false
test "[length] Repeated field test":
var pb1 = initProtoBuffer()
pb1.write(1, "TEST1")
pb1.write(1, "TEST2")
pb1.write(2, "TEST5")
pb1.write(1, "TEST3")
pb1.write(1, "TEST4")
pb1.finish()
var pb2 = initProtoBuffer(pb1.buffer)
var fieldarr1: seq[seq[byte]]
var fieldarr2: seq[seq[byte]]
var fieldarr3: seq[seq[byte]]
let r1 = pb2.getRepeatedField(1, fieldarr1)
let r2 = pb2.getRepeatedField(2, fieldarr2)
let r3 = pb2.getRepeatedField(3, fieldarr3)
check:
r1 == true
r2 == true
r3 == false
len(fieldarr3) == 0
len(fieldarr2) == 1
len(fieldarr1) == 4
cast[string](fieldarr1[0]) == "TEST1"
cast[string](fieldarr1[1]) == "TEST2"
cast[string](fieldarr1[2]) == "TEST3"
cast[string](fieldarr1[3]) == "TEST4"
cast[string](fieldarr2[0]) == "TEST5"
test "Different value types in one message with same field number test":
proc getEncodedValue(): seq[byte] =
var pb = initProtoBuffer()
pb.write(1, VarintValues[1])
pb.write(2, cast[float32](Fixed32Values[1]))
pb.write(3, cast[float64](Fixed64Values[1]))
pb.write(4, LengthValues[1])
pb.write(1, VarintValues[2])
pb.write(2, cast[float32](Fixed32Values[2]))
pb.write(3, cast[float64](Fixed64Values[2]))
pb.write(4, LengthValues[2])
pb.write(1, cast[float32](Fixed32Values[3]))
pb.write(2, cast[float64](Fixed64Values[3]))
pb.write(3, LengthValues[3])
pb.write(4, VarintValues[3])
pb.write(1, cast[float64](Fixed64Values[4]))
pb.write(2, LengthValues[4])
pb.write(3, VarintValues[4])
pb.write(4, cast[float32](Fixed32Values[4]))
pb.write(1, VarintValues[1])
pb.write(2, cast[float32](Fixed32Values[1]))
pb.write(3, cast[float64](Fixed64Values[1]))
pb.write(4, LengthValues[1])
pb.finish()
pb.buffer
let msg = getEncodedValue()
let pb = initProtoBuffer(msg)
var varintValue: uint64
var fixed32Value: float32
var fixed64Value: float64
var lengthValue = newString(10)
var lengthSize: int
check:
pb.getField(1, varintValue) == true
pb.getField(2, fixed32Value) == true
pb.getField(3, fixed64Value) == true
pb.getField(4, lengthValue, lengthSize) == true
lengthValue.setLen(lengthSize)
check:
varintValue == VarintValues[1]
cast[uint32](fixed32Value) == Fixed32Values[1]
cast[uint64](fixed64Value) == Fixed64Values[1]
lengthValue == LengthValues[1]