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

New matcher that asserts presence of the given fields #35

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ json_spec defines five new RSpec matchers:
* `be_json_eql`
* `include_json`
* `have_json_path`
* `have_json_keys`

Choose a reason for hiding this comment

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

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

* `have_json_type`
* `have_json_size`

Expand Down
39 changes: 39 additions & 0 deletions features/keys.feature
Original file line number Diff line number Diff line change
@@ -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 |
21 changes: 21 additions & 0 deletions lib/json_spec/cucumber.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Choose a reason for hiding this comment

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

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.

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)
Expand All @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions lib/json_spec/matchers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

Expand Down
35 changes: 35 additions & 0 deletions lib/json_spec/matchers/have_json_keys.rb
Original file line number Diff line number Diff line change
@@ -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
43 changes: 43 additions & 0 deletions spec/json_spec/matchers/have_json_keys_spec.rb
Original file line number Diff line number Diff line change
@@ -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