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

Allow structs to be self-verifying. #293

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

nolag
Copy link
Contributor

@nolag nolag commented Oct 10, 2024

This is useful if the struct is created by the user, or parsed with something like mapstructure and the user wants to verify it against the json schema.

@nolag nolag marked this pull request as draft October 10, 2024 16:39
@nolag nolag force-pushed the main branch 3 times, most recently from dfa67ca to b5d4107 Compare October 10, 2024 16:47
Copy link

codecov bot commented Oct 10, 2024

Codecov Report

Attention: Patch coverage is 66.00660% with 103 lines in your changes missing coverage. Please review.

Project coverage is 72.54%. Comparing base (d963216) to head (d301e4c).
Report is 77 commits behind head on main.

Files with missing lines Patch % Lines
pkg/generator/verify_formatter.go 73.88% 35 Missing ⚠️
...s/data/validation/requiredFields/requiredFields.go 0.00% 15 Missing ⚠️
...data/validation/requiredFields/requiredNullable.go 0.00% 8 Missing ⚠️
...ta/validation/exclusiveMaximum/exclusiveMaximum.go 57.14% 4 Missing and 2 partials ⚠️
...ta/validation/exclusiveMinimum/exclusiveMinimum.go 57.14% 4 Missing and 2 partials ⚠️
tests/data/validation/maximum/maximum.go 57.14% 4 Missing and 2 partials ⚠️
tests/data/validation/minimum/minimum.go 57.14% 4 Missing and 2 partials ⚠️
tests/data/validation/multipleOf/multipleOf.go 57.14% 4 Missing and 2 partials ⚠️
...s/data/validation/primitive_defs/primitive_defs.go 70.58% 4 Missing and 1 partial ⚠️
tests/data/validation/pattern/pattern.go 55.55% 3 Missing and 1 partial ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #293      +/-   ##
==========================================
- Coverage   76.58%   72.54%   -4.05%     
==========================================
  Files          24       44      +20     
  Lines        1892     3136    +1244     
==========================================
+ Hits         1449     2275     +826     
- Misses        354      675     +321     
- Partials       89      186      +97     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@nolag nolag marked this pull request as ready for review October 10, 2024 16:48
@omissis omissis added this to the v0.18.0 milestone Oct 30, 2024
@omissis
Copy link
Owner

omissis commented Oct 30, 2024

hey @nolag , thanks for this PR! I'll try to review it asap. In the meantime can you rebase it and resolve the conflicts? thank you!

@nolag
Copy link
Contributor Author

nolag commented Oct 31, 2024

hey @nolag , thanks for this PR! I'll try to review it asap. In the meantime can you rebase it and resolve the conflicts? thank you!

Done, I rebased the PR.

Copy link
Owner

@omissis omissis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hey @nolag, a few points here:

  1. the generated code for enums in the tests seem to lack a v variable
  2. was it intended not to check for required in the verify functions?
  3. I think this flag should be orthogonal to --only-models, or maybe we should rethink the two features so that they can work well with one another. at the moment --struct-verify is ignored if --only-models is passed
  4. I would like to have a suite of integration tests (eg: verify_test.go) that run on the Verify functions of the generated code, similarly to what's been done in tests/unmarshal_test.go: that is because just verifying that the generated code is what we expect is not sufficient, we should also verify it is valid and that it behaves properly

Thank you!

