Skip to content
This repository
Browse code

Break matchers out into their own files for better organization

  • Loading branch information...
commit 633546e51dbaa1ec35fd1f748b7a19eecb6ed7b8 1 parent 36d08d0
Steve Richert laserlemon authored
2  lib/json_spec.rb
... ... @@ -1,3 +1,5 @@
  1 +require "json"
  2 +require "rspec"
1 3 require "json_spec/version"
2 4 require "json_spec/errors"
3 5 require "json_spec/configuration"
233 lib/json_spec/matchers.rb
... ... @@ -1,234 +1,11 @@
1   -require "json"
2   -require "rspec"
  1 +require "json_spec/matchers/be_json_eql"
  2 +require "json_spec/matchers/include_json"
  3 +require "json_spec/matchers/have_json_path"
  4 +require "json_spec/matchers/have_json_type"
  5 +require "json_spec/matchers/have_json_size"
3 6
4 7 module JsonSpec
5 8 module Matchers
6   - class BeJsonEql
7   - include JsonSpec::Helpers
8   - include JsonSpec::Exclusion
9   -
10   - attr_reader :expected, :actual
11   -
12   - def diffable?
13   - true
14   - end
15   -
16   - def initialize(expected_json = nil)
17   - @expected_json = expected_json
18   - end
19   -
20   - def matches?(actual_json)
21   - raise "Expected equivalent JSON not provided" if @expected_json.nil?
22   -
23   - @actual, @expected = scrub(actual_json, @path), scrub(@expected_json)
24   - @actual == @expected
25   - end
26   -
27   - def at_path(path)
28   - @path = path
29   - self
30   - end
31   -
32   - def to_file(path)
33   - @expected_json = load_json(path)
34   - self
35   - end
36   -
37   - def excluding(*keys)
38   - excluded_keys.merge(keys.map{|k| k.to_s })
39   - self
40   - end
41   -
42   - def including(*keys)
43   - excluded_keys.subtract(keys.map{|k| k.to_s })
44   - self
45   - end
46   -
47   - def failure_message_for_should
48   - message = "Expected equivalent JSON"
49   - message << %( at path "#{@path}") if @path
50   - message
51   - end
52   -
53   - def failure_message_for_should_not
54   - message = "Expected inequivalent JSON"
55   - message << %( at path "#{@path}") if @path
56   - message
57   - end
58   -
59   - def description
60   - message = "equal JSON"
61   - message << %( at path "#{@path}") if @path
62   - message
63   - end
64   -
65   - private
66   - def scrub(json, path = nil)
67   - generate_normalized_json(exclude_keys(parse_json(json, path))).chomp + "\n"
68   - end
69   - end
70   -
71   - class IncludeJson
72   - include JsonSpec::Helpers
73   - include JsonSpec::Exclusion
74   -
75   - def initialize(expected_json = nil)
76   - @expected_json = expected_json
77   - end
78   -
79   - def matches?(actual_json)
80   - raise "Expected included JSON not provided" if @expected_json.nil?
81   -
82   - actual = parse_json(actual_json, @path)
83   - expected = exclude_keys(parse_json(@expected_json))
84   - case actual
85   - when Hash then actual.values.map{|v| exclude_keys(v) }.include?(expected)
86   - when Array then actual.map{|e| exclude_keys(e) }.include?(expected)
87   - else false
88   - end
89   - end
90   -
91   - def at_path(path)
92   - @path = path
93   - self
94   - end
95   -
96   - def from_file(path)
97   - @expected_json = load_json(path)
98   - self
99   - end
100   -
101   - def excluding(*keys)
102   - excluded_keys.merge(keys.map{|k| k.to_s })
103   - self
104   - end
105   -
106   - def including(*keys)
107   - excluded_keys.subtract(keys.map{|k| k.to_s })
108   - self
109   - end
110   -
111   - def failure_message_for_should
112   - message = "Expected included JSON"
113   - message << %( at path "#{@path}") if @path
114   - message
115   - end
116   -
117   - def failure_message_for_should_not
118   - message = "Expected excluded JSON"
119   - message << %( at path "#{@path}") if @path
120   - message
121   - end
122   -
123   - def description
124   - message = "include JSON"
125   - message << %( at path "#{@path}") if @path
126   - message
127   - end
128   - end
129   -
130   - class HaveJsonPath
131   - include JsonSpec::Helpers
132   -
133   - def initialize(path)
134   - @path = path
135   - end
136   -
137   - def matches?(json)
138   - begin
139   - parse_json(json, @path)
140   - true
141   - rescue JsonSpec::MissingPathError
142   - false
143   - end
144   - end
145   -
146   - def failure_message_for_should
147   - %(Expected JSON path "#{@path}")
148   - end
149   -
150   - def failure_message_for_should_not
151   - %(Expected no JSON path "#{@path}")
152   - end
153   -
154   - def description
155   - %(have JSON path "#{@path}")
156   - end
157   - end
158   -
159   - class HaveJsonType
160   - include JsonSpec::Helpers
161   -
162   - def initialize(klass)
163   - @klass = klass
164   - end
165   -
166   - def matches?(json)
167   - @ruby = parse_json(json, @path)
168   - @ruby.is_a?(@klass)
169   - end
170   -
171   - def at_path(path)
172   - @path = path
173   - self
174   - end
175   -
176   - def failure_message_for_should
177   - message = "Expected JSON value type to be #{@klass}, got #{@ruby.class}"
178   - message << %( at path "#{@path}") if @path
179   - message
180   - end
181   -
182   - def failure_message_for_should_not
183   - message = "Expected JSON value type to not be #{@klass}, got #{@ruby.class}"
184   - message << %( at path "#{@path}") if @path
185   - message
186   - end
187   -
188   - def description
189   - message = %(have JSON type "#{@klass.to_s}")
190   - message << %( at path "#{@path}") if @path
191   - message
192   - end
193   - end
194   -
195   - class HaveJsonSize
196   - include JsonSpec::Helpers
197   -
198   - def initialize(size)
199   - @expected = size
200   - end
201   -
202   - def matches?(json)
203   - ruby = parse_json(json, @path)
204   - @actual = ruby.is_a?(Enumerable) ? ruby.size : 1
205   - @actual == @expected
206   - end
207   -
208   - def at_path(path)
209   - @path = path
210   - self
211   - end
212   -
213   - def failure_message_for_should
214   - message = "Expected JSON value size to be #{@expected}, got #{@actual}"
215   - message << %( at path "#{@path}") if @path
216   - message
217   - end
218   -
219   - def failure_message_for_should_not
220   - message = "Expected JSON value size to not be #{@expected}, got #{@actual}"
221   - message << %( at path "#{@path}") if @path
222   - message
223   - end
224   -
225   - def description
226   - message = %(have JSON size "#{@expected}")
227   - message << %( at path "#{@path}") if @path
228   - message
229   - end
230   - end
231   -
232 9 def be_json_eql(json = nil)
233 10 JsonSpec::Matchers::BeJsonEql.new(json)
234 11 end
68 lib/json_spec/matchers/be_json_eql.rb
... ... @@ -0,0 +1,68 @@
  1 +module JsonSpec
  2 + module Matchers
  3 + class BeJsonEql
  4 + include JsonSpec::Helpers
  5 + include JsonSpec::Exclusion
  6 +
  7 + attr_reader :expected, :actual
  8 +
  9 + def diffable?
  10 + true
  11 + end
  12 +
  13 + def initialize(expected_json = nil)
  14 + @expected_json = expected_json
  15 + end
  16 +
  17 + def matches?(actual_json)
  18 + raise "Expected equivalent JSON not provided" if @expected_json.nil?
  19 +
  20 + @actual, @expected = scrub(actual_json, @path), scrub(@expected_json)
  21 + @actual == @expected
  22 + end
  23 +
  24 + def at_path(path)
  25 + @path = path
  26 + self
  27 + end
  28 +
  29 + def to_file(path)
  30 + @expected_json = load_json(path)
  31 + self
  32 + end
  33 +
  34 + def excluding(*keys)
  35 + excluded_keys.merge(keys.map{|k| k.to_s })
  36 + self
  37 + end
  38 +
  39 + def including(*keys)
  40 + excluded_keys.subtract(keys.map{|k| k.to_s })
  41 + self
  42 + end
  43 +
  44 + def failure_message_for_should
  45 + message = "Expected equivalent JSON"
  46 + message << %( at path "#{@path}") if @path
  47 + message
  48 + end
  49 +
  50 + def failure_message_for_should_not
  51 + message = "Expected inequivalent JSON"
  52 + message << %( at path "#{@path}") if @path
  53 + message
  54 + end
  55 +
  56 + def description
  57 + message = "equal JSON"
  58 + message << %( at path "#{@path}") if @path
  59 + message
  60 + end
  61 +
  62 + private
  63 + def scrub(json, path = nil)
  64 + generate_normalized_json(exclude_keys(parse_json(json, path))).chomp + "\n"
  65 + end
  66 + end
  67 + end
  68 +end
