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

has_only: enforce a fixed sets of JSON object properties #8

Merged
merged 1 commit into from Apr 20, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Expand Up @@ -58,6 +58,26 @@ assert_json '[{"id":1, "key":"test", "name":"test"}, {"id":2, "key":"test", "nam
end
```

To test that objects have the declared set of properties and nothing more,
include `has_only` at any level, like this

```ruby
assert_json '[{"id":1, "key":"test", "name":"test"}, {"id":2, "key":"test", "name":"test"}, {"id":3, "key":"test", "name":"test"}]' do
has_only
item 0 do
has :id, 1
has :key, 'test'
has :name, 'test'
end
item 1 do
has 'id', 2
has 'key', 'test'
end
end

# Failure: element 1 has unexpected keys: name
```


## Changelog ##

Expand Down
38 changes: 37 additions & 1 deletion lib/assert_json/assert_json.rb
Expand Up @@ -5,6 +5,7 @@ def assert_json(json_string, &block)
@json = AssertJson::Json.new(json_string)
# json.instance_exec(json, &block)
yield @json
@json.test_for_unexpected_keys('root')
end
end

Expand All @@ -20,19 +21,31 @@ def has_not(*args, &block)
@json.has_not(*args, &block)
end

def has_only
@json.has_only
end

class Json

def initialize(json_string)
@decoded_json = ActiveSupport::JSON.decode(json_string)
@expected_keys = []
@only = false
end

def item(index, &block)
only_in_scope = @only
expected_keys_in_scope = @expected_keys
@expected_keys = []
decoded_json_in_scope = @decoded_json
@decoded_json = @decoded_json[index]
begin
yield if block_given?
test_for_unexpected_keys(index)
ensure
@decoded_json = decoded_json_in_scope
@expected_keys = expected_keys_in_scope
@only = only_in_scope
end
end

Expand Down Expand Up @@ -79,8 +92,13 @@ def element(*args, &block)
flunk
end

@expected_keys.push arg

if block_given?
begin
only_in_scope = @only
expected_keys_in_scope = @expected_keys
@expected_keys = []
decoded_json_in_scope = @decoded_json
@decoded_json = case token
when Hash
Expand All @@ -89,11 +107,13 @@ def element(*args, &block)
token
end
yield
test_for_unexpected_keys(arg)
ensure
@expected_keys = expected_keys_in_scope
@only = only_in_scope
@decoded_json = decoded_json_in_scope
end
end

end
alias has element

Expand All @@ -109,6 +129,22 @@ def not_element(*args, &block)
end
alias has_not not_element

def only
@only = true
end
alias has_only only

def test_for_unexpected_keys(name = 'root')
return unless @only

if @decoded_json.is_a?(Hash)
unexpected_keys = @decoded_json.keys - @expected_keys
if unexpected_keys.count > 0
raise_error("element #{name} has unexpected keys: #{unexpected_keys.join(', ')}")
end
end
end

private

def raise_error(message)
Expand Down
94 changes: 94 additions & 0 deletions test/assert_json_has_only_test.rb
@@ -0,0 +1,94 @@
require_relative './test_helper'

class AssertJsonHasNoUnexpectedKeysTest < Minitest::Test
include AssertJson

def test_on_root_object
assert_json '{"keyA":"value","keyB":"value"}' do
has_only
has 'keyA'
has 'keyB'
end
end

def test_on_root_object_failure
err = assert_raises(MiniTest::Assertion) do
assert_json '{"keyA":"value","keyB":"value"}' do
has_only
has 'keyA', 'value'
end
end
assert_equal 'element root has unexpected keys: keyB', err.message
end

def test_on_root_object_with_sub_object
assert_json '{"keyA":{"subKeyA":"value","subKeyB":"value"},"keyB":"value"}' do
has_only
has 'keyA' do
has 'subKeyA'
has 'subKeyB'
end
has 'keyB'
end
end

def test_on_root_object_with_sub_object_failure
err = assert_raises(MiniTest::Assertion) do
assert_json '{"keyA":{"subKeyA":"value","subKeyB":"value"},"keyB":"value"}' do
has_only
has 'keyA' do
has 'subKeyA'
has 'subKeyB'
end
end
end
assert_equal 'element root has unexpected keys: keyB', err.message
end

def test_on_sub_object
assert_json '{"keyA":{"subKeyA":"value","subKeyB":"value"},"keyB":"value"}' do
has 'keyA' do
has_only
has 'subKeyA'
has 'subKeyB'
end
end
end

def test_on_sub_object_failure
err = assert_raises(MiniTest::Assertion) do
assert_json '{"keyA":{"subKeyA":"value","subKeyB":"value"},"keyB":"value"}' do
has 'keyA' do
has_only
has 'subKeyA'
end
end
end
assert_equal 'element keyA has unexpected keys: subKeyB', err.message
end

def test_on_root_array_of_objects
assert_json '[{"id":1, "key":"test", "name":"test"}, {"id":2, "key":"test", "name":"test"}, {"id":3, "key":"test", "name":"test"}]' do
has_only
item 0 do
has :id, 1
has :key, 'test'
has :name, 'test'
end
end
end

def test_on_root_array_of_objects_failure
err = assert_raises(MiniTest::Assertion) do
assert_json '[{"id":1, "key":"test", "name":"test"}, {"id":2, "key":"test", "name":"test"}, {"id":3, "key":"test", "name":"test"}]' do
has_only
item 0 do
has :id, 1
has :key, 'test'
end
end
end
assert_equal 'element 0 has unexpected keys: name', err.message
end

end