fixturama 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +29 -0
- data/README.md +32 -4
- data/fixturama.gemspec +1 -1
- data/lib/fixturama.rb +48 -20
- data/lib/fixturama/changes.rb +71 -0
- data/lib/fixturama/changes/base.rb +28 -0
- data/lib/fixturama/changes/chain.rb +64 -0
- data/lib/fixturama/changes/chain/actions.rb +31 -0
- data/lib/fixturama/changes/chain/arguments.rb +59 -0
- data/lib/fixturama/changes/chain/raise_action.rb +35 -0
- data/lib/fixturama/changes/chain/return_action.rb +33 -0
- data/lib/fixturama/changes/const.rb +30 -0
- data/lib/fixturama/changes/request.rb +91 -0
- data/lib/fixturama/changes/request/response.rb +62 -0
- data/lib/fixturama/changes/request/responses.rb +22 -0
- data/lib/fixturama/changes/seed.rb +39 -0
- data/lib/fixturama/config.rb +5 -0
- data/lib/fixturama/fixture_error.rb +31 -0
- data/lib/fixturama/loader.rb +1 -0
- data/lib/fixturama/loader/context.rb +1 -0
- data/lib/fixturama/loader/value.rb +1 -0
- data/spec/fixturama/seed_fixture/_spec.rb +1 -0
- data/spec/fixturama/seed_fixture/seed.yml +0 -5
- metadata +34 -34
- data/lib/fixturama/seed.rb +0 -15
- data/lib/fixturama/stubs.rb +0 -79
- data/lib/fixturama/stubs/chain.rb +0 -90
- data/lib/fixturama/stubs/chain/actions.rb +0 -39
- data/lib/fixturama/stubs/chain/actions/raise.rb +0 -21
- data/lib/fixturama/stubs/chain/actions/return.rb +0 -23
- data/lib/fixturama/stubs/chain/arguments.rb +0 -86
- data/lib/fixturama/stubs/const.rb +0 -43
- data/lib/fixturama/stubs/request.rb +0 -98
- data/lib/fixturama/stubs/request/response.rb +0 -43
- data/lib/fixturama/stubs/request/responses.rb +0 -20
- data/lib/fixturama/utils.rb +0 -39
data/lib/fixturama/seed.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
module Fixturama
|
2
|
-
module Seed
|
3
|
-
module_function
|
4
|
-
|
5
|
-
def call(opts)
|
6
|
-
opts = Utils.symbolize_hash(opts)
|
7
|
-
type = opts[:type].to_sym
|
8
|
-
traits = Utils.symbolize_array opts[:traits]
|
9
|
-
params = Utils.symbolize_hash opts[:params]
|
10
|
-
count = opts.fetch(:count, 1).to_i
|
11
|
-
|
12
|
-
FactoryBot.create_list(type, count, *traits, **params) if count.positive?
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
data/lib/fixturama/stubs.rb
DELETED
@@ -1,79 +0,0 @@
|
|
1
|
-
module Fixturama
|
2
|
-
#
|
3
|
-
# Collection of stubbed calls
|
4
|
-
#
|
5
|
-
class Stubs
|
6
|
-
require_relative "stubs/chain"
|
7
|
-
require_relative "stubs/const"
|
8
|
-
require_relative "stubs/request"
|
9
|
-
|
10
|
-
#
|
11
|
-
# Register new action and apply the corresponding stub
|
12
|
-
#
|
13
|
-
# @params [Hash<#to_s, _>] options
|
14
|
-
# @return [self] itself
|
15
|
-
#
|
16
|
-
def add(options)
|
17
|
-
options = symbolize(options)
|
18
|
-
find_or_create_stub!(options)&.update!(options)
|
19
|
-
self
|
20
|
-
end
|
21
|
-
|
22
|
-
#
|
23
|
-
# Applies the stub to RSpec example
|
24
|
-
#
|
25
|
-
def apply(example)
|
26
|
-
@stubs.values.each { |stub| stub.apply!(example) }
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
def initialize
|
32
|
-
@stubs = {}
|
33
|
-
end
|
34
|
-
|
35
|
-
def find_or_create_stub!(options)
|
36
|
-
stub = case stub_type(options)
|
37
|
-
when :message_chain then Chain.new(options)
|
38
|
-
when :constant then Const.new(options)
|
39
|
-
when :request then Request.new(options)
|
40
|
-
end
|
41
|
-
|
42
|
-
@stubs[stub.key] ||= stub if stub
|
43
|
-
end
|
44
|
-
|
45
|
-
def stub_type(options)
|
46
|
-
key = (TYPES.keys & options.keys).first
|
47
|
-
return TYPES[key] if key
|
48
|
-
|
49
|
-
raise ArgumentError, <<~MESSAGE
|
50
|
-
Cannot figure out what to stub from #{options}.
|
51
|
-
You should define either a class and a message chain, or some const.
|
52
|
-
MESSAGE
|
53
|
-
end
|
54
|
-
|
55
|
-
# Matches keys to the type of the stub
|
56
|
-
TYPES = {
|
57
|
-
arguments: :message_chain,
|
58
|
-
actions: :message_chain,
|
59
|
-
basic_auth: :request,
|
60
|
-
body: :request,
|
61
|
-
chain: :message_chain,
|
62
|
-
class: :message_chain,
|
63
|
-
const: :constant,
|
64
|
-
headers: :request,
|
65
|
-
http_method: :request,
|
66
|
-
object: :message_chain,
|
67
|
-
query: :request,
|
68
|
-
response: :request,
|
69
|
-
responses: :request,
|
70
|
-
uri: :request,
|
71
|
-
url: :request,
|
72
|
-
value: :constant,
|
73
|
-
}.freeze
|
74
|
-
|
75
|
-
def symbolize(options)
|
76
|
-
Hash(options).transform_keys { |key| key.to_s.to_sym }
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
module Fixturama
|
2
|
-
#
|
3
|
-
# Stubbed chain of messages
|
4
|
-
#
|
5
|
-
class Stubs::Chain
|
6
|
-
require_relative "chain/actions"
|
7
|
-
require_relative "chain/arguments"
|
8
|
-
|
9
|
-
attr_reader :receiver, :messages
|
10
|
-
|
11
|
-
#
|
12
|
-
# Human-readable representation of the chain
|
13
|
-
# @return [String]
|
14
|
-
#
|
15
|
-
def to_s
|
16
|
-
"#{receiver}.#{messages.join(".")}"
|
17
|
-
end
|
18
|
-
alias to_str to_s
|
19
|
-
alias key to_s
|
20
|
-
|
21
|
-
#
|
22
|
-
# Register new action for some arguments
|
23
|
-
#
|
24
|
-
# @option [Array<#to_s>, #to_s] :arguments The specific arguments
|
25
|
-
# @option (see Fixturama::Stubs::Arguments#add_action)
|
26
|
-
# @return [self]
|
27
|
-
#
|
28
|
-
def update!(actions:, arguments: nil, **)
|
29
|
-
Utils.array(arguments).tap do |args|
|
30
|
-
stub = find_by(args)
|
31
|
-
unless stub
|
32
|
-
stub = Stubs::Chain::Arguments.new(self, args)
|
33
|
-
stubs << stub
|
34
|
-
end
|
35
|
-
stub.add!(*actions)
|
36
|
-
stubs.sort_by! { |stub| -stub.arguments.count }
|
37
|
-
end
|
38
|
-
|
39
|
-
self
|
40
|
-
end
|
41
|
-
|
42
|
-
#
|
43
|
-
# Apply the stub to RSpec example
|
44
|
-
#
|
45
|
-
def apply!(example)
|
46
|
-
reset!
|
47
|
-
|
48
|
-
call_action = example.send(:receive_message_chain, *messages) do |*args|
|
49
|
-
call! args
|
50
|
-
end
|
51
|
-
|
52
|
-
example.send(:allow, receiver).to call_action
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def initialize(**options)
|
58
|
-
@receiver = Utils.constantize options[:class] if options.key?(:class)
|
59
|
-
@receiver ||= Object.send :eval, options[:object] if options.key?(:object)
|
60
|
-
raise SyntaxError, "Undefined receiver of messages" unless receiver
|
61
|
-
|
62
|
-
@messages = Utils.symbolize_array options[:chain]
|
63
|
-
return if messages.any?
|
64
|
-
|
65
|
-
raise SyntaxError, <<~MESSAGE.squish
|
66
|
-
Undefined message chain for stubbing #{receiver}.
|
67
|
-
Use option `chain` to define it.
|
68
|
-
MESSAGE
|
69
|
-
end
|
70
|
-
|
71
|
-
def stubs
|
72
|
-
@stubs ||= []
|
73
|
-
end
|
74
|
-
|
75
|
-
def find_by(arguments)
|
76
|
-
stubs.find { |stub| stub.arguments == arguments }
|
77
|
-
end
|
78
|
-
|
79
|
-
def reset!
|
80
|
-
tap { stubs.each(&:reset!) }
|
81
|
-
end
|
82
|
-
|
83
|
-
def call!(actual_arguments)
|
84
|
-
stub = stubs.find { |item| item.applicable_to?(actual_arguments) }
|
85
|
-
raise "Unexpected arguments #{actual_arguments}" unless stub
|
86
|
-
|
87
|
-
stub.call_next!
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
module Fixturama
|
2
|
-
#
|
3
|
-
# Factory to provide a specific action from options
|
4
|
-
#
|
5
|
-
module Stubs::Chain::Actions
|
6
|
-
extend self
|
7
|
-
|
8
|
-
require_relative "actions/raise"
|
9
|
-
require_relative "actions/return"
|
10
|
-
|
11
|
-
#
|
12
|
-
# Builds an action
|
13
|
-
# @option [#to_s] :raise
|
14
|
-
# @option [Object] :return
|
15
|
-
# @option [true] :call_original
|
16
|
-
# @return [#call] a callable action
|
17
|
-
#
|
18
|
-
def build(stub, **options)
|
19
|
-
check!(stub, options)
|
20
|
-
key, value = options.to_a.first
|
21
|
-
TYPES[key].new(stub, value)
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def check!(stub, options)
|
27
|
-
keys = options.keys & TYPES.keys
|
28
|
-
return if keys.count == 1
|
29
|
-
|
30
|
-
raise SyntaxError, <<~MESSAGE.squish
|
31
|
-
Invalid settings for stubbing message chain #{stub}: #{options}.
|
32
|
-
The action MUST have one and only one of the keys:
|
33
|
-
`#{TYPES.keys.join('`, `')}`.
|
34
|
-
MESSAGE
|
35
|
-
end
|
36
|
-
|
37
|
-
TYPES = { raise: Raise, return: Return }.freeze
|
38
|
-
end
|
39
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
class Fixturama::Stubs::Chain::Actions::Raise
|
2
|
-
def call
|
3
|
-
raise @exception
|
4
|
-
end
|
5
|
-
|
6
|
-
#
|
7
|
-
# Human-readable representation of the expectation
|
8
|
-
# @return [String]
|
9
|
-
#
|
10
|
-
def to_s
|
11
|
-
"#{@stub} # raise #{@exception}"
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
|
16
|
-
def initialize(stub, name)
|
17
|
-
@stub = stub
|
18
|
-
name = name.to_s
|
19
|
-
@exception = name == "true" ? StandardError : Kernel.const_get(name)
|
20
|
-
end
|
21
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
class Fixturama::Stubs::Chain::Actions::Return
|
2
|
-
attr_reader :stub, :call
|
3
|
-
|
4
|
-
#
|
5
|
-
# Human-readable representation of the expectation
|
6
|
-
# @return [String]
|
7
|
-
#
|
8
|
-
def to_s
|
9
|
-
"#{@stub} # => #{call}"
|
10
|
-
end
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def initialize(stub, output)
|
15
|
-
@stub = stub
|
16
|
-
@call = \
|
17
|
-
begin # in ruby 2.3.0 Fixnum#dup is defined, but raises TypeError
|
18
|
-
output.respond_to?(:dup) ? output.dup : output
|
19
|
-
rescue TypeError
|
20
|
-
output
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
module Fixturama
|
2
|
-
#
|
3
|
-
# Collection of arguments for a stub with a list of actions to be called
|
4
|
-
#
|
5
|
-
class Stubs::Chain::Arguments
|
6
|
-
attr_reader :chain, :arguments
|
7
|
-
|
8
|
-
#
|
9
|
-
# Register new action for these set of arguments
|
10
|
-
# @option [#to_i] :repeat (1)
|
11
|
-
# How much the action should be repeated during the consecutive calls
|
12
|
-
# @return [self] itself
|
13
|
-
#
|
14
|
-
def add!(*actions)
|
15
|
-
actions.each do |settings|
|
16
|
-
settings = Utils.symbolize_hash(settings)
|
17
|
-
repeat = [0, settings.fetch(:repeat, 1).to_i].max
|
18
|
-
repeat.times { list << Stubs::Chain::Actions.build(self, settings) }
|
19
|
-
end
|
20
|
-
|
21
|
-
self
|
22
|
-
end
|
23
|
-
|
24
|
-
#
|
25
|
-
# Whether the current stub is applicable to actual arguments
|
26
|
-
# @param [Array<Object>] actual_arguments
|
27
|
-
# @return [Boolean]
|
28
|
-
#
|
29
|
-
def applicable_to?(actual_arguments)
|
30
|
-
last_index = actual_arguments.count
|
31
|
-
@arguments.zip(actual_arguments)
|
32
|
-
.each.with_index(1)
|
33
|
-
.reduce(true) do |obj, ((expected, actual), index)|
|
34
|
-
obj && (
|
35
|
-
expected == actual ||
|
36
|
-
index == last_index &&
|
37
|
-
Fixturama::Utils.matched_hash_args?(actual, expected)
|
38
|
-
)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
#
|
43
|
-
# Reset the counter of calls
|
44
|
-
# @return [self] itself
|
45
|
-
#
|
46
|
-
def reset!
|
47
|
-
@counter = 0
|
48
|
-
self
|
49
|
-
end
|
50
|
-
|
51
|
-
#
|
52
|
-
# Calls the next action for these set of agruments
|
53
|
-
# @return [Object]
|
54
|
-
# @raise [StandardError]
|
55
|
-
#
|
56
|
-
def call_next!
|
57
|
-
list.fetch(counter) { list.last }.call.tap { @counter += 1 }
|
58
|
-
end
|
59
|
-
|
60
|
-
#
|
61
|
-
# Human-readable representation of arguments
|
62
|
-
# @return [String]
|
63
|
-
#
|
64
|
-
def to_s
|
65
|
-
args = [*arguments.map(&:to_s), "*"].join(", ")
|
66
|
-
"#{chain}(#{args})"
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
# @param [Fixturama::Stubs::Chain] chain Back reference
|
72
|
-
# @param [Array<Object>] list Definition of arguments
|
73
|
-
def initialize(chain, list)
|
74
|
-
@chain = chain
|
75
|
-
@arguments = Utils.array(list)
|
76
|
-
end
|
77
|
-
|
78
|
-
def counter
|
79
|
-
@counter ||= 0
|
80
|
-
end
|
81
|
-
|
82
|
-
def list
|
83
|
-
@list ||= []
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
module Fixturama
|
2
|
-
#
|
3
|
-
# Definition for stubbing a constant
|
4
|
-
#
|
5
|
-
class Stubs::Const
|
6
|
-
attr_reader :const, :value
|
7
|
-
|
8
|
-
#
|
9
|
-
# Human-readable representation of the chain
|
10
|
-
# @return [String]
|
11
|
-
#
|
12
|
-
def to_s
|
13
|
-
const.to_s
|
14
|
-
end
|
15
|
-
alias to_str to_s
|
16
|
-
alias key to_s
|
17
|
-
|
18
|
-
#
|
19
|
-
# Overload the definition for the constant
|
20
|
-
# @option [Object] value
|
21
|
-
# @return [self]
|
22
|
-
#
|
23
|
-
def update!(value:, **)
|
24
|
-
@value = value
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
|
-
#
|
29
|
-
# Apply the stub to RSpec example
|
30
|
-
# @return [self]
|
31
|
-
#
|
32
|
-
def apply!(example)
|
33
|
-
example.send(:stub_const, const, value)
|
34
|
-
self
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def initialize(const:, **)
|
40
|
-
@const = const.to_s
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
@@ -1,98 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# Stubbed request
|
3
|
-
#
|
4
|
-
class Fixturama::Stubs::Request
|
5
|
-
require_relative "request/response"
|
6
|
-
require_relative "request/responses"
|
7
|
-
|
8
|
-
def to_s
|
9
|
-
"#{http_method.upcase} #{uri.to_s == "" ? "*" : uri}"
|
10
|
-
end
|
11
|
-
alias to_str to_s
|
12
|
-
|
13
|
-
# every stub is unique
|
14
|
-
alias key hash
|
15
|
-
def update!(_); end
|
16
|
-
|
17
|
-
def apply!(example)
|
18
|
-
stub = example.stub_request(http_method, uri)
|
19
|
-
stub = stub.with(request) if request.any?
|
20
|
-
stub.to_return { |_| responses.next }
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
attr_reader :options
|
26
|
-
|
27
|
-
def initialize(options)
|
28
|
-
@options = options
|
29
|
-
with_error { @options = Hash(options).symbolize_keys }
|
30
|
-
end
|
31
|
-
|
32
|
-
HTTP_METHODS = %i[get post put patch delete head options any].freeze
|
33
|
-
|
34
|
-
def http_method
|
35
|
-
value = with_error("method") { options[:method]&.to_sym&.downcase } || :any
|
36
|
-
return value if HTTP_METHODS.include?(value)
|
37
|
-
|
38
|
-
raise ArgumentError, "Invalid HTTP method #{value} in #{@optons}"
|
39
|
-
end
|
40
|
-
|
41
|
-
def uri
|
42
|
-
with_error("uri") { maybe_regexp(options[:uri] || options[:url]) }
|
43
|
-
end
|
44
|
-
|
45
|
-
def headers
|
46
|
-
with_error("headers") do
|
47
|
-
Hash(options[:headers]).transform_keys(&:to_s) if options.key?(:headers)
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
def query
|
52
|
-
with_error("query") do
|
53
|
-
Hash(options[:query]).transform_keys(&:to_s) if options.key?(:query)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def body
|
58
|
-
with_error("body") do
|
59
|
-
case options[:body]
|
60
|
-
when NilClass then nil
|
61
|
-
when Hash then options[:body]
|
62
|
-
else maybe_regexp(options[:body])
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def basic_auth
|
68
|
-
with_error("basic auth") do
|
69
|
-
value = options[:auth] || options[:basic_auth]
|
70
|
-
Hash(value).transform_keys(&:to_s).values_at("user", "pass") if value
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def request
|
75
|
-
@request ||= {
|
76
|
-
headers: headers,
|
77
|
-
body: body,
|
78
|
-
query: query,
|
79
|
-
basic_auth: basic_auth
|
80
|
-
}.select { |_, val| val }
|
81
|
-
end
|
82
|
-
|
83
|
-
def responses
|
84
|
-
@responses ||= Responses.new(options[:response] || options[:responses])
|
85
|
-
end
|
86
|
-
|
87
|
-
def with_error(part = nil)
|
88
|
-
yield
|
89
|
-
rescue RuntimeError
|
90
|
-
message = ["Cannot extract a request", part, "from #{options}"].join(" ")
|
91
|
-
raise ArgumentError, message, __FILE__, __LINE__ - 1
|
92
|
-
end
|
93
|
-
|
94
|
-
def maybe_regexp(str)
|
95
|
-
str = str.to_s
|
96
|
-
str[%r{\A/.*/\z}] ? Regexp.new(str[1..-2]) : str
|
97
|
-
end
|
98
|
-
end
|