restful-matchers 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa23bf113f67c1d2ebcec7749f06a5297fe44ad0
4
- data.tar.gz: 2ef8175345a2c7abc59b4f3cc2a0f00b3bcb9bdd
3
+ metadata.gz: 1ebf655f0413ddd8082f291573ce0072759b5578
4
+ data.tar.gz: 60d70c76fdc3491752fec9639bfc87129b759b04
5
5
  SHA512:
6
- metadata.gz: e694f1dfa908ccdb0292d6f8ffb0c04ce130ee345072c7640ebed3cf2afed1993e2637bd93fb2965c8b93cfd38e76cfd7680684d3ec79c8a6f970db5efb54f4f
7
- data.tar.gz: 23bac76446ef247fdcf053e98d65032bca1245b1d6f21b53b0d2eaaf1742bee9fe41730a4cb3a1c419c752336515642e4f673b33652164eed052d2aac92da999
6
+ metadata.gz: 94c24744350d3810781943ea6e4c6db4029c8fbc82a8fab38ce65d65b31daca232d8fdf0cbf6b039a0b95365b0f9d952a5836ca290bd17063cc15bc3c915fbb2
7
+ data.tar.gz: 73146b6bae167a0443c4cb072220bab85b9b07c39c8a59906ffa9648c70f8d607fd89b8e247a405758d62bdd4e653cc33d9ced3a9702cb2e841bc486892bb7f3
data/CHANGELOG.md ADDED
@@ -0,0 +1,16 @@
1
+ # HEAD
2
+ nothing yet.
3
+
4
+ # v0.3.0
5
+ * New matcher `have_links` to match many links at once.
6
+
7
+ # v0.2.1
8
+ * Show matched content on failure;
9
+
10
+ # v0.2.0
11
+ * Process both raw and parsed (hash) JSON representations;
12
+ * Attribute `href` is now optional;
13
+ * `have_restful_json_link` is an alias for `have_link` matcher (preffered).
14
+
15
+ # v0.1
16
+ * Initial version with `have_restful_json_link` matcher.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- restful-matchers (0.2.1)
4
+ restful-matchers (0.3.0)
5
5
  rspec (~> 2.0)
6
6
 
7
7
  GEM
@@ -26,9 +26,6 @@ GEM
26
26
  diff-lcs (>= 1.1.3, < 2.0)
27
27
  rspec-mocks (2.14.3)
28
28
  slop (3.4.6)
29
- step-up (0.9.1)
30
- thor (>= 0.14.6)
31
- thor (0.18.1)
32
29
 
33
30
  PLATFORMS
34
31
  ruby
@@ -39,4 +36,3 @@ DEPENDENCIES
39
36
  pry-nav (~> 0.2)
40
37
  rake (~> 10.1)
41
38
  restful-matchers!
42
- step-up (~> 0.9)
data/README.md CHANGED
@@ -5,32 +5,47 @@ RSpec matchers to test RESTful HATEOAS-compliant resource links. Currently it su
5
5
 
6
6
  ## Usage
7
7
 
8
- Given the following JSON response:
8
+ Let's say we have a `MyRestfulController#index` controller action that returns the following JSON representation, with links represented as an array of `{rel: ... , href: ...}` objects:
9
9
 
10
10
  ```json
11
11
  {
12
12
  "attribute1": "value1",
13
13
  "attribute2": "value2",
14
14
  "links": [
15
- { "rel": "self", "href": "http://example.com" }
15
+ { "rel": "foo", "href": "http://example.com/foo" }
16
+ { "rel": "bar", "href": "http://example.com/bar" }
17
+ { "rel": "baz", "href": "http://example.com/baz" }
18
+ { "rel": "qux", "href": "http://example.com/qux" }
16
19
  ]
17
20
  }
18
21
  ```
19
22
 
20
- You can match links represented as an array of `{rel: ... , href: ...}` objects named as `links`:
23
+ You can match those links using `have_link` or `have_links` matchers as follow:
21
24
 
22
25
  ```ruby
23
26
  describe MyRestfulController do
24
- render_views
27
+ render_views # don't forget this!
25
28
 
26
29
  it "should have links" do
27
30
  get :index
28
31
 
29
- response.body.should have_link "resource1", "http://example.com/resource1"
30
- response.body.should have_link "resource2", "http://example.com/resource1"
32
+ # you can match against both raw ...
33
+ response.body.should have_link "foo", "http://example.com/foo"
34
+ response.body.should have_link "bar", "http://example.com/bar"
31
35
 
32
- parsed_json = JSON.parse(response.body) # you can match both raw or parsed (hash) JSON
33
- parsed_json.should have_link "self" # href attribute is optional
36
+ # ... or parsed JSON (as a Hash)
37
+ parsed_json = JSON.parse(response.body)
38
+
39
+ # href attribute is optional
40
+ parsed_json.should have_link "baz"
41
+
42
+ # match many links at once using have_links matcher
43
+ response.body.should have_links([
44
+ { rel: "foo", href: "http://example.com/foo" },
45
+ { rel: "bar", href: "http://example.com/bar" },
46
+ { rel: "baz", href: "http://example.com/baz" },
47
+ { rel: "qux", href: "http://example.com/qux" },
48
+ ])
34
49
  end
35
50
  end
36
51
  ```
