-
-
Notifications
You must be signed in to change notification settings - Fork 23
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
Add tests for nullable
type
#26
base: main
Are you sure you want to change the base?
Conversation
types/nullable.go
Outdated
// MarshalJSON implements the Marshaler interface. | ||
func (t Nullable[T]) MarshalJSON() ([]byte, error) { | ||
if t.IsNull() { | ||
return nullBytes, nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to replace this with:
return nullBytes, nil | |
return []byte("null"), nil |
Right now, we've got the risk that someone could do something like:
func TestF(t *testing.T) {
var n Nullable[string]
n.Null = true
b, err := n.MarshalJSON()
fmt.Printf("b: %v\n", b)
fmt.Printf("b: %s\n", b)
fmt.Printf("err: %v\n", err)
b[1] = '_'
b_, err := n.MarshalJSON()
fmt.Printf("b: %v\n", b_)
fmt.Printf("b: %s\n", b_)
fmt.Printf("err: %v\n", err)
}
Which outputs:
b: [110 117 108 108]
b: null
err: <nil>
b: [110 95 108 108]
b: n_ll
err: <nil>
Note that nullBytes
from the package is changed.
We could alternatively perform a protective copy, or in this case, just return a literal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did not grok this in the first read. Trying to understand it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! Makes sense now.. So basically some one can alter the nullByte. Good catch.
types/nullable_test.go
Outdated
assert.NoError(t, err) | ||
assert.Equalf(t, tt.wantNull, obj.Name.IsNull(), "IsNull()") | ||
assert.Equalf(t, tt.wantSet, obj.Name.IsSet(), "IsSet()") | ||
fmt.Println(obj.Name.Get()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fmt.Println(obj.Name.Get()) |
types/nullable.go
Outdated
return t.Set | ||
} | ||
|
||
func (t *Nullable[T]) Get() (value T, null bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Think this should be:
func (t *Nullable[T]) Get() (value T, null bool) { | |
func (t *Nullable[T]) Get() (value *T, set bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On similar line -- now I am thinking we do not need this Get() method too.. Especially when I used in my own implementation -- I did not feel them need to use it especially when it returns 2 values, the code becomes little clumsy.
I think we should add these util functions as and when we need them. wdyt?
types/nullable.go
Outdated
// IsNull returns true if the value is explicitly provided `null` in json | ||
func (t *Nullable[T]) IsNull() bool { | ||
return t.Null | ||
} | ||
|
||
// IsSet returns true if the value is provided in json | ||
func (t *Nullable[T]) IsSet() bool { | ||
return t.Set | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unsure if these are needed if we export the values from the struct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm.. Agreed.
- Not exporting the
Set
andNull
keys is not a good idea as to create a Nullable type it is just easy to have them. - Now, since we have the fields exported the methods really does not do any useful stuff.
I was thinking on that and figured we should have something like the following:
// HasValue returns true if the value is provided in json
func (t *Nullable[T]) HasValue() bool {
return t.Set && !t.Null
}
HasValue() is a good util to have as I felt the need to that while using this type to answer this question:
- Is the value provided in JSON as well as is not null.
If this util is not present then one will have to do:
if t.Set && !t.Null {// do something}
vs
if t.HasValue() {// do something}
types/nullable_test.go
Outdated
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t1 *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
t.Run(tt.name, func(t1 *testing.T) { | |
t.Run(tt.name, func(t *testing.T) { |
Otherwise we're not passing in the correct type.
Shadowing here is fine (in my opinion - happy to chat if there are things to be aware of)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo.. thanks.
Will fix that.
types/nullable_test.go
Outdated
assert: func(obj TestComplex, t *testing.T) { | ||
assert.Equalf(t, true, obj.StringList.IsSet(), "string_list should be set") | ||
assert.Equalf(t, false, obj.StringList.IsNull(), "string_list should not be null") | ||
gotStringList, isNull := obj.StringList.Get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mind adding newlines for readability?
gotStringList, isNull := obj.StringList.Get() | |
gotStringList, isNull := obj.StringList.Get() |
types/nullable_test.go
Outdated
t.Run(tt.name, func(t1 *testing.T) { | ||
var obj SimplePointerInt | ||
err := json.Unmarshal(tt.jsonInput, &obj) | ||
assert.NoError(t, err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May be worth replacing this and similar ones with:
assert.NoError(t, err) | |
require.NoError(t, err) |
So we're failing earlier
Was the original implementation of the code adapted from https://github.com/guregu/null ? It looks like it but we've not declared so, as the licence would expect? |
Not really but definitely adapted the So if we need to declare it or do anything needful, sure! Thanks for bringing this. |
bfc1c43
to
cbea05b
Compare
We have spun out a separate package, `oapi-codegen/nullable` as a step towards oapi-codegen/oapi-codegen#1039. Until we have implemented oapi-codegen#27, we cannot add an explicit type alias in this package, so we can at least add some tests to cover additional functionality and expectations that the package should have when interplaying with `oapi-codegen`. Co-authored-by: Sebastien Guilloux <[email protected]> Co-authored-by: Ashutosh Kumar <[email protected]>
cbea05b
to
f26cbc7
Compare
Signed-off-by: Ashutosh Kumar <[email protected]>
types/nullable_test.go
Outdated
}) | ||
} | ||
} | ||
|
||
// Idempotency tests for nullable and optional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these actually Idempotency
tests? Or can we find a better name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the word idempotency can be simple removed. I will do that.
types/nullable_test.go
Outdated
|
||
var obj2 StringNullableOptional | ||
originalJSON2 := []byte(`{"id":"12esd412"}`) | ||
err2 := json.Unmarshal(originalJSON2, &obj2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not re-use err
?
types/nullable_test.go
Outdated
}, | ||
}, | ||
|
||
{ | ||
name: "when explicitly set to a specific value", | ||
json: []byte(`{"replica_count":5}`), | ||
assert: func(t *testing.T, obj SimpleIntNullableRequired) { | ||
assert: func(obj SimpleIntNullableRequired, t *testing.T) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛑 please revert this back, the ordering was changed on purpose
types/nullable_test.go
Outdated
t.Helper() | ||
|
||
assert.Truef(t, obj.ReplicaCount.IsNull(), "replica count should be null") | ||
assert.Equalf(t, true, obj.ReplicaCount.IsSpecified(), "replica count should be set") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert this, we're using Truef
on purpose
types/nullable_test.go
Outdated
@@ -437,8 +466,61 @@ func TestNullableRequired_UnmarshalJSON(t *testing.T) { | |||
var obj SimpleIntNullableRequired | |||
err := json.Unmarshal(tt.json, &obj) | |||
require.NoError(t, err) | |||
|
|||
tt.assert(t, obj) | |||
tt.assert(obj, t) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
newline was added on purpose
types/nullable_test.go
Outdated
type testCase struct { | ||
name string | ||
jsonInput []byte | ||
assert func(obj ComplexNullable, t *testing.T) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert func(obj ComplexNullable, t *testing.T) | |
assert func(t *testing.T, obj ComplexNullable) |
Signed-off-by: Ashutosh Kumar <[email protected]>
ab5218f
to
e6e916a
Compare
We have spun out a separate package,
oapi-codegen/nullable
as a steptowards oapi-codegen/oapi-codegen#1039.
Until we have implemented #27, we cannot add an explicit type alias in
this package, so we can at least add some tests to cover additional
functionality and expectations that the package should have when
interplaying with
oapi-codegen
.Co-authored-by: Sebastien Guilloux [email protected]
Co-authored-by: Ashutosh Kumar [email protected]