Conversation
| to.Set(pointerize(to.Type(), v.Type(), v)) | ||
| if v.IsValid() { | ||
| to.Set(pointerize(to.Type(), v.Type(), v)) | ||
| } |
There was a problem hiding this comment.
Given the test case I don't see why v can be invalid. Do we have an original issue with sample code? v should always be assignable to to, and return a zero value at least.
As reifyGetField is an internal function processing a sub-tree only, I wonder if the issue can occur in other edge cases as well.
There was a problem hiding this comment.
Do we have an original issue with sample code?
This is the exact extracted part from the linked PR in the issue. Just unpack the given YAML file into a structure with interface{}
There was a problem hiding this comment.
What I'm wondering about is, if this or a similar error can occur when we unpack into some alternative type. For example if one unpacks into a map, then the call to.SetMapIndex(key, v) at line 224 would be the equivalent for maps. For arrays/slices the equivalent call is to.Index(idx).Set(v) in reifyDoArray. Both calls do not check for an invalid reflect.Value yet. Given the bug at hand, I doubt the other 2 cases have tests that might show an error.
There was a problem hiding this comment.
I've added more test cases, but couldn't reproduce. If you see any potential weird structure that can cause an error, I can add a test case.
Other way round is to wrap all to.Set() calls with a condition checking if the target is valid.
There was a problem hiding this comment.
If the tests show that we are fine, I'm ok with that.
maybe we can add these combinations for maps as well:
map[string]interface{}{} , `{"a": []}`
map[string]interface{}{"a": nil} , `{"a": []}`
map[string][]interface{}{}, `{"a": []}`
map[string][]interface{}{"a": nil}, `{"a": []}`
and for arrays:
[]interface{} , `[[]]`
[][]interface{}, `[[]]`
There was a problem hiding this comment.
I've updated test cases, but I think we need to review/accept the final unmarshaled forms (I'm referring specifically to this case: map[string]interface{}{"a": nil} where the field disappears).
There was a problem hiding this comment.
Hm, the field a should not just disappear. If the input configuration does not contain the field, or if it is an empty array, then it should not be overwritten. We want to merge the configuration into the object given. Yet one can discuss what it means to merge an empty array... But it kinda looks like we just found another bug.
I don't want increase the scope for this PR any further. How about skipping this tests that do remove a and create a follow up issue?
There was a problem hiding this comment.
I think I've just fixed this case by checking if the target is valid:
if v.IsValid() {
to.SetMapIndex(key, v)
}
yaml/yaml_test.go
Outdated
| assert.Nil(t, verify.Vars[0].Default) | ||
| assert.Nil(t, verify.Vars[1].Default) | ||
| assert.Equal(t, uint64(3), verify.Vars[2].Default) | ||
| assert.Len(t, verify.Vars[3].Default.([]interface{}), 3) |
There was a problem hiding this comment.
Can we split this up into 4 test cases (e.g. table driven test), or is the error only triggered by this setup?
Was the error triggered for each of these cases?
There was a problem hiding this comment.
Let's add a sample test with an empty array as has been shown in the issue.
There was a problem hiding this comment.
Good catch. It seems that an empty array is also an issue. I simplified the test case.
|
|
||
| type variable struct { | ||
| Default interface{} | ||
| } |
There was a problem hiding this comment.
these types are unique to the test case only. Consider moving the type declaration into TestStructEmptyArray
|
Is this error reproducible if we just unpack into an array, instead of an array within a struct? |
I replied above. It's reproducible - I simplified the test case, a single line seems to be enough. |
|
Should we add a chanelog entry? |
Yes, please. |
Fixed. |
|
I think we might have hit also this: golang/go@201cb04 |
Codecov Report
@@ Coverage Diff @@
## master #160 +/- ##
==========================================
- Coverage 78.63% 78.52% -0.11%
==========================================
Files 24 24
Lines 2822 2827 +5
==========================================
+ Hits 2219 2220 +1
- Misses 440 445 +5
+ Partials 163 162 -1
Continue to review full report at Codecov.
|
This removes testify/assert from only one test file in the ucfg package, and it brings in go-spew to improve the readability of test failures.
error_test.go
Outdated
| adjusted = strings.Replace(adjusted, "\" in duration \"", " in duration ", 1) | ||
| adjusted = strings.Replace(adjusted, "\" accessing", " accessing", 1) | ||
| return adjusted | ||
| } |
There was a problem hiding this comment.
Which go version failed here? For go tip only? If we need it for tip and it is a known error in tip to be fixed soon I would ignore it for now. We check with tip to see if we might be hit by a change in reflection in the stdlib early in time.
If it fails for a released go version let's add a conditional.
There was a problem hiding this comment.
Oh, it's a bug in go1.14 :(
Checking the travis file, I noticed 1.14 is still missing.
There was a problem hiding this comment.
In this case it was "devel". I can adjust the Travis file too, unless you think this should go in a separate PR.
There was a problem hiding this comment.
Hm, if it's just tip I'd remove the function altogether. Although I'd prefer to add go 1.14 in another PR, I'd like to have some assurance that 1.14 does not contain the bug :)
There was a problem hiding this comment.
Let me prepare a PR for this.
| err = c.Unpack(&verify) | ||
| assert.Nil(t, err) | ||
| assert.Equal(t, map[string]interface{}{}, verify) | ||
| } |
There was a problem hiding this comment.
there is quite some repetition here. How about moving the test cases into a table like so?
cases := map[string]struct{
input string
to interface{}
want interface{}
}{
"empty map into map of interfaces": {
input: "{}",
to: &map[string]interface{}{},
want: &map[string]interface{}{},
},
...
}
for name, test := range cases {
t.Run(name, func(t *testing.T) {
c, err := MustNewConfig(byte(test.input))
mustUnpack(t, c, test.to)
assert.Equal(t, test.want, test.to)
})
}
There was a problem hiding this comment.
mustUnpack should be available already if you rebase.
There was a problem hiding this comment.
Rebased and refactored as it wasn't exposed.
| golden := string(tmp) | ||
| assert.Equal(t, golden, message) | ||
| message = adjustMessageFormat(message) | ||
| assert.Equal(t, golden, message, "Go runtime version: %s", runtime.Version()) |
This PR fixes the issue reported in #159 .
Check if the target is valid, before setting the value. The target field will stay
nil./cc @ruflin