traefik / yaegi

Yaegi is Another Elegant Go Interpreter
https://pkg.go.dev/github.com/traefik/yaegi
Apache License 2.0
6.94k stars 343 forks source link

custom json.Marshall and json.Unmarshall fails for object used in array #1486

Open taliesins opened 1 year ago

taliesins commented 1 year ago

The following program sample.go triggers an unexpected result

package int

import (
    "encoding/json"
    "fmt"
    "strings"
    "testing"
)

type CollectionOfTestObject struct {
    Collection []TestObject
}

type TestObject struct {
    Name    string
    Surname string
}

type customTestObject struct {
    FullName string
}

func (t *TestObject) MarshalJSON() ([]byte, error) {
    custom := &customTestObject{
        FullName: fmt.Sprintf("%s %s", t.Name, t.Surname),
    }
    return json.Marshal(custom)
}

func (t *TestObject) UnmarshalJSON(b []byte) error {
    custom := &customTestObject{}
    json.Unmarshal(b, custom)
    fields := strings.Fields(custom.FullName)

    *t = TestObject{
        Name:    fields[0],
        Surname: fields[1],
    }

    return nil
}

func TestObjectSerialization(t *testing.T) {
    testObject := &TestObject{
        Name:    "Name",
        Surname: "Surname",
    }

    json, _ := json.Marshal(testObject)
    actualJson := string(json)
    expectedJson := `{"FullName":"Name Surname"}`

    if actualJson == expectedJson {
        fmt.Println("Passed")
    } else {
        panic(fmt.Errorf("Failed"))
    }
}

func TestObjectDeserialization(t *testing.T) {
    expectedName := "Name"
    expectedSurname := "Surname"
    objectJsonBytes := []byte(fmt.Sprintf(`{"FullName":"%s %s"}`, expectedName, expectedSurname))
    testObject := &TestObject{}
    testObject.UnmarshalJSON(objectJsonBytes)

    if testObject.Name == expectedName && testObject.Surname == expectedSurname {
        fmt.Println("Passed")
    } else {
        panic(fmt.Errorf("Failed"))
    }
}

func TestCollectionObjectSerialization(t *testing.T) {
    testCollectionObject := &CollectionOfTestObject{
        Collection: []TestObject{
            {
                Name:    "Name",
                Surname: "Surname",
            },
        },
    }

    json, _ := json.Marshal(testCollectionObject)
    actualJson := string(json)
    expectedJson := `{"Collection":[{"FullName":"Name Surname"}]}`

    if actualJson == expectedJson {
        fmt.Println("Passed")
    } else {
        panic(fmt.Errorf("Failed"))
    }
}

func TestCollectionObjectDeserialization(t *testing.T) {
    expectedName := "Name"
    expectedSurname := "Surname"
    collectionObjectJsonBytes := []byte(fmt.Sprintf(`{"Collection":[{"FullName":"%s %s"}]}`, expectedName, expectedSurname))
    testCollectionObject := &CollectionOfTestObject{}

    json.Unmarshal(collectionObjectJsonBytes, testCollectionObject)

    if testCollectionObject.Collection[0].Name == expectedName && testCollectionObject.Collection[0].Surname == expectedSurname {
        fmt.Println("Passed")
    } else {
        panic(fmt.Errorf("Failed"))
    }
}

Expected result

=== RUN   TestObjectSerialization
Passed
--- PASS: TestObjectSerialization (0.00s)
=== RUN   TestObjectDeserialization
Passed
--- PASS: TestObjectDeserialization (0.00s)
=== RUN   TestCollectionObjectSerialization
Passed
--- PASS: TestCollectionObjectSerialization (0.00s)
=== RUN   TestCollectionObjectDeserialization
Passed
--- PASS: TestCollectionObjectDeserialization (0.00s)
PASS

Got

C:\Users\taliesin.sisson\go\src\github.com\taliesins\traefik-plugin-oidc>yaegi test -v github.com/taliesins/traefik-plugin-oidc/int
=== RUN   TestCollectionObjectDeserialization
C:\Users\taliesin.sisson\go\src\github.com\taliesins\traefik-plugin-oidc\int\do_test.go:96:2: panic
--- FAIL: TestCollectionObjectDeserialization (0.00s)
panic: <error Value> [recovered]
        panic: <error Value> [recovered]
        panic: <error Value>

goroutine 18 [running]:
testing.tRunner.func1.2({0x13e9360, 0xc00010b2f0})
        C:/Program Files/Go/src/testing/testing.go:1396 +0x24e
testing.tRunner.func1()
        C:/Program Files/Go/src/testing/testing.go:1399 +0x39f
panic({0x13e9360, 0xc00010b2f0})
        C:/Program Files/Go/src/runtime/panic.go:884 +0x212
github.com/traefik/yaegi/interp.runCfg.func1()
        C:/Users/taliesin.sisson/go/pkg/mod/github.com/traefik/yaegi@v0.14.3/interp/run.go:192 +0x148
panic({0x13e9360, 0xc00010b2f0})
        C:/Program Files/Go/src/runtime/panic.go:884 +0x212
github.com/traefik/yaegi/interp._panic.func1(0xc0002f44d0?)
        C:/Users/taliesin.sisson/go/pkg/mod/github.com/traefik/yaegi@v0.14.3/interp/run.go:888 +0x4c
github.com/traefik/yaegi/interp.runCfg(0xc00042b200, 0xc0002f44d0, 0x0?, 0x13d5d40?)
        C:/Users/taliesin.sisson/go/pkg/mod/github.com/traefik/yaegi@v0.14.3/interp/run.go:200 +0x29d
github.com/traefik/yaegi/interp.genFunctionWrapper.func1.1({0xc00010b068, 0x1, 0x1?})
        C:/Users/taliesin.sisson/go/pkg/mod/github.com/traefik/yaegi@v0.14.3/interp/run.go:1002 +0x4a5
testing.tRunner(0xc000105380, 0xc00046a690)
        C:/Program Files/Go/src/testing/testing.go:1446 +0x10b
created by testing.(*T).Run
        C:/Program Files/Go/src/testing/testing.go:1493 +0x35f

C:\Users\taliesin.sisson\go\src\github.com\taliesins\traefik-plugin-oidc>

Yaegi Version

v0.14.3

Additional Notes

No response

taliesins commented 1 year ago

Might be related to #1019