32 lib/json_spec/matchers/have_json_path.rb
... ... @@ -0,0 +1,32 @@
  1 +module JsonSpec
  2 + module Matchers
  3 + class HaveJsonPath
  4 + include JsonSpec::Helpers
  5 +
  6 + def initialize(path)
  7 + @path = path
  8 + end
  9 +
  10 + def matches?(json)
  11 + begin
  12 + parse_json(json, @path)
  13 + true
  14 + rescue JsonSpec::MissingPathError
  15 + false
  16 + end
  17 + end
  18 +
  19 + def failure_message_for_should
  20 + %(Expected JSON path "#{@path}")
  21 + end
  22 +
  23 + def failure_message_for_should_not
  24 + %(Expected no JSON path "#{@path}")
  25 + end
  26 +
  27 + def description
  28 + %(have JSON path "#{@path}")
  29 + end
  30 + end
  31 + end
  32 +end
40 lib/json_spec/matchers/have_json_size.rb
... ... @@ -0,0 +1,40 @@
  1 +module JsonSpec
  2 + module Matchers
  3 + class HaveJsonSize
  4 + include JsonSpec::Helpers
  5 +
  6 + def initialize(size)
  7 + @expected = size
  8 + end
  9 +
  10 + def matches?(json)
  11 + ruby = parse_json(json, @path)
  12 + @actual = ruby.is_a?(Enumerable) ? ruby.size : 1
  13 + @actual == @expected
  14 + end
  15 +
  16 + def at_path(path)
  17 + @path = path
  18 + self
  19 + end
  20 +
  21 + def failure_message_for_should
  22 + message = "Expected JSON value size to be #{@expected}, got #{@actual}"
  23 + message << %( at path "#{@path}") if @path
  24 + message
  25 + end
  26 +
  27 + def failure_message_for_should_not
  28 + message = "Expected JSON value size to not be #{@expected}, got #{@actual}"
  29 + message << %( at path "#{@path}") if @path
  30 + message
  31 + end
  32 +
  33 + def description
  34 + message = %(have JSON size "#{@expected}")
  35 + message << %( at path "#{@path}") if @path
  36 + message
  37 + end
  38 + end
  39 + end
  40 +end