@@ -42,3 +57,11 @@ Add it to the `test` group in your Gemfile and be happy!
42
57
  ```ruby
43
58
  gem 'restful-matchers', '~> 0.2', :group => :test
44
59
  ```
60
+
61
+ ## Changelog
62
+
63
+ See [CHANGELOG](https://github.com/marcoshack/restful-matchers/blob/master/CHANGELOG.md).
64
+
65
+ ## License
66
+
67
+ restful-matchers is Copyright © 2013 Marcos Hack. It is free software, and may be redistributed under the terms specified in the LICENSE file.
@@ -1,4 +1,7 @@
1
+ require "restful/matchers/errors"
2
+ require "restful/matchers/parsers"
1
3
  require "restful/matchers/have_link"
4
+ require "restful/matchers/have_links"
2
5
 
3
6
  if defined?(RSpec)
4
7
  require 'restful/matchers/integrations/rspec'
@@ -0,0 +1,2 @@
1
+ ERRORS_DIR = File.expand_path(File.join(File.dirname(__FILE__), 'errors')).freeze
2
+ Dir[File.join(ERRORS_DIR, '**', '*.rb')].each { |file| require(file) }
@@ -0,0 +1,7 @@
1
+ module RESTful
2
+ module Matchers
3
+ module Errors
4
+ class InvalidLink < StandardError; end
5
+ end
6
+ end
7
+ end
@@ -1,11 +1,13 @@
1
1
  require 'json'
2
+ require 'restful/matchers/parsers'
2
3
 
3
4
  module RESTful
4
5
  module Matchers
5
6
  # Ensures that JSON response body has the given link.
6
7
  #
7
8
  # Example:
8
- # response.body.should have_json_link("self", "http://example.com")
9
+ #
10
+ # response.body.should have_json_link("self", "http://example.com")
9
11
  #
10
12
  def have_link(rel, href = nil)
11
13
  HaveLink.new(rel, href)
@@ -20,7 +22,7 @@ module RESTful
20
22
 
21
23
  def matches?(content)
22
24
  @content = content
23
- if links = parse_links_from(content)
25
+ if links = RESTful::Matchers::Parsers::JSONLinkParser.parse(content)
24
26
  return @href ? links[@rel] == @href : links.has_key?(@rel)
25
27
  else
26
28
  return false
@@ -39,16 +41,6 @@ module RESTful
39
41
  def error_message(message)
40
42
  "#{message} '{\"rel\": \"#{@rel}\", \"href\": \"#{@href || "<any>" }\"}' in '#{@content}'"
41
43
  end
42
-
43
- def parse_links_from(content)
44
- json = content.is_a?(Hash) ? content : JSON.parse(content)
45
- links = nil
46
- if json["links"]
47
- links = {}
48
- json["links"].each { |link| links[link["rel"]] = link["href"] }
49
- end
50
- return links
51
- end
52
44
  end
53
45
  end
54
46
  end
@@ -0,0 +1,68 @@
1
+ require 'json'
2
+ require 'restful/matchers/parsers'
3
+
4
+ module RESTful
5
+ module Matchers
6
+ # Ensures that JSON response body has the given links, represented as an
7
+ # array of hashes with `rel` and `href` keys.
8
+ #
9
+ # Example:
10
+ #
11
+ # response.body.should have_links([
12
+ # { rel: "self", href: "http://example.com" },
13
+ # { rel: "foo" , href: "http://example.com/foo" },
14
+ # { rel: "bar" , href: "http://example.com/bar" }
15
+ # ])
16
+ #
17
+ def have_links(links)
18
+ HaveLinks.new(links)
19
+ end
20
+
21
+ class HaveLinks
22
+ def initialize(links)
23
+ @match_links = {}
24
+
25
+ if links.is_a?(Array)
26
+ links.each do |link|
27
+ rel = link[:rel] || link["rel"]
28
+ href = link[:href] || link["href"]
29
+ if rel
30
+ @match_links[rel.to_s] = href
31
+ else
32
+ raise ::Errors::InvalidLink("Link has no `rel`: #{link}")
33
+ end
34
+ end
35
+ else
36
+ raise ArgumentError.new("matcher expects an array of hashes containing `rel` and `href` keys as argument")
37
+ end
38
+ end
39
+
40
+ def matches?(content)
41
+ @content = content
42
+ @content_links = RESTful::Matchers::Parsers::JSONLinkParser.parse(content)
43
+ if @content_links
44
+ @content_links.each do |rel, href|
45
+ match = href ? @match_links[rel] == href : @match_links.has_key?(rel)
46
+ return false unless match
47
+ end
48
+ return true
49
+ else
50
+ return false
51
+ end
52
+ end
53
+
54
+ def failure_message_for_should
55
+ "Expected links weren't found. #{content_and_match_links_message}"
56
+ end
57
+
58
+ def failure_message_for_should_not
59
+ "Not expected links where found. #{content_and_match_links_message}"
60
+ end
61
+
62
+ private
63
+ def content_and_match_links_message
64
+ "Expect '#{@match_links}', but got '#{@content_links}'."
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,2 @@
1
+ PARSERS_DIR = File.expand_path(File.join(File.dirname(__FILE__), 'parsers')).freeze
2
+ Dir[File.join(PARSERS_DIR, '**', '*.rb')].each { |file| require(file) }
@@ -0,0 +1,17 @@
1
+ module RESTful
2
+ module Matchers
3
+ module Parsers
4
+ module JSONLinkParser
5
+ def self.parse(content)
6
+ json = content.is_a?(Hash) ? content : JSON.parse(content)
7
+ links = nil
8
+ if json["links"]
9
+ links = {}
10
+ json["links"].each { |link| links[link["rel"]] = link["href"] }
11
+ end
12
+ return links
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module RESTful
2
+ module Matchers
3
+ VERSION = "0.3.0".freeze
4
+ end
5
+ end
@@ -1,9 +1,10 @@
1
- # encoding: utf-8
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
2
+ require 'restful/matchers/version'
2
3
 
3
4
  Gem::Specification.new do |gem|
4
- gem.name = "restful-matchers"
5
- gem.version = "0.2.1"
6
-
5
+ gem.name = "restful-matchers"
6
+ gem.version = RESTful::Matchers::VERSION.dup
7
+ gem.date = Time.now.strftime("%Y-%m-%d")
7
8
  gem.authors = [ "Marcos Hack" ]
8
9
  gem.email = [ "marcoshack@gmail.com" ]
9
10
  gem.summary = "RSpec matchers to test RESTful HATEOAS-compliant resource links."
@@ -11,10 +12,12 @@ Gem::Specification.new do |gem|
11
12
  gem.homepage = "https://github.com/marcoshack/restful-matchers"
12
13
  gem.license = "MIT"
13
14
 
15
+ gem.files = `git ls-files`.split("\n")
16
+ gem.test_files = `git ls-files -- {spec}/*`.split("\n")
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.required_ruby_version = '>= 1.9.2'
20
+
14
21
  gem.add_dependency "rspec", "~> 2.0"
15
22
  gem.add_development_dependency "bundler", "~> 1.0"
16
-
17
- gem.files = `git ls-files`.split($\)
18
- gem.test_files = gem.files.grep(/^(test)/)
19
- gem.require_paths = ["lib"]
20
23
  end
@@ -0,0 +1,9 @@
1
+ {
2
+ "attr1": "value1",
3
+ "attr2": "value2",
4
+ "links": [
5
+ { "rel": "self", "href": "http://example.com" },
6
+ { "rel": "foo", "href": "http://example.com/foo" },
7
+ { "rel": "bar", "href": "http://example.com/bar" }
8
+ ]
9
+ }
@@ -2,30 +2,18 @@ require 'spec_helper'
2
2
 
3
3
  describe RESTful::Matchers::HaveLink do
4
4
 
5
- shared_examples_for "Matcher" do
6
- it "should find a json link" do
7
- @content.should have_restful_json_link("self", "http://example.com")
8
- @content.should have_link("self", "http://example.com")
9
- end
5
+ before(:each) { @content = open("spec/fixtures/json/resource_with_links.json").read }
10
6
 
11
- it "should not find an unexistant link" do
12
- @content.should_not have_restful_json_link("foo", "http://bar.com")
13
- @content.should_not have_link("foo", "http://bar.com")
14
- end
15
-
16
- it "should find a link matching only the rel attribute" do
17
- @content.should have_link("self")
18
- end
7
+ it "should match a valid link" do
8
+ @content.should have_link("self", "http://example.com")
19
9
  end
20
10
 
21
- context "when processing a JSON content" do
22
- before(:each) { @content = open("spec/fixtures/json/resource.json").read }
23
- it_behaves_like "Matcher"
11
+ it "should not match a non-existing link" do
12
+ @content.should_not have_link("foo", "http://bar.com")
24
13
  end
25
14
 
26
- context "when processing a parsed JSON" do
27
- before(:each) { @content = JSON.parse(open("spec/fixtures/json/resource.json").read) }
28
- it_behaves_like "Matcher"
15
+ it "should match only by rel attribute" do
16
+ @content.should have_link("self")
29
17
  end
30
18
 
31
19
  it "should show matched content on fail" do
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe RESTful::Matchers::HaveLinks do
4
+
5
+ context "when processing a valid JSON with links" do
6
+ let(:content) { open("spec/fixtures/json/resource_with_links.json").read }
7
+
8
+ it "should match an array of links using symbols as keys" do
9
+ content.should have_links([
10
+ { rel: "self", href: "http://example.com" },
11
+ { rel: "foo" , href: "http://example.com/foo" },
12
+ { rel: "bar" , href: "http://example.com/bar" }
13
+ ])
14
+ end
15
+
16
+ it "should match an array of links using string as keys" do
17
+ content.should have_links([
18
+ { "rel" => "self", "href" => "http://example.com" },
19
+ { "rel" => "foo" , "href" => "http://example.com/foo" },
20
+ { "rel" => "bar" , "href" => "http://example.com/bar" }
21
+ ])
22
+ end
23
+
24
+ it "should not match an empty array" do
25
+ content.should_not have_links []
26
+ end
27
+
28
+ it "should fail to match an empty array" do
29
+ expect { content.should have_links [] }.to raise_error(/.*Expect '{}'.*/)
30
+ end
31
+
32
+ it "should fail to match an invalid argument" do
33
+ [ 1, "", {}, :a_symbol, nil ].each do |value|
34
+ expect { content.should have_links value }.to raise_error(ArgumentError)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+ require 'restful/matchers/parsers/json_link_parser'
3
+
4
+ describe RESTful::Matchers::Parsers::JSONLinkParser do
5
+ shared_examples_for "parser" do
6
+ it "should parser links" do
7
+ links = RESTful::Matchers::Parsers::JSONLinkParser.parse(content)
8
+ links.keys.should include "self", "foo", "bar"
9
+ links["self"].should == "http://example.com"
10
+ links["foo" ].should == "http://example.com/foo"
11
+ links["bar" ].should == "http://example.com/bar"
12
+ end
13
+ end
14
+
15
+ context "when parsing raw JSON" do
16
+ let(:content) { open("spec/fixtures/json/resource_with_links.json").read }
17
+ it_behaves_like "parser"
18
+ end
19
+
20
+ context "when parsing parsed JSON" do
21
+ let(:content) { JSON.parse(open("spec/fixtures/json/resource_with_links.json").read) }
22
+ it_behaves_like "parser"
23
+ end
24
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restful-matchers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marcos Hack
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-08-21 00:00:00.000000000 Z
11
+ date: 2013-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -49,6 +49,7 @@ extra_rdoc_files: []
49
49
  files:
50
50
  - .gitignore
51
51
  - .travis.yml
52
+ - CHANGELOG.md
52
53
  - Gemfile
53
54
  - Gemfile.lock
54
55
  - LICENSE
@@ -56,11 +57,19 @@ files:
56
57
  - Rakefile
57
58
  - lib/restful-matchers.rb
58
59
  - lib/restful/matchers.rb
60
+ - lib/restful/matchers/errors.rb
61
+ - lib/restful/matchers/errors/invalid_link.rb
59
62
  - lib/restful/matchers/have_link.rb
63
+ - lib/restful/matchers/have_links.rb
60
64
  - lib/restful/matchers/integrations/rspec.rb
65
+ - lib/restful/matchers/parsers.rb
66
+ - lib/restful/matchers/parsers/json_link_parser.rb
67
+ - lib/restful/matchers/version.rb
61
68
  - restful-matchers.gemspec
62
- - spec/fixtures/json/resource.json
69
+ - spec/fixtures/json/resource_with_links.json
63
70
  - spec/restful/matchers/have_link_spec.rb
71
+ - spec/restful/matchers/have_links_spec.rb
72
+ - spec/restful/parsers/json_link_parser_spec.rb
64
73
  - spec/spec_helper.rb
65
74
  homepage: https://github.com/marcoshack/restful-matchers
66
75
  licenses:
@@ -74,7 +83,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
74
83
  requirements:
75
84
  - - '>='
76
85
  - !ruby/object:Gem::Version
77
- version: '0'
86
+ version: 1.9.2
78
87
  required_rubygems_version: !ruby/object:Gem::Requirement
79
88
  requirements:
80
89
  - - '>='
@@ -1,7 +0,0 @@
1
- {
2
- "attr1": "value1",
3
- "attr2": "value2",
4
- "links": [
5
- { "rel": "self", "href": "http://example.com" }
6
- ]
7
- }