Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add RuboCop #164

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require:
- rubocop-performance
- rubocop-rake
- rubocop-rspec

AllCops:
TargetRubyVersion: 2.7
NewCops: enable

### Metrics ###

Metrics:
Exclude:
- lib/airborne/request_expectations.rb

Metrics/MethodLength:
CountAsOne:
- hash

### Style ###

Style/Documentation:
Enabled: false

Style/SymbolArray:
EnforcedStyle: brackets

### RSpec ###

RSpec/ContextWording:
Enabled: false

RSpec/DescribeClass:
Enabled: false

RSpec/ExampleLength:
Enabled: false

RSpec/MultipleDescribes:
Enabled: false

RSpec/MultipleExpectations:
Enabled: false

RSpec/NotToNot:
EnforcedStyle: to_not

RSpec/RepeatedDescription:
Enabled: false
8 changes: 7 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
# frozen_string_literal: true

source 'https://rubygems.org'

gemspec

gem 'coveralls', require: false
gem 'faraday-retry', require: false
gem 'rubocop', require: false
gem 'rubocop-performance', require: false
gem 'rubocop-rake', require: false
gem 'rubocop-rspec', require: false

group :test do
gem 'webmock'
gem 'sinatra'
gem 'webmock'
end
2 changes: 2 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# frozen_string_literal: true

task default: [:spec]
23 changes: 14 additions & 9 deletions airborne.gemspec
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
# frozen_string_literal: true

require 'date'

Gem::Specification.new do |s|
Gem::Specification.new do |s| # rubocop:disable Gemspec/RequireMFA
s.name = 'airborne'
s.version = '0.3.7'
s.date = Date.today.to_s
s.summary = 'RSpec driven API testing framework'
s.authors = ['Alex Friedman', 'Seth Pollack']
s.email = ['a.friedman07@gmail.com', 'seth@sethpollack.net']
s.require_paths = ['lib']
s.files = `git ls-files`.split("\n")
s.license = 'MIT'
s.add_runtime_dependency 'rspec', '~> 3.8'
s.add_runtime_dependency 'rest-client', '< 3.0', '>= 2.0.2'
s.add_runtime_dependency 'rack-test', '< 2.0', '>= 1.1.0'
s.add_runtime_dependency 'rack'
s.license = 'MIT'

s.required_ruby_version = ['>= 2.7', '< 4']

s.add_runtime_dependency 'activesupport'
s.add_development_dependency 'webmock', '~> 3'
s.add_development_dependency 'rake', '~> 12'
s.add_runtime_dependency 'rack'
s.add_runtime_dependency 'rack-test', '< 2.0', '>= 1.1.0'
s.add_runtime_dependency 'rest-client', '< 3.0', '>= 2.0.2'
s.add_runtime_dependency 'rspec', '~> 3.8'

s.add_development_dependency 'github_changelog_generator', '~> 1.14'
s.add_development_dependency 'rake', '~> 12'
s.add_development_dependency 'webmock', '~> 3'
end
25 changes: 18 additions & 7 deletions lib/airborne.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# frozen_string_literal: true

require 'airborne/optional_hash_type_expectations'
require 'airborne/path_matcher'
require 'airborne/request_expectations'
require 'airborne/rest_client_requester'
require 'airborne/rack_test_requester'
require 'airborne/base'

RSpec.configure do |config|
RSpec.configure do |config| # rubocop:disable Metrics/BlockLength
config.add_setting :base_url
config.add_setting :match_expected
config.add_setting :match_actual
Expand All @@ -17,12 +19,21 @@
config.add_setting :requester_module
config.add_setting :verify_ssl, default: true
config.before do |example|
config.match_expected = example.metadata[:match_expected].nil? ?
Airborne.configuration.match_expected_default? : example.metadata[:match_expected]
config.match_actual = example.metadata[:match_actual].nil? ?
Airborne.configuration.match_actual_default? : example.metadata[:match_actual]
config.verify_ssl = example.metadata[:verify_ssl].nil? ?
Airborne.configuration.verify_ssl? : example.metadata[:verify_ssl]
config.match_expected = if example.metadata[:match_expected].nil?
Airborne.configuration.match_expected_default?
else
example.metadata[:match_expected]
end
config.match_actual = if example.metadata[:match_actual].nil?
Airborne.configuration.match_actual_default?
else
example.metadata[:match_actual]
end
config.verify_ssl = if example.metadata[:verify_ssl].nil?
Airborne.configuration.verify_ssl?
else
example.metadata[:verify_ssl]
end
end

# Include last since it depends on the configuration already being added
Expand Down
18 changes: 8 additions & 10 deletions lib/airborne/base.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

require 'json'
require 'active_support'
require 'active_support/core_ext/hash/indifferent_access'
Expand All @@ -7,12 +9,10 @@ class InvalidJsonError < StandardError; end

