chancancode / json_expressions

JSON matchmaking for all your API testing needs.
MIT License
414 stars 38 forks source link

Support for arbitrary custom matchers #25

Closed searls closed 10 years ago

searls commented 10 years ago

Love the library so far. I have a feeling that what I want will be possible if I start perusing your implementation details, but just to put this out there, I think it'd be really nice to support custom matchers. Suppose I have a lot of ISO8601 dates that I publish from my JSON API as strings.

//...
"received_at": "2014-03-19T16:25:28.311016Z",
//...

I'd like a pattern to match that value with an API like this:

"received_at"=> iso_date_matcher(1.minute.ago)

And the matcher's implementation could/should look something like this:

class IsoDateMatcher
  def initialize(earliest_matching_time)
    @earliest_matching_time = earliest_matching_time
  end

  def match?(actual)
     Time.zone.parse(actual) > @earliest_matching_time && actual =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z/
  end
end
def iso_date_matcher(earliest_matching_time)
  IsoDateMatcher.new(earliest_matching_time)
end

Would be really nice to be able to do this, that way I could easily one-line assertions of very large documents without having to break up my assertions into multiple imperative statements.

Thoughts? Perhaps this is already possible depending on how what built-in matchers respond to.

chancancode commented 10 years ago

Yes! You can in fact do this :) The key is to define #===.

class IsoDateMatcher
  def initialize(earliest_matching_time)
    @earliest_matching_time = earliest_matching_time
  end

  def ===(actual)
     Time.zone.parse(actual) > @earliest_matching_time && actual =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z/
  end
end

def iso_date_matcher(earliest_matching_time)
  IsoDateMatcher.new(earliest_matching_time)
end

....or...

def iso_date_matcher(earliest_matching_time)
  ->(actual) { Time.zone.parse(actual) > earliest_matching_time && actual =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z/ }
end

Although to be honest, I usually just match the date fields with String :smile:

searls commented 10 years ago

Awesome. Documenting this in the README would be fantastic.

chancancode commented 10 years ago

https://github.com/chancancode/json_expressions#object-equality :smile:

PR to improve that is welcomed!