Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: Field overrides part of anonymous struct in order preserving mode #421

Closed
oncilla opened this issue Jul 1, 2020 · 3 comments
Closed
Assignees

Comments

@oncilla
Copy link
Contributor

oncilla commented Jul 1, 2020

Describe the bug

When encoding a struct that includes the anonymous in order preserving mode, the last field of the anonymous struct is overridden with the next field in the parent struct.

When reproducing the problem, I also found out that anonymous pointer types are not encoded at all.

To Reproduce

Following test can be used to reproduce the bug:

func TestMarshalNestedAnonymousStructsBug(t *testing.T) {
	type Basic struct {
		Address string `toml:"address"`
		Port    int    `toml:"port"`
	}
	type Extended struct {
		Basic
		Secret string `toml:"secret"`
	}
	type ExtendedPtr struct {
		*Basic
		Secret string `toml:"secret"`
	}

	expected := `
[config]
  address = ""
  port = 0
  secret = ""
`
	tests := map[string]struct {
		Encoder func(w io.Writer) *Encoder
		Input   interface{}
	}{
		"alphabetical": {
			Encoder: func(w io.Writer) *Encoder { return NewEncoder(w).Order(OrderAlphabetical) },
			Input: struct {
				Config Extended `toml:"config"`
			}{},
		},
		"alphabetical pointer": {
			Encoder: func(w io.Writer) *Encoder { return NewEncoder(w).Order(OrderAlphabetical) },
			Input: struct {
				Config ExtendedPtr `toml:"config"`
			}{},
		},
		"preserve": {
			Encoder: func(w io.Writer) *Encoder { return NewEncoder(w).Order(OrderPreserve) },
			Input: struct {
				Config Extended `toml:"config"`
			}{},
		},
		"preserve pointer": {
			Encoder: func(w io.Writer) *Encoder { return NewEncoder(w).Order(OrderPreserve) },
			Input: struct {
				Config ExtendedPtr `toml:"config"`
			}{},
		},
	}
	for name, test := range tests {
		t.Run(name, func(t *testing.T) {
			var buf bytes.Buffer
			if err := test.Encoder(&buf).Encode(test.Input); err != nil {
				t.Fatalf("unexpected error: %s", err.Error())
			}
			if !bytes.Equal(buf.Bytes(), []byte(expected)) {
				t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, buf.String())
			}
		})
	}
}

Output:

--- FAIL: TestMarshalNestedAnonymousStructsBug (0.00s)
    --- FAIL: TestMarshalNestedAnonymousStructsBug/preserve_pointer (0.00s)
        marshal_test.go:2513: Bad marshal: expected
            -----
            
            [config]
              address = ""
              port = 0
              secret = ""
            
            -----
            got
            -----
            
            [config]
              secret = ""
            
            -----
    --- FAIL: TestMarshalNestedAnonymousStructsBug/alphabetical_pointer (0.00s)
        marshal_test.go:2513: Bad marshal: expected
            -----
            
            [config]
              address = ""
              port = 0
              secret = ""
            
            -----
            got
            -----
            
            [config]
              secret = ""
            
            -----
    --- FAIL: TestMarshalNestedAnonymousStructsBug/preserve (0.00s)
        marshal_test.go:2513: Bad marshal: expected
            -----
            
            [config]
              address = ""
              port = 0
              secret = ""
            
            -----
            got
            -----
            
            [config]
              address = ""
              secret = ""
              secret = ""
            
            -----

Expected behavior

No error in the above test case.
I.e., the output for all test cases is:

[config]
  address = ""
  port = 0
  secret = ""

Versions

  • go-toml: 88263a0
  • go: 1.14
  • operating system: Linux
@AllenX2018
Copy link
Contributor

Thanks for reporting!

@AllenX2018 AllenX2018 self-assigned this Jul 3, 2020
AllenX2018 added a commit that referenced this issue Jul 8, 2020
@AllenX2018
Copy link
Contributor

When encoding a struct that includes the anonymous in order preserving mode, the last field of the anonymous struct is overridden with the next field in the parent struct.

I've fixed this via 34de94e, you can check again with the latest version

When reproducing the problem, I also found out that anonymous pointer types are not encoded at all.

I also check this and I found that's because your pointer is nil. In this case, it can not be dereferenced so it will not be encoded.

@oncilla
Copy link
Contributor Author

oncilla commented Jul 11, 2020

@AllenX2018 Tank you very much for the swift fix. Much appreciated.

I verified it works on the test case I attached to this issue.

@oncilla oncilla closed this as completed Jul 11, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants