sanposhiho / gomockhandler

Mr. gomockhandler is the clever and more agile manager of golang/mock (uber/mock) 👔
MIT License
111 stars 9 forks source link

the order on generated configuration is randomly changed #57

Closed handball811 closed 3 years ago

handball811 commented 3 years ago

Currently if we do gomockhandler mockgen order of content randomly changed, although there is no changes. For Example:

// before
{
    "mocks": {
        "a_mock.go": {
            "checksum": "xxxxxxxxxxx",
            "source_checksum": "aaaaaaaaaaaaa",
            "mode": "SOURCE_MODE",
            "source_mode_runner": {
                "source": "a.go",
                "destination": "a_mock.go",
                "package": "main"
            }
        },
        "b_mock.go": {
            "checksum": "yyyyyyyyyyyy",
            "source_checksum": "bbbbbbbbbbb",
            "mode": "SOURCE_MODE",
            "source_mode_runner": {
                "source": "b.go",
                "destination": "b_mock.go",
                "package": "main"
            }
        }
}
// after
{
    "mocks": {
        "b_mock.go": {
            "checksum": "yyyyyyyyyyyy",
            "source_checksum": "bbbbbbbbbbb",
            "mode": "SOURCE_MODE",
            "source_mode_runner": {
                "source": "b.go",
                "destination": "b_mock.go",
                "package": "main"
            }
        },
        "a_mock.go": {
            "checksum": "xxxxxxxxxxx",
            "source_checksum": "aaaaaaaaaaaaa",
            "mode": "SOURCE_MODE",
            "source_mode_runner": {
                "source": "a.go",
                "destination": "a_mock.go",
                "package": "main"
            }
        }
}

This behavior becomes some noise when we manage config file by git. I recommend those contents to be dictionary order to avoid this problem.

I think the part below leads this phenomenon. https://github.com/sanposhiho/gomockhandler/blob/6247fdf33a84302a90a32bd84a33bff28386351e/internal/model/config_easyjson.go#L87

Thank you.

sanposhiho commented 3 years ago

Hi @handball811~ Thank you for reporting the issue.

Currently if we do gomockhandler mockgen order of content randomly changed

Definitely, it should be fixed. I'll check it and work on the issue.

sanposhiho commented 3 years ago

Hm, the issue came from the issue on easyjson. https://github.com/mailru/easyjson/issues/292

We may have to say goodbye to easyjson.

handball811 commented 3 years ago

Thank you for your response! If you don't mind of taking time of marshaling, you can use this code for example. (encoding/json generally supports dictionary order.)

package model

import (
    "encoding/base64"
    "encoding/json"
    "fmt"

    reflectmode "github.com/sanposhiho/gomockhandler/internal/mockgen/reflectmode"
    sourcemode "github.com/sanposhiho/gomockhandler/internal/mockgen/sourcemode"
)

type ConfigJson struct {
    // key: destination
    Mocks map[string]*MockJson `json:"mocks"`
}

type MockJson struct {
    MockCheckSum      string              `json:"checksum,omitempty"`
    SourceChecksum    string              `json:"source_checksum,omitempty"`
    Mode              mode                `json:"mode"`
    ReflectModeRunner *reflectmode.Runner `json:"reflect_mode_runner,omitempty"`
    SourceModeRunner  *sourcemode.Runner  `json:"source_mode_runner,omitempty"`
}

func (j *MockJson) FromMock(src *Mock) {
    if src.MockCheckSum != [16]byte{} {
        j.MockCheckSum = base64.StdEncoding.EncodeToString(src.MockCheckSum[:])
    }
    if src.SourceChecksum != [16]byte{} {
        j.SourceChecksum = base64.StdEncoding.EncodeToString(src.SourceChecksum[:])
    }
    j.Mode = src.Mode
    j.ReflectModeRunner = src.ReflectModeRunner
    j.SourceModeRunner = src.SourceModeRunner
}

func GenerateConfig(src *Config) *ConfigJson {
    dst := &ConfigJson{
        Mocks: make(map[string]*MockJson),
    }
    for k, v := range src.Mocks {
        mockJson := new(MockJson)
        mockJson.FromMock(v)
        dst.Mocks[k] = mockJson
    }
    return dst
}

func ExampleConfig() {
    config := Config{
        Mocks: map[string]*Mock{
            "a": {
                MockCheckSum:   [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5},
                SourceChecksum: [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5},
                Mode:           SourceMode,
            },
            "b": {
                MockCheckSum: [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5},
                Mode:         SourceMode,
            },
        },
    }

    bytes, _ := json.Marshal(config)

    fmt.Println(string(bytes))

    // Output:
    // {"mocks":{"a":{"checksum":"AAECAwQFBgcICQABAgMEBQ==","source_checksum":"AAECAwQFBgcICQABAgMEBQ==","mode":"SOURCE_MODE"},"b":{"checksum":"AAECAwQFBgcICQABAgMEBQ==","source_checksum":"AAAAAAAAAAAAAAAAAAAAAA==","mode":"SOURCE_MODE"}}}
}

func ExampleConfigJson() {
    config := Config{
        Mocks: map[string]*Mock{
            "a": {
                MockCheckSum:   [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5},
                SourceChecksum: [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5},
                Mode:           SourceMode,
            },
            "b": {
                MockCheckSum: [16]byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5},
                Mode:         SourceMode,
            },
        },
    }

    jsonConfig := GenerateConfig(&config)

    bytes, _ := json.Marshal(jsonConfig)

    fmt.Println(string(bytes))

    // Output:
    // {"mocks":{"a":{"checksum":"AAECAwQFBgcICQABAgMEBQ==","source_checksum":"AAECAwQFBgcICQABAgMEBQ==","mode":"SOURCE_MODE"},"b":{"checksum":"AAECAwQFBgcICQABAgMEBQ==","mode":"SOURCE_MODE"}}}
}
sanposhiho commented 3 years ago

Thanks @handball811, fixed in #58