adding float and double as types with name and size tests

add translate to type cases

replace float compare by Nextafter and Nextafter32

add parser for floats and doubles

add float and double parsers

add support for doubles and floats in FormatFrom functions

add ReadFloats and ReadDoubles for context

add float32 and double encoder

merging

merge

add float and double parsers

add ReadFloats and ReadDoubles for context

add float32 and double encoder

removing log alias from parser

removing log alias from parser_test

removing log alias from type

removing log alias from type_test

removing log alias from value_context

removing aliases from value_contex_test

removing log alias from value_encoder

removing log alias from value_encoder_test

update parser slices from floats and doubles

merge

update values for tests

raise exception when parsing with different expected size
pull/51/head
WendelHime 2020-11-30 18:05:55 -03:00 committed by WendelHime
parent b3f4f3b4b7
commit 2a2ee8aaf1
8 changed files with 520 additions and 57 deletions

View File

@ -2,6 +2,7 @@ package exifcommon
import ( import (
"bytes" "bytes"
"math"
"encoding/binary" "encoding/binary"
@ -135,6 +136,50 @@ func (p *Parser) ParseLongs(data []byte, unitCount uint32, byteOrder binary.Byte
return value, nil return value, nil
} }
// ParseFloats knows how to encode an encoded list of floats.
func (p *Parser) ParseFloats(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []float32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
count := int(unitCount)
if len(data) != (TypeFloat.Size() * count) {
log.Panic(ErrNotEnoughData)
}
value = make([]float32, count)
for i := 0; i < count; i++ {
value[i] = math.Float32frombits(byteOrder.Uint32(data[i*4 : (i+1)*4]))
}
return value, nil
}
// ParseDoubles knows how to encode an encoded list of doubles.
func (p *Parser) ParseDoubles(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []float64, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
count := int(unitCount)
if len(data) != (TypeDouble.Size() * count) {
log.Panic(ErrNotEnoughData)
}
value = make([]float64, count)
for i := 0; i < count; i++ {
value[i] = math.Float64frombits(byteOrder.Uint64(data[i*8 : (i+1)*8]))
}
return value, nil
}
// ParseRationals knows how to parse an encoded list of unsigned rationals. // ParseRationals knows how to parse an encoded list of unsigned rationals.
func (p *Parser) ParseRationals(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []Rational, err error) { func (p *Parser) ParseRationals(data []byte, unitCount uint32, byteOrder binary.ByteOrder) (value []Rational, err error) {
defer func() { defer func() {

View File

@ -2,6 +2,7 @@ package exifcommon
import ( import (
"bytes" "bytes"
"math"
"reflect" "reflect"
"testing" "testing"
@ -170,6 +171,78 @@ func TestParser_ParseLongs__Multiple(t *testing.T) {
} }
} }
func TestParser_ParseFloats__Single(t *testing.T) {
p := new(Parser)
encoded := []byte{0x40, 0x49, 0x0f, 0xdb}
value, err := p.ParseFloats(encoded, 1, TestDefaultByteOrder)
log.PanicIf(err)
expectedResult := []float32{3.14159265}
for i, v := range value {
if v < expectedResult[i] ||
v >= math.Nextafter32(expectedResult[i], expectedResult[i]+1) {
t.Fatalf("Encoding not correct (1): %v", value)
}
}
}
func TestParser_ParseFloats__Multiple(t *testing.T) {
p := new(Parser)
encoded := []byte{0x40, 0x49, 0x0f, 0xdb, 0x40, 0x2d, 0xf8, 0x54}
value, err := p.ParseFloats(encoded, 2, TestDefaultByteOrder)
log.PanicIf(err)
expectedResult := []float32{3.14159265, 2.71828182}
for i, v := range value {
if v < expectedResult[i] ||
v >= math.Nextafter32(expectedResult[i], expectedResult[i]+1) {
t.Fatalf("Encoding not correct (1): %v", value)
}
}
}
func TestParser_ParseDoubles__Single(t *testing.T) {
p := new(Parser)
encoded := []byte{0x40, 0x09, 0x21, 0xfb, 0x53, 0xc8, 0xd4, 0xf1}
value, err := p.ParseDoubles(encoded, 1, TestDefaultByteOrder)
log.PanicIf(err)
expectedResult := []float64{3.14159265}
for i, v := range value {
if v < expectedResult[i] ||
v >= math.Nextafter(expectedResult[i], expectedResult[i]+1) {
t.Fatalf("Encoding not correct (1): %v", value)
}
}
}
func TestParser_ParseDoubles__Multiple(t *testing.T) {
p := new(Parser)
encoded := []byte{0x40, 0x09, 0x21, 0xfb, 0x53, 0xc8, 0xd4, 0xf1,
0x40, 0x05, 0xbf, 0x0a, 0x89, 0xf1, 0xb0, 0xdd}
value, err := p.ParseDoubles(encoded, 2, TestDefaultByteOrder)
log.PanicIf(err)
expectedResult := []float64{3.14159265, 2.71828182}
for i, v := range value {
if v < expectedResult[i] ||
v >= math.Nextafter(expectedResult[i], expectedResult[i]+1) {
t.Fatalf("Encoding not correct: %v", value)
}
}
}
func TestParser_ParseRationals__Single(t *testing.T) { func TestParser_ParseRationals__Single(t *testing.T) {
p := new(Parser) p := new(Parser)

View File

@ -64,6 +64,12 @@ const (
// TypeSignedRational describes an encoded list of signed rationals. // TypeSignedRational describes an encoded list of signed rationals.
TypeSignedRational TagTypePrimitive = 10 TypeSignedRational TagTypePrimitive = 10
// TypeFloat describes an encoded list of floats
TypeFloat TagTypePrimitive = 11
// TypeDouble describes an encoded list of doubles.
TypeDouble TagTypePrimitive = 12
// TypeAsciiNoNul is just a pseudo-type, for our own purposes. // TypeAsciiNoNul is just a pseudo-type, for our own purposes.
TypeAsciiNoNul TagTypePrimitive = 0xf0 TypeAsciiNoNul TagTypePrimitive = 0xf0
) )
@ -75,23 +81,19 @@ func (typeType TagTypePrimitive) String() string {
// Size returns the size of one atomic unit of the type. // Size returns the size of one atomic unit of the type.
func (tagType TagTypePrimitive) Size() int { func (tagType TagTypePrimitive) Size() int {
if tagType == TypeByte { switch tagType {
case TypeByte, TypeAscii, TypeAsciiNoNul:
return 1 return 1
} else if tagType == TypeAscii || tagType == TypeAsciiNoNul { case TypeShort:
return 1
} else if tagType == TypeShort {
return 2 return 2
} else if tagType == TypeLong { case TypeLong, TypeSignedLong, TypeFloat:
return 4 return 4
} else if tagType == TypeRational { case TypeRational, TypeSignedRational, TypeDouble:
return 8 return 8
} else if tagType == TypeSignedLong { default:
return 4 log.Panicf("can not determine tag-value size for type (%d): [%s]",
} else if tagType == TypeSignedRational { tagType,
return 8 TypeNames[tagType])
} else {
log.Panicf("can not determine tag-value size for type (%d): [%s]", tagType, TypeNames[tagType])
// Never called. // Never called.
return 0 return 0
} }
@ -110,6 +112,8 @@ func (tagType TagTypePrimitive) IsValid() bool {
tagType == TypeRational || tagType == TypeRational ||
tagType == TypeSignedLong || tagType == TypeSignedLong ||
tagType == TypeSignedRational || tagType == TypeSignedRational ||
tagType == TypeFloat ||
tagType == TypeDouble ||
tagType == TypeUndefined tagType == TypeUndefined
} }
@ -124,6 +128,8 @@ var (
TypeUndefined: "UNDEFINED", TypeUndefined: "UNDEFINED",
TypeSignedLong: "SLONG", TypeSignedLong: "SLONG",
TypeSignedRational: "SRATIONAL", TypeSignedRational: "SRATIONAL",
TypeFloat: "FLOAT",
TypeDouble: "DOUBLE",
TypeAsciiNoNul: "_ASCII_NO_NUL", TypeAsciiNoNul: "_ASCII_NO_NUL",
} }
@ -186,36 +192,23 @@ func FormatFromType(value interface{}, justFirst bool) (phrase string, err error
} }
return t, nil return t, nil
case []uint16: case []uint16, []uint32, []int32, []float64, []float32:
if len(t) == 0 { val := reflect.ValueOf(t)
if val.Len() == 0 {
return "", nil return "", nil
} }
if justFirst == true { if justFirst == true {
var valueSuffix string var valueSuffix string
if len(t) > 1 { if val.Len() > 1 {
valueSuffix = "..." valueSuffix = "..."
} }
return fmt.Sprintf("%v%s", t[0], valueSuffix), nil return fmt.Sprintf("%v%s", val.Index(0), valueSuffix), nil
} }
return fmt.Sprintf("%v", t), nil return fmt.Sprintf("%v", val), nil
case []uint32:
if len(t) == 0 {
return "", nil
}
if justFirst == true {
var valueSuffix string
if len(t) > 1 {
valueSuffix = "..."
}
return fmt.Sprintf("%v%s", t[0], valueSuffix), nil
}
return fmt.Sprintf("%v", t), nil
case []Rational: case []Rational:
if len(t) == 0 { if len(t) == 0 {
return "", nil return "", nil
@ -240,21 +233,6 @@ func FormatFromType(value interface{}, justFirst bool) (phrase string, err error
} }
return fmt.Sprintf("%v", parts), nil return fmt.Sprintf("%v", parts), nil
case []int32:
if len(t) == 0 {
return "", nil
}
if justFirst == true {
var valueSuffix string
if len(t) > 1 {
valueSuffix = "..."
}
return fmt.Sprintf("%v%s", t[0], valueSuffix), nil
}
return fmt.Sprintf("%v", t), nil
case []SignedRational: case []SignedRational:
if len(t) == 0 { if len(t) == 0 {
return "", nil return "", nil
@ -348,6 +326,16 @@ func FormatFromBytes(rawBytes []byte, tagType TagTypePrimitive, justFirst bool,
value, err = parser.ParseLongs(rawBytes, unitCount, byteOrder) value, err = parser.ParseLongs(rawBytes, unitCount, byteOrder)
log.PanicIf(err) log.PanicIf(err)
case TypeFloat:
var err error
value, err = parser.ParseFloats(rawBytes, unitCount, byteOrder)
log.PanicIf(err)
case TypeDouble:
var err error
value, err = parser.ParseDoubles(rawBytes, unitCount, byteOrder)
log.PanicIf(err)
case TypeRational: case TypeRational:
var err error var err error
@ -432,6 +420,16 @@ func TranslateStringToType(tagType TagTypePrimitive, valueString string) (value
log.PanicIf(err) log.PanicIf(err)
return int32(n), nil return int32(n), nil
} else if tagType == TypeFloat {
n, err := strconv.ParseFloat(valueString, 32)
log.PanicIf(err)
return float32(n), nil
} else if tagType == TypeDouble {
n, err := strconv.ParseFloat(valueString, 64)
log.PanicIf(err)
return float64(n), nil
} else if tagType == TypeSignedRational { } else if tagType == TypeSignedRational {
parts := strings.SplitN(valueString, "/", 2) parts := strings.SplitN(valueString, "/", 2)

View File

@ -1,6 +1,7 @@
package exifcommon package exifcommon
import ( import (
"math"
"testing" "testing"
"github.com/dsoprea/go-logging" "github.com/dsoprea/go-logging"
@ -54,6 +55,18 @@ func TestTypeSignedRational_String(t *testing.T) {
} }
} }
func TestTypeFloat_String(t *testing.T) {
if TypeFloat.String() != "FLOAT" {
t.Fatalf("Type name not correct (float): [%s]", TypeFloat.String())
}
}
func TestTypeDouble_String(t *testing.T) {
if TypeDouble.String() != "DOUBLE" {
t.Fatalf("Type name not correct (double): [%s]", TypeDouble.String())
}
}
func TestTypeByte_Size(t *testing.T) { func TestTypeByte_Size(t *testing.T) {
if TypeByte.Size() != 1 { if TypeByte.Size() != 1 {
t.Fatalf("Type size not correct (byte): (%d)", TypeByte.Size()) t.Fatalf("Type size not correct (byte): (%d)", TypeByte.Size())
@ -102,6 +115,18 @@ func TestTypeSignedRational_Size(t *testing.T) {
} }
} }
func TestTypeFloat_Size(t *testing.T) {
if TypeFloat.Size() != 4 {
t.Fatalf("Type size not correct (float): (%d)", TypeFloat.Size())
}
}
func TestTypeDouble_Size(t *testing.T) {
if TypeDouble.Size() != 8 {
t.Fatalf("Type size not correct (double): (%d)", TypeDouble.Size())
}
}
func TestFormat__Byte(t *testing.T) { func TestFormat__Byte(t *testing.T) {
r := []byte{1, 2, 3, 4, 5, 6, 7, 8} r := []byte{1, 2, 3, 4, 5, 6, 7, 8}
@ -157,6 +182,30 @@ func TestFormat__Long(t *testing.T) {
} }
} }
func TestFormat__Float(t *testing.T) {
r := []byte{0x3f, 0x80, 0x00, 0x00,
0x40, 0x00, 0x00, 0x00}
s, err := FormatFromBytes(r, TypeFloat, false, TestDefaultByteOrder)
log.PanicIf(err)
if s != "[1 2]" {
t.Fatalf("Format output not correct (floats): [%s]", s)
}
}
func TestFormat__Double(t *testing.T) {
r := []byte{0x40, 0x09, 0x21, 0xfb, 0x53, 0xc8, 0xd4, 0xf1,
0x40, 0x05, 0xbf, 0x0a, 0x89, 0xf1, 0xb0, 0xdd}
s, err := FormatFromBytes(r, TypeDouble, false, TestDefaultByteOrder)
log.PanicIf(err)
if s != "[3.14159265 2.71828182]" {
t.Fatalf("Format output not correct (doubles): [%s]", s)
}
}
func TestFormat__Rational(t *testing.T) { func TestFormat__Rational(t *testing.T) {
r := []byte{ r := []byte{
0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2,
@ -261,6 +310,26 @@ func TestTranslateStringToType__TypeLong(t *testing.T) {
} }
} }
func TestTranslateStringToType__TypeFloat(t *testing.T) {
v, err := TranslateStringToType(TypeFloat, "3.14159265")
log.PanicIf(err)
expected := float32(3.14159265)
if v.(float32) < expected || v.(float32) >= math.Nextafter32(expected, expected+1) {
t.Fatalf("Translation of string to type not correct (float32): %v", v)
}
}
func TestTranslateStringToType__TypeDouble(t *testing.T) {
v, err := TranslateStringToType(TypeDouble, "3.14159265")
log.PanicIf(err)
expected := float64(3.14159265)
if v.(float64) < expected || v.(float64) >= math.Nextafter(expected, expected+1) {
t.Fatalf("Translation of string to type not correct (double): %v", v)
}
}
func TestTranslateStringToType__TypeRational(t *testing.T) { func TestTranslateStringToType__TypeRational(t *testing.T) {
v, err := TranslateStringToType(TypeRational, "11/22") v, err := TranslateStringToType(TypeRational, "11/22")
log.PanicIf(err) log.PanicIf(err)

View File

@ -315,6 +315,40 @@ func (vc *ValueContext) ReadLongs() (value []uint32, err error) {
return value, nil return value, nil
} }
// ReadFloats parses the list of encoded, floats from the value-context.
func (vc *ValueContext) ReadFloats() (value []float32, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
rawValue, err := vc.readRawEncoded()
log.PanicIf(err)
value, err = parser.ParseFloats(rawValue, vc.unitCount, vc.byteOrder)
log.PanicIf(err)
return value, nil
}
// ReadDoubles parses the list of encoded, doubles from the value-context.
func (vc *ValueContext) ReadDoubles() (value []float64, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
rawValue, err := vc.readRawEncoded()
log.PanicIf(err)
value, err = parser.ParseDoubles(rawValue, vc.unitCount, vc.byteOrder)
log.PanicIf(err)
return value, nil
}
// ReadRationals parses the list of encoded, unsigned rationals from the value- // ReadRationals parses the list of encoded, unsigned rationals from the value-
// context. // context.
func (vc *ValueContext) ReadRationals() (value []Rational, err error) { func (vc *ValueContext) ReadRationals() (value []Rational, err error) {

View File

@ -2,6 +2,7 @@ package exifcommon
import ( import (
"bytes" "bytes"
"math"
"reflect" "reflect"
"testing" "testing"
@ -950,6 +951,72 @@ func TestValueContext_ReadLongs(t *testing.T) {
} }
} }
func TestValueContext_ReadFloats(t *testing.T) {
unitCount := uint32(2)
rawValueOffset := []byte{0, 0, 0, 4}
valueOffset := uint32(4)
data := []byte{0x40, 0x49, 0x0f, 0xdb, 0x40, 0x2d, 0xf8, 0x54}
addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeFloat,
TestDefaultByteOrder)
value, err := vc.ReadFloats()
log.PanicIf(err)
expectedResult := []float32{3.14159265, 2.71828182}
for i, v := range value {
if v < expectedResult[i] || v >= math.Nextafter32(expectedResult[i], expectedResult[i]+1) {
t.Fatalf("ReadFloats expecting %v, received %v", expectedResult[i], v)
}
}
}
func TestValueContext_ReadDoubles(t *testing.T) {
unitCount := uint32(2)
rawValueOffset := []byte{0, 0, 0, 4}
valueOffset := uint32(4)
data := []byte{0x40, 0x09, 0x21, 0xfb, 0x53, 0xc8, 0xd4, 0xf1,
0x40, 0x05, 0xbf, 0x0a, 0x89, 0xf1, 0xb0, 0xdd}
addressableData := []byte{0, 0, 0, 0}
addressableData = append(addressableData, data...)
sb := rifs.NewSeekableBufferWithBytes(addressableData)
vc := NewValueContext(
"aa/bb",
0x1234,
unitCount,
valueOffset,
rawValueOffset,
sb,
TypeDouble,
TestDefaultByteOrder)
value, err := vc.ReadDoubles()
log.PanicIf(err)
expectedResult := []float64{3.14159265, 2.71828182}
for i, v := range value {
if v < expectedResult[i] || v >= math.Nextafter(expectedResult[i], expectedResult[i]+1) {
t.Fatalf("ReadDoubles expecting %v, received %v", expectedResult[i], v)
}
}
}
func TestValueContext_ReadRationals(t *testing.T) { func TestValueContext_ReadRationals(t *testing.T) {
unitCount := uint32(2) unitCount := uint32(2)

View File

@ -2,6 +2,7 @@ package exifcommon
import ( import (
"bytes" "bytes"
"math"
"reflect" "reflect"
"time" "time"
@ -113,6 +114,44 @@ func (ve *ValueEncoder) encodeLongs(value []uint32) (ed EncodedData, err error)
return ed, nil return ed, nil
} }
func (ve *ValueEncoder) encodeFloats(value []float32) (ed EncodedData, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
ed.UnitCount = uint32(len(value))
ed.Encoded = make([]byte, ed.UnitCount*4)
for i := uint32(0); i < ed.UnitCount; i++ {
ve.byteOrder.PutUint32(ed.Encoded[i*4:(i+1)*4], math.Float32bits(value[i]))
}
ed.Type = TypeFloat
return ed, nil
}
func (ve *ValueEncoder) encodeDoubles(value []float64) (ed EncodedData, err error) {
defer func() {
if state := recover(); state != nil {
err = log.Wrap(state.(error))
}
}()
ed.UnitCount = uint32(len(value))
ed.Encoded = make([]byte, ed.UnitCount*8)
for i := uint32(0); i < ed.UnitCount; i++ {
ve.byteOrder.PutUint64(ed.Encoded[i*8:(i+1)*8], math.Float64bits(value[i]))
}
ed.Type = TypeDouble
return ed, nil
}
func (ve *ValueEncoder) encodeRationals(value []Rational) (ed EncodedData, err error) { func (ve *ValueEncoder) encodeRationals(value []Rational) (ed EncodedData, err error) {
defer func() { defer func() {
if state := recover(); state != nil { if state := recover(); state != nil {
@ -190,33 +229,38 @@ func (ve *ValueEncoder) Encode(value interface{}) (ed EncodedData, err error) {
} }
}() }()
switch value.(type) { switch t := value.(type) {
case []byte: case []byte:
ed, err = ve.encodeBytes(value.([]byte)) ed, err = ve.encodeBytes(t)
log.PanicIf(err) log.PanicIf(err)
case string: case string:
ed, err = ve.encodeAscii(value.(string)) ed, err = ve.encodeAscii(t)
log.PanicIf(err) log.PanicIf(err)
case []uint16: case []uint16:
ed, err = ve.encodeShorts(value.([]uint16)) ed, err = ve.encodeShorts(t)
log.PanicIf(err) log.PanicIf(err)
case []uint32: case []uint32:
ed, err = ve.encodeLongs(value.([]uint32)) ed, err = ve.encodeLongs(t)
log.PanicIf(err)
case []float32:
ed, err = ve.encodeFloats(t)
log.PanicIf(err)
case []float64:
ed, err = ve.encodeDoubles(t)
log.PanicIf(err) log.PanicIf(err)
case []Rational: case []Rational:
ed, err = ve.encodeRationals(value.([]Rational)) ed, err = ve.encodeRationals(t)
log.PanicIf(err) log.PanicIf(err)
case []int32: case []int32:
ed, err = ve.encodeSignedLongs(value.([]int32)) ed, err = ve.encodeSignedLongs(t)
log.PanicIf(err) log.PanicIf(err)
case []SignedRational: case []SignedRational:
ed, err = ve.encodeSignedRationals(value.([]SignedRational)) ed, err = ve.encodeSignedRationals(t)
log.PanicIf(err) log.PanicIf(err)
case time.Time: case time.Time:
// For convenience, if the user doesn't want to deal with translation // For convenience, if the user doesn't want to deal with translation
// semantics with timestamps. // semantics with timestamps.
t := value.(time.Time)
s := ExifFullTimestampString(t) s := ExifFullTimestampString(t)
ed, err = ve.encodeAscii(s) ed, err = ve.encodeAscii(s)

View File

@ -2,6 +2,7 @@ package exifcommon
import ( import (
"bytes" "bytes"
"math"
"reflect" "reflect"
"testing" "testing"
"time" "time"
@ -173,6 +174,80 @@ func TestValueEncoder_encodeLongs__Cycle(t *testing.T) {
} }
} }
func TestValueEncoder_encodeFloats__Cycle(t *testing.T) {
byteOrder := TestDefaultByteOrder
ve := NewValueEncoder(byteOrder)
original := []float32{3.14159265, 2.71828182, 51.0, 68.0, 85.0}
ed, err := ve.encodeFloats(original)
log.PanicIf(err)
if ed.Type != TypeFloat {
t.Fatalf("IFD type not expected.")
}
expected := []byte{
0x40, 0x49, 0x0f, 0xdb,
0x40, 0x2d, 0xf8, 0x54,
0x42, 0x4c, 0x00, 0x00,
0x42, 0x88, 0x00, 0x00,
0x42, 0xaa, 0x00, 0x00,
}
if bytes.Equal(ed.Encoded, expected) != true {
t.Fatalf("Data not encoded correctly.")
} else if ed.UnitCount != 5 {
t.Fatalf("Unit-count not correct.")
}
recovered, err := parser.ParseFloats(ed.Encoded, ed.UnitCount, byteOrder)
log.PanicIf(err)
for i, v := range recovered {
if v < original[i] || v >= math.Nextafter32(original[i], original[i]+1) {
t.Fatalf("ReadFloats expecting %v, received %v", original[i], v)
}
}
}
func TestValueEncoder_encodeDoubles__Cycle(t *testing.T) {
byteOrder := TestDefaultByteOrder
ve := NewValueEncoder(byteOrder)
original := []float64{3.14159265, 2.71828182, 954877.1230695, 68.0, 85.0}
ed, err := ve.encodeDoubles(original)
log.PanicIf(err)
if ed.Type != TypeDouble {
t.Fatalf("IFD type not expected.")
}
expected := []byte{
0x40, 0x09, 0x21, 0xfb, 0x53, 0xc8, 0xd4, 0xf1,
0x40, 0x05, 0xbf, 0x0a, 0x89, 0xf1, 0xb0, 0xdd,
0x41, 0x2d, 0x23, 0xfa, 0x3f, 0x02, 0xf7, 0x2b,
0x40, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
}
if reflect.DeepEqual(ed.Encoded, expected) != true {
t.Fatalf("Data not encoded correctly.")
} else if ed.UnitCount != 5 {
t.Fatalf("Unit-count not correct.")
}
recovered, err := parser.ParseDoubles(ed.Encoded, ed.UnitCount, byteOrder)
log.PanicIf(err)
for i, v := range recovered {
if v < original[i] || v >= math.Nextafter(original[i], original[i]+1) {
t.Fatalf("ReadDoubles expecting %v, received %v", original[i], v)
}
}
}
func TestValueEncoder_encodeRationals__Cycle(t *testing.T) { func TestValueEncoder_encodeRationals__Cycle(t *testing.T) {
byteOrder := TestDefaultByteOrder byteOrder := TestDefaultByteOrder
ve := NewValueEncoder(byteOrder) ve := NewValueEncoder(byteOrder)
@ -431,6 +506,64 @@ func TestValueEncoder_Encode__Long(t *testing.T) {
} }
} }
func TestValueEncoder_Encode__Float(t *testing.T) {
byteOrder := TestDefaultByteOrder
ve := NewValueEncoder(byteOrder)
original := []float32{3.14159265, 2.71828182, 51.0, 68.0, 85.0}
ed, err := ve.Encode(original)
log.PanicIf(err)
if ed.Type != TypeFloat {
t.Fatalf("IFD type not expected.")
}
expected := []byte{
0x40, 0x49, 0x0f, 0xdb,
0x40, 0x2d, 0xf8, 0x54,
0x42, 0x4c, 0x00, 0x00,
0x42, 0x88, 0x00, 0x00,
0x42, 0xaa, 0x00, 0x00,
}
if bytes.Equal(ed.Encoded, expected) != true {
t.Fatalf("Data not encoded correctly.")
} else if ed.UnitCount != 5 {
t.Fatalf("Unit-count not correct.")
}
}
func TestValueEncoder_Encode__Doubles(t *testing.T) {
byteOrder := TestDefaultByteOrder
ve := NewValueEncoder(byteOrder)
original := []float64{3.14159265, 2.71828182, 954877.1230695, 68.0, 85.0}
ed, err := ve.Encode(original)
log.PanicIf(err)
if ed.Type != TypeDouble {
t.Fatalf("IFD type not expected.")
}
expected := []byte{
0x40, 0x09, 0x21, 0xfb, 0x53, 0xc8, 0xd4, 0xf1,
0x40, 0x05, 0xbf, 0x0a, 0x89, 0xf1, 0xb0, 0xdd,
0x41, 0x2d, 0x23, 0xfa, 0x3f, 0x02, 0xf7, 0x2b,
0x40, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0x55, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00,
}
if bytes.Equal(ed.Encoded, expected) != true {
t.Fatalf("Data not encoded correctly.")
} else if ed.UnitCount != 5 {
t.Fatalf("Unit-count not correct.")
}
}
func TestValueEncoder_Encode__Rational(t *testing.T) { func TestValueEncoder_Encode__Rational(t *testing.T) {
byteOrder := TestDefaultByteOrder byteOrder := TestDefaultByteOrder
ve := NewValueEncoder(byteOrder) ve := NewValueEncoder(byteOrder)