From d06df02d8171fe44889ebae840ca2cdac42d1547 Mon Sep 17 00:00:00 2001 From: Andy Rusterholz Date: Thu, 23 Oct 2014 19:00:20 -0600 Subject: [PATCH 1/2] Added .order_indifferent to enable matching out-of-order arrays when desired --- lib/json_spec.rb | 1 + lib/json_spec/indifference.rb | 25 +++++++++++++++++++++ lib/json_spec/matchers/be_json_eql.rb | 8 ++++++- spec/json_spec/matchers/be_json_eql_spec.rb | 21 +++++++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 lib/json_spec/indifference.rb diff --git a/lib/json_spec.rb b/lib/json_spec.rb index 8044741..d0b2e76 100644 --- a/lib/json_spec.rb +++ b/lib/json_spec.rb @@ -5,6 +5,7 @@ require "json_spec/exclusion" require "json_spec/helpers" require "json_spec/messages" +require "json_spec/indifference" require "json_spec/matchers" require "json_spec/memory" diff --git a/lib/json_spec/indifference.rb b/lib/json_spec/indifference.rb new file mode 100644 index 0000000..81fbc72 --- /dev/null +++ b/lib/json_spec/indifference.rb @@ -0,0 +1,25 @@ +module JsonSpec + module Indifference + extend self + + def toggle_indifference( toggle ) + @indifferent = !!toggle + end + + def indifferize(ruby) + return ruby unless @indifferent + + case ruby + when Hash + ruby.sort.inject({}) do |hash, (key, value)| + hash[key] = indifferize(value) + hash + end + when Array + ruby.map{|v| indifferize(v) }.sort_by{|v| generate_normalized_json(v) } + else ruby + end + end + + end +end diff --git a/lib/json_spec/matchers/be_json_eql.rb b/lib/json_spec/matchers/be_json_eql.rb index 951dc5a..ec583ce 100644 --- a/lib/json_spec/matchers/be_json_eql.rb +++ b/lib/json_spec/matchers/be_json_eql.rb @@ -3,6 +3,7 @@ module Matchers class BeJsonEql include JsonSpec::Helpers include JsonSpec::Exclusion + include JsonSpec::Indifference include JsonSpec::Messages attr_reader :expected, :actual @@ -42,6 +43,11 @@ def including(*keys) self end + def order_indifferent(state = true) + toggle_indifference(state) + self + end + def failure_message message_with_path("Expected equivalent JSON") end @@ -58,7 +64,7 @@ def description private def scrub(json, path = nil) - generate_normalized_json(exclude_keys(parse_json(json, path))).chomp + "\n" + generate_normalized_json(indifferize(exclude_keys(parse_json(json, path)))).chomp + "\n" end end end diff --git a/spec/json_spec/matchers/be_json_eql_spec.rb b/spec/json_spec/matchers/be_json_eql_spec.rb index 7eb8e1a..9e1c3f5 100644 --- a/spec/json_spec/matchers/be_json_eql_spec.rb +++ b/spec/json_spec/matchers/be_json_eql_spec.rb @@ -17,6 +17,18 @@ %(["json","spec"]).should_not be_json_eql(%(["spec","json"])) end + it "matches out-of-order arrays when chained with order_indifferent" do + %(["json","spec"]).should be_json_eql(%(["spec","json"])).order_indifferent + end + + it "doesn't match out-of-order arrays when chained with order_indifferent if passed false" do + %(["json","spec"]).should_not be_json_eql(%(["spec","json"])).order_indifferent(false) + end + + it "matches complex nested out-of-order arrays when chained with order_indifferent" do + %({"json":[{"spec":4,"laser":[{"id":2,"lemon":"a"},{"id":5,"lemon":"b"}]},{"spec":9,"laser":[{"id":3,"lemon":"c"},{"id":1,"lemon":"d"}]}]}).should be_json_eql(%({"json":[{"laser":[{"lemon":"d","id":1},{"lemon":"c","id":3}],"spec":9},{"laser":[{"lemon":"b","id":5},{"lemon":"a","id":2}],"spec":4}]})).order_indifferent + end + it "matches valid JSON values, yet invalid JSON documents" do %("json_spec").should be_json_eql(%("json_spec")) end @@ -25,6 +37,10 @@ %({"json":["spec"]}).should be_json_eql(%("spec")).at_path("json/0") end + it "matches out-of-order arrays at a path when chained with order_indifferent" do + %({"json":[{"spec":[4,2,3,1,5]}]}).should be_json_eql(%([1,2,3,4,5])).at_path("json/0/spec").order_indifferent + end + it "ignores excluded-by-default hash keys" do JsonSpec.excluded_keys.should_not be_empty @@ -66,6 +82,11 @@ %({"id":1,"json":"spec"}).should be_json_eql(%({"id":2,"json":"spec"})).excluding(:id) end + it "excludes extra hash keys given as symbols and matches out-of-order arrays when chained with order_indifferent" do + JsonSpec.excluded_keys = [] + %([{"id":1,"json":"spec"},{"id":4,"json":"laser"}]).should be_json_eql(%([{"id":3,"json":"laser"},{"id":2,"json":"spec"}])).excluding(:id).order_indifferent + end + it "excludes multiple keys" do JsonSpec.excluded_keys = [] %({"id":1,"json":"spec"}).should be_json_eql(%({"id":2,"json":"different"})).excluding(:id, :json) From 5fc70aa6b973d22cc724848f9d9c352b581c57c8 Mon Sep 17 00:00:00 2001 From: Andy Rusterholz Date: Sat, 7 Mar 2015 17:59:55 -0700 Subject: [PATCH 2/2] Feedback from PR --- lib/json_spec.rb | 2 +- lib/json_spec/matchers/be_json_eql.rb | 6 ++--- ...{indifference.rb => order_indifference.rb} | 6 ++--- spec/json_spec/matchers/be_json_eql_spec.rb | 24 +++++++++++-------- 4 files changed, 21 insertions(+), 17 deletions(-) rename lib/json_spec/{indifference.rb => order_indifference.rb} (76%) diff --git a/lib/json_spec.rb b/lib/json_spec.rb index d0b2e76..8833e91 100644 --- a/lib/json_spec.rb +++ b/lib/json_spec.rb @@ -5,7 +5,7 @@ require "json_spec/exclusion" require "json_spec/helpers" require "json_spec/messages" -require "json_spec/indifference" +require "json_spec/order_indifference" require "json_spec/matchers" require "json_spec/memory" diff --git a/lib/json_spec/matchers/be_json_eql.rb b/lib/json_spec/matchers/be_json_eql.rb index ec583ce..ba840b1 100644 --- a/lib/json_spec/matchers/be_json_eql.rb +++ b/lib/json_spec/matchers/be_json_eql.rb @@ -3,7 +3,7 @@ module Matchers class BeJsonEql include JsonSpec::Helpers include JsonSpec::Exclusion - include JsonSpec::Indifference + include JsonSpec::OrderIndifference include JsonSpec::Messages attr_reader :expected, :actual @@ -43,8 +43,8 @@ def including(*keys) self end - def order_indifferent(state = true) - toggle_indifference(state) + def in_any_order(state = true) + toggle_order_indifference(state) self end diff --git a/lib/json_spec/indifference.rb b/lib/json_spec/order_indifference.rb similarity index 76% rename from lib/json_spec/indifference.rb rename to lib/json_spec/order_indifference.rb index 81fbc72..14718e4 100644 --- a/lib/json_spec/indifference.rb +++ b/lib/json_spec/order_indifference.rb @@ -1,8 +1,8 @@ module JsonSpec - module Indifference + module OrderIndifference extend self - def toggle_indifference( toggle ) + def toggle_order_indifference(toggle) @indifferent = !!toggle end @@ -11,7 +11,7 @@ def indifferize(ruby) case ruby when Hash - ruby.sort.inject({}) do |hash, (key, value)| + ruby.inject({}) do |hash, (key, value)| hash[key] = indifferize(value) hash end diff --git a/spec/json_spec/matchers/be_json_eql_spec.rb b/spec/json_spec/matchers/be_json_eql_spec.rb index 9e1c3f5..1306d50 100644 --- a/spec/json_spec/matchers/be_json_eql_spec.rb +++ b/spec/json_spec/matchers/be_json_eql_spec.rb @@ -17,16 +17,20 @@ %(["json","spec"]).should_not be_json_eql(%(["spec","json"])) end - it "matches out-of-order arrays when chained with order_indifferent" do - %(["json","spec"]).should be_json_eql(%(["spec","json"])).order_indifferent + it "matches out-of-order arrays when chained with in_any_order" do + %(["json","spec"]).should be_json_eql(%(["spec","json"])).in_any_order end - it "doesn't match out-of-order arrays when chained with order_indifferent if passed false" do - %(["json","spec"]).should_not be_json_eql(%(["spec","json"])).order_indifferent(false) + it "matches out-of-order hashes when chained with in_any_order" do + %({"laser":"lemon","json":"spec"}).should be_json_eql(%({"json":"spec","laser":"lemon"})).in_any_order end - it "matches complex nested out-of-order arrays when chained with order_indifferent" do - %({"json":[{"spec":4,"laser":[{"id":2,"lemon":"a"},{"id":5,"lemon":"b"}]},{"spec":9,"laser":[{"id":3,"lemon":"c"},{"id":1,"lemon":"d"}]}]}).should be_json_eql(%({"json":[{"laser":[{"lemon":"d","id":1},{"lemon":"c","id":3}],"spec":9},{"laser":[{"lemon":"b","id":5},{"lemon":"a","id":2}],"spec":4}]})).order_indifferent + it "doesn't match out-of-order arrays when chained with in_any_order if passed false" do + %(["json","spec"]).should_not be_json_eql(%(["spec","json"])).in_any_order(false) + end + + it "matches complex nested out-of-order arrays when chained with in_any_order" do + %({"json":[{"spec":4,"laser":[{"id":2,"lemon":"a"},{"id":5,"lemon":"b"}]},{"spec":9,"laser":[{"id":3,"lemon":"c"},{"id":1,"lemon":"d"}]}]}).should be_json_eql(%({"json":[{"laser":[{"lemon":"d","id":1},{"lemon":"c","id":3}],"spec":9},{"laser":[{"lemon":"b","id":5},{"lemon":"a","id":2}],"spec":4}]})).in_any_order end it "matches valid JSON values, yet invalid JSON documents" do @@ -37,8 +41,8 @@ %({"json":["spec"]}).should be_json_eql(%("spec")).at_path("json/0") end - it "matches out-of-order arrays at a path when chained with order_indifferent" do - %({"json":[{"spec":[4,2,3,1,5]}]}).should be_json_eql(%([1,2,3,4,5])).at_path("json/0/spec").order_indifferent + it "matches out-of-order arrays at a path when chained with in_any_order" do + %({"json":[{"spec":[4,2,3,1,5]}]}).should be_json_eql(%([1,2,3,4,5])).at_path("json/0/spec").in_any_order end it "ignores excluded-by-default hash keys" do @@ -82,9 +86,9 @@ %({"id":1,"json":"spec"}).should be_json_eql(%({"id":2,"json":"spec"})).excluding(:id) end - it "excludes extra hash keys given as symbols and matches out-of-order arrays when chained with order_indifferent" do + it "excludes extra hash keys given as symbols and matches out-of-order arrays when chained with in_any_order" do JsonSpec.excluded_keys = [] - %([{"id":1,"json":"spec"},{"id":4,"json":"laser"}]).should be_json_eql(%([{"id":3,"json":"laser"},{"id":2,"json":"spec"}])).excluding(:id).order_indifferent + %([{"id":1,"json":"spec"},{"id":4,"json":"laser"}]).should be_json_eql(%([{"id":3,"json":"laser"},{"id":2,"json":"spec"}])).excluding(:id).in_any_order end it "excludes multiple keys" do