json_spec-1.1.5/0000755000004100000410000000000013123610203013520 5ustar www-datawww-datajson_spec-1.1.5/Rakefile0000644000004100000410000000066213123610203015171 0ustar www-datawww-datarequire "bundler/gem_tasks" require "rspec/core/rake_task" require "cucumber/rake/task" RSpec::Core::RakeTask.new(:spec) do |task| task.rspec_opts = "--warnings" end Cucumber::Rake::Task.new(:cucumber) do |task| task.cucumber_opts = "--tags ~@fail" end Cucumber::Rake::Task.new(:negative_cucumber) do |task| task.cucumber_opts = "--tags @fail --wip" end task test: [:spec, :cucumber, :negative_cucumber] task default: :test json_spec-1.1.5/Gemfile0000644000004100000410000000012613123610203015012 0ustar www-datawww-datasource "https://rubygems.org" gemspec group :test do gem "cucumber", "~> 1.3" end json_spec-1.1.5/features/0000755000004100000410000000000013123610203015336 5ustar www-datawww-datajson_spec-1.1.5/features/step_definitions/0000755000004100000410000000000013123610203020704 5ustar www-datawww-datajson_spec-1.1.5/features/step_definitions/steps.rb0000644000004100000410000000014513123610203022367 0ustar www-datawww-dataGiven "the JSON is:" do |json| @json = json end When "I get the JSON" do @last_json = @json end json_spec-1.1.5/features/types.feature0000644000004100000410000000126713123610203020065 0ustar www-datawww-dataFeature: Types Scenario: All types Given the JSON is: """ { "array": [], "false": true, "float": 10.0, "hash": {}, "integer": 10, "string": "json_spec", "true": true } """ When I get the JSON Then the JSON should be a hash And the JSON at "array" should be an array And the JSON at "false" should be a boolean And the JSON at "float" should be a float And the JSON at "hash" should be a hash And the JSON at "hash" should be an object And the JSON at "integer" should be an integer And the JSON at "string" should be a string And the JSON at "true" should be a boolean json_spec-1.1.5/features/equivalence.feature0000644000004100000410000001572713123610203021230 0ustar www-datawww-dataFeature: Equivalence Background: Given the JSON is: """ { "array": [ "json", "spec" ], "created_at": "2011-07-08 02:27:34", "empty_array": [ ], "empty_hash": { }, "false": false, "float": 10.0, "hash": { "json": "spec" }, "id": 1, "integer": 10, "negative": -10, "null": null, "string": "json_spec", "true": true, "updated_at": "2011-07-08 02:28:50" } """ Scenario: Identical JSON When I get the JSON Then the JSON should be: """ { "array": [ "json", "spec" ], "created_at": "2011-07-08 02:27:34", "empty_array": [ ], "empty_hash": { }, "false": false, "float": 10.0, "hash": { "json": "spec" }, "id": 1, "integer": 10, "negative": -10, "null": null, "string": "json_spec", "true": true, "updated_at": "2011-07-08 02:28:50" } """ Scenario: Reverse order When I get the JSON Then the JSON should be: """ { "updated_at": "2011-07-08 02:28:50", "true": true, "string": "json_spec", "null": null, "negative": -10, "integer": 10, "id": 1, "hash": { "json": "spec" }, "float": 10.0, "false": false, "empty_hash": { }, "empty_array": [ ], "created_at": "2011-07-08 02:27:34", "array": [ "json", "spec" ] } """ Scenario: Excluding keys When I get the JSON Then the JSON should be: """ { "array": [ "json", "spec" ], "empty_array": [ ], "empty_hash": { }, "false": false, "float": 10.0, "hash": { "json": "spec" }, "integer": 10, "negative": -10, "null": null, "string": "json_spec", "true": true } """ Scenario: String When I get the JSON Then the JSON at "string" should be "json_spec" And the JSON at "string" should be: """ "json_spec" """ Scenario: Integer When I get the JSON Then the JSON at "integer" should be 10 And the JSON at "integer" should be: """ 10 """ Scenario: Negative integer When I get the JSON Then the JSON at "negative" should be -10 And the JSON at "negative" should be: """ -10 """ Scenario: Float When I get the JSON Then the JSON at "float" should be 10.0 And the JSON at "float" should be 10.0e0 And the JSON at "float" should be 10.0e+0 And the JSON at "float" should be 10.0e-0 And the JSON at "float" should be 10e0 And the JSON at "float" should be 10e+0 And the JSON at "float" should be 10e-0 And the JSON at "float" should be 1.0e1 And the JSON at "float" should be 1.0e+1 And the JSON at "float" should be 1e1 And the JSON at "float" should be 1e+1 And the JSON at "float" should be 100.0e-1 And the JSON at "float" should be 100e-1 And the JSON at "float" should be: """ 10.0 """ Scenario: Array When I get the JSON Then the JSON at "array" should be ["json","spec"] And the JSON at "array/0" should be "json" And the JSON at "array/1" should be "spec" And the JSON at "array" should be: """ [ "json", "spec" ] """ Scenario: Empty array When I get the JSON Then the JSON at "empty_array" should be [] And the JSON at "empty_array" should be: """ [ ] """ Scenario: Hash When I get the JSON Then the JSON at "hash" should be {"json":"spec"} And the JSON at "hash/json" should be "spec" And the JSON at "hash" should be: """ { "json": "spec" } """ Scenario: Empty hash When I get the JSON Then the JSON at "empty_hash" should be {} And the JSON at "empty_hash" should be: """ { } """ Scenario: True When I get the JSON Then the JSON at "true" should be true And the JSON at "true" should be: """ true """ Scenario: False When I get the JSON Then the JSON at "false" should be false And the JSON at "false" should be: """ false """ Scenario: Null When I get the JSON Then the JSON at "null" should be null And the JSON at "null" should be: """ null """ Scenario: Excluded value When I get the JSON Then the JSON at "created_at" should be "2011-07-08 02:27:34" And the JSON at "id" should be 1 And the JSON at "updated_at" should be "2011-07-08 02:28:50" Scenario: Table format When I get the JSON Then the JSON should have the following: | array | ["json","spec"] | | array/0 | "json" | | array/1 | "spec" | | created_at | "2011-07-08 02:27:34" | | empty_array | [] | | empty_hash | {} | | false | false | | float | 10.0 | | hash | {"json":"spec"} | | hash/json | "spec" | | id | 1 | | integer | 10 | | negative | -10 | | null | null | | string | "json_spec" | | true | true | | updated_at | "2011-07-08 02:28:50" | And the JSON at "array" should have the following: | 0 | "json" | | 1 | "spec" | And the JSON at "hash" should have the following: | json | "spec" | @fail Scenario: Table format can fail equivalence When I get the JSON Then the JSON should have the following: | array | ["bad","garbage"] | | array/0 | "json" | | array/1 | "spec" | | created_at | "2011-07-08 02:27:34" | | empty_array | [] | | empty_hash | {} | | false | false | | float | 10.0 | | hash | {"json":"spec"} | | hash/json | "spec" | | id | 1 | | integer | 10 | | negative | -10 | | null | null | | string | "json_spec" | | true | true | | updated_at | "2011-07-08 02:28:50" | And the JSON at "array" should have the following: | should | "fail" | | 1 | "spec" | And the JSON at "hash" should have the following: | random | "junk" | json_spec-1.1.5/features/sizes.feature0000644000004100000410000000127513123610203020055 0ustar www-datawww-dataFeature: Sizes Background: Given the JSON is: """ { "id": null, "one": [ 1 ], "three": [ 1, 2, 3 ], "two": [ 1, 2 ], "zero": [ ] } """ Scenario: Hash When I get the JSON Then the JSON should have 5 keys And the JSON should have 5 values Scenario: Empty array When I get the JSON Then the JSON at "zero" should have 0 entries Scenario: Array When I get the JSON Then the JSON at "one" should have 1 entry And the JSON at "two" should have 2 values And the JSON at "three" should have 3 numbers json_spec-1.1.5/features/memory.feature0000644000004100000410000001152613123610203020230 0ustar www-datawww-dataFeature: Memory Background: Given the JSON is: """ { "array": [ ], "false": false, "float": 10.0, "hash": { }, "integer": 10, "null": null, "string": "json_spec", "true": true } """ And I get the JSON Scenario: Entire JSON When I keep the JSON as "JSON" Then the JSON should be %{JSON} And the JSON should be: """ %{JSON} """ Scenario: String When I keep the JSON at "string" as "STRING" Then the JSON at "string" should be %{STRING} And the JSON should be: """ { "array": [ ], "false": false, "float": 10.0, "hash": { }, "integer": 10, "null": null, "string": %{STRING}, "true": true } """ Scenario: Integer When I keep the JSON at "integer" as "INTEGER" Then the JSON at "integer" should be %{INTEGER} And the JSON should be: """ { "array": [ ], "false": false, "float": 10.0, "hash": { }, "integer": %{INTEGER}, "null": null, "string": "json_spec", "true": true } """ Scenario: Float When I keep the JSON at "float" as "FLOAT" Then the JSON at "float" should be %{FLOAT} And the JSON should be: """ { "array": [ ], "false": false, "float": %{FLOAT}, "hash": { }, "integer": 10, "null": null, "string": "json_spec", "true": true } """ Scenario: Array When I keep the JSON at "array" as "ARRAY" Then the JSON at "array" should be %{ARRAY} And the JSON should be: """ { "array": %{ARRAY}, "false": false, "float": 10.0, "hash": { }, "integer": 10, "null": null, "string": "json_spec", "true": true } """ Scenario: Hash When I keep the JSON at "hash" as "HASH" Then the JSON at "hash" should be %{HASH} And the JSON should be: """ { "array": [ ], "false": false, "float": 10.0, "hash": %{HASH}, "integer": 10, "null": null, "string": "json_spec", "true": true } """ Scenario: True When I keep the JSON at "true" as "TRUE" Then the JSON at "true" should be %{TRUE} And the JSON should be: """ { "array": [ ], "false": false, "float": 10.0, "hash": { }, "integer": 10, "null": null, "string": "json_spec", "true": %{TRUE} } """ Scenario: False When I keep the JSON at "false" as "FALSE" Then the JSON at "false" should be %{FALSE} And the JSON should be: """ { "array": [ ], "false": %{FALSE}, "float": 10.0, "hash": { }, "integer": 10, "null": null, "string": "json_spec", "true": true } """ Scenario: Null When I keep the JSON at "null" as "NULL" Then the JSON at "null" should be %{NULL} And the JSON should be: """ { "array": [ ], "false": false, "float": 10.0, "hash": { }, "integer": 10, "null": %{NULL}, "string": "json_spec", "true": true } """ Scenario: Table format When I keep the JSON at "string" as "STRING" And I keep the JSON at "integer" as "INTEGER" And I keep the JSON at "float" as "FLOAT" And I keep the JSON at "array" as "ARRAY" And I keep the JSON at "hash" as "HASH" And I keep the JSON at "true" as "TRUE" And I keep the JSON at "false" as "FALSE" And I keep the JSON at "null" as "NULL" Then the JSON should have the following: | string | %{STRING} | | integer | %{INTEGER} | | float | %{FLOAT} | | array | %{ARRAY} | | hash | %{HASH} | | true | %{TRUE} | | false | %{FALSE} | | null | %{NULL} | Scenario: Inclusion When I keep the JSON at "string" as "STRING" And I keep the JSON at "integer" as "INTEGER" And I keep the JSON at "float" as "FLOAT" And I keep the JSON at "array" as "ARRAY" And I keep the JSON at "hash" as "HASH" And I keep the JSON at "true" as "TRUE" And I keep the JSON at "false" as "FALSE" And I keep the JSON at "null" as "NULL" Then the JSON should include %{STRING} And the JSON should include %{INTEGER} And the JSON should include %{FLOAT} And the JSON should include %{ARRAY} And the JSON should include %{HASH} And the JSON should include %{TRUE} And the JSON should include %{FALSE} And the JSON should include %{NULL} json_spec-1.1.5/features/support/0000755000004100000410000000000013123610203017052 5ustar www-datawww-datajson_spec-1.1.5/features/support/env.rb0000644000004100000410000000030413123610203020164 0ustar www-datawww-data$: << File.expand_path("../../../lib", __FILE__) require "json_spec/cucumber" JsonSpec.directory = File.expand_path("../../../spec/support/files", __FILE__) def last_json @last_json.to_s end json_spec-1.1.5/features/files.feature0000644000004100000410000000340113123610203020013 0ustar www-datawww-dataFeature: Files Scenario: Equivalence from a file Given the JSON is: """ { "array": [ "json", "spec" ], "false": false, "float": 10.0, "hash": { "json": "spec" }, "created_at": "2011-07-08 02:27:34", "empty_array": [ ], "empty_hash": { }, "id": 1, "integer": 10, "negative": -10, "null": null, "string": "json_spec", "true": true, "updated_at": "2011-07-08 02:28:50" } """ When I get the JSON Then the JSON should be file "two.json" Scenario: Inequivalence from a file Given the JSON is: """ { "string": "json_spec", "true": true, "updated_at": "2011-07-08 02:28:50" } """ When I get the JSON Then the JSON should not be file "two.json" Scenario: Inclusion from a file Given the JSON is: """ { "array": [ "json", "spec" ], "created_at": "2011-07-08 02:27:34", "empty_array": [ ], "empty_hash": { }, "false": false, "float": 10.0, "hash": { "json": "spec" } } """ When I get the JSON Then the JSON should include file "project/version/two.json" Scenario: Exclusion from a file Given the JSON is: """ { "array": [ "json", "spec" ], "created_at": "2011-07-08 02:27:34", "empty_array": [ ], "empty_hash": { }, "false": false, "float": 10.0 } """ When I get the JSON Then the JSON should not include file "project/version/two.json" json_spec-1.1.5/features/inclusion.feature0000644000004100000410000000630013123610203020715 0ustar www-datawww-dataFeature: Inclusion Background: Given the JSON is: """ { "array": [ "json", "spec" ], "created_at": "2011-07-08 02:27:34", "empty_array": [ ], "empty_hash": { }, "false": false, "float": 10.0, "hash": { "json": "spec" }, "id": 1, "integer": 10, "negative": -10, "null": null, "string": "json_spec", "true": true, "updated_at": "2011-07-08 02:28:50", "nested": { "id": 2, "key": "value" } } """ Scenario: String When I get the JSON Then the JSON should include "json_spec" And the JSON should include: """ "json_spec" """ Scenario: Integer When I get the JSON Then the JSON should include 10 And the JSON should include: """ 10 """ Scenario: Negative integer When I get the JSON Then the JSON should include -10 And the JSON should include: """ -10 """ Scenario: Float When I get the JSON Then the JSON should include 10.0 And the JSON should include 10.0e0 And the JSON should include 10.0e+0 And the JSON should include 10.0e-0 And the JSON should include 10e0 And the JSON should include 10e+0 And the JSON should include 10e-0 And the JSON should include 1.0e1 And the JSON should include 1.0e+1 And the JSON should include 1e1 And the JSON should include 1e+1 And the JSON should include 100.0e-1 And the JSON should include 100e-1 And the JSON should include: """ 10.0 """ Scenario: Array When I get the JSON Then the JSON should include ["json","spec"] And the JSON at "array" should include "json" And the JSON at "array" should include "spec" And the JSON should include: """ [ "json", "spec" ] """ Scenario: Empty array When I get the JSON Then the JSON should include [] And the JSON should include: """ [ ] """ Scenario: Hash When I get the JSON Then the JSON should include {"json":"spec"} And the JSON at "hash" should include "spec" And the JSON should include: """ { "json": "spec" } """ Scenario: Empty hash When I get the JSON Then the JSON should include {} And the JSON should include: """ { } """ Scenario: True When I get the JSON Then the JSON should include true And the JSON should include: """ true """ Scenario: False When I get the JSON Then the JSON should include false And the JSON should include: """ false """ Scenario: Null When I get the JSON Then the JSON should include null And the JSON should include: """ null """ Scenario: Excluded value When I get the JSON Then the JSON should include "2011-07-08 02:27:34" And the JSON should include 1 And the JSON should include "2011-07-08 02:28:50" Scenario: Nested exclusions When I get the JSON Then the JSON should include {"key":"value"} json_spec-1.1.5/features/paths.feature0000644000004100000410000000326013123610203020033 0ustar www-datawww-dataFeature: Paths Background: Given the JSON is: """ { "array": [ { "one": 1, "two": 2 }, { "four": 4, "three": 3 } ], "hash": { "even": [ 6, 8 ], "odd": [ 5, 7 ] }, "id": null } """ Scenario: Base paths When I get the JSON Then the JSON should have "array" And the JSON should have "hash" And the JSON should have "id" Scenario: Nested paths When I get the JSON Then the JSON should have "array/0" And the JSON should have "array/1" And the JSON should have "hash/even" And the JSON should have "hash/odd" Scenario: Deeply nested paths When I get the JSON Then the JSON should have "array/0/one" And the JSON should have "array/0/two" And the JSON should have "array/1/four" And the JSON should have "array/1/three" And the JSON should have "hash/even/0" And the JSON should have "hash/even/1" And the JSON should have "hash/odd/0" And the JSON should have "hash/odd/1" Scenario: Ignored paths When I get the JSON Then the JSON should have "id" Scenario: Table format When I get the JSON Then the JSON should have the following: | array | | hash | | array/0 | | array/1 | | hash/even | | hash/odd | | array/0/one | | array/0/two | | array/1/four | | array/1/three | | hash/even/0 | | hash/even/1 | | hash/odd/0 | | hash/odd/1 | json_spec-1.1.5/json_spec.gemspec0000644000004100000410000000132713123610203017053 0ustar www-datawww-data# encoding: utf-8 Gem::Specification.new do |gem| gem.name = "json_spec" gem.version = "1.1.5" gem.authors = ["Steve Richert"] gem.email = ["steve.richert@gmail.com"] gem.summary = "Easily handle JSON in RSpec and Cucumber" gem.description = "RSpec matchers and Cucumber steps for testing JSON content" gem.homepage = "https://github.com/collectiveidea/json_spec" gem.license = "MIT" gem.add_dependency "multi_json", "~> 1.0" gem.add_dependency "rspec", ">= 2.0", "< 4.0" gem.add_development_dependency "bundler", "~> 1.0" gem.add_development_dependency "rake", "~> 10.0" gem.files = `git ls-files`.split($\) gem.test_files = gem.files.grep(/^(features|spec)/) end json_spec-1.1.5/LICENSE.txt0000644000004100000410000000204013123610203015337 0ustar www-datawww-dataCopyright © 2011 Steve Richert Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. json_spec-1.1.5/spec/0000755000004100000410000000000013123610203014452 5ustar www-datawww-datajson_spec-1.1.5/spec/spec_helper.rb0000644000004100000410000000047313123610203017274 0ustar www-datawww-datarequire "json_spec" RSpec.configure do |config| config.before do JsonSpec.reset end config.expect_with :rspec do |c| c.syntax = [:should, :expect] end config.mock_with :rspec do |c| c.syntax = [:should, :expect] end end def files_path File.expand_path("../support/files", __FILE__) end json_spec-1.1.5/spec/json_spec/0000755000004100000410000000000013123610203016435 5ustar www-datawww-datajson_spec-1.1.5/spec/json_spec/memory_spec.rb0000644000004100000410000000127613123610203021312 0ustar www-datawww-datarequire "spec_helper" describe JsonSpec::Memory do it "has a memory" do JsonSpec.memory.should == {} end it "memorizes strings" do JsonSpec.memorize(:key, "value") JsonSpec.memory.should == { key: "value" } end it "symbolizes keys" do JsonSpec.memorize("key", "value") JsonSpec.memory.should == { key: "value" } end it "regurgitates unremembered strings" do JsonSpec.remember("foo%{bar}").should == "foo%{bar}" end it "remembers strings" do JsonSpec.memorize(:bar, "baz") JsonSpec.remember("foo%{bar}").should == "foobaz" end it "forgets" do JsonSpec.memorize(:key, "value") JsonSpec.forget JsonSpec.memory.should == {} end end json_spec-1.1.5/spec/json_spec/matchers_spec.rb0000644000004100000410000000365213123610203021610 0ustar www-datawww-datarequire "spec_helper" describe JsonSpec::Matchers do let(:environment) do klass = Class.new klass.send(:include, JsonSpec::Matchers) klass.new end let(:json){ %({"json":"spec"}) } context "be_json_eql" do it "instantiates its matcher" do JsonSpec::Matchers::BeJsonEql.should_receive(:new).with(json) environment.be_json_eql(json) end it "returns its matcher" do matcher = environment.be_json_eql(json) matcher.should be_a(JsonSpec::Matchers::BeJsonEql) end end context "include_json" do it "instantiates its matcher" do JsonSpec::Matchers::IncludeJson.should_receive(:new).with(json) environment.include_json(json) end it "returns its matcher" do matcher = environment.include_json(json) matcher.should be_a(JsonSpec::Matchers::IncludeJson) end end context "have_json_path" do let(:path){ "json" } it "instantiates its matcher" do JsonSpec::Matchers::HaveJsonPath.should_receive(:new).with(path) environment.have_json_path(path) end it "returns its matcher" do matcher = environment.have_json_path(path) matcher.should be_a(JsonSpec::Matchers::HaveJsonPath) end end context "have_json_type" do let(:type){ Hash } it "instantiates its matcher" do JsonSpec::Matchers::HaveJsonType.should_receive(:new).with(type) environment.have_json_type(type) end it "returns its matcher" do matcher = environment.have_json_type(type) matcher.should be_a(JsonSpec::Matchers::HaveJsonType) end end context "have_json_size" do let(:size){ 1 } it "instantiates its matcher" do JsonSpec::Matchers::HaveJsonSize.should_receive(:new).with(size) environment.have_json_size(size) end it "returns its matcher" do matcher = environment.have_json_size(size) matcher.should be_a(JsonSpec::Matchers::HaveJsonSize) end end end json_spec-1.1.5/spec/json_spec/matchers/0000755000004100000410000000000013123610203020243 5ustar www-datawww-datajson_spec-1.1.5/spec/json_spec/matchers/have_json_size_spec.rb0000644000004100000410000000427413123610203024617 0ustar www-datawww-datarequire "spec_helper" describe JsonSpec::Matchers::HaveJsonSize do it "counts array entries" do %([1,2,3]).should have_json_size(3) end it "counts null array entries" do %([1,null,3]).should have_json_size(3) end it "counts hash key/value pairs" do %({"one":1,"two":2,"three":3}).should have_json_size(3) end it "counts null hash values" do %({"one":1,"two":null,"three":3}).should have_json_size(3) end it "matches at a path" do %({"one":[1,2,3]}).should have_json_size(3).at_path("one") end it "provides a failure message" do matcher = have_json_size(3) matcher.matches?(%([1,2])) matcher.failure_message.should eq "Expected JSON value size to be 3, got 2" matcher.failure_message_for_should.should eq "Expected JSON value size to be 3, got 2" # RSpec 2 interface end it "provides a failure message for negation" do matcher = have_json_size(3) matcher.matches?(%([1,2,3])) matcher.failure_message_when_negated.should eq "Expected JSON value size to not be 3, got 3" matcher.failure_message_for_should_not.should eq "Expected JSON value size to not be 3, got 3" # RSpec 2 interface end it "provides a description message" do matcher = have_json_size(1) matcher.matches?(%({"id":1,"json":["spec"]})) matcher.description.should eq %(have JSON size "1") end it "provides a description message with path" do matcher = have_json_size(1).at_path("json") matcher.matches?(%({"id":1,"json":["spec"]})) matcher.description.should eq %(have JSON size "1" at path "json") end it "provides an error when parsing nil" do matcher = have_json_size(0).at_path("json") expect { matcher.matches?(%({"id":1,"json":null})) }.to raise_error(JsonSpec::EnumerableExpected, "Enumerable expected, got nil") end it "provides an error when parsing non-enumerables" do matcher = have_json_size(0).at_path("json") expect { matcher.matches?(%({"id":1,"json":12345})) }.to raise_error(JsonSpec::EnumerableExpected, "Enumerable expected, got 12345") end end json_spec-1.1.5/spec/json_spec/matchers/include_json_spec.rb0000644000004100000410000000576313123610203024271 0ustar www-datawww-datarequire "spec_helper" describe JsonSpec::Matchers::IncludeJson do it "matches included array elements" do json = %(["one",1,1.0,true,false,null]) json.should include_json(%("one")) json.should include_json(%(1)) json.should include_json(%(1.0)) json.should include_json(%(true)) json.should include_json(%(false)) json.should include_json(%(null)) end it "matches an array included in an array" do json = %([[1,2,3],[4,5,6]]) json.should include_json(%([1,2,3])) json.should include_json(%([4,5,6])) end it "matches a hash included in an array" do json = %([{"one":1},{"two":2}]) json.should include_json(%({"one":1})) json.should include_json(%({"two":2})) end it "matches included hash values" do json = %({"string":"one","integer":1,"float":1.0,"true":true,"false":false,"null":null}) json.should include_json(%("one")) json.should include_json(%(1)) json.should include_json(%(1.0)) json.should include_json(%(true)) json.should include_json(%(false)) json.should include_json(%(null)) end it "matches a hash included in a hash" do json = %({"one":{"two":3},"four":{"five":6}}) json.should include_json(%({"two":3})) json.should include_json(%({"five":6})) end it "matches an array included in a hash" do json = %({"one":[2,3],"four":[5,6]}) json.should include_json(%([2,3])) json.should include_json(%([5,6])) end it "matches a substring" do json = %("json") json.should include_json(%("js")) json.should include_json(%("json")) end it "matches at a path" do %({"one":{"two":[3,4]}}).should include_json(%([3,4])).at_path("one") end it "ignores excluded keys" do %([{"id":1,"two":3}]).should include_json(%({"two":3})) end it "provides a description message" do matcher = include_json(%({"json":"spec"})) matcher.matches?(%({"id":1,"json":"spec"})) matcher.description.should == "include JSON" end it "provides a description message with path" do matcher = include_json(%("spec")).at_path("json/0") matcher.matches?(%({"id":1,"json":["spec"]})) matcher.description.should == %(include JSON at path "json/0") end it "provides a useful failure message for should" do matcher = include_json(%([4,5,6])) matcher.matches?(%([1,2,3])) matcher.failure_message_for_should.should == "Expected [1,2,3] to include [4,5,6]" end it "provides a useful failure message for should not" do matcher = include_json(%(3)) matcher.matches?(%([1,2,3])) matcher.failure_message_for_should_not.should == "Expected [1,2,3] to not include 3" end it "raises an error when not given expected JSON" do expect{ %([{"id":1,"two":3}]).should include_json }.to raise_error do |error| error.message.should == "Expected included JSON not provided" end end it "matches file contents" do JsonSpec.directory = files_path %({"one":{"value":"from_file"},"four":{"five":6}}).should include_json.from_file("one.json") end end json_spec-1.1.5/spec/json_spec/matchers/have_json_type_spec.rb0000644000004100000410000000506413123610203024624 0ustar www-datawww-datarequire "spec_helper" describe JsonSpec::Matchers::HaveJsonType do it "matches hashes" do hash = %({}) hash.should have_json_type(Hash) hash.should have_json_type(:object) end it "matches arrays" do %([]).should have_json_type(Array) end it "matches at a path" do %({"root":[]}).should have_json_type(Array).at_path("root") end it "matches strings" do %(["json_spec"]).should have_json_type(String).at_path("0") end it "matches a valid JSON value, yet invalid JSON document" do %("json_spec").should have_json_type(String) end it "matches empty strings" do %("").should have_json_type(String) end it "matches integers" do %(10).should have_json_type(Integer) end it "matches floats" do %(10.0).should have_json_type(Float) %(1e+1).should have_json_type(Float) end it "matches booleans" do %(true).should have_json_type(:boolean) %(false).should have_json_type(:boolean) end it "matches ancestor classes" do %(10).should have_json_type(Numeric) %(10.0).should have_json_type(Numeric) end it "provides a failure message" do matcher = have_json_type(Numeric) matcher.matches?(%("foo")) matcher.failure_message.should eq "Expected JSON value type to be Numeric, got String" matcher.failure_message_for_should.should eq "Expected JSON value type to be Numeric, got String" # RSpec 2 interface end it "provides a failure message for negation" do matcher = have_json_type(Numeric) matcher.matches?(%(10)) matcher.failure_message_when_negated.should eq "Expected JSON value type to not be Numeric, got Fixnum" matcher.failure_message_for_should_not.should eq "Expected JSON value type to not be Numeric, got Fixnum" # RSpec 2 interface end it "provides a description message" do matcher = have_json_type(String) matcher.matches?(%({"id":1,"json":"spec"})) matcher.description.should eq %(have JSON type "String") end it "provides a description message with path" do matcher = have_json_type(String).at_path("json") matcher.matches?(%({"id":1,"json":"spec"})) matcher.description.should eq %(have JSON type "String" at path "json") end context "somewhat uselessly" do it "matches true" do %(true).should have_json_type(TrueClass) end it "matches false" do %(false).should have_json_type(FalseClass) end it "matches null" do null = %(null) null.should have_json_type(NilClass) null.should have_json_type(:nil) null.should have_json_type(:null) end end end json_spec-1.1.5/spec/json_spec/matchers/have_json_path_spec.rb0000644000004100000410000000150113123610203024567 0ustar www-datawww-datarequire "spec_helper" describe JsonSpec::Matchers::HaveJsonPath do it "matches hash keys" do %({"one":{"two":{"three":4}}}).should have_json_path("one/two/three") end it "doesn't match values" do %({"one":{"two":{"three":4}}}).should_not have_json_path("one/two/three/4") end it "matches array indexes" do %([1,[1,2,[1,2,3,4]]]).should have_json_path("1/2/3") end it "respects null array values" do %([null,[null,null,[null,null,null,null]]]).should have_json_path("1/2/3") end it "matches hash keys and array indexes" do %({"one":[1,2,{"three":4}]}).should have_json_path("one/2/three") end it "provides a description message" do matcher = have_json_path("json") matcher.matches?(%({"id":1,"json":"spec"})) matcher.description.should == %(have JSON path "json") end end json_spec-1.1.5/spec/json_spec/matchers/be_json_eql_spec.rb0000644000004100000410000000742713123610203024074 0ustar www-datawww-datarequire "spec_helper" describe JsonSpec::Matchers::BeJsonEql do it "matches identical JSON" do %({"json":"spec"}).should be_json_eql(%({"json":"spec"})) end it "matches differently-formatted JSON" do %({"json": "spec"}).should be_json_eql(%({"json":"spec"})) end it "matches out-of-order hashes" do %({"laser":"lemon","json":"spec"}).should be_json_eql(%({"json":"spec","laser":"lemon"})) end it "doesn't match out-of-order arrays" do %(["json","spec"]).should_not be_json_eql(%(["spec","json"])) end it "matches valid JSON values, yet invalid JSON documents" do %("json_spec").should be_json_eql(%("json_spec")) end it "matches at a path" do %({"json":["spec"]}).should be_json_eql(%("spec")).at_path("json/0") end it "ignores excluded-by-default hash keys" do JsonSpec.excluded_keys.should_not be_empty actual = expected = { "json" => "spec" } JsonSpec.excluded_keys.each { |k| actual[k] = k } actual.to_json.should be_json_eql(expected.to_json) end it "ignores custom excluded hash keys" do JsonSpec.exclude_keys("ignore") %({"json":"spec","ignore":"please"}).should be_json_eql(%({"json":"spec"})) end it "ignores nested, excluded hash keys" do JsonSpec.exclude_keys("ignore") %({"json":"spec","please":{"ignore":"this"}}).should be_json_eql(%({"json":"spec","please":{}})) end it "ignores hash keys when included in the expected value" do JsonSpec.exclude_keys("ignore") %({"json":"spec","ignore":"please"}).should be_json_eql(%({"json":"spec","ignore":"this"})) end it "doesn't match Ruby-equivalent, JSON-inequivalent values" do %({"one":1}).should_not be_json_eql(%({"one":1.0})) end it "matches different looking, JSON-equivalent values" do %({"ten":10.0}).should be_json_eql(%({"ten":1e+1})) end it "excludes extra hash keys per matcher" do JsonSpec.excluded_keys = %w(ignore) %({"id":1,"json":"spec","ignore":"please"}).should be_json_eql(%({"id":2,"json":"spec","ignore":"this"})).excluding("id") end it "excludes extra hash keys given as symbols" do JsonSpec.excluded_keys = [] %({"id":1,"json":"spec"}).should be_json_eql(%({"id":2,"json":"spec"})).excluding(:id) end it "excludes multiple keys" do JsonSpec.excluded_keys = [] %({"id":1,"json":"spec"}).should be_json_eql(%({"id":2,"json":"different"})).excluding(:id, :json) end it "includes globally-excluded hash keys per matcher" do JsonSpec.excluded_keys = %w(id ignore) %({"id":1,"json":"spec","ignore":"please"}).should_not be_json_eql(%({"id":2,"json":"spec","ignore":"this"})).including("id") end it "includes globally-included hash keys given as symbols" do JsonSpec.excluded_keys = %w(id) %({"id":1,"json":"spec"}).should_not be_json_eql(%({"id":2,"json":"spec"})).including(:id) end it "includes multiple keys" do JsonSpec.excluded_keys = %w(id json) %({"id":1,"json":"spec"}).should_not be_json_eql(%({"id":2,"json":"different"})).including(:id, :json) end it "provides a description message" do matcher = be_json_eql(%({"id":2,"json":"spec"})) matcher.matches?(%({"id":1,"json":"spec"})) matcher.description.should == "equal JSON" end it "provides a description message with path" do matcher = be_json_eql(%({"id":1,"json":["spec"]})).at_path("json/0") matcher.matches?(%({"id":1,"json":["spec"]})) matcher.description.should == %(equal JSON at path "json/0") end it "raises an error when not given expected JSON" do expect{ %({"id":1,"json":"spec"}).should be_json_eql }.to raise_error do |error| error.message.should == "Expected equivalent JSON not provided" end end it "matches file contents" do JsonSpec.directory = files_path %({ "value" : "from_file" }).should be_json_eql.to_file("one.json") end end json_spec-1.1.5/spec/json_spec/configuration_spec.rb0000644000004100000410000000314013123610203022641 0ustar www-datawww-datarequire "spec_helper" describe JsonSpec::Configuration do it "excludes id and timestamps by default" do JsonSpec.excluded_keys.should eq ["id", "created_at", "updated_at"] end it "excludes custom keys" do JsonSpec.exclude_keys("token") JsonSpec.excluded_keys.should eq ["token"] end it "excludes custom keys via setter" do JsonSpec.excluded_keys = ["token"] JsonSpec.excluded_keys.should eq ["token"] end it "excludes custom keys via block" do JsonSpec.configure { |c| c.exclude_keys("token") } JsonSpec.excluded_keys.should eq ["token"] end it "excludes custom keys via block setter" do JsonSpec.configure { |c| c.excluded_keys = ["token"] } JsonSpec.excluded_keys.should eq ["token"] end it "excludes custom keys via instance-evaluated block" do JsonSpec.configure{ exclude_keys("token") } JsonSpec.excluded_keys.should eq ["token"] end it "ensures its excluded keys are strings" do JsonSpec.exclude_keys(:token) JsonSpec.excluded_keys.should eq ["token"] end it "ensures its excluded keys are unique" do JsonSpec.exclude_keys("token", :token) JsonSpec.excluded_keys.should eq ["token"] end it "resets its excluded keys" do original = JsonSpec.excluded_keys JsonSpec.exclude_keys("token") JsonSpec.excluded_keys.should_not eq original JsonSpec.reset JsonSpec.excluded_keys.should eq original end it "resets its directory" do JsonSpec.directory.should be_nil JsonSpec.directory = "/" JsonSpec.directory.should_not be_nil JsonSpec.reset JsonSpec.directory.should be_nil end end json_spec-1.1.5/spec/json_spec/helpers_spec.rb0000644000004100000410000000563613123610203021450 0ustar www-datawww-datarequire "spec_helper" describe JsonSpec::Helpers do include described_class context "parse_json" do it "parses JSON documents" do parse_json(%({"json":["spec"]})).should eq({"json" => ["spec"]}) end it "parses JSON values" do parse_json(%("json_spec")).should eq "json_spec" end it "raises a parser error for invalid JSON" do expect{ parse_json("json_spec") }.to raise_error(MultiJson::DecodeError) end it "parses at a path if given" do json = %({"json":["spec"]}) parse_json(json, "json").should eq ["spec"] parse_json(json, "json/0").should eq "spec" end it "raises an error for a missing path" do json = %({"json":["spec"]}) %w(spec json/1).each do |path| expect{ parse_json(json, path) }.to raise_error(JsonSpec::MissingPath) end end it "parses at a numeric string path" do json = %({"1":"two"}) parse_json(json, "1").should eq "two" end end context "normalize_json" do it "normalizes a JSON document" do normalized = <<-JSON { "json": [ "spec" ] } JSON normalize_json(%({"json":["spec"]})).should eq normalized.chomp end it "normalizes at a path" do normalize_json(%({"json":["spec"]}), "json/0").should eq %("spec") end it "accepts a JSON value" do normalize_json(%("json_spec")).should eq %("json_spec") end it "normalizes JSON values" do normalize_json(%(1e+1)).should eq %(10.0) end end context "generate_normalized_json" do it "generates a normalized JSON document" do normalized = <<-JSON { "json": [ "spec" ] } JSON generate_normalized_json({"json" => ["spec"]}).should eq normalized.chomp end it "generates a normalized JSON value" do generate_normalized_json(nil).should eq %(null) end end context "load_json_file" do it "raises an error when no directory is set" do expect{ load_json("one.json") }.to raise_error(JsonSpec::MissingDirectory) end it "returns JSON when the file exists" do JsonSpec.directory = files_path load_json("one.json").should eq %({"value":"from_file"}) end it "ignores extra slashes" do JsonSpec.directory = "/#{files_path}/" load_json("one.json").should eq %({"value":"from_file"}) end it "raises an error when the file doesn't exist" do JsonSpec.directory = files_path expect{ load_json("bogus.json") }.to raise_error(JsonSpec::MissingFile) end it "raises an error when the directory doesn't exist" do JsonSpec.directory = "#{files_path}_bogus" expect{ load_json("one.json") }.to raise_error(JsonSpec::MissingFile) end it "finds nested files" do JsonSpec.directory = files_path load_json("project/one.json").should eq %({"nested":"inside_folder"}) load_json("project/version/one.json").should eq %({"nested":"deeply"}) end end end json_spec-1.1.5/spec/support/0000755000004100000410000000000013123610203016166 5ustar www-datawww-datajson_spec-1.1.5/spec/support/files/0000755000004100000410000000000013123610203017270 5ustar www-datawww-datajson_spec-1.1.5/spec/support/files/one.json0000644000004100000410000000002513123610203020741 0ustar www-datawww-data{"value":"from_file"}json_spec-1.1.5/spec/support/files/two.json0000644000004100000410000000053013123610203020772 0ustar www-datawww-data{ "array": [ "json", "spec" ], "created_at": "2011-07-08 02:27:34", "empty_array": [ ], "empty_hash": { }, "false": false, "float": 10.0, "hash": { "json": "spec" }, "id": 1, "integer": 10, "negative": -10, "null": null, "string": "json_spec", "true": true, "updated_at": "2011-07-08 02:28:50" }json_spec-1.1.5/spec/support/files/project/0000755000004100000410000000000013123610203020736 5ustar www-datawww-datajson_spec-1.1.5/spec/support/files/project/one.json0000644000004100000410000000003213123610203022405 0ustar www-datawww-data{"nested":"inside_folder"}json_spec-1.1.5/spec/support/files/project/two.json0000644000004100000410000000017313123610203022443 0ustar www-datawww-data{ "id": null, "one": [ 1 ], "three": [ 1, 2, 3 ], "two": [ 1, 2 ], "zero": [ ] }json_spec-1.1.5/spec/support/files/project/version/0000755000004100000410000000000013123610203022423 5ustar www-datawww-datajson_spec-1.1.5/spec/support/files/project/version/one.json0000644000004100000410000000002313123610203024072 0ustar www-datawww-data{"nested":"deeply"}json_spec-1.1.5/spec/support/files/project/version/two.json0000644000004100000410000000002413123610203024123 0ustar www-datawww-data{ "json": "spec" }json_spec-1.1.5/.travis.yml0000644000004100000410000000035413123610203015633 0ustar www-datawww-databranches: only: - master gemfile: - gemfiles/rspec2.gemfile - gemfiles/rspec3.gemfile language: ruby matrix: allow_failures: - rvm: ruby-head - rvm: "2.0" rvm: - "2.0" - "2.1" - "2.2" - "2.3.4" - ruby-head json_spec-1.1.5/lib/0000755000004100000410000000000013123610203014266 5ustar www-datawww-datajson_spec-1.1.5/lib/json_spec/0000755000004100000410000000000013123610203016251 5ustar www-datawww-datajson_spec-1.1.5/lib/json_spec/matchers.rb0000644000004100000410000000137613123610203020413 0ustar www-datawww-datarequire "json_spec/matchers/be_json_eql" require "json_spec/matchers/include_json" require "json_spec/matchers/have_json_path" require "json_spec/matchers/have_json_type" require "json_spec/matchers/have_json_size" module JsonSpec module Matchers def be_json_eql(json = nil) JsonSpec::Matchers::BeJsonEql.new(json) end def include_json(json = nil) JsonSpec::Matchers::IncludeJson.new(json) end def have_json_path(path) JsonSpec::Matchers::HaveJsonPath.new(path) end def have_json_type(type) JsonSpec::Matchers::HaveJsonType.new(type) end def have_json_size(size) JsonSpec::Matchers::HaveJsonSize.new(size) end end end RSpec.configure do |config| config.include JsonSpec::Matchers end json_spec-1.1.5/lib/json_spec/configuration.rb0000644000004100000410000000103413123610203021443 0ustar www-datawww-datarequire "set" module JsonSpec module Configuration DEFAULT_EXCLUDED_KEYS = %w(id created_at updated_at) attr_accessor :directory def configure(&block) instance_eval(&block) end def excluded_keys @excluded_keys ||= DEFAULT_EXCLUDED_KEYS end def excluded_keys=(keys) @excluded_keys = keys.map(&:to_s).uniq end def exclude_keys(*keys) self.excluded_keys = keys end def reset instance_variables.each { |ivar| remove_instance_variable(ivar) } end end end json_spec-1.1.5/lib/json_spec/errors.rb0000644000004100000410000000131013123610203020105 0ustar www-datawww-datamodule JsonSpec class Error < StandardError end class MissingPath < Error attr_reader :path def initialize(path) @path = path end def to_s %(Missing JSON path "#{path}") end end class MissingDirectory < Error def to_s "No JsonSpec.directory set" end end class MissingFile < Error attr_reader :path def initialize(path) @path = path end def to_s "No JSON file at #{path}" end end class EnumerableExpected < Error attr_reader :actual_value def initialize(actual_value) @actual_value = actual_value end def to_s "Enumerable expected, got #{actual_value.inspect}" end end end json_spec-1.1.5/lib/json_spec/cucumber.rb0000644000004100000410000000617713123610203020416 0ustar www-datawww-datarequire File.expand_path("../../json_spec", __FILE__) World(JsonSpec::Helpers, JsonSpec::Matchers) After do JsonSpec.forget end When /^(?:I )?keep the (?:JSON|json)(?: response)?(?: at "(.*)")? as "(.*)"$/ do |path, key| JsonSpec.memorize(key, normalize_json(last_json, path)) end Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? be:$/ do |path, negative, json| if negative last_json.should_not be_json_eql(JsonSpec.remember(json)).at_path(path) else last_json.should be_json_eql(JsonSpec.remember(json)).at_path(path) end end Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? be file "(.+)"$/ do |path, negative, file_path| if negative last_json.should_not be_json_eql.to_file(file_path).at_path(path) else last_json.should be_json_eql.to_file(file_path).at_path(path) end end Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? be (".*"|\-?\d+(?:\.\d+)?(?:[eE][\+\-]?\d+)?|\[.*\]|%?\{.*\}|true|false|null)$/ do |path, negative, value| if negative last_json.should_not be_json_eql(JsonSpec.remember(value)).at_path(path) else last_json.should be_json_eql(JsonSpec.remember(value)).at_path(path) end end Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? include:$/ do |path, negative, json| if negative last_json.should_not include_json(JsonSpec.remember(json)).at_path(path) else last_json.should include_json(JsonSpec.remember(json)).at_path(path) end end Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? include file "(.+)"$/ do |path, negative, file_path| if negative last_json.should_not include_json.from_file(file_path).at_path(path) else last_json.should include_json.from_file(file_path).at_path(path) end end Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? include (".*"|\-?\d+(?:\.\d+)?(?:[eE][\+\-]?\d+)?|\[.*\]|%?\{.*\}|true|false|null)$/ do |path, negative, value| if negative last_json.should_not include_json(JsonSpec.remember(value)).at_path(path) else last_json.should include_json(JsonSpec.remember(value)).at_path(path) end end Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should have the following:$/ do |base, table| table.raw.each do |path, value| path = [base, path].compact.join("/") if value step %(the JSON at "#{path}" should be:), value else step %(the JSON should have "#{path}") end end end Then /^the (?:JSON|json)(?: response)? should( not)? have "(.*)"$/ do |negative, path| if negative last_json.should_not have_json_path(path) else last_json.should have_json_path(path) 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) else last_json.should have_json_type(type).at_path(path) end end Then /^the (?:JSON|json)(?: response)?(?: at "(.*)")? should( not)? have (\d+)/ do |path, negative, size| if negative last_json.should_not have_json_size(size.to_i).at_path(path) else last_json.should have_json_size(size.to_i).at_path(path) end end json_spec-1.1.5/lib/json_spec/memory.rb0000644000004100000410000000042313123610203020105 0ustar www-datawww-datamodule JsonSpec module Memory def memory @memory ||= {} end def memorize(key, value) memory[key.to_sym] = value end def remember(json) memory.empty? ? json : json % memory end def forget memory.clear end end end json_spec-1.1.5/lib/json_spec/helpers.rb0000644000004100000410000000276513123610203020252 0ustar www-datawww-datarequire "multi_json" module JsonSpec module Helpers extend self def parse_json(json, path = nil) ruby = MultiJson.decode("[#{json}]").first value_at_json_path(ruby, path) rescue MultiJson::DecodeError MultiJson.decode(json) end def normalize_json(json, path = nil) ruby = parse_json(json, path) generate_normalized_json(ruby) end def generate_normalized_json(ruby) case ruby when Hash, Array then JSON.pretty_generate(ruby) else ruby.to_json end end def load_json(relative_path) missing_json_directory! if JsonSpec.directory.nil? path = File.join(JsonSpec.directory, relative_path) missing_json_file!(path) unless File.exist?(path) File.read(path) end private def value_at_json_path(ruby, path) return ruby unless path path.split("/").inject(ruby) do |value, key| case value when Hash value.fetch(key){ missing_json_path!(path) } when Array missing_json_path!(path) unless key =~ /^\d+$/ value.fetch(key.to_i){ missing_json_path!(path) } else missing_json_path!(path) end end end def missing_json_path!(path) raise JsonSpec::MissingPath.new(path) end def missing_json_directory! raise JsonSpec::MissingDirectory end def missing_json_file!(path) raise JsonSpec::MissingFile.new(path) end end end json_spec-1.1.5/lib/json_spec/exclusion.rb0000644000004100000410000000100313123610203020601 0ustar www-datawww-datamodule JsonSpec module Exclusion extend self def exclude_keys(ruby) case ruby when Hash ruby.sort.inject({}) do |hash, (key, value)| hash[key] = exclude_keys(value) unless exclude_key?(key) hash end when Array ruby.map{|v| exclude_keys(v) } else ruby end end def exclude_key?(key) excluded_keys.include?(key) end def excluded_keys @excluded_keys ||= Set.new(JsonSpec.excluded_keys) end end end json_spec-1.1.5/lib/json_spec/matchers/0000755000004100000410000000000013123610203020057 5ustar www-datawww-datajson_spec-1.1.5/lib/json_spec/matchers/be_json_eql.rb0000644000004100000410000000273213123610203022670 0ustar www-datawww-datamodule JsonSpec module Matchers class BeJsonEql include JsonSpec::Helpers include JsonSpec::Exclusion include JsonSpec::Messages attr_reader :expected, :actual def diffable? true end def initialize(expected_json = nil) @expected_json = expected_json @path = nil end def matches?(actual_json) raise "Expected equivalent JSON not provided" if @expected_json.nil? @actual, @expected = scrub(actual_json, @path), scrub(@expected_json) @actual == @expected end def at_path(path) @path = path self end def to_file(path) @expected_json = load_json(path) self end def excluding(*keys) excluded_keys.merge(keys.map(&:to_s)) self end def including(*keys) excluded_keys.subtract(keys.map(&:to_s)) self end def failure_message message_with_path("Expected equivalent JSON") end alias :failure_message_for_should :failure_message def failure_message_when_negated message_with_path("Expected inequivalent JSON") end alias :failure_message_for_should_not :failure_message_when_negated def description message_with_path("equal JSON") end private def scrub(json, path = nil) generate_normalized_json(exclude_keys(parse_json(json, path))).chomp + "\n" end end end end json_spec-1.1.5/lib/json_spec/matchers/have_json_type.rb0000644000004100000410000000262613123610203023427 0ustar www-datawww-datamodule JsonSpec module Matchers class HaveJsonType include JsonSpec::Helpers include JsonSpec::Messages def initialize(type) @classes = type_to_classes(type) @path = nil end def matches?(json) @ruby = parse_json(json, @path) @classes.any? { |c| c === @ruby } end def at_path(path) @path = path self end def failure_message message_with_path("Expected JSON value type to be #{@classes.join(", ")}, got #{@ruby.class}") end alias :failure_message_for_should :failure_message def failure_message_when_negated message_with_path("Expected JSON value type to not be #{@classes.join(", ")}, got #{@ruby.class}") end alias :failure_message_for_should_not :failure_message_when_negated def description message_with_path(%(have JSON type "#{@classes.join(", ")}")) end private def type_to_classes(type) case type when Class then [type] when Array then type.map { |t| type_to_classes(t) }.flatten else case type.to_s.downcase when "boolean" then [TrueClass, FalseClass] when "object" then [Hash] when "nil", "null" then [NilClass] else [Module.const_get(type.to_s.capitalize)] end end end end end end json_spec-1.1.5/lib/json_spec/matchers/have_json_path.rb0000644000004100000410000000123513123610203023375 0ustar www-datawww-datamodule JsonSpec module Matchers class HaveJsonPath include JsonSpec::Helpers def initialize(path) @path = path end def matches?(json) parse_json(json, @path) true rescue JsonSpec::MissingPath false end def failure_message %(Expected JSON path "#{@path}") end alias :failure_message_for_should :failure_message def failure_message_when_negated %(Expected no JSON path "#{@path}") end alias :failure_message_for_should_not :failure_message_when_negated def description %(have JSON path "#{@path}") end end end end json_spec-1.1.5/lib/json_spec/matchers/include_json.rb0000644000004100000410000000314013123610203023056 0ustar www-datawww-datamodule JsonSpec module Matchers class IncludeJson include JsonSpec::Helpers include JsonSpec::Exclusion include JsonSpec::Messages def initialize(expected_json = nil) @expected_json = expected_json @path = nil end def matches?(actual_json) raise "Expected included JSON not provided" if @expected_json.nil? @actual_json = actual_json actual = parse_json(actual_json, @path) expected = exclude_keys(parse_json(@expected_json)) case actual when Hash then actual.values.map { |v| exclude_keys(v) }.include?(expected) when Array then actual.map { |e| exclude_keys(e) }.include?(expected) when String then actual.include?(expected) else false end end def at_path(path) @path = path self end def from_file(path) @expected_json = load_json(path) self end def excluding(*keys) excluded_keys.merge(keys.map(&:to_s)) self end def including(*keys) excluded_keys.subtract(keys.map(&:to_s)) self end def failure_message message_with_path("Expected #{@actual_json} to include #{@expected_json}") end alias :failure_message_for_should :failure_message def failure_message_when_negated message_with_path("Expected #{@actual_json} to not include #{@expected_json}") end alias :failure_message_for_should_not :failure_message_when_negated def description message_with_path("include JSON") end end end end json_spec-1.1.5/lib/json_spec/matchers/have_json_size.rb0000644000004100000410000000173313123610203023416 0ustar www-datawww-datamodule JsonSpec module Matchers class HaveJsonSize include JsonSpec::Helpers include JsonSpec::Messages def initialize(size) @expected = size @path = nil end def matches?(json) ruby = parse_json(json, @path) raise EnumerableExpected.new(ruby) unless Enumerable === ruby @actual = ruby.size @actual == @expected end def at_path(path) @path = path self end def failure_message message_with_path("Expected JSON value size to be #{@expected}, got #{@actual}") end alias :failure_message_for_should :failure_message def failure_message_when_negated message_with_path("Expected JSON value size to not be #{@expected}, got #{@actual}") end alias :failure_message_for_should_not :failure_message_when_negated def description message_with_path(%(have JSON size "#{@expected}")) end end end end json_spec-1.1.5/lib/json_spec/messages.rb0000644000004100000410000000022613123610203020405 0ustar www-datawww-datamodule JsonSpec module Messages def message_with_path(message) message << %( at path "#{@path}") if @path message end end end json_spec-1.1.5/lib/json_spec.rb0000644000004100000410000000044713123610203016603 0ustar www-datawww-datarequire "json" require "rspec" require "json_spec/errors" require "json_spec/configuration" require "json_spec/exclusion" require "json_spec/helpers" require "json_spec/messages" require "json_spec/matchers" require "json_spec/memory" module JsonSpec extend Configuration extend Memory end json_spec-1.1.5/gemfiles/0000755000004100000410000000000013123610203015313 5ustar www-datawww-datajson_spec-1.1.5/gemfiles/rspec2.gemfile0000644000004100000410000000017013123610203020041 0ustar www-datawww-datasource "https://rubygems.org" gemspec path: ".." gem "rspec", "~> 2.0" group :test do gem "cucumber", "~> 1.3" end json_spec-1.1.5/gemfiles/rspec3.gemfile0000644000004100000410000000017013123610203020042 0ustar www-datawww-datasource "https://rubygems.org" gemspec path: ".." gem "rspec", "~> 3.0" group :test do gem "cucumber", "~> 1.3" end json_spec-1.1.5/.gitignore0000644000004100000410000000005113123610203015504 0ustar www-datawww-data.bundle Gemfile.lock gemfiles/*.lock pkg json_spec-1.1.5/CHANGELOG.md0000644000004100000410000000047013123610203015332 0ustar www-datawww-data## Unreleased (master) - Added Changelog - Fix RSpec warnings for uninitialized instance variables on matchers [#78](https://github.com/collectiveidea/json_spec/pull/78) ## Version 1.1.4 - Raise error when checking a size of a json ruby value of nil [#82](https://github.com/collectiveidea/json_spec/pull/82) json_spec-1.1.5/README.md0000644000004100000410000002207213123610203015002 0ustar www-datawww-data# json_spec Easily handle JSON in RSpec and Cucumber [![Gem Version](https://img.shields.io/gem/v/json_spec.svg?style=flat)](http://rubygems.org/gems/json_spec) [![Build Status](https://img.shields.io/travis/collectiveidea/json_spec/master.svg?style=flat)](https://travis-ci.org/collectiveidea/json_spec) [![Code Climate](https://img.shields.io/codeclimate/github/collectiveidea/json_spec.svg?style=flat)](https://codeclimate.com/github/collectiveidea/json_spec) [![Dependency Status](https://img.shields.io/gemnasium/collectiveidea/json_spec.svg?style=flat)](https://gemnasium.com/collectiveidea/json_spec) ## RSpec json_spec defines five new RSpec matchers: * `be_json_eql` * `include_json` * `have_json_path` * `have_json_type` * `have_json_size` The new matchers could be used in RSpec as follows: ```ruby describe User do let(:user){ User.create!(first_name: "Steve", last_name: "Richert") } context "#to_json" do it "includes names" do names = %({"first_name":"Steve","last_name":"Richert"}) user.to_json.should be_json_eql(names).excluding("friends") end it "includes the ID" do user.to_json.should have_json_path("id") user.to_json.should have_json_type(Integer).at_path("id") end it "includes friends" do user.to_json.should have_json_size(0).at_path("friends") friend = User.create!(first_name: "Catie", last_name: "Richert") user.friends << friend user.to_json.should have_json_size(1).at_path("friends") user.to_json.should include_json(friend.to_json) end end end ``` json_spec also provides some useful helpers for RSpec tests: * `parse_json` * `normalize_json` * `generate_normalized_json` * `load_json` To start using them add an include them in your RSpec configuration: ```ruby RSpec.configure do |config| config.include JsonSpec::Helpers end ``` You can find usage examples for the helpers in [`spec/json_spec/helpers_spec.rb`](https://github.com/collectiveidea/json_spec/blob/master/spec/json_spec/helpers_spec.rb) ### Exclusions json_spec ignores certain hash keys by default when comparing JSON: * `id` * `created_at` * `updated_at` It's oftentimes helpful when evaluating JSON representations of newly-created ActiveRecord records so that the new ID and timestamps don't have to be known. These exclusions are globally customizeable: ```ruby JsonSpec.configure do exclude_keys "created_at", "updated_at" end ``` Now, the `id` key will be included in json_spec's comparisons. Keys can also be excluded/included per matcher by chaining the `excluding` or `including` methods (as shown above) which will add or subtract from the globally excluded keys, respectively. ### Paths Each of json_spec's matchers deal with JSON "paths." These are simple strings of "/" separated hash keys and array indexes. For instance, with the following JSON: { "first_name": "Steve", "last_name": "Richert", "friends": [ { "first_name": "Catie", "last_name": "Richert" } ] } We could access the first friend's first name with the path `"friends/0/first_name"`. ## Cucumber json_spec provides Cucumber steps that utilize its RSpec matchers and that's where json_spec really shines. This is perfect for testing your app's JSON API. In order to use the Cucumber steps, in your `env.rb` you must: ```ruby require "json_spec/cucumber" ``` You also need to define a `last_json` method. If you're using Capybara, it could be as simple as: ```ruby def last_json page.source end ``` Now, you can use the json_spec steps in your features: ```cucumber Feature: User API Background: Given the following users exist: | id | first_name | last_name | | 1 | Steve | Richert | | 2 | Catie | Richert | And "Steve Richert" is friends with "Catie Richert" Scenario: Index action When I visit "/users.json" Then the JSON response should have 2 users And the JSON response at "0/id" should be 1 And the JSON response at "1/id" should be 2 Scenario: Show action When I visit "/users/1.json" Then the JSON response at "first_name" should be "Steve" And the JSON response at "last_name" should be "Richert" And the JSON response should have "created_at" And the JSON response at "created_at" should be a string And the JSON response at "friends" should be: """ [ { "id": 2, "first_name": "Catie", "last_name": "Richert" } ] """ ``` The background steps above aren't provided by json_spec and the "visit" steps are provided by Capybara. The remaining steps, json_spec provides. They're versatile and can be used in plenty of different formats: ```cucumber Then the JSON should be: """ { "key": "value" } """ Then the JSON at "path" should be: """ [ "entry", "entry" ] """ Then the JSON should be {"key":"value"} Then the JSON at "path" should be {"key":"value"} Then the JSON should be ["entry","entry"] Then the JSON at "path" should be ["entry","entry"] Then the JSON at "path" should be "string" Then the JSON at "path" should be 10 Then the JSON at "path" should be 10.0 Then the JSON at "path" should be 1e+1 Then the JSON at "path" should be true Then the JSON at "path" should be false Then the JSON at "path" should be null Then the JSON should include: """ { "key": "value" } """ Then the JSON at "path" should include: """ [ "entry", "entry" ] """ Then the JSON should include {"key":"value"} Then the JSON at "path" should include {"key":"value"} Then the JSON should include ["entry","entry"] Then the JSON at "path" should include ["entry","entry"] Then the JSON should include "string" Then the JSON at "path" should include "string" Then the JSON should include 10 Then the JSON at "path" should include 10 Then the JSON should include 10.0 Then the JSON at "path" should include 10.0 Then the JSON should include 1e+1 Then the JSON at "path" should include 1e+1 Then the JSON should include true Then the JSON at "path" should include true Then the JSON should include false Then the JSON at "path" should include false Then the JSON should include null Then the JSON at "path" should include null Then the JSON should have "path" Then the JSON should be a hash Then the JSON at "path" should be an array Then the JSON at "path" should be a float Then the JSON should have 1 entry Then the JSON at "path" should have 2 entries Then the JSON should have 3 keys Then the JSON should have 4 whatevers ``` _All instances of "should" above could be followed by "not" and all instances of "JSON" could be downcased and/or followed by "response."_ ### Table Format Another step exists that uses Cucumber's table formatting and wraps two of the above steps: ```cucumber Then the JSON should have the following: | path/0 | {"key":"value"} | | path/1 | ["entry","entry"] | ``` Any number of rows can be given. The step above is equivalent to: ```cucumber Then the JSON at "path/0" should be {"key":"value"} And the JSON at "path/1" should be ["entry","entry"] ``` If only one column is given: ```cucumber Then the JSON should have the following: | path/0 | | path/1 | ``` This is equivalent to: ```cucumber Then the JSON should have "path/0" And the JSON should have "path/1" ``` ### JSON Memory There's one more Cucumber step that json_spec provides which hasn't been used above. It's used to memorize JSON for reuse in later steps. You can "keep" all or a portion of the JSON by giving a name by which to remember it. ```cucumber Feature: User API Scenario: Index action includes full user JSON Given the following user exists: | id | first_name | last_name | | 1 | Steve | Richert | And I visit "/users/1.json" And I keep the JSON response as "USER_1" When I visit "/users.json" Then the JSON response should be: """ [ %{USER_1} ] """ ``` You can memorize JSON at a path: ```cucumber Given I keep the JSON response at "first_name" as "FIRST_NAME" ``` You can remember JSON at a path: ```cucumber Then the JSON response at "0/first_name" should be: """ %{FIRST_NAME} """ ``` You can also remember JSON inline: ```cucumber Then the JSON response at "0/first_name" should be %{FIRST_NAME} ``` ### More Check out the [specs](https://github.com/collectiveidea/json_spec/blob/master/spec) and [features](https://github.com/collectiveidea/json_spec/blob/master/features) to see all the various ways you can use json_spec. ## Contributing If you come across any issues, please [tell us](https://github.com/collectiveidea/json_spec/issues). Pull requests (with tests) are appreciated. No pull request is too small. Please help with: * Reporting bugs * Suggesting features * Writing or improving documentation * Fixing typos * Cleaning whitespace * Refactoring code * Adding tests * Closing [issues](https://github.com/collectiveidea/json_spec/issues) If you report a bug and don't include a fix, please include a failing test. ## Copyright Copyright © 2011 Steve Richert See [LICENSE](https://github.com/collectiveidea/json_spec/blob/master/LICENSE) for details.