rspec_api_blueprint_matchers 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +33 -0
  3. data/.gitignore +1 -0
  4. data/.rubocop.yml +26 -0
  5. data/.ruby-version +1 -0
  6. data/Rakefile +2 -1
  7. data/config/rubocop/.lint_rubocop.yml +749 -0
  8. data/config/rubocop/.metrics_rubocop.yml +94 -0
  9. data/config/rubocop/.performance_rubocop.yml +323 -0
  10. data/config/rubocop/.rails_rubocop.yml +256 -0
  11. data/config/rubocop/.style_rubocop.yml +2299 -0
  12. data/docker-compose.yml +17 -0
  13. data/lib/rspec_api_blueprint_matchers.rb +1 -0
  14. data/lib/rspec_apib/config.rb +1 -0
  15. data/lib/rspec_apib/elements/annotation.rb +1 -0
  16. data/lib/rspec_apib/elements/array.rb +1 -0
  17. data/lib/rspec_apib/elements/asset.rb +1 -0
  18. data/lib/rspec_apib/elements/base.rb +11 -10
  19. data/lib/rspec_apib/elements/category.rb +2 -1
  20. data/lib/rspec_apib/elements/copy.rb +2 -1
  21. data/lib/rspec_apib/elements/data_structure.rb +2 -0
  22. data/lib/rspec_apib/elements/href_variables.rb +3 -2
  23. data/lib/rspec_apib/elements/http_headers.rb +5 -4
  24. data/lib/rspec_apib/elements/http_message_payload.rb +3 -2
  25. data/lib/rspec_apib/elements/http_request.rb +16 -10
  26. data/lib/rspec_apib/elements/http_response.rb +3 -1
  27. data/lib/rspec_apib/elements/http_transaction.rb +4 -3
  28. data/lib/rspec_apib/elements/member.rb +3 -2
  29. data/lib/rspec_apib/elements/object.rb +2 -1
  30. data/lib/rspec_apib/elements/parse_result.rb +1 -0
  31. data/lib/rspec_apib/elements/resource.rb +1 -0
  32. data/lib/rspec_apib/elements/source_map.rb +1 -0
  33. data/lib/rspec_apib/elements/string.rb +1 -0
  34. data/lib/rspec_apib/elements/templated_href.rb +1 -0
  35. data/lib/rspec_apib/elements/transition.rb +1 -0
  36. data/lib/rspec_apib/elements.rb +1 -0
  37. data/lib/rspec_apib/extractors/http_transaction.rb +1 -0
  38. data/lib/rspec_apib/extractors/resource.rb +1 -0
  39. data/lib/rspec_apib/extractors.rb +1 -0
  40. data/lib/rspec_apib/parser.rb +2 -1
  41. data/lib/rspec_apib/request.rb +7 -10
  42. data/lib/rspec_apib/response.rb +2 -2
  43. data/lib/rspec_apib/rspec.rb +4 -3
  44. data/lib/rspec_apib/transaction_coverage_report.rb +4 -3
  45. data/lib/rspec_apib/transaction_coverage_validator.rb +4 -3
  46. data/lib/rspec_apib/transaction_validator.rb +1 -0
  47. data/lib/rspec_apib/transcluder.rb +2 -2
  48. data/lib/rspec_apib/version.rb +2 -1
  49. data/lib/rspec_apib.rb +2 -1
  50. data/lib/transcluder.rb +1 -0
  51. data/rspec_api_blueprint_matchers.gemspec +6 -4
  52. metadata +25 -2
@@ -0,0 +1,17 @@
1
+ version: '2'
2
+
3
+ services:
4
+ test:
5
+ image: rspec_api_blueprint_matchers
6
+ build:
7
+ context: .
8
+ dockerfile: Dockerfile
9
+ command: bash -c "bundle install && bundle exec rspec"
10
+ volumes:
11
+ - .:/app
12
+ - rubygems_cache:/rubygems
13
+ environment:
14
+ GEM_HOME: '/rubygems'
15
+ BUNDLE_PATH: '/rubygems'
16
+ volumes:
17
+ rubygems_cache:
@@ -1 +1,2 @@
1
+ # frozen_string_literal: true
1
2
  require "rspec_apib"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  class Config
3
4
  attr_accessor :default_blueprint_file
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
3
4
  class Annotation < Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
3
4
  class Array < ::Array
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
3
4
  class Asset < Base