39 lib/json_spec/matchers/have_json_type.rb
... ... @@ -0,0 +1,39 @@
  1 +module JsonSpec
  2 + module Matchers
  3 + class HaveJsonType
  4 + include JsonSpec::Helpers
  5 +
  6 + def initialize(klass)
  7 + @klass = klass
  8 + end
  9 +
  10 + def matches?(json)
  11 + @ruby = parse_json(json, @path)
  12 + @ruby.is_a?(@klass)
  13 + end
  14 +
  15 + def at_path(path)
  16 + @path = path
  17 + self
  18 + end
  19 +
  20 + def failure_message_for_should
  21 + message = "Expected JSON value type to be #{@klass}, got #{@ruby.class}"
  22 + message << %( at path "#{@path}") if @path
  23 + message
  24 + end
  25 +
  26 + def failure_message_for_should_not
  27 + message = "Expected JSON value type to not be #{@klass}, got #{@ruby.class}"
  28 + message << %( at path "#{@path}") if @path
  29 + message
  30 + end
  31 +
  32 + def description
  33 + message = %(have JSON type "#{@klass.to_s}")
  34 + message << %( at path "#{@path}") if @path
  35 + message
  36 + end
  37 + end
  38 + end
  39 +end
62 lib/json_spec/matchers/include_json.rb
... ... @@ -0,0 +1,62 @@
  1 +module JsonSpec
  2 + module Matchers
  3 + class IncludeJson
  4 + include JsonSpec::Helpers
  5 + include JsonSpec::Exclusion
  6 +
  7 + def initialize(expected_json = nil)
  8 + @expected_json = expected_json
  9 + end
  10 +
  11 + def matches?(actual_json)
  12 + raise "Expected included JSON not provided" if @expected_json.nil?
  13 +
  14 + actual = parse_json(actual_json, @path)
  15 + expected = exclude_keys(parse_json(@expected_json))
  16 + case actual
  17 + when Hash then actual.values.map{|v| exclude_keys(v) }.include?(expected)
  18 + when Array then actual.map{|e| exclude_keys(e) }.include?(expected)
  19 + else false
  20 + end
  21 + end
  22 +
  23 + def at_path(path)
  24 + @path = path
  25 + self
  26 + end
  27 +
  28 + def from_file(path)
  29 + @expected_json = load_json(path)
  30 + self
  31 + end
  32 +
  33 + def excluding(*keys)
  34 + excluded_keys.merge(keys.map{|k| k.to_s })
  35 + self
  36 + end
  37 +
  38 + def including(*keys)
  39 + excluded_keys.subtract(keys.map{|k| k.to_s })
  40 + self
  41 + end
  42 +
  43 + def failure_message_for_should
  44 + message = "Expected included JSON"
  45 + message << %( at path "#{@path}") if @path
  46 + message
  47 + end
  48 +
  49 + def failure_message_for_should_not
  50 + message = "Expected excluded JSON"
  51 + message << %( at path "#{@path}") if @path
  52 + message
  53 + end
  54 +
  55 + def description
  56 + message = "include JSON"
  57 + message << %( at path "#{@path}") if @path
  58 + message
  59 + end
  60 + end
  61 + end
  62 +end
