gnl / ghostwheel

Hassle-free inline clojure.spec with semi-automatic generative testing and side effect detection
Eclipse Public License 2.0
603 stars 14 forks source link

Use metadata key for fn-body spec generation. #27

Open pithyless opened 5 years ago

pithyless commented 5 years ago

This is an issue that started out as a comment to https://github.com/gnl/ghostwheel/issues/26

Existing Feature

Proposed Problem (1)

Proposed Solution (1)

  1. Improve documentation: the feature is mentioned in the readme #introduction, but that would also be a good place to mention (or link to) how to disable/enable it.
  2. The feature is not mentioned :ghostwheel.core/ghostwheel-config nor ghostwheel.utils/ghostwheel-default-config
  3. Honestly, as a user - I am still not sure if and how I can disable this feature.
  4. It's a jarring experience if one is not aware of it, so make it opt-in via configuration.

Alternative Feature

Once I started thinking about this problem, I'd like to suggest an alternative approach.

Proposed Problem (2)

Proposed Solution (2)

Instead of global enabled/disabled feature of nil-body functions, we could configure it via metadata (similar to ::g/trace). That way:

(>defn ^::g/fake some-string-to-int
  [x] [string? => int?]
  nil)

We could even take this even a step-further and remove the nil-body constraint. Any time we add the metadata key ::g/fake to a function, it will simply ignore the body and generate random data from spec. Possible use-cases for this? Stubbing out in development an I/O function, etc.

What we call the metadata key itself (::g/fake) is open to discussion. I'm just wondering if this idea has any legs. Thoughts?

gnl commented 5 years ago

This is definitely a problem and yes, at the moment it cannot be turned off. There is already a fix in the in-progress 0.4.0 release, which is that nil-body functions work precisely as you would expect them to, but no-body functions generate the stub and print a warning in the console about the fact when called.

I am considering adding an option to disable it, which would work like all the others with overrideable metadata and all that. Might also be better to still default to off, because its usage doesn't seem that common to justify having it on by default.

What I'm also thinking about is overriding the defn specs in clojure.core.specs.alpha to disallow body-less defns, so that if you forgot a stub somewhere your production build wouldn't even compile. At the moment it's perfectly legit to do (defn foo [a b]) in Clojure, which doesn't make much sense to me.

The force-stubbing a function with an existing body is an interesting idea, but I'm not quite sure about it. If you enable the option with metadata during development and everything seems to work so that you forget about it, in production it would of course not be stubbed and things might break without you having properly tested it in development.

Seems like an easy mistake to make and I'd rather force the programmer to comment out the function body if they want something stubbed, because this seems harder to screw up, especially in combination with the potential disallowing of body-less functions mentioned above.

gnl commented 4 years ago

đź‘‹ Hi. I'm posting this same comment to all issue threads to just give a quick heads up that the project, despite rumours and some evidence to the contrary, is not dead. It was hibernating for a little while and now nearing the long-awaited next release, which will fix some long-standing issues (and introduce some breaking changes to the config).

I'll be reviewing all open issues and PRs over the next couple of weeks, so stay tuned and thanks for the patience.

See also this Slack thread

gnl commented 1 year ago

Project update July 2023: DO NOT PANIC – this is not a eulogy