@@ -1,8 +1,11 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
3
- class Base < Struct.new(:element, :meta, :attributes, :content, :parent)
4
+ BaseStruct = Struct.new(:element, :meta, :attributes, :content, :parent)
4
5
 
5
- def inspect(*args)
6
+ # A base class for all objects in api-elements (http://api-elements.readthedocs.io/en/latest/)
7
+ class Base < BaseStruct
8
+ def inspect
6
9
  "##{self.class} (element: #{element}, meta: #{meta}, attributes: #{attributes.inspect}, content: #{content.inspect}, parent: ##{parent.class})"
7
10
  end
8
11
 
@@ -14,11 +17,11 @@ module RSpecApib
14
17
 
15
18
  def self.parse(node_or_nodes, index:, parent:, klass: nil)
16
19
  return node_or_nodes.map { |node| parse(node, index: index, parent: parent) } if node_or_nodes.is_a?(::Array)
17
- return transformed_basic_hash(node_or_nodes, index: index, parent: parent) if is_basic_hash?(node_or_nodes)
18
- return node_or_nodes unless !klass.nil? || is_base_element?(node_or_nodes)
20
+ return transformed_basic_hash(node_or_nodes, index: index, parent: parent) if basic_hash?(node_or_nodes)
21
+ return node_or_nodes unless !klass.nil? || base_element?(node_or_nodes)
19
22
  hash = node_or_nodes
20
23
  klass_name = klass
21
- klass_name ||= hash["element"].slice(0,1).capitalize + hash["element"].slice(1..-1).gsub(" ", "")
24
+ klass_name ||= hash["element"].slice(0, 1).capitalize + hash["element"].slice(1..-1).delete(" ")
22
25
  return node_or_nodes unless RSpecApib::Element.const_defined?(klass_name)
23
26
  klass = RSpecApib::Element.const_get(klass_name)
24
27
  index[klass] ||= []
@@ -61,12 +64,10 @@ module RSpecApib
61
64
  {}
62
65
  end
63
66
 
64
- def self.is_base_element?(node)
67
+ def self.base_element?(node)
65
68
  node.is_a?(::Hash) && node.keys.include?("element")
66
69
  end
67
70
 
68
- private
69
-
70
71
  def self.attributes_schema
71
72
  {}
72
73
  end
@@ -81,8 +82,8 @@ module RSpecApib
81
82
  node
82
83
  end
83
84
 
84
- def self.is_basic_hash?(node)
85
- node.is_a?(::Hash) && !is_base_element?(node)
85
+ def self.basic_hash?(node)
86
+ node.is_a?(::Hash) && !base_element?(node)
86
87
  end
87
88
 
88
89
  def self.transformed_basic_hash(node, index:, parent:)
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
4
+ # Represents a category in api-elements (http://api-elements.readthedocs.io/en/latest/)
3
5
  class Category < Base
4
-
5
6
  end
6
7
  end
7
8
  end
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
4
+ # Represents copy text in api-elements (http://api-elements.readthedocs.io/en/latest/)
3
5
  class Copy < Base
4
-
5
6
  end
6
7
  end
7
8
  end
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
4
+ # Represents a data structure in api-elements (http://api-elements.readthedocs.io/en/latest/)
3
5
  class DataStructure < Base
4
6
 
5
7
  end
@@ -1,13 +1,14 @@
1
+ # frozen_string_literal: true
1
2
  require "addressable"
2
3
  module RSpecApib
3
4
  module Element
5
+ # Represents a collection of href variables in api-elements (http://api-elements.readthedocs.io/en/latest/)
4
6
  class HrefVariables < Base
5
7
  def [](key)
6
- member = content.find {|h| h.is_a?(Member) && h.content.key?(key) }
8
+ member = content.find { |h| h.is_a?(Member) && h.content.key?(key) }
7
9
  return nil if member.nil?
8
10
  member.content[key]
9
11
  end
10
-
11
12
  end
12
13
  end
13
14
  end
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
4
+ # Represents a collection of http headers in api-elements (http://api-elements.readthedocs.io/en/latest/)
3
5
  class HttpHeaders < Base
4
6
  def [](key)
5
- member = content.find {|h| h.is_a?(Member) && h.content.key?(key) }
7
+ member = content.find { |h| h.is_a?(Member) && h.content.key?(key) }
6
8
  return nil if member.nil?
7
9
  member.content[key]
