Skip to content

New matcher that asserts presence of the given fields #35

Open
wants to merge 7 commits into from
View
1 README.md
@@ -11,6 +11,7 @@ json_spec defines five new RSpec matchers:
* `be_json_eql`
* `include_json`
* `have_json_path`
+* `have_json_keys`

Also need to update the count of methods this gem adds a few lines above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
* `have_json_type`
* `have_json_size`
View
39 features/keys.feature
@@ -0,0 +1,39 @@
+Feature: Paths
+ Background:
+ Given the JSON is:
+ """
+ {
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ "z" : {
+ "d": 4,
+ "e": 5
+ },
+ "strange keys: '\_(\")_/', FTW!": true
+ }
+ """
+
+ Scenario: Base paths
+ When I get the JSON
+ Then the JSON should have keys "a", "b", "c"
+ And the JSON should not have keys "d", "e"
+ And the JSON at "z" should have keys "d", "e"
+ And the JSON at "z" should not have keys "m", "z"
+ And the JSON should have keys "strange keys: '\_(\")_/', FTW!", "a", "b"
+
+ Scenario: Table format
+ When I get the JSON
+ Then the JSON should have the following keys:
+ | a |
+ | b |
+ | c |
+ And the JSON should not have the following keys:
+ | d |
+ | e |
+ And the JSON at "z" should have the following keys:
+ | d |
+ | e |
+ And the JSON at "z" should not have the following keys:
+ | m |
+ | z |
View
21 lib/json_spec/cucumber.rb
@@ -70,6 +70,16 @@
end
end
+Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? have the following keys:$/ do |base, negative, table|
+ match = have_json_keys(table.raw)
+ match = match.at_path(base) if base

Please rename base to path to be consistent.
Can then shorten to one line as its works if path is nil.

match = have_json_keys(table.raw).at_path(path)

Nice drying up. Will make use of this pattern to dry up the rest of cucumber later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ if negative
+ last_json.should_not match
+ else
+ last_json.should match
+ end
+end
+
Then /^the (?:JSON|json)(?: response)? should( not)? have "(.*)"$/ do |negative, path|
if negative
last_json.should_not have_json_path(path)
@@ -78,6 +88,17 @@
end
end
+Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? have keys (.*)$/ do |base, negative, keys|
+ keys = eval("[#{keys}]")
+ match = have_json_keys(keys)
+ match = match.at_path(base) if base
+ if negative
+ last_json.should_not match
+ else
+ last_json.should match
+ end
+end
+
Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? be an? (.*)$/ do |path, negative, type|
if negative
last_json.should_not have_json_type(type).at_path(path)
View
5 lib/json_spec/matchers.rb
@@ -3,6 +3,7 @@
require "json_spec/matchers/have_json_path"
require "json_spec/matchers/have_json_type"
require "json_spec/matchers/have_json_size"
+require "json_spec/matchers/have_json_keys"
module JsonSpec
module Matchers
@@ -25,6 +26,10 @@ def have_json_type(type)
def have_json_size(size)
JsonSpec::Matchers::HaveJsonSize.new(size)
end
+
+ def have_json_keys(*keys)
+ JsonSpec::Matchers::HaveJsonKeys.new(keys.flatten)
+ end
end
end
View
35 lib/json_spec/matchers/have_json_keys.rb
@@ -0,0 +1,35 @@
+module JsonSpec
+ module Matchers
+ class HaveJsonKeys
+ include JsonSpec::Helpers
+ include JsonSpec::Messages
+
+ def initialize(keys)
+ @keys = keys
+ end
+
+ def matches?(json)
+ @data = parse_json(json, @path)
+ return false unless @data.is_a?(Hash)
+ @keys.all?{|key| @data.has_key?(key.to_s)}
+ end
+
+ def at_path(path)
+ @path = path
+ self
+ end
+
+ def failure_message_for_should
+ message_with_path("Expected JSON to contain all of the following keys #{@keys.join(", ")}")
+ end
+
+ def failure_message_for_should_not
+ message_with_path("Expected JSON to not contain any of the following keys #{@keys.join(", ")}")
+ end
+
+ def description
+ message_with_path(%(have JSON keys "#{@keys.join(", ")}"))
+ end
+ end
+ end
+end
View
43 spec/json_spec/matchers/have_json_keys_spec.rb
@@ -0,0 +1,43 @@
+require "spec_helper"
+
+describe JsonSpec::Matchers::HaveJsonKeys do
+ it "fails for non-hashes" do
+ %([1,2,3]).should_not have_json_keys
+ %(1).should_not have_json_keys
+ %("test").should_not have_json_keys
+ end
+
+ it "fails for bigger set of keys" do
+ %({"a": "1", "b": "2"}).should_not have_json_keys(:a, :b, :c)
+ end
+
+ it "matches for equal set of keys" do
+ [:a, :b, :c].permutation.each do |keys|
+ %({"a": "1", "b": "2", "c": "3"}).should have_json_keys(*keys)
+ end
+ end
+
+ it "matches for smaller set of keys" do
+ %({"a": "1", "b": "2", "c": "3"}).should have_json_keys(:a, :b)
+ end
+
+ it "matches for empty set of keys" do
+ %({"a": "1", "b": "2", "c": "3"}).should have_json_keys
+ end
+
+ it "accepts array of symbol keys" do
+ %({"a": "1", "b": "2"}).should have_json_keys([:a, :b])
+ end
+
+ it "accepts array of string keys" do
+ %({"a": "1", "b": "2"}).should have_json_keys(['a', 'b'])
+ end
+
+ it "accepts symbol keys" do
+ %({"a": "1", "b": "2"}).should have_json_keys(:a, :b)
+ end
+
+ it "accepts string keys" do
+ %({"a": "1", "b": "2"}).should have_json_keys('a', 'b')
+ end
+end
Something went wrong with that request. Please try again.