109 spec/json_spec/matchers/be_json_eql_spec.rb
... ... @@ -0,0 +1,109 @@
  1 +require "spec_helper"
  2 +
  3 +describe JsonSpec::Matchers::BeJsonEql do
  4 + it "matches identical JSON" do
  5 + %({"json":"spec"}).should be_json_eql(%({"json":"spec"}))
  6 + end
  7 +
  8 + it "matches differently-formatted JSON" do
  9 + %({"json": "spec"}).should be_json_eql(%({"json":"spec"}))
  10 + end
  11 +
  12 + it "matches out-of-order hashes" do
  13 + %({"laser":"lemon","json":"spec"}).should be_json_eql(%({"json":"spec","laser":"lemon"}))
  14 + end
  15 +
  16 + it "doesn't match out-of-order arrays" do
  17 + %(["json","spec"]).should_not be_json_eql(%(["spec","json"]))
  18 + end
  19 +
  20 + it "matches valid JSON values, yet invalid JSON documents" do
  21 + %("json_spec").should be_json_eql(%("json_spec"))
  22 + end
  23 +
  24 + it "matches at a path" do
  25 + %({"json":["spec"]}).should be_json_eql(%("spec")).at_path("json/0")
  26 + end
  27 +
  28 + it "ignores excluded-by-default hash keys" do
  29 + JsonSpec.excluded_keys.should_not be_empty
  30 +
  31 + actual = expected = {"json" => "spec"}
  32 + JsonSpec.excluded_keys.each{|k| actual[k] = k }
  33 + actual.to_json.should be_json_eql(expected.to_json)
  34 + end
  35 +
  36 + it "ignores custom excluded hash keys" do
  37 + JsonSpec.exclude_keys("ignore")
  38 + %({"json":"spec","ignore":"please"}).should be_json_eql(%({"json":"spec"}))
  39 + end
  40 +
  41 + it "ignores nested, excluded hash keys" do
  42 + JsonSpec.exclude_keys("ignore")
  43 + %({"json":"spec","please":{"ignore":"this"}}).should be_json_eql(%({"json":"spec","please":{}}))
  44 + end
  45 +
  46 + it "ignores hash keys when included in the expected value" do
  47 + JsonSpec.exclude_keys("ignore")
  48 + %({"json":"spec","ignore":"please"}).should be_json_eql(%({"json":"spec","ignore":"this"}))
  49 + end
  50 +
  51 + it "doesn't match Ruby-equivalent, JSON-inequivalent values" do
  52 + %({"one":1}).should_not be_json_eql(%({"one":1.0}))
  53 + end
  54 +
  55 + it "matches different looking, JSON-equivalent values" do
  56 + %({"ten":10.0}).should be_json_eql(%({"ten":1e+1}))
  57 + end
  58 +
  59 + it "excludes extra hash keys per matcher" do
  60 + JsonSpec.excluded_keys = %w(ignore)
  61 + %({"id":1,"json":"spec","ignore":"please"}).should be_json_eql(%({"id":2,"json":"spec","ignore":"this"})).excluding("id")
  62 + end
  63 +
  64 + it "excludes extra hash keys given as symbols" do
  65 + JsonSpec.excluded_keys = []
  66 + %({"id":1,"json":"spec"}).should be_json_eql(%({"id":2,"json":"spec"})).excluding(:id)
  67 + end
  68 +
  69 + it "excludes multiple keys" do
  70 + JsonSpec.excluded_keys = []
  71 + %({"id":1,"json":"spec"}).should be_json_eql(%({"id":2,"json":"different"})).excluding(:id, :json)
  72 + end
  73 +
  74 + it "includes globally-excluded hash keys per matcher" do
  75 + JsonSpec.excluded_keys = %w(id ignore)
  76 + %({"id":1,"json":"spec","ignore":"please"}).should_not be_json_eql(%({"id":2,"json":"spec","ignore":"this"})).including("id")
  77 + end
  78 +
  79 + it "includes globally-included hash keys given as symbols" do
  80 + JsonSpec.excluded_keys = %w(id)
  81 + %({"id":1,"json":"spec"}).should_not be_json_eql(%({"id":2,"json":"spec"})).including(:id)
  82 + end
  83 +
  84 + it "includes multiple keys" do
  85 + JsonSpec.excluded_keys = %w(id json)
  86 + %({"id":1,"json":"spec"}).should_not be_json_eql(%({"id":2,"json":"different"})).including(:id, :json)
  87 + end
  88 +
  89 + it "provide a description message" do
  90 + matcher = be_json_eql(%({"id":2,"json":"spec"}))
  91 + matcher.matches?(%({"id":1,"json":"spec"}))
  92 + matcher.description.should == "equal JSON"
  93 + end
  94 +
  95 + it "provide a description message with path" do
  96 + matcher = be_json_eql(%({"id":1,"json":["spec"]})).at_path("json/0")
  97 + matcher.matches?(%({"id":1,"json":["spec"]}))
  98 + matcher.description.should == %(equal JSON at path "json/0")
  99 + end
  100 +
  101 + it "raises an error when not given expected JSON" do
  102 + expect{ %({"id":1,"json":"spec"}).should be_json_eql }.to raise_error
  103 + end
  104 +
  105 + it "matches file contents" do
  106 + JsonSpec.directory = files_path
  107 + %({ "value" : "from_file" }).should be_json_eql.to_file("one.json")
  108 + end
  109 +end
29 spec/json_spec/matchers/have_json_path_spec.rb
... ... @@ -0,0 +1,29 @@
  1 +require "spec_helper"
  2 +
  3 +describe JsonSpec::Matchers::HaveJsonPath do
  4 + it "matches hash keys" do
  5 + %({"one":{"two":{"three":4}}}).should have_json_path("one/two/three")
  6 + end
  7 +
  8 + it "doesn't match values" do
  9 + %({"one":{"two":{"three":4}}}).should_not have_json_path("one/two/three/4")
  10 + end
  11 +
  12 + it "matches array indexes" do
  13 + %([1,[1,2,[1,2,3,4]]]).should have_json_path("1/2/3")
  14 + end
  15 +
  16 + it "respects null array values" do
  17 + %([null,[null,null,[null,null,null,null]]]).should have_json_path("1/2/3")
  18 + end
  19 +
  20 + it "matches hash keys and array indexes" do
  21 + %({"one":[1,2,{"three":4}]}).should have_json_path("one/2/three")
  22 + end
  23 +
  24 + it "provide a description message" do
  25 + matcher = have_json_path("json")
  26 + matcher.matches?(%({"id":1,"json":"spec"}))
  27 + matcher.description.should == %(have JSON path "json")
  28 + end
  29 +end
