restful-matchers 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
- }