8
10
  end
9
11
 
10
12
  def each_pair
11
- content.select {|h| h.is_a?(Member)}.each do |header|
13
+ content.select { |h| h.is_a?(Member) }.each do |header|
12
14
  yield header.key, header.value
13
15
  end
14
16
  end
@@ -16,12 +18,11 @@ module RSpecApib
16
18
  def keep_if
17
19
  results = dup
18
20
  results.content = []
19
- content.select {|h| h.is_a?(Member)}.each do |header|
21
+ content.select { |h| h.is_a?(Member) }.each do |header|
20
22
  results.content << header if yield header.key, header.value
21
23
  end
22
24
  results
23
25
  end
24
-
25
26
  end
26
27
  end
27
28
  end
@@ -1,9 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  require "json-schema"
2
3
  require "rspec_apib/elements/http_message_payload"
3
4
  module RSpecApib
4
5
  module Element
6
+ # Represents a http message payload in api-elements (http://api-elements.readthedocs.io/en/latest/)
5
7
  class HttpMessagePayload < Base
6
-
7
8
  # The content type if defined else nil
8
9
  # @return [String | NilClass] The content type header or nil
9
10
  def content_type
@@ -31,7 +32,7 @@ module RSpecApib
31
32
  reason: "Schema validation failure",
32
33
  details: errors
33
34
  }
34
- return [failure_reason]
35
+ [failure_reason]
35
36
  end
36
37
 
37
38
  private
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
1
2
  require "json-schema"
2
3
  require "rspec_apib/elements/http_message_payload"
3
4
  module RSpecApib
4
5
  module Element
6
+ # Represents a http request in api-elements (http://api-elements.readthedocs.io/en/latest/)
5
7
  class HttpRequest < HttpMessagePayload
6
8
 
7
9
  # Indicates if the incoming request matches the method, path and path vars
@@ -9,8 +11,8 @@ module RSpecApib
9
11
  # @return [Boolean] true if matches else false
10
12
  def matches?(request, options: {})
11
13
  matches_method?(request) &&
12
- matches_path?(request) &&
13
- matches_headers?(request, options)
14
+ matches_path?(request) &&
15
+ matches_headers?(request, options)
14
16
  end
15
17
 
16
18
  # Inherit href and hrefVariables from any ancestor
@@ -30,10 +32,16 @@ module RSpecApib
30
32
  attributes && attributes["href"].to_s
31
33
  end
32
34
 
35
+ def self.attributes_schema
36
+ {
37
+ href: "TemplatedHref"
38
+ }
39
+ end
40
+
33
41
  private
34
42
 
35
- def matches_headers?(request_or_response, options)
36
- headers = attributes && attributes["headers"] && attributes["headers"].keep_if {|k, v| k == "Content-Type" || k == "Accept"}
43
+ def matches_headers?(request_or_response, _options)
44
+ headers = compared_headers
37
45
  return true if headers.nil?
38
46
  headers.each_pair do |header_key, header_value|
39
47
  return false unless request_or_response.headers.key?(header_key) &&
@@ -41,6 +49,10 @@ module RSpecApib
41
49
  end
42
50
  end
43
51
 
52
+ def compared_headers
53
+ attributes && attributes["headers"] && attributes["headers"].keep_if {|k, _v| k == "Content-Type" || k == "Accept"}
54
+ end
55
+
44
56
  def matches_method?(request)
45
57
  attributes && attributes["method"] && attributes["method"].downcase.to_sym == request.request_method
46
58
  end
@@ -48,12 +60,6 @@ module RSpecApib
48
60
  def matches_path?(request)
49
61
  attributes && attributes["href"] && attributes["href"].matches_path?(request)
50
62
  end
51
-
52
- def self.attributes_schema
53
- {
54
- href: "TemplatedHref"
55
- }
56
- end
57
63
  end
58
64
  end
59
65
  end
@@ -1,13 +1,15 @@
1
+ # frozen_string_literal: true
1
2
  require "rspec_apib/elements/http_message_payload"
2
3
  module RSpecApib
3
4
  module Element
5
+ # Represents a http response in api-elements (http://api-elements.readthedocs.io/en/latest/)
4
6
  class HttpResponse < HttpMessagePayload
5
7
  # Indicates if the incoming request matches the method, path and path vars
6
8
  # @param [::RSpecApib::Request] The incoming request - normalized