47 spec/json_spec/matchers/have_json_size_spec.rb
... ... @@ -0,0 +1,47 @@
  1 +require "spec_helper"
  2 +
  3 +describe JsonSpec::Matchers::HaveJsonSize do
  4 + it "counts array entries" do
  5 + %([1,2,3]).should have_json_size(3)
  6 + end
  7 +
  8 + it "counts null array entries" do
  9 + %([1,null,3]).should have_json_size(3)
  10 + end
  11 +
  12 + it "counts hash key/value pairs" do
  13 + %({"one":1,"two":2,"three":3}).should have_json_size(3)
  14 + end
  15 +
  16 + it "counts null hash values" do
  17 + %({"one":1,"two":null,"three":3}).should have_json_size(3)
  18 + end
  19 +
  20 + it "matches at a path" do
  21 + %({"one":[1,2,3]}).should have_json_size(3).at_path("one")
  22 + end
  23 +
  24 + it "provides a failure message for should" do
  25 + matcher = have_json_size(3)
  26 + matcher.matches?(%([1,2]))
  27 + matcher.failure_message_for_should.should == "Expected JSON value size to be 3, got 2"
  28 + end
  29 +
  30 + it "provides a failure message for should not" do
  31 + matcher = have_json_size(3)
  32 + matcher.matches?(%([1,2,3]))
  33 + matcher.failure_message_for_should_not.should == "Expected JSON value size to not be 3, got 3"
  34 + end
  35 +
  36 + it "provide a description message" do
  37 + matcher = have_json_size(1)
  38 + matcher.matches?(%({"id":1,"json":["spec"]}))
  39 + matcher.description.should == %(have JSON size "1")
  40 + end
  41 +
  42 + it "provide a description message with path" do
  43 + matcher = have_json_size(1).at_path("json")
  44 + matcher.matches?(%({"id":1,"json":["spec"]}))
  45 + matcher.description.should == %(have JSON size "1" at path "json")
  46 + end
  47 +end
79 spec/json_spec/matchers/have_json_type_spec.rb
... ... @@ -0,0 +1,79 @@
  1 +require "spec_helper"
  2 +
  3 +describe JsonSpec::Matchers::HaveJsonType do
  4 + it "matches hashes" do
  5 + %({}).should have_json_type(Hash)
  6 + end
  7 +
  8 + it "matches arrays" do
  9 + %([]).should have_json_type(Array)
  10 + end
  11 +
  12 + it "matches at a path" do
  13 + %({"root":[]}).should have_json_type(Array).at_path("root")
  14 + end
  15 +
  16 + it "matches strings" do
  17 + %(["json_spec"]).should have_json_type(String).at_path("0")
  18 + end
  19 +
  20 + it "matches a valid JSON value, yet invalid JSON document" do
  21 + %("json_spec").should have_json_type(String)
  22 + end
  23 +
  24 + it "matches empty strings" do
  25 + %("").should have_json_type(String)
  26 + end
  27 +
  28 + it "matches integers" do
  29 + %(10).should have_json_type(Integer)
  30 + end
  31 +
  32 + it "matches floats" do
  33 + %(10.0).should have_json_type(Float)
  34 + %(1e+1).should have_json_type(Float)
  35 + end
  36 +
  37 + it "matches ancestor classes" do
  38 + %(10).should have_json_type(Numeric)
  39 + %(10.0).should have_json_type(Numeric)
  40 + end
  41 +
  42 + it "provides a failure message for should" do
  43 + matcher = have_json_type(Numeric)
  44 + matcher.matches?(%("foo"))
  45 + matcher.failure_message_for_should.should == "Expected JSON value type to be Numeric, got String"
  46 + end
  47 +
  48 + it "provides a failure message for should not" do
  49 + matcher = have_json_type(Numeric)
  50 + matcher.matches?(%(10))
  51 + matcher.failure_message_for_should_not.should == "Expected JSON value type to not be Numeric, got Fixnum"
  52 + end
  53 +
  54 + it "provide a description message" do
  55 + matcher = have_json_type(String)
  56 + matcher.matches?(%({"id":1,"json":"spec"}))
  57 + matcher.description.should == %(have JSON type "String")
  58 + end
  59 +
  60 + it "provide a description message with path" do
  61 + matcher = have_json_type(String).at_path("json")
  62 + matcher.matches?(%({"id":1,"json":"spec"}))
  63 + matcher.description.should == %(have JSON type "String" at path "json")
  64 + end
  65 +
  66 + context "somewhat uselessly" do
  67 + it "matches true" do
  68 + %(true).should have_json_type(TrueClass)
  69 + end
  70 +
  71 + it "matches false" do
  72 + %(false).should have_json_type(FalseClass)
  73 + end
  74 +
  75 + it "matches null" do
  76 + %(null).should have_json_type(NilClass)
  77 + end
  78 + end
  79 +end
