Skip to content

Commit

Permalink
returns goavro specific error type structures
Browse files Browse the repository at this point in the history
  • Loading branch information
Karrick S. McDermott committed Mar 27, 2015
1 parent 70fcb51 commit abf705a
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 239 deletions.
231 changes: 140 additions & 91 deletions codec.go

Large diffs are not rendered by default.

34 changes: 17 additions & 17 deletions codec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func TestCodecDecoderPrimitives(t *testing.T) {
// null
checkCodecDecoderResult(t, `"null"`, []byte("\x01"), nil)
// boolean
checkCodecDecoderError(t, `"boolean"`, []byte("\x02"), "cannot decode boolean: 2")
checkCodecDecoderError(t, `"boolean"`, []byte("\x02"), "cannot decode boolean")
checkCodecDecoderError(t, `"boolean"`, []byte(""), "cannot decode boolean: EOF")
checkCodecDecoderResult(t, `"boolean"`, []byte("\x00"), false)
checkCodecDecoderResult(t, `"boolean"`, []byte("\x01"), true)
Expand Down Expand Up @@ -315,9 +315,9 @@ func TestCodecEncoderPrimitives(t *testing.T) {
func TestCodecUnionChecksSchema(t *testing.T) {
var err error
_, err = NewCodec(`[]`)
checkErrorFatal(t, err, "union ought have at least one member")
checkErrorFatal(t, err, "ought have at least one member")
_, err = NewCodec(`["null","flubber"]`)
checkErrorFatal(t, err, "union member ought to be decodable")
checkErrorFatal(t, err, "member ought to be decodable")
}

func TestCodecUnionPrimitives(t *testing.T) {
Expand Down Expand Up @@ -405,7 +405,7 @@ func TestCodecDecoderEnum(t *testing.T) {

func TestCodecEncoderEnum(t *testing.T) {
schema := `{"type":"enum","name":"cards","symbols":["HEARTS","DIAMONDS","SPADES","CLUBS"]}`
checkCodecEncoderError(t, schema, []byte("\x01"), "expected: string; actual: []uint8")
checkCodecEncoderError(t, schema, []byte("\x01"), "expected: string; received: []uint8")
checkCodecEncoderError(t, schema, "some symbol not in schema", "symbol not defined")
checkCodecEncoderResult(t, schema, "SPADES", []byte("\x04"))
}
Expand All @@ -430,9 +430,9 @@ func TestCodecFixed(t *testing.T) {
schema := `{"type":"fixed","name":"fixed1","size":5}`
checkCodecDecoderError(t, schema, []byte(""), "EOF")
checkCodecDecoderError(t, schema, []byte("hap"), "buffer underrun")
checkCodecEncoderError(t, schema, "happy day", "expected: []byte; actual: string")
checkCodecEncoderError(t, schema, []byte("day"), "expected: 5 bytes; actual: 3")
checkCodecEncoderError(t, schema, []byte("happy day"), "expected: 5 bytes; actual: 9")
checkCodecEncoderError(t, schema, "happy day", "expected: []byte; received: string")
checkCodecEncoderError(t, schema, []byte("day"), "expected: 5 bytes; received: 3")
checkCodecEncoderError(t, schema, []byte("happy day"), "expected: 5 bytes; received: 9")
checkCodecEncoderResult(t, schema, []byte("happy"), []byte("happy"))
}

Expand Down Expand Up @@ -465,7 +465,7 @@ func TestCodecRecordFieldChecksDefaultType(t *testing.T) {

bb := new(bytes.Buffer)
err = codec.Encode(bb, someRecord)
checkError(t, err, "expected: int32; actual: bool")
checkError(t, err, "expected: int32; received: bool")
// checkError(t, err, "field default value is wrong type")
}

Expand All @@ -476,7 +476,7 @@ func TestCodecEncoderArrayChecksSchema(t *testing.T) {
_, err = NewCodec(`{"type":"array","items":"flubber"}`)
checkErrorFatal(t, err, "unknown type name")

checkCodecEncoderError(t, `{"type":"array","items":"long"}`, int64(5), "expected: []interface{}; actual: int64")
checkCodecEncoderError(t, `{"type":"array","items":"long"}`, int64(5), "expected: []interface{}; received: int64")
}

func TestCodecDecoderArrayEOF(t *testing.T) {
Expand Down Expand Up @@ -660,8 +660,8 @@ func TestCodecMapChecksSchema(t *testing.T) {
_, err = NewCodec(`{"type":"map","values":"flubber"}`)
checkErrorFatal(t, err, "unknown type name")

checkCodecEncoderError(t, `{"type":"map","values":"long"}`, int64(5), "expected: map[string]interface{}; actual: int64")
checkCodecEncoderError(t, `{"type":"map","values":"string"}`, 3, "expected: map[string]interface{}; actual: int")
checkCodecEncoderError(t, `{"type":"map","values":"long"}`, int64(5), "expected: map[string]interface{}; received: int64")
checkCodecEncoderError(t, `{"type":"map","values":"string"}`, 3, "expected: map[string]interface{}; received: int")
}

func TestCodecDecoderMapEOF(t *testing.T) {
Expand All @@ -682,7 +682,7 @@ func TestCodecDecoderMapZeroBlocks(t *testing.T) {
t.Errorf("Actual: %#v; Expected: %#v", ok, true)
}
if len(someMap) != 0 {
t.Errorf(`Actual: %v; Expected: %v`, len(someMap), 0)
t.Errorf(`received: %v; Expected: %v`, len(someMap), 0)
}
}

Expand All @@ -699,7 +699,7 @@ func TestCodecDecoderMapReturnsExpectedMap(t *testing.T) {
t.Errorf("Actual: %#v; Expected: %#v", ok, true)
}
if len(someMap) != 1 {
t.Errorf(`Actual: %v; Expected: %v`, len(someMap), 1)
t.Errorf(`received: %v; Expected: %v`, len(someMap), 1)
}
datum, ok := someMap["foo"]
if !ok {
Expand All @@ -718,7 +718,7 @@ func TestCodecEncoderMapChecksValueTypeDuringWrite(t *testing.T) {
schema := `{"type":"map","values":"string"}`
datum := make(map[string]interface{})
datum["name"] = 13
checkCodecEncoderError(t, schema, datum, "expected: string; actual: int")
checkCodecEncoderError(t, schema, datum, "expected: string; received: int")
}

func TestCodecEncoderMapMetadataSchema(t *testing.T) {
Expand Down Expand Up @@ -750,7 +750,7 @@ func TestCodecRecordChecksSchema(t *testing.T) {
checkError(t, err, "name ought to be non-empty string")

_, err = NewCodec(`{"type":"record","name":"Foo"}`)
checkError(t, err, "record requires fields")
checkError(t, err, "record requires one or more fields")

_, err = NewCodec(`{"type":"record","name":"Foo","fields":5}`)
checkError(t, err, "fields ought to be non-empty array")
Expand All @@ -759,13 +759,13 @@ func TestCodecRecordChecksSchema(t *testing.T) {
checkError(t, err, "fields ought to be non-empty array")

_, err = NewCodec(`{"type":"record","name":"Foo","fields":["foo"]}`)
checkError(t, err, "cannot create record field: schema expected")
checkError(t, err, "schema expected")

_, err = NewCodec(`{"type":"record","name":"Foo","fields":[{"type":"int"}]}`)
checkError(t, err, "ought to have name key")

_, err = NewCodec(`{"type":"record","name":"Foo","fields":[{"name":"field1","type":5}]}`)
checkError(t, err, "schema type")
checkError(t, err, "type ought to be")

_, err = NewCodec(`{"type":"record","name":"Foo","fields":[{"type":"int"}]}`)
checkError(t, err, "ought to have name key")
Expand Down
36 changes: 0 additions & 36 deletions common.go

This file was deleted.

32 changes: 0 additions & 32 deletions common_test.go

This file was deleted.

85 changes: 59 additions & 26 deletions decoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,52 @@ import (
"math"
)

// ErrDecoder is returned when the encoder encounters an error.
type ErrDecoder struct {
Message string
Err error
}

func (e ErrDecoder) Error() string {
if e.Err == nil {
return "cannot decode " + e.Message
} else {
return "cannot decode " + e.Message + ": " + e.Err.Error()
}
}

func newDecoderError(dataType string, a ...interface{}) *ErrDecoder {
var err error
var format, message string
var ok bool
if len(a) == 0 {
return &ErrDecoder{dataType + ": no reason given", nil}
}
// if last item is error: save it
if err, ok = a[len(a)-1].(error); ok {
a = a[:len(a)-1] // pop it
}
// if items left, first ought to be format string
if len(a) > 0 {
if format, ok = a[0].(string); ok {
a = a[1:] // unshift
message = fmt.Sprintf(format, a...)
}
}
if message != "" {
message = ": " + message
}
return &ErrDecoder{dataType + message, err}
}

func nullDecoder(_ io.Reader) (interface{}, error) {
return nil, nil
}

func booleanDecoder(r io.Reader) (interface{}, error) {
bb := make([]byte, 1)
_, err := r.Read(bb)
if err != nil {
return nil, fmt.Errorf("cannot decode boolean: %v", err)
if _, err := r.Read(bb); err != nil {
return nil, newDecoderError("boolean", err)
}
var datum bool
switch bb[0] {
Expand All @@ -42,7 +79,7 @@ func booleanDecoder(r io.Reader) (interface{}, error) {
case byte(1):
datum = true
default:
return nil, fmt.Errorf("cannot decode boolean: %x", bb[0])
return nil, newDecoderError("boolean", "expected 1 or 0; received: %d", bb[0])
}
return datum, nil
}
Expand All @@ -52,9 +89,8 @@ func intDecoder(r io.Reader) (interface{}, error) {
var err error
bb := make([]byte, 1)
for shift := uint(0); ; shift += 7 {
_, err = r.Read(bb)
if err != nil {
return nil, fmt.Errorf("cannot decode int: %v", err)
if _, err = r.Read(bb); err != nil {
return nil, newDecoderError("int", err)
}
b := bb[0]
v |= int(b&mask) << shift
Expand All @@ -71,9 +107,8 @@ func longDecoder(r io.Reader) (interface{}, error) {
var err error
bb := make([]byte, 1)
for shift := uint(0); ; shift += 7 {
_, err = r.Read(bb)
if err != nil {
return nil, fmt.Errorf("cannot decode long: %v", err)
if _, err = r.Read(bb); err != nil {
return nil, newDecoderError("long", err)
}
b := bb[0]
v |= int(b&mask) << shift
Expand All @@ -87,9 +122,8 @@ func longDecoder(r io.Reader) (interface{}, error) {

func floatDecoder(r io.Reader) (interface{}, error) {
buf := make([]byte, 4)
_, err := r.Read(buf)
if err != nil {
return nil, fmt.Errorf("cannot decode float: %v", err)
if _, err := r.Read(buf); err != nil {
return nil, newDecoderError("float", err)
}
bits := binary.LittleEndian.Uint32(buf)
datum := math.Float32frombits(bits)
Expand All @@ -98,9 +132,8 @@ func floatDecoder(r io.Reader) (interface{}, error) {

func doubleDecoder(r io.Reader) (interface{}, error) {
buf := make([]byte, 8)
_, err := r.Read(buf)
if err != nil {
return nil, fmt.Errorf("cannot decode double: %v", err)
if _, err := r.Read(buf); err != nil {
return nil, newDecoderError("double", err)
}
datum := math.Float64frombits(binary.LittleEndian.Uint64(buf))
return datum, nil
Expand All @@ -109,22 +142,22 @@ func doubleDecoder(r io.Reader) (interface{}, error) {
func bytesDecoder(r io.Reader) (interface{}, error) {
someValue, err := longDecoder(r)
if err != nil {
return nil, fmt.Errorf("cannot decode bytes: %v", err)
return nil, newDecoderError("bytes", err)
}
size, ok := someValue.(int64)
if !ok {
return nil, fmt.Errorf("cannot decode bytes: expected int64; actual: %T", someValue)
return nil, newDecoderError("bytes", "expected int64; received: %T", someValue)
}
if size < 0 {
return nil, fmt.Errorf("cannot decode bytes: negative length: %d", size)
return nil, newDecoderError("bytes", "negative length: %d", size)
}
buf := make([]byte, size)
bytesRead, err := r.Read(buf)
if err != nil {
return nil, fmt.Errorf("cannot decode bytes: %v", err)
return nil, newDecoderError("bytes", err)
}
if int64(bytesRead) < size {
return nil, fmt.Errorf("cannot decode bytes: buffer underrun")
return nil, newDecoderError("bytes", "buffer underrun")
}
return buf, nil
}
Expand All @@ -134,22 +167,22 @@ func stringDecoder(r io.Reader) (interface{}, error) {
// but prefer to not have nested error messages
someValue, err := longDecoder(r)
if err != nil {
return nil, fmt.Errorf("cannot decode string: %v", err)
return nil, newDecoderError("string", err)
}
size, ok := someValue.(int64)
if !ok {
return nil, fmt.Errorf("cannot decode string: expected int64; actual: %T", someValue)
return nil, newDecoderError("string", "expected int64; received: %T", someValue)
}
if size < 0 {
return nil, fmt.Errorf("cannot decode string: negative length: %d", size)
return nil, newDecoderError("string", "negative length: %d", size)
}
buf := make([]byte, size)
byteCount, err := r.Read(buf)
if err != nil {
return nil, fmt.Errorf("cannot decode string: %v", err)
return nil, newDecoderError("string", err)
}
if int64(byteCount) < size {
return nil, fmt.Errorf("cannot decode string: buffer underrun")
return nil, newDecoderError("string", "buffer underrun")
}
return string(buf), nil
}
Loading

0 comments on commit abf705a

Please sign in to comment.