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

bugfix to make the coercion work properly with s/or #219

Merged
merged 6 commits into from
Apr 5, 2020

Conversation

wandersoncferreira
Copy link
Contributor

@wandersoncferreira wandersoncferreira commented Mar 22, 2020

Fixes #178 . The solution is a bit more convoluted than I expected because of the special case for clojure.core/any? forms that would introduce a bug if I stopped the reduce operation when I first get a valid data from a or spec.

The example provided in the issue is now working as expected:

(st/coerce ::vehicle chevy st/strip-extra-keys-transformer)
;; => {:doors 4}

@coveralls
Copy link

coveralls commented Mar 22, 2020

Coverage Status

Coverage increased (+0.08%) to 96.487% when pulling ce88495 on wandersoncferreira:bugfix/or-spec-coercion into b02175b on metosin:master.

Copy link
Member

@ikitommi ikitommi left a comment

Choose a reason for hiding this comment

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

Thanks! This needs a test to verify that it works (and won't regress later). I didn't understand the any? guard. Could you clarify why it is needed?

@wandersoncferreira
Copy link
Contributor Author

wandersoncferreira commented Mar 28, 2020

I did a bit more of investigation about this any workaround. What happened was the following:

Consider these specs:

(s/def ::car (st/spec (s/keys :req-un [::doors])))
(s/def ::bike (st/spec (s/keys :req-un [::wheels])))
(s/def ::tires (s/coll-of (s/and int?) :into #{}))
(s/def ::vehicle (s/or :car ::car
                       :bike ::bike))
(s/def ::new-vehicle (s/map-of
                      keyword?
                      (s/or :vehicle ::vehicle
                            :tires (s/coll-of (s/and int?) :into #{}))))

The issue happened in one of the specs in the test suite that used the (s/coll-of (s/and int?) :into {}) construct. It seems that if you define the coll-of as a "unnamed spec" the current implementation will leave the :into {} operation as a separate iteration in the recursive path performed during the coercion.

Therefore you should be expecting this:

(st/coerce ::new-vehicle {:rodas [1 "1" 3]} st/strip-extra-keys-transformer)
;; => {:rodas #{1 "1" 3}}

But you will get

(st/coerce ::new-vehicle {:rodas [1 "1" 3]} st/strip-extra-keys-transformer)
;; => {:rodas [1 "1" 3]}

This happens because the spec created by (st/create-spec...) will match the vector because the into {} is not part of that spec in the current iteration, if I reduced the answer now, it will prevent to get into the second iteration where the into {} operation will happen. I also noticed the created spec produced a property :form equal to clojure.core/any therefore I skipped to the old behavior as soon as I encounter this situation.

I'll push some tests.

@wandersoncferreira
Copy link
Contributor Author

The breaking test was

@wandersoncferreira
Copy link
Contributor Author

@ikitommi I will study this better today and tomorrow. I started to investigate the issue #212 and it seems related somehow to the problem I described earlier. Need more time to look in more depth.

@wandersoncferreira
Copy link
Contributor Author

wandersoncferreira commented Apr 4, 2020

@ikitommi Now this is correct, I improved the mechanism to perform the validity check from coerced values and all went more smoothly now. There is no special case to handle. Solve both issues.

@ikitommi
Copy link
Member

ikitommi commented Apr 5, 2020

Awesome, thanks!

@ikitommi ikitommi merged commit 74d4d80 into metosin:master Apr 5, 2020
@ikitommi
Copy link
Member

ikitommi commented Apr 5, 2020

Simplified a bit more: f0bd074. Tests pass, does that look correct?

@wandersoncferreira
Copy link
Contributor Author

Sure! Great, seems like specize has an implementation to fn interfaces, didn't know that.

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.

strip-extra-keys-transformer not working with s/or
3 participants