76 spec/json_spec/matchers/include_json_spec.rb
... ... @@ -0,0 +1,76 @@
  1 +require "spec_helper"
  2 +
  3 +describe JsonSpec::Matchers::IncludeJson do
  4 + it "matches included array elements" do
  5 + json = %(["one",1,1.0,true,false,null])
  6 + json.should include_json(%("one"))
  7 + json.should include_json(%(1))
  8 + json.should include_json(%(1.0))
  9 + json.should include_json(%(true))
  10 + json.should include_json(%(false))
  11 + json.should include_json(%(null))
  12 + end
  13 +
  14 + it "matches an array included in an array" do
  15 + json = %([[1,2,3],[4,5,6]])
  16 + json.should include_json(%([1,2,3]))
  17 + json.should include_json(%([4,5,6]))
  18 + end
  19 +
  20 + it "matches a hash included in an array" do
  21 + json = %([{"one":1},{"two":2}])
  22 + json.should include_json(%({"one":1}))
  23 + json.should include_json(%({"two":2}))
  24 + end
  25 +
  26 + it "matches include hash values" do
  27 + json = %({"string":"one","integer":1,"float":1.0,"true":true,"false":false,"null":null})
  28 + json.should include_json(%("one"))
  29 + json.should include_json(%(1))
  30 + json.should include_json(%(1.0))
  31 + json.should include_json(%(true))
  32 + json.should include_json(%(false))
  33 + json.should include_json(%(null))
  34 + end
  35 +
  36 + it "matches a hash included in a hash" do
  37 + json = %({"one":{"two":3},"four":{"five":6}})
  38 + json.should include_json(%({"two":3}))
  39 + json.should include_json(%({"five":6}))
  40 + end
  41 +
  42 + it "matches an array included in a hash" do
  43 + json = %({"one":[2,3],"four":[5,6]})
  44 + json.should include_json(%([2,3]))
  45 + json.should include_json(%([5,6]))
  46 + end
  47 +
  48 + it "matches at a path" do
  49 + %({"one":{"two":[3,4]}}).should include_json(%([3,4])).at_path("one")
  50 + end
  51 +
  52 + it "ignores excluded keys" do
  53 + %([{"id":1,"two":3}]).should include_json(%({"two":3}))
  54 + end
  55 +
  56 + it "provide a description message" do
  57 + matcher = include_json(%({"json":"spec"}))
  58 + matcher.matches?(%({"id":1,"json":"spec"}))
  59 + matcher.description.should == "include JSON"
  60 + end
  61 +
  62 + it "provide a description message with path" do
  63 + matcher = include_json(%("spec")).at_path("json/0")
  64 + matcher.matches?(%({"id":1,"json":["spec"]}))
  65 + matcher.description.should == %(include JSON at path "json/0")
  66 + end
  67 +
  68 + it "raises an error when not given expected JSON" do
  69 + expect{ %([{"id":1,"two":3}]).should include_json }.to raise_error
  70 + end
  71 +
  72 + it "matches file contents" do
  73 + JsonSpec.directory = files_path
  74 + %({"one":{"value":"from_file"},"four":{"five":6}}).should include_json.from_file("one.json")
  75 + end
  76 +end
