testing and improvements to the common data structures

This commit is contained in:
Hayden Parker
2016-02-05 02:23:11 -08:00
parent f5e806dd14
commit b3fa7082cf
24 changed files with 551 additions and 235 deletions

View File

@ -1,7 +1,7 @@
package common
import (
"github.com/bounce-chat/go-i2p/lib/crypto"
"errors"
)
const (
@ -28,73 +28,46 @@ const (
KEYCERT_CRYPTO_ELG = iota
)
// used to append data to existing data structures
type Certificate []byte
// return the type of this certificate
func (c Certificate) Type() byte {
return c[0]
func (certificate Certificate) Type() byte {
return certificate[0]
}
// get the length of the data in this certificate
// return -1 if the size of the certificate is invalid
func (c Certificate) Len() int {
if len(c) <= 2 {
// invalid size
return -1
func (certificate Certificate) Length() (int, error) {
if len(certificate) < 3 {
// log
return 0, errors.New("error parsing certificate length: certificate is too short")
}
return Integer(c[1:3])
}
// get the data for this certificate or null if none exists
func (c Certificate) Data() (d []byte) {
l := c.Len()
if l > 0 && len(c) <= 3+l {
d = c[3 : 3+l]
length := Integer(certificate[1:3])
inferred_len := length + 3
cert_len := len(certificate)
if inferred_len > cert_len {
// log
return length, errors.New("certificate parsing warning: certificate data is shorter than specified by length")
} else if cert_len > inferred_len {
//log
return length, errors.New("certificate parsing warning: certificate contains data beyond length")
}
return
return length, nil
}
// a Certificate of type KEY
type KeyCert []byte
func (c KeyCert) Type() byte {
return Certificate(c).Type()
}
func (c KeyCert) Data() []byte {
return Certificate(c).Data()
}
// get the signing public key from this key cert
func (c KeyCert) SigningPublicKey() (k crypto.SigningPublicKey) {
data := c.Data()
ktype := Integer(data[:2])
// set data to be the key data now
data = data[4:]
// determine the key type
if ktype == KEYCERT_SIGN_DSA_SHA1 {
var pk crypto.DSAPublicKey
copy(pk[:], data[:pk.Len()])
k = pk
} else if ktype == KEYCERT_SIGN_P256 {
var pk crypto.ECP256PublicKey
copy(pk[:], data[:pk.Len()])
k = pk
} else if ktype == KEYCERT_SIGN_P384 {
var pk crypto.ECP384PublicKey
copy(pk[:], data[:pk.Len()])
k = pk
} else if ktype == KEYCERT_SIGN_P521 {
var pk crypto.ECP521PublicKey
copy(pk[:], data[:pk.Len()])
k = pk
func (certificate Certificate) Data() ([]byte, error) {
length, err := certificate.Length()
if err != nil {
switch err.Error() {
case "error parsing certificate length: certificate is too short":
return make([]byte, 0), err
case "certificate parsing warning: certificate data is shorter than specified by length":
return certificate[3:], err
case "certificate parsing warning: certificate contains data beyond length":
return certificate[3 : length+3], err
}
}
// TODO: rsa/eddsa
return
return certificate[3:], nil
}
func (c Certificate) signatureSize() int {
func (certificate Certificate) SignatureSize() int {
sizes := map[int]int{
KEYCERT_SIGN_DSA_SHA1: 40,
KEYCERT_SIGN_P256: 64,
@ -105,5 +78,21 @@ func (c Certificate) signatureSize() int {
KEYCERT_SIGN_RSA4096: 512,
KEYCERT_SIGN_ED25519: 64,
}
return sizes[int(c.Type())]
return sizes[int(certificate.Type())]
}
func ReadCertificate(data []byte) (Certificate, []byte, error) {
certificate := Certificate(data)
length, err := certificate.Length()
if err != nil {
switch err.Error() {
case "error parsing certificate length: certificate is too short":
return Certificate{}, make([]byte, 0), err
case "certificate parsing warning: certificate data is shorter than specified by length":
return certificate, make([]byte, 0), err
case "certificate parsing warning: certificate contains data beyond length":
return Certificate(certificate[:length+3]), certificate[length+3:], nil
}
}
return certificate, make([]byte, 0), nil
}

View File

@ -0,0 +1,160 @@
package common
import "testing"
func TestCertificateTypeIsFirstByte(t *testing.T) {
bytes := []byte{0x03, 0x00, 0x00}
certificate := Certificate(bytes)
if certificate.Type() != 0x03 {
t.Fatal("certificate.Type() is not first byte")
}
}
func TestCertificateLengthCorrect(t *testing.T) {
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff}
certificate := Certificate(bytes)
cert_len, err := certificate.Length()
if cert_len != 2 {
t.Fatal("certificate.Length() is not correct:", cert_len)
}
if err != nil {
t.Fatal("certificate.Length() returned err", err)
}
}
func TestCertificateLengthErrWhenTooShort(t *testing.T) {
bytes := []byte{0x03, 0x00}
certificate := Certificate(bytes)
cert_len, err := certificate.Length()
if cert_len != 0 {
t.Fatal("certificate.Length() is not correct:", cert_len)
}
if err == nil || err.Error() != "error parsing certificate length: certificate is too short" {
t.Fatal("certificate.Length() did not return correct err:", err)
}
}
func TestCertificateLengthErrWhenDataTooShort(t *testing.T) {
bytes := []byte{0x03, 0x00, 0x02, 0xff}
certificate := Certificate(bytes)
cert_len, err := certificate.Length()
if cert_len != 2 {
t.Fatal("certificate.Length() is not correct:", cert_len)
}
if err == nil || err.Error() != "certificate parsing warning: certificate data is shorter than specified by length" {
t.Fatal("certificate.Length() did not return correct err:", err)
}
}
func TestCertificateDataWhenCorrectSize(t *testing.T) {
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff}
certificate := Certificate(bytes)
cert_data, err := certificate.Data()
if err != nil {
t.Fatal("certificate.Data() returned error", err)
}
cert_len := len(cert_data)
if cert_len != 2 {
t.Fatal("certificate.Data() did not return correct length:", cert_len)
}
if cert_data[0] != 0xff || cert_data[1] != 0xff {
t.Fatal("certificate.Data() returned incorrect data")
}
}
func TestCertificateDataWhenTooLong(t *testing.T) {
bytes := []byte{0x03, 0x00, 0x02, 0xff, 0xff, 0xaa, 0xaa}
certificate := Certificate(bytes)
cert_data, err := certificate.Data()
if err == nil || err.Error() != "certificate parsing warning: certificate contains data beyond length" {
t.Fatal("certificate.Data() returned wrong error:", err)
}
cert_len := len(cert_data)
if cert_len != 2 {
t.Fatal("certificate.Data() did not return correct length:", cert_len)
}
if cert_data[0] != 0xff || cert_data[1] != 0xff {
t.Fatal("certificate.Data() returned incorrect data")
}
}
func TestCertificateDataWhenTooShort(t *testing.T) {
bytes := []byte{0x03, 0x00, 0x02, 0xff}
certificate := Certificate(bytes)
cert_data, err := certificate.Data()
if err == nil || err.Error() != "certificate parsing warning: certificate data is shorter than specified by length" {
t.Fatal("certificate.Data() did not return correct error:", err)
}
cert_len := len(cert_data)
if cert_len != 1 {
t.Fatal("certificate.Data() did not return correct length when too short:", cert_len)
}
if cert_data[0] != 0xff {
t.Fatal("certificate.Data() returned incorrect data")
}
}
func TestReadCertificateWithCorrectData(t *testing.T) {
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff}
cert, remainder, err := ReadCertificate(bytes)
cert_len := len(cert)
if cert_len != 5 {
t.Fatal("ReadCertificate() did not return correct certificate length:", cert_len)
}
if len(remainder) != 0 {
t.Fatal("ReadCertificate() returned a remainder incorrectly:", len(remainder))
}
if err != nil {
t.Fatal("ReadCertificate returned error:", err)
}
}
func TestReadCertificateWithDataTooShort(t *testing.T) {
bytes := []byte{0x00, 0x00, 0x02, 0xff}
cert, remainder, err := ReadCertificate(bytes)
cert_len := len(cert)
if cert_len != 4 {
t.Fatal("ReadCertificate() did not return correct certificate length:", cert_len)
}
if len(remainder) != 0 {
t.Fatal("ReadCertificate() returned a remainder incorrectly when data too short:", len(remainder))
}
if err == nil || err.Error() != "certificate parsing warning: certificate data is shorter than specified by length" {
t.Fatal("ReadCertificate returned incorrect error:", err)
}
}
func TestReadCertificateWithRemainder(t *testing.T) {
bytes := []byte{0x00, 0x00, 0x02, 0xff, 0xff, 0x00}
cert, remainder, err := ReadCertificate(bytes)
cert_len := len(cert)
if cert_len != 5 {
t.Fatal("ReadCertificate() did not return correct certificate length:", cert_len)
}
if len(remainder) != 1 {
t.Fatal("ReadCertificate() returned a remainder incorrectly:", len(remainder))
}
if remainder[0] != 0x00 {
t.Fatal("ReadCertificate() did not return correct remainder value")
}
if err != nil {
t.Fatal("ReadCertificate returned error:", err)
}
}
func TestReadCertificateWithInvalidLength(t *testing.T) {
bytes := []byte{0x00, 0x00}
cert, remainder, err := ReadCertificate(bytes)
cert_len := len(cert)
if cert_len != 0 {
t.Fatal("ReadCertificate() did not return 0 length certificate with invalid length:", cert_len)
}
remainder_len := len(remainder)
if remainder_len != 0 {
t.Fatal("ReadCertificate() did not return 0 length remainder with invalid length:", remainder_len)
}
if err == nil || err.Error() != "error parsing certificate length: certificate is too short" {
t.Fatal("ReadCertificate() returned an incorrect error with invalid length:", err)
}
}

View File

@ -1,4 +0,0 @@
package common
// the sha256 of some datastructure
type IdentHash [32]byte

View File

@ -7,53 +7,26 @@ import (
"strings"
)
// a network endpoint inside i2p
// effectively a public key blob
type Destination []byte
// obtain public elgamal key
func (dest Destination) PublicKey() (k crypto.PublicEncryptionKey) {
cert := dest.Certificate()
if cert.Type() == CERT_KEY {
// TODO(psi): check for key cert and included encryption key
} else {
var ek crypto.ElgPublicKey
copy(ek[:], dest[:256])
k = ek
}
return
func (destination Destination) PublicKey() (key crypto.ElgPublicKey) {
return KeysAndCert(destination).PublicKey()
}
// obtain destination certificate
func (dest Destination) Certificate() Certificate {
return Certificate(dest[128+256:])
func (destination Destination) SigningPublicKey() (key crypto.SigningPublicKey) {
return KeysAndCert(destination).SigningPublicKey()
}
// gets this destination's signing key
// if there is a keycert in this destination the signing key in there is used
func (dest Destination) SigningPublicKey() (k crypto.SigningPublicKey) {
cert := dest.Certificate()
if cert.Type() == CERT_KEY {
// we have a key certificate
// extract the signing key from the key cert
k = KeyCert(cert).SigningPublicKey()
} else {
var pk crypto.DSAPublicKey
copy(pk[:], dest[256:256+128])
k = pk
}
return
func (destination Destination) Certificate() (cert Certificate) {
return KeysAndCert(destination).Certificate()
}
// return the .b32.i2p address
func (dest Destination) Base32Address() (str string) {
h := crypto.SHA256(dest)
str = strings.Trim(base32.EncodeToString(h[:]), "=")
str += ".b32.i2p"
return
func (destination Destination) Base32Address() string {
hash := crypto.SHA256(destination)
str := strings.Trim(base32.EncodeToString(hash[:]), "=")
return str + ".b32.i2p"
}
func (dest Destination) Base64() (str string) {
str = base64.EncodeToString(dest)
return
func (destination Destination) Base64() string {
return base64.EncodeToString(destination)
}

3
lib/common/hash.go Normal file
View File

@ -0,0 +1,3 @@
package common
type Hash [32]byte

View File

@ -0,0 +1,46 @@
package common
import (
"github.com/bounce-chat/go-i2p/lib/crypto"
)
type KeyCertificate []byte
func (key_certificate KeyCertificate) Type() byte {
return Certificate(key_certificate).Type()
}
func (key_certificate KeyCertificate) Data() ([]byte, error) {
return Certificate(key_certificate).Data()
}
// get the signing public key from this key cert
func (key_certificate KeyCertificate) SigningPublicKey() (k crypto.SigningPublicKey) {
data, err := key_certificate.Data()
if err != nil {
return
}
ktype := Integer(data[:2])
// set data to be the key data now
data = data[4:]
// determine the key type
if ktype == KEYCERT_SIGN_DSA_SHA1 {
var pk crypto.DSAPublicKey
copy(pk[:], data[:pk.Len()])
k = pk
} else if ktype == KEYCERT_SIGN_P256 {
var pk crypto.ECP256PublicKey
copy(pk[:], data[:pk.Len()])
k = pk
} else if ktype == KEYCERT_SIGN_P384 {
var pk crypto.ECP384PublicKey
copy(pk[:], data[:pk.Len()])
k = pk
} else if ktype == KEYCERT_SIGN_P521 {
var pk crypto.ECP521PublicKey
copy(pk[:], data[:pk.Len()])
k = pk
}
// TODO: rsa/eddsa
return
}

View File

@ -0,0 +1 @@
package common

View File

@ -1,7 +1,43 @@
package common
//
// Both Destination and RouterIdentity share the same structure
// https://geti2p.net/en/docs/spec/common-structures#struct_KeysAndCert
// Perhaps we can avoid repeating ourselves being using commong functions
//
import (
"github.com/bounce-chat/go-i2p/lib/crypto"
)
type KeysAndCert []byte
func (keys_and_cert KeysAndCert) PublicKey() (key crypto.ElgPublicKey) {
if len(keys_and_cert) < 387 {
}
copy(keys_and_cert[:256], key[:])
return
}
func (keys_and_cert KeysAndCert) SigningPublicKey() (key crypto.SigningPublicKey) {
cert := keys_and_cert.Certificate()
if cert.Type() == CERT_KEY {
key = KeyCertificate(cert).SigningPublicKey()
} else {
var pk crypto.DSAPublicKey
copy(pk[:], keys_and_cert[256:256+128])
key = pk
}
return
}
func (keys_and_cert KeysAndCert) Certificate() (cert Certificate) {
copy(keys_and_cert[256+128:], cert)
return
}
func ReadKeysAndCert(data []byte) (KeysAndCert, []byte, error) {
var keys_and_cert KeysAndCert
copy(data[:387], keys_and_cert)
n, err := keys_and_cert.Certificate().Length()
if err != nil {
return keys_and_cert, data, err
}
keys_and_cert = append(keys_and_cert, data[387:n]...)
return keys_and_cert, data[387+n:], nil
}

View File

@ -0,0 +1 @@
package common

View File

@ -10,7 +10,7 @@ const (
type Lease [LEASE_SIZE]byte
func (lease Lease) TunnelGateway() (h IdentHash) {
func (lease Lease) TunnelGateway() (h Hash) {
copy(lease[:32], h[:])
return
}

View File

@ -49,7 +49,7 @@ func (lease_set LeaseSet) Signature() []byte {
sig_size := lease_set.
Destination().
Certificate().
signatureSize()
SignatureSize()
return lease_set[data_end : data_end+sig_size]
}

View File

@ -0,0 +1 @@
package common

1
lib/common/lease_test.go Normal file
View File

@ -0,0 +1 @@
package common

View File

@ -1,41 +1,49 @@
package common
import (
"encoding/binary"
"strings"
// "encoding/binary"
// "strings"
)
type Mapping []byte
func (mapping Mapping) ToMap() map[string]string {
gomap := make(map[string]string)
kv_store := string(mapping[2:])
pairs := strings.Split(kv_store, ";")
for _, pair := range pairs {
values := strings.Split(pair, "=")
if len(values) != 2 {
continue
}
gomap[values[0]] = values[1]
}
return gomap
func (mapping Mapping) Values() [][2][]byte {
return make([][2][]byte, 0)
}
func MappingFromMap(gomap map[string]string) Mapping {
kv_store := make([]byte, 0)
for k, v := range gomap {
key_bytes := []byte(k)
key_bytes = append(key_bytes, 0x3d)
value_bytes := []byte(v)
value_bytes = append(value_bytes, 0x3b)
kv_store = append(kv_store, key_bytes...)
kv_store = append(kv_store, value_bytes...)
}
kv_size := uint16(len(kv_store))
var size [2]byte
binary.BigEndian.PutUint16(size[:], kv_size)
mapping := Mapping{}
mapping = append(mapping, size[:]...)
mapping = append(mapping, kv_store...)
return mapping
func ValuesToMapping(values [][2][]byte) Mapping {
return Mapping{}
}
//func (mapping Mapping) ToMap() map[string]string {
// gomap := make(map[string]string)
// kv_store := string(mapping[2:])
// pairs := strings.Split(kv_store, ";")
// for _, pair := range pairs {
// values := strings.Split(pair, "=")
// if len(values) != 2 {
// continue
// }
// gomap[values[0]] = values[1]
// }
// return gomap
//}
//func MappingFromMap(gomap map[string]string) Mapping {
// kv_store := make([]byte, 0)
// for k, v := range gomap {
// key_bytes := []byte(k)
// key_bytes = append(key_bytes, 0x3d)
// value_bytes := []byte(v)
// value_bytes = append(value_bytes, 0x3b)
// kv_store = append(kv_store, key_bytes...)
// kv_store = append(kv_store, value_bytes...)
// }
// kv_size := uint16(len(kv_store))
// var size [2]byte
// binary.BigEndian.PutUint16(size[:], kv_size)
// mapping := Mapping{}
// mapping = append(mapping, size[:]...)
// mapping = append(mapping, kv_store...)
// return mapping
//}

View File

@ -1,37 +1 @@
package common
import (
"bytes"
"testing"
)
func TestToMapping(t *testing.T) {
gomap := map[string]string{
"a": "1",
}
mapping := MappingFromMap(gomap)
if !bytes.Equal(mapping, []byte{0x00, 0x04, 0x61, 0x3d, 0x31, 0x3b}) {
t.Fatal("go map to mapping did not create correct mapping")
}
}
func TestMappingToMap(t *testing.T) {
mapping := Mapping{0x00, 0x08, 0x61, 0x3d, 0x31, 0x3b, 0x62, 0x3d, 0x32, 0x3b}
gomap := mapping.ToMap()
if gomap["a"] != "1" {
t.Fatal("map does not contain encoded data")
}
if gomap["b"] != "2" {
t.Fatal("map does not comtain encoded data")
}
}
func TestToAndFromMapping(t *testing.T) {
gomap := make(map[string]string)
gomap["foo"] = "bar"
mapping := MappingFromMap(gomap)
gomap2 := mapping.ToMap()
if gomap["foo"] != gomap2["foo"] {
t.Fatal("rebuilt map has different data")
}
}

View File

@ -12,7 +12,7 @@ func (router_address RouterAddress) Expiration() (d Date) {
}
func (router_address RouterAddress) TransportStyle() string {
return string(
return string( //String
router_address[10:router_address.stringLength()],
)
}

View File

@ -0,0 +1 @@
package common

View File

@ -1,41 +1,24 @@
package common
import (
"errors"
"github.com/bounce-chat/go-i2p/lib/crypto"
)
type RouterIdentity []byte
func (router_identity RouterIdentity) PublicKey() (key crypto.ElgPublicKey) {
copy(router_identity[:256], key[:])
return
return KeysAndCert(router_identity).PublicKey()
}
func (router_identity RouterIdentity) SigningPublicKey() (key crypto.SigningPublicKey) {
cert := router_identity.Certificate()
if cert.Type() == CERT_KEY {
key = KeyCert(cert).SigningPublicKey()
} else {
var pk crypto.DSAPublicKey
copy(pk[:], router_identity[256:256+128])
key = pk
}
return
return KeysAndCert(router_identity).SigningPublicKey()
}
func (router_identity RouterIdentity) Certificate() (cert Certificate) {
copy(router_identity[256+128:], cert)
return
return KeysAndCert(router_identity).Certificate()
}
func readRouterIdentity(data []byte) (RouterIdentity, []byte, error) {
var router_identity RouterIdentity
copy(data[:387], router_identity)
n := router_identity.Certificate().Len()
if n == -1 {
return router_identity, data, errors.New("invalid certificate")
}
router_identity = append(router_identity, data[387:n]...)
return router_identity, data[387+n:], nil
func ReadRouterIdentity(data []byte) (RouterIdentity, []byte, error) {
keys_and_certs, remainder, err := ReadKeysAndCert(data)
return RouterIdentity(keys_and_certs), remainder, err
}

View File

@ -3,18 +3,18 @@ package common
type RouterInfo []byte
func (router_info RouterInfo) RouterIdentity() RouterIdentity {
router_identity, _, _ := readRouterIdentity(router_info)
router_identity, _, _ := ReadRouterIdentity(router_info)
return router_identity
}
func (router_info RouterInfo) Published() (d Date) {
_, remainder, _ := readRouterIdentity(router_info)
_, remainder, _ := ReadRouterIdentity(router_info)
copy(remainder[:8], d[:])
return
}
func (router_info RouterInfo) RouterAddressCount() int {
_, remainder, _ := readRouterIdentity(router_info)
_, remainder, _ := ReadRouterIdentity(router_info)
return Integer([]byte{remainder[8]})
}
@ -47,7 +47,7 @@ func (router_info RouterInfo) Signature() []byte {
sig_size := router_info.
RouterIdentity().
Certificate().
signatureSize()
SignatureSize()
return router_info[offset:sig_size]
}

View File

@ -0,0 +1 @@
package common

View File

@ -0,0 +1,3 @@
package common
type SessionKey [32]byte

View File

@ -0,0 +1,3 @@
package common
type SessionTag [32]byte

View File

@ -6,20 +6,66 @@ import (
type String []byte
func ReadString(data []byte) (str String, remainder []byte, err error) {
if len(data) == 0 {
err = errors.New("no string in empty byte slice")
return
func (str String) Length() (int, error) {
if len(str) == 0 {
// log
return 0, errors.New("error parsing string: zero length")
}
length := Integer([]byte{data[0]})
data = data[1:]
if len(data) < length {
str = data
err = errors.New("string longer than provided slice")
return
length := Integer([]byte{str[0]})
inferred_len := length + 1
str_len := len(str)
if inferred_len > str_len {
// log
return length, errors.New("string parsing warning: string data is shorter than specified by length")
} else if str_len > inferred_len {
//log
return length, errors.New("string parsing warning: string contains data beyond length")
}
str = data[:length]
remainder = data[length:]
return
return length, nil
}
func (str String) Data() ([]byte, error) {
length, err := str.Length()
if err != nil {
switch err.Error() {
case "error parsing string: zero length":
return make([]byte, 0), err
case "string parsing warning: string data is shorter than specified by length":
return str[1:], err
case "string parsing warning: string contains data beyond length":
return str[1 : length+1], err
}
}
return str[1:], nil
}
func (str String) GoString() (string, error) {
content, err := str.Data()
return string(content), err
}
func ToI2PString(data []byte) (String, error) {
data_len := len(data)
if data_len >= 256 {
return make([]byte, 0), errors.New("cannot store that much data in I2P string")
}
i2p_string := []byte{byte(data_len)}
i2p_string = append(i2p_string, data...)
return String(i2p_string), nil
}
func ReadString(data []byte) (String, []byte, error) {
str := String(data)
length, err := String(data).Length()
if err != nil {
switch err.Error() {
case "error parsing string: zero length":
return String{}, make([]byte, 0), err
case "string parsing warning: string data is shorter than specified by length":
return str, make([]byte, 0), err
case "string parsing warning: string contains data beyond length":
return String(str[:length+1]), str[length+1:], err
}
}
return str, make([]byte, 0), nil
}

View File

@ -2,47 +2,147 @@ package common
import "testing"
func TestStringReportsCorrectLength(t *testing.T) {
str_len, err := String([]byte{0x02, 0x00, 0x00}).Length()
if str_len != 2 {
t.Fatal("string.Length() did not report correct length")
}
if err != nil {
t.Fatal("string.Length() reported an error on valid string:", err)
}
}
func TestStringReportsLengthZeroError(t *testing.T) {
str_len, err := String(make([]byte, 0)).Length()
if str_len != 0 {
t.Fatal("string.Length() reported non-zero length on empty slice")
}
if err == nil || err.Error() != "error parsing string: zero length" {
t.Fatal("string.Length() reported incorrect error on zero length slice:", err)
}
}
func TestStringReportsExtraDataError(t *testing.T) {
str_len, err := String([]byte{0x01, 0x00, 0x00}).Length()
if str_len != 1 {
t.Fatal("string.Length() reported wrong size when extra data present")
}
if err == nil || err.Error() != "string parsing warning: string contains data beyond length" {
t.Fatal("string.Length() reported incorrect error on extra data:", err)
}
}
func TestStringDataReportsLengthZeroError(t *testing.T) {
str_len, err := String([]byte{0x01}).Length()
if str_len != 1 {
t.Fatal("string.Length() reported wring length with missing data", str_len)
}
if err == nil || err.Error() != "string parsing warning: string data is shorter than specified by length" {
t.Fatal("string.Length() reported wrong error when data was missing", err)
}
}
func TestStringDataReportsExtraDataError(t *testing.T) {
data, err := String([]byte{0x01, 0x00, 0x01}).Data()
data_len := len(data)
if data_len != 1 {
t.Fatal("string.Data() returned wrong size data for length with extra data:", data_len)
}
if err == nil || err.Error() != "string parsing warning: string contains data beyond length" {
t.Fatal("string.Length() reported wrong error with extra data", err)
}
}
func TestStringDataEmptyWhenZeroLength(t *testing.T) {
data, err := String(make([]byte, 0)).Data()
data_len := len(data)
if data_len != 0 {
t.Fatal("string.Data() returned data when none was present:", data_len)
}
if err == nil || err.Error() != "error parsing string: zero length" {
t.Fatal("string.Length() reported wrong error with no data", err)
}
}
func TestStringDataErrorWhenNonZeroLengthOnly(t *testing.T) {
data, err := String([]byte{0x01}).Data()
data_len := len(data)
if data_len != 0 {
t.Fatal("string.Data() returned data when only length was present:", data_len)
}
if err == nil || err.Error() != "string parsing warning: string data is shorter than specified by length" {
t.Fatal("string.Length() reported wrong error with length but no data", err)
}
}
func TestToI2PStringFormatsCorrectly(t *testing.T) {
i2p_string, err := ToI2PString([]byte{0x22, 0x33})
if err != nil {
t.Fatal("ToI2PString() returned error on valid data:", err)
}
if i2p_string[0] != 0x02 {
t.Fatal("ToI2PString() did not prepend the correct length")
}
if i2p_string[1] != 0x22 && i2p_string[2] != 0x33 {
t.Fatal("ToI2PString() did not preserve string")
}
}
func TestToI2PStringReportsOverflows(t *testing.T) {
i2p_string, err := ToI2PString(make([]byte, 256))
if len(i2p_string) != 0 {
t.Fatal("ToI2PString() returned data when overflowed")
}
if err == nil || err.Error() != "cannot store that much data in I2P string" {
t.Fatal("ToI2pString() did not report overflow")
}
_, err = ToI2PString(make([]byte, 255))
if err != nil {
t.Fatal("ToI2PString() reported error with acceptable size:", err)
}
}
func TestReadStringReadsLength(t *testing.T) {
bytes := []byte{0x01, 0x04, 0x06}
str, remainder, err := ReadString(bytes)
if err != nil {
t.Fatal("ReadString() returner error,", err)
if err == nil || err.Error() != "string parsing warning: string contains data beyond length" {
t.Fatal("ReadString(t *testing.T) returned incorrect error,", err)
}
if len(str) != 1 {
t.Fatal("ReadString() did not return correct string length:", len(str))
if len(str) != 2 {
t.Fatal("ReadString(t *testing.T) did not return correct string length:", len(str))
}
if str[0] != 0x04 {
t.Fatal("ReadString() did not return correct string")
if str[0] != 0x01 && str[1] != 0x04 {
t.Fatal("ReadString(t *testing.T) did not return correct string")
}
if len(remainder) != 1 {
t.Fatal("ReadString() did not return correct remainder length")
t.Fatal("ReadString(t *testing.T) did not return correct remainder length")
}
if remainder[0] != 0x06 {
t.Fatal("ReadString() did not return correct remainder")
t.Fatal("ReadString(t *testing.T) did not return correct remainder")
}
}
func TestReadStringErrWhenEmptySlice(t *testing.T) {
bytes := make([]byte, 0)
_, _, err := ReadString(bytes)
if err != nil && err.Error() != "no string in empty byte slice" {
t.Fatal("ReadString() did not report empty slice error", err)
if err != nil && err.Error() != "error parsing string: zero length" {
t.Fatal("ReadString(t *testing.T) did not report empty slice error", err)
}
}
func TestReadStringErrWhenStringTooLong(t *testing.T) {
func TestReadStringErrWhenDataTooShort(t *testing.T) {
bytes := []byte{0x03, 0x01}
str, remainder, err := ReadString(bytes)
if err != nil && err.Error() != "string longer than provided slice" {
t.Fatal("ReadString() did not report string too long", err)
if err != nil && err.Error() != "string parsing warning: string data is shorter than specified by length" {
t.Fatal("ReadString(t *testing.T) did not report string too long", err)
}
if len(str) != 1 {
t.Fatal("ReadString() did not return the slice as string when too long")
if len(str) != 2 {
t.Fatal("ReadString(t *testing.T) did not return the slice as string when too long")
}
if str[0] != 0x01 {
t.Fatal("ReadString() did not return the correct partial string")
if str[0] != 0x03 && str[1] != 0x01 {
t.Fatal("ReadString(t *testing.T) did not return the correct partial string")
}
if len(remainder) != 0 {
t.Fatal("ReadString() returned a remainder when the string was too long")
t.Fatal("ReadString(t *testing.T) returned a remainder when the string data was too short")
}
}