From 4fafd0845ed1b8cc46cfc3a2a9ba64f2000ff405 Mon Sep 17 00:00:00 2001 From: "Gerasimos (Makis) Maropoulos" Date: Tue, 1 Sep 2020 11:35:13 +0300 Subject: [PATCH] fixes from upstream --- decoder.go | 11 +++++++++++ decoder_test.go | 39 +++++++++++++++++++++++++++++++++++++++ encoder.go | 7 +++++++ encoder_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) diff --git a/decoder.go b/decoder.go index 18222a1..99538e2 100644 --- a/decoder.go +++ b/decoder.go @@ -192,6 +192,17 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values } v = v.Elem() } + + // alloc embedded structs + if v.Type().Kind() == reflect.Struct { + for i := 0; i < v.NumField(); i++ { + field := v.Field(i) + if field.Type().Kind() == reflect.Ptr && field.IsNil() && v.Type().Field(i).Anonymous == true { + field.Set(reflect.New(field.Type().Elem())) + } + } + } + v = v.FieldByName(name) } // Don't even bother for unexported fields. diff --git a/decoder_test.go b/decoder_test.go index c368ee9..5820b10 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -1968,3 +1968,42 @@ func TestTextUnmarshalerEmpty(t *testing.T) { t.Errorf("Expected %v errors, got %v", expected, s.Value) } } + +type S23n struct { + F2 string `schema:"F2"` + F3 string `schema:"F3"` +} + +type S23e struct { + *S23n + F1 string `schema:"F1"` +} + +type S23 []*S23e + +func TestUnmashalPointerToEmbedded(t *testing.T) { + data := map[string][]string{ + "A.0.F2": {"raw a"}, + "A.0.F3": {"raw b"}, + } + + // Implements encoding.TextUnmarshaler, should not throw invalid path + // error. + s := struct { + Value S23 `schema:"A"` + }{} + decoder := NewDecoder() + + if err := decoder.Decode(&s, data); err != nil { + t.Fatal("Error while decoding:", err) + } + + expected := S23{ + &S23e{ + S23n: &S23n{"raw a", "raw b"}, + }, + } + if !reflect.DeepEqual(expected, s.Value) { + t.Errorf("Expected %v errors, got %v", expected, s.Value) + } +} diff --git a/encoder.go b/encoder.go index 4a538a2..7caf865 100644 --- a/encoder.go +++ b/encoder.go @@ -62,6 +62,13 @@ func isZero(v reflect.Value) bool { } return z case reflect.Struct: + type zero interface { + IsZero() bool + } + if v.Type().Implements(reflect.TypeOf((*zero)(nil)).Elem()) { + iz := v.MethodByName("IsZero").Call([]reflect.Value{})[0] + return iz.Interface().(bool) + } z := true for i := 0; i < v.NumField(); i++ { z = z && isZero(v.Field(i)) diff --git a/encoder_test.go b/encoder_test.go index 200cb32..5d26e5a 100644 --- a/encoder_test.go +++ b/encoder_test.go @@ -4,6 +4,7 @@ import ( "fmt" "reflect" "testing" + "time" ) type E1 struct { @@ -417,3 +418,48 @@ func TestRegisterEncoderCustomArrayType(t *testing.T) { encoder.Encode(s, vals) } } + +func TestRegisterEncoderStructIsZero(t *testing.T) { + type S1 struct { + SomeTime1 time.Time `schema:"tim1,omitempty"` + SomeTime2 time.Time `schema:"tim2,omitempty"` + } + + ss := []*S1{ + { + SomeTime1: time.Date(2020, 8, 4, 13, 30, 1, 0, time.UTC), + }, + } + + for s := range ss { + vals := map[string][]string{} + + encoder := NewEncoder() + encoder.RegisterEncoder(time.Time{}, func(value reflect.Value) string { + return value.Interface().(time.Time).Format(time.RFC3339Nano) + }) + + err := encoder.Encode(ss[s], vals) + if err != nil { + t.Errorf("Encoder has non-nil error: %v", err) + } + + ta, ok := vals["tim1"] + if !ok { + t.Error("expected tim1 to be present") + } + + if len(ta) != 1 { + t.Error("expected tim1 to be present") + } + + if "2020-08-04T13:30:01Z" != ta[0] { + t.Error("expected correct tim1 time") + } + + _, ok = vals["tim2"] + if ok { + t.Error("expected tim1 not to be present") + } + } +}