348 spec/json_spec/matchers_spec.rb
... ... @@ -1,339 +1,77 @@
1 1 require "spec_helper"
2 2
3   -describe "Matchers:" do
4   - context "be_json_eql" do
5   - it "matches identical JSON" do
6   - %({"json":"spec"}).should be_json_eql(%({"json":"spec"}))
7   - end
8   -
9   - it "matches differently-formatted JSON" do
10   - %({"json": "spec"}).should be_json_eql(%({"json":"spec"}))
11   - end
12   -
13   - it "matches out-of-order hashes" do
14   - %({"laser":"lemon","json":"spec"}).should be_json_eql(%({"json":"spec","laser":"lemon"}))
15   - end
16   -
17   - it "doesn't match out-of-order arrays" do
18   - %(["json","spec"]).should_not be_json_eql(%(["spec","json"]))
19   - end
20   -
21   - it "matches valid JSON values, yet invalid JSON documents" do
22   - %("json_spec").should be_json_eql(%("json_spec"))
23   - end
24   -
25   - it "matches at a path" do
26   - %({"json":["spec"]}).should be_json_eql(%("spec")).at_path("json/0")
27   - end
28   -
29   - it "ignores excluded-by-default hash keys" do
30   - JsonSpec.excluded_keys.should_not be_empty
31   -
32   - actual = expected = {"json" => "spec"}
33   - JsonSpec.excluded_keys.each{|k| actual[k] = k }
34   - actual.to_json.should be_json_eql(expected.to_json)
35   - end
36   -
37   - it "ignores custom excluded hash keys" do
38   - JsonSpec.exclude_keys("ignore")
39   - %({"json":"spec","ignore":"please"}).should be_json_eql(%({"json":"spec"}))
40   - end
41   -
42   - it "ignores nested, excluded hash keys" do
43   - JsonSpec.exclude_keys("ignore")
44   - %({"json":"spec","please":{"ignore":"this"}}).should be_json_eql(%({"json":"spec","please":{}}))
45   - end
46   -
47   - it "ignores hash keys when included in the expected value" do
48   - JsonSpec.exclude_keys("ignore")
49   - %({"json":"spec","ignore":"please"}).should be_json_eql(%({"json":"spec","ignore":"this"}))
50   - end
51   -
52   - it "doesn't match Ruby-equivalent, JSON-inequivalent values" do
53   - %({"one":1}).should_not be_json_eql(%({"one":1.0}))
54   - end
55   -
56   - it "matches different looking, JSON-equivalent values" do
57   - %({"ten":10.0}).should be_json_eql(%({"ten":1e+1}))
58   - end
59   -
60   - it "excludes extra hash keys per matcher" do
61   - JsonSpec.excluded_keys = %w(ignore)
62   - %({"id":1,"json":"spec","ignore":"please"}).should be_json_eql(%({"id":2,"json":"spec","ignore":"this"})).excluding("id")
63   - end
64   -
65   - it "excludes extra hash keys given as symbols" do
66   - JsonSpec.excluded_keys = []
67   - %({"id":1,"json":"spec"}).should be_json_eql(%({"id":2,"json":"spec"})).excluding(:id)
68   - end
69   -
70   - it "excludes multiple keys" do
71   - JsonSpec.excluded_keys = []
72   - %({"id":1,"json":"spec"}).should be_json_eql(%({"id":2,"json":"different"})).excluding(:id, :json)
73   - end
74   -
75   - it "includes globally-excluded hash keys per matcher" do
76   - JsonSpec.excluded_keys = %w(id ignore)
77   - %({"id":1,"json":"spec","ignore":"please"}).should_not be_json_eql(%({"id":2,"json":"spec","ignore":"this"})).including("id")
78   - end
79   -
80   - it "includes globally-included hash keys given as symbols" do
81   - JsonSpec.excluded_keys = %w(id)
82   - %({"id":1,"json":"spec"}).should_not be_json_eql(%({"id":2,"json":"spec"})).including(:id)
83   - end
84   -
85   - it "includes multiple keys" do
86   - JsonSpec.excluded_keys = %w(id json)
87   - %({"id":1,"json":"spec"}).should_not be_json_eql(%({"id":2,"json":"different"})).including(:id, :json)
88   - end
89   -
90   - it "provide a description message" do
91   - matcher = be_json_eql(%({"id":2,"json":"spec"}))
92   - matcher.matches?(%({"id":1,"json":"spec"}))
93   - matcher.description.should == "equal JSON"
94   - end
95   -
96   - it "provide a description message with path" do
97   - matcher = be_json_eql(%({"id":1,"json":["spec"]})).at_path("json/0")
98   - matcher.matches?(%({"id":1,"json":["spec"]}))
99   - matcher.description.should == %(equal JSON at path "json/0")
100   - end
101   -
102   - it "raises an error when not given expected JSON" do
103   - expect{ %({"id":1,"json":"spec"}).should be_json_eql }.to raise_error
104   - end
105   -
106   - it "matches file contents" do
107   - JsonSpec.directory = files_path
108   - %({ "value" : "from_file" }).should be_json_eql.to_file("one.json")
109   - end
  3 +describe JsonSpec::Matchers do
  4 + let(:environment) do
  5 + klass = Class.new
  6 + klass.send(:include, JsonSpec::Matchers)
  7 + klass.new
110 8 end
111 9
112   - context "include_json" do
113   - it "matches included array elements" do
114   - json = %(["one",1,1.0,true,false,null])
115   - json.should include_json(%("one"))
116   - json.should include_json(%(1))
117   - json.should include_json(%(1.0))
118   - json.should include_json(%(true))
119   - json.should include_json(%(false))
120   - json.should include_json(%(null))
121   - end
122   -
123   - it "matches an array included in an array" do
124   - json = %([[1,2,3],[4,5,6]])
125   - json.should include_json(%([1,2,3]))
126   - json.should include_json(%([4,5,6]))
127   - end
128   -
129   - it "matches a hash included in an array" do
130   - json = %([{"one":1},{"two":2}])
131   - json.should include_json(%({"one":1}))
132   - json.should include_json(%({"two":2}))
133   - end
134   -
135   - it "matches include hash values" do
136   - json = %({"string":"one","integer":1,"float":1.0,"true":true,"false":false,"null":null})
137   - json.should include_json(%("one"))
138   - json.should include_json(%(1))
139   - json.should include_json(%(1.0))
140   - json.should include_json(%(true))
141   - json.should include_json(%(false))
142   - json.should include_json(%(null))
143   - end
144   -
145   - it "matches a hash included in a hash" do
146   - json = %({"one":{"two":3},"four":{"five":6}})
147   - json.should include_json(%({"two":3}))
148   - json.should include_json(%({"five":6}))
149   - end
150   -
151   - it "matches an array included in a hash" do
152   - json = %({"one":[2,3],"four":[5,6]})
153   - json.should include_json(%([2,3]))
154   - json.should include_json(%([5,6]))
155   - end
156   -
157   - it "matches at a path" do
158   - %({"one":{"two":[3,4]}}).should include_json(%([3,4])).at_path("one")
159   - end
160   -
161   - it "ignores excluded keys" do
162   - %([{"id":1,"two":3}]).should include_json(%({"two":3}))
163   - end
164   -
165   - it "provide a description message" do
166   - matcher = include_json(%({"json":"spec"}))
167   - matcher.matches?(%({"id":1,"json":"spec"}))
168   - matcher.description.should == "include JSON"
169   - end
  10 + let(:json){ %({"json":"spec"}) }