Comment on lines 41 to 48
func TestValidation(t *testing.T) {
t.Parallel()

testExamples(t, basicConfig, "./data/validation")
cfg := basicConfig
cfg.StructVerify = true

testExamples(t, cfg, "./data/validation")
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer having two suites of tests, one with the classic validation and one with the struct verify. wdyt?

// Verify checks all fields on the struct match the schema.
func (plain EnumMyBooleanTypedEnum) Verify() error {
for _, expected := range enumValues_EnumMyBooleanTypedEnum {
if reflect.DeepEqual(v, expected) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this v come from? I don't see it declared anywhere, are you sure it's valid?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting, that means that the compiled enum.go file wasn't ever validated before.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

correct. I started slowly adding that kind of coverage when I took ownership of maintaining this library, but it'll take some time.

// Verify checks all fields on the struct match the schema.
func (plain EnumMyBooleanUntypedEnum) Verify() error {
for _, expected := range enumValues_EnumMyBooleanUntypedEnum {
if reflect.DeepEqual(v, expected) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this v come from? I don't see it declared anywhere, are you sure it's valid?

// Verify checks all fields on the struct match the schema.
func (plain EnumMyIntegerTypedEnum) Verify() error {
for _, expected := range enumValues_EnumMyIntegerTypedEnum {
if reflect.DeepEqual(v, expected) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this v come from? I don't see it declared anywhere, are you sure it's valid?

// Verify checks all fields on the struct match the schema.
func (plain EnumMyNumberTypedEnum) Verify() error {
for _, expected := range enumValues_EnumMyNumberTypedEnum {
if reflect.DeepEqual(v, expected) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this v come from? I don't see it declared anywhere, are you sure it's valid?

// Verify checks all fields on the struct match the schema.
func (plain EnumMyNumberUntypedEnum) Verify() error {
for _, expected := range enumValues_EnumMyNumberUntypedEnum {
if reflect.DeepEqual(v, expected) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this v come from? I don't see it declared anywhere, are you sure it's valid?

// Verify checks all fields on the struct match the schema.
func (plain EnumMyStringTypedEnum) Verify() error {
for _, expected := range enumValues_EnumMyStringTypedEnum {
if reflect.DeepEqual(v, expected) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this v come from? I don't see it declared anywhere, are you sure it's valid?

// Verify checks all fields on the struct match the schema.
func (plain EnumMyStringUntypedEnum) Verify() error {
for _, expected := range enumValues_EnumMyStringUntypedEnum {
if reflect.DeepEqual(v, expected) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where does this v come from? I don't see it declared anywhere, are you sure it's valid?

@nolag
Copy link
Contributor Author

nolag commented Nov 4, 2024

Not sure if I'll get to your comments this week or not, but I'll share some thoughts for now.

  1. the generated code for enums in the tests seem to lack a v variable
    Ack, will fix. This does mean that the tests never checked that compiled file.
  1. was it intended not to check for required in the verify functions?

Yes, once it's in the structure already, you don't know if they set it to a default or not (since required fields are not a pointer). I was thinking of allowing users to pass a set or unset fields list (like the one that mapstructure can set for unset variables), or a func that returns if a field was set, but the overhead seemed pretty high. Also, the caller may not know what was set at the time of calling.

  1. I think this flag should be orthogonal to --only-models, or maybe we should rethink the two features so that they can work well with one another. at the moment --struct-verify is ignored if --only-models is passed

I can take a look. I agree it should work with --only-models.

  1. I would like to have a suite of integration tests (eg: verify_test.go) that run on the Verify functions of the generated code, similarly to what's been done in tests/unmarshal_test.go: that is because just verifying that the generated code is what we expect is not sufficient, we should also verify it is valid and that it behaves properly

I had extended all the tests I wrote before that tested anything outside of code matching to do it for this too. I can look for other tests that do the same and extend them.

I would prefer having two suites of tests, one with the classic validation and one with the struct verify. wdyt?

I wrote them together to ensure the same tests are always run (when applicable). That way, if you add a feature, you'll see that you should test both. A bug fix would also automatically test both too. Thoughts?

@omissis
Copy link
Owner

omissis commented Nov 16, 2024

@nolag ok for pts. 2 and 4. pt 1 should probably be fixed and covered by a test that exercises the generated code (I started introducing them, but they are still very few). pt 3 is a bit challenging as I feel we should rethink the flags before proceeding. Should we make them additive (--struct-verify, --unmarshall-validate) or subtractive (--only-model, --no-verify) by default?

@omissis omissis removed this from the v0.18.0 milestone Nov 17, 2024
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

Successfully merging this pull request may close these issues.

2 participants