include RequestExpectations

attr_reader :response, :headers, :body
attr_reader :response

def self.configure
RSpec.configure do |config|
yield config
end
def self.configure(&block)
RSpec.configure(&block)
end

def self.included(base)
Expand Down Expand Up @@ -57,10 +57,6 @@ def options(url, headers = nil)
@response = make_request(:options, url, headers: headers)
end

def response
@response
end

def headers
HashWithIndifferentAccess.new(response.headers)
end
Expand All @@ -70,7 +66,9 @@ def body
end

def json_body
JSON.parse(response.body, symbolize_names: true) rescue fail InvalidJsonError, 'Api request returned invalid json'
JSON.parse(response.body, symbolize_names: true)
rescue StandardError
raise InvalidJsonError, 'Api request returned invalid json'
end

private
Expand Down
9 changes: 5 additions & 4 deletions lib/airborne/optional_hash_type_expectations.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
# frozen_string_literal: true

module Airborne
class OptionalHashTypeExpectations
include Enumerable
attr_accessor :hash

def initialize(hash)
@hash = hash
end

def each
@hash.each do|k, v|
yield(k, v)
end
def each(&block)
@hash.each(&block)
end

def [](val)
Expand Down
63 changes: 41 additions & 22 deletions lib/airborne/path_matcher.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,44 @@
# frozen_string_literal: true

module Airborne
class PathError < StandardError; end

module PathMatcher
def get_by_path(path, json, &block)
fail PathError, "Invalid Path, contains '..'" if /\.\./ =~ path
WILDCARDS = ['*', '?'].freeze

def get_by_path(path, json, &block) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
raise PathError, "Invalid Path, contains '..'" if /\.\./.match?(path)

type = false
parts = path.split('.')
exit_now = false
parts.each_with_index do |part, index|
if part == '*' || part == '?'
if WILDCARDS.include?(part)
ensure_array(path, json)
type = part

if index < parts.length.pred
walk_with_path(type, index, path, parts, json, &block) && return
walk_with_path(type, index, path, parts, json, &block)
exit_now = true
break
end

next
end

begin
json = process_json(part, json)
rescue
rescue StandardError
raise PathError, "Expected #{json.class}\nto be an object with property #{part}"
end
end
if type == '*'

return if exit_now

case type
when '*'
expect_all(json, &block)
elsif type == '?'
when '?'
expect_one(path, json, &block)
else
yield json
Expand All @@ -32,15 +47,15 @@ def get_by_path(path, json, &block)

private

def walk_with_path(type, index, path, parts, json, &block)
last_error = nil
def walk_with_path(type, index, path, parts, json, &block) # rubocop:disable Metrics/MethodLength
last_error = nil
item_count = json.length
error_count = 0
json.each do |element|
begin
sub_path = parts[(index.next)...(parts.length)].join('.')
get_by_path(sub_path, element, &block)
rescue Exception => e
rescue Exception => e # rubocop:disable Lint/RescueException
last_error = e
error_count += 1
end
Expand All @@ -63,39 +78,43 @@ def index?(part)
part =~ /^\d+$/
end

def expect_one(path, json, &block)
def expect_one(path, json)
item_count = json.length
error_count = 0
json.each do |part|
begin
yield part
rescue Exception
error_count += 1
ensure_match_one(path, item_count, error_count)
end
yield part
rescue Exception # rubocop:disable Lint/RescueException
error_count += 1
ensure_match_one(path, item_count, error_count)
end
end

def expect_all(json, &block)
last_error = nil
begin
json.each { |part| yield part }
rescue Exception => e
json.each(&block)
rescue Exception => e # rubocop:disable Lint/RescueException
last_error = e
end
ensure_match_all(last_error)
end

def ensure_match_one(path, item_count, error_count)
fail RSpec::Expectations::ExpectationNotMetError, "Expected one object in path #{path} to match provided JSON values" if item_count == error_count
return unless item_count == error_count

raise RSpec::Expectations::ExpectationNotMetError,
"Expected one object in path #{path} to match provided JSON values"
end

def ensure_match_all(error)
fail error unless error.nil?
raise error unless error.nil?
end

def ensure_array(path, json)
fail RSpec::Expectations::ExpectationNotMetError, "Expected #{path} to be array got #{json.class} from JSON response" unless json.class == Array
return if json.is_a?(Array)

raise RSpec::Expectations::ExpectationNotMetError,
"Expected #{path} to be array got #{json.class} from JSON response"
end
end
end
2 changes: 2 additions & 0 deletions lib/airborne/rack_test_requester.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# frozen_string_literal: true

require 'rack/test'

module Airborne
Expand Down
Loading
You are viewing a condensed version of this merge commit. You can view the full changes here.