170 11
171   - it "provide a description message with path" do
172   - matcher = include_json(%("spec")).at_path("json/0")
173   - matcher.matches?(%({"id":1,"json":["spec"]}))
174   - matcher.description.should == %(include JSON at path "json/0")
175   - end
176   -
177   - it "raises an error when not given expected JSON" do
178   - expect{ %([{"id":1,"two":3}]).should include_json }.to raise_error
  12 + context "be_json_eql" do
  13 + it "instantiates its matcher" do
  14 + JsonSpec::Matchers::BeJsonEql.should_receive(:new).with(json)
  15 + environment.be_json_eql(json)
179 16 end
180 17
181   - it "matches file contents" do
182   - JsonSpec.directory = files_path
183   - %({"one":{"value":"from_file"},"four":{"five":6}}).should include_json.from_file("one.json")
  18 + it "returns its matcher" do
  19 + matcher = environment.be_json_eql(json)
  20 + matcher.should be_a(JsonSpec::Matchers::BeJsonEql)
184 21 end
185 22 end
186 23
187   - context "have_json_size" do
188   - it "counts array entries" do
189   - %([1,2,3]).should have_json_size(3)
190   - end
191   -
192   - it "counts null array entries" do
193   - %([1,null,3]).should have_json_size(3)
194   - end
195   -
196   - it "counts hash key/value pairs" do
197   - %({"one":1,"two":2,"three":3}).should have_json_size(3)
198   - end
199   -
200   - it "counts null hash values" do
201   - %({"one":1,"two":null,"three":3}).should have_json_size(3)
202   - end
203   -
204   - it "matches at a path" do
205   - %({"one":[1,2,3]}).should have_json_size(3).at_path("one")
206   - end
207   -
208   - it "provides a failure message for should" do
209   - matcher = have_json_size(3)
210   - matcher.matches?(%([1,2]))
211   - matcher.failure_message_for_should.should == "Expected JSON value size to be 3, got 2"
212   - end
213   -
214   - it "provides a failure message for should not" do
215   - matcher = have_json_size(3)
216   - matcher.matches?(%([1,2,3]))
217   - matcher.failure_message_for_should_not.should == "Expected JSON value size to not be 3, got 3"
218   - end
219   -
220   - it "provide a description message" do
221   - matcher = have_json_size(1)
222   - matcher.matches?(%({"id":1,"json":["spec"]}))
223   - matcher.description.should == %(have JSON size "1")
  24 + context "include_json" do
  25 + it "instantiates its matcher" do
  26 + JsonSpec::Matchers::IncludeJson.should_receive(:new).with(json)
  27 + environment.include_json(json)
224 28 end
225 29
226   - it "provide a description message with path" do
227   - matcher = have_json_size(1).at_path("json")
228   - matcher.matches?(%({"id":1,"json":["spec"]}))
229   - matcher.description.should == %(have JSON size "1" at path "json")
  30 + it "returns its matcher" do
  31 + matcher = environment.include_json(json)
  32 + matcher.should be_a(JsonSpec::Matchers::IncludeJson)
230 33 end
231 34 end
232 35
233 36 context "have_json_path" do
234   - it "matches hash keys" do
235   - %({"one":{"two":{"three":4}}}).should have_json_path("one/two/three")
236   - end
237   -
238   - it "doesn't match values" do
239   - %({"one":{"two":{"three":4}}}).should_not have_json_path("one/two/three/4")
240   - end
241   -
242   - it "matches array indexes" do
243   - %([1,[1,2,[1,2,3,4]]]).should have_json_path("1/2/3")
244   - end
  37 + let(:path){ "json" }
245 38
246   - it "respects null array values" do
247   - %([null,[null,null,[null,null,null,null]]]).should have_json_path("1/2/3")
  39 + it "instantiates its matcher" do
  40 + JsonSpec::Matchers::HaveJsonPath.should_receive(:new).with(path)
  41 + environment.have_json_path(path)
248 42 end
249 43
250   - it "matches hash keys and array indexes" do
251   - %({"one":[1,2,{"three":4}]}).should have_json_path("one/2/three")
  44 + it "returns its matcher" do
  45 + matcher = environment.have_json_path(path)
  46 + matcher.should be_a(JsonSpec::Matchers::HaveJsonPath)
252 47 end
253   -
254   - it "provide a description message" do
255   - matcher = have_json_path("json")
256   - matcher.matches?(%({"id":1,"json":"spec"}))
257   - matcher.description.should == %(have JSON path "json")
258   - end
259   -
260 48 end
261 49
262 50 context "have_json_type" do
263   - it "matches hashes" do
264   - %({}).should have_json_type(Hash)
265   - end
266   -
267   - it "matches arrays" do
268