7
9
  # @return [Boolean] true if matches else false
8
10
  def matches?(response, options: {})
9
11
  matches_status?(response) &&
10
- matches_content_type?(response)
12
+ matches_content_type?(response)
11
13
  end
12
14
 
13
15
  def status
@@ -1,15 +1,16 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
4
+ # Represents a http transaction in api-elements (http://api-elements.readthedocs.io/en/latest/)
3
5
  class HttpTransaction < Base
4
-
5
6
  def matches?(request_in, response_in, options: {})
6
7
  request.matches?(request_in, options: options) && response.matches?(response_in, options: options)
7
8
  end
8
9
 
9
10
  def potential_match?(path:, request_method:, content_type:)
10
11
  potential_match_content_type?(content_type) &&
11
- (request_method == :any || request_method == request.request_method) &&
12
- (path == :any || request.path == path)
12
+ (request_method == :any || request_method == request.request_method) &&
13
+ (path == :any || request.path == path)
13
14
  end
14
15
 
15
16
  def validate_schema(request_in, response_in, validate_request_schema: :always, validate_response_schema: :always)
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
4
+ # Represents a member in api-elements (http://api-elements.readthedocs.io/en/latest/)
3
5
  class Member < Base
4
-
5
6
  def self.from_hash(hash, index:, parent:)
6
7
  child = super
7
8
  content = child.content
8
- child.content = {content["key"] => content["value"]}
9
+ child.content = { content["key"] => content["value"] }
9
10
  child
10
11
  end
11
12
 
@@ -1,7 +1,8 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
4
+ # Represents an object request in api-elements (http://api-elements.readthedocs.io/en/latest/)
3
5
  class Object < Base
4
-
5
6
  end
6
7
  end
7
8
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
3
4
  class ParseResult < Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
3
4
  # (byebug) parent.parent["attributes"]
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
3
4
  class SourceMap < Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
3
4
  class String < ::String
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "addressable"
2
3
  module RSpecApib
3
4
  module Element
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Element
3
4
  class Transition < Base
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "rspec_apib/elements/base"
2
3
  require "rspec_apib/elements/parse_result"
3
4
  require "rspec_apib/elements/category"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Extractor
3
4
  class HttpTransaction
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module RSpecApib
2
3
  module Extractor
3
4
  class Resource
@@ -1,2 +1,3 @@
1
+ # frozen_string_literal: true
1
2
  require "rspec_apib/extractors/resource"
2
3
  require "rspec_apib/extractors/http_transaction"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require "rspec_apib/transcluder"
2
3
  require "rspec_apib/extractors"
3
4
  require "rspec_apib/elements"
@@ -65,7 +66,7 @@ module RSpecApib
65
66
 
66
67
  def call_parser(file)
67
68
  op = nil
68
- Open3.popen3("#{bin_path} -f json") do |stdin, stdout, stderr, wait_thr|
69
+ Open3.popen3("#{bin_path} -f json") do |stdin, stdout, _stderr, wait_thr|
69
70
  transcluder.each_line(file) do |line|
70
71
  stdin.write line
71
72
  end
@@ -1,5 +1,8 @@
1
+ # frozen_string_literal: true
2
+ require "forwardable"
1
3
  module RSpecApib
2
4
  class Request
5
+ extend Forwardable
3
6
  def initialize(request)
4
7
  self.raw_request = request
5
8
  end
@@ -8,19 +11,15 @@ module RSpecApib
8
11
  raw_request.method
9
12
  end
10
13
 
11
- def url
12
- raw_request.url
13
- end
14
+ delegate url: :raw_request
14
15
 
15
16
  def validate_body_with_json_schema?
16
- request_method != :get && is_json?
17
+ request_method != :get && json?
17
18
  end
18
19
 
19
20
  # The request body
20
21
  # @return [String] The request body - always as a string
21
- def body
22
- raw_request.body
23
- end
22
+ delegate body: :raw_request
24
23
 
25
24
  def content_type
26
25
  headers["Content-Type"]
@@ -30,15 +29,13 @@ module RSpecApib
30
29
  raw_request.request_headers
31
30
  end
32
31
 
33
-
34
32
  private
35
33
 
36
34
  attr_accessor :raw_request
37
35
 
38
- def is_json?
36
+ def json?
39
37
  content_type =~ /json/
40
38
  end
41
39
 
42
-
43
40
  end
44
41
  end