fixturama 0.1.0 → 0.5.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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +99 -0
  3. data/README.md +76 -4
  4. data/lib/fixturama.rb +48 -20
  5. data/lib/fixturama/changes.rb +72 -0
  6. data/lib/fixturama/changes/base.rb +28 -0
  7. data/lib/fixturama/changes/chain.rb +64 -0
  8. data/lib/fixturama/changes/chain/actions.rb +31 -0
  9. data/lib/fixturama/changes/chain/arguments.rb +59 -0
  10. data/lib/fixturama/changes/chain/raise_action.rb +43 -0
  11. data/lib/fixturama/changes/chain/return_action.rb +33 -0
  12. data/lib/fixturama/changes/const.rb +30 -0
  13. data/lib/fixturama/changes/env.rb +35 -0
  14. data/lib/fixturama/changes/request.rb +91 -0
  15. data/lib/fixturama/changes/request/response.rb +62 -0
  16. data/lib/fixturama/changes/request/responses.rb +22 -0
  17. data/lib/fixturama/changes/seed.rb +39 -0
  18. data/lib/fixturama/config.rb +5 -0
  19. data/lib/fixturama/fixture_error.rb +31 -0
  20. data/lib/fixturama/loader.rb +6 -2
  21. data/lib/fixturama/loader/context.rb +14 -5
  22. data/lib/fixturama/loader/value.rb +1 -0
  23. data/lib/fixturama/version.rb +4 -0
  24. metadata +85 -73
  25. data/.gitignore +0 -12
  26. data/.rspec +0 -2
  27. data/.rubocop.yml +0 -22
  28. data/.travis.yml +0 -17
  29. data/Gemfile +0 -9
  30. data/LICENSE.txt +0 -21
  31. data/Rakefile +0 -6
  32. data/fixturama.gemspec +0 -24
  33. data/lib/fixturama/seed.rb +0 -15
  34. data/lib/fixturama/stubs.rb +0 -79
  35. data/lib/fixturama/stubs/chain.rb +0 -90
  36. data/lib/fixturama/stubs/chain/actions.rb +0 -39
  37. data/lib/fixturama/stubs/chain/actions/raise.rb +0 -21
  38. data/lib/fixturama/stubs/chain/actions/return.rb +0 -23
  39. data/lib/fixturama/stubs/chain/arguments.rb +0 -86
  40. data/lib/fixturama/stubs/const.rb +0 -43
  41. data/lib/fixturama/stubs/request.rb +0 -98
  42. data/lib/fixturama/stubs/request/response.rb +0 -43
  43. data/lib/fixturama/stubs/request/responses.rb +0 -20
  44. data/lib/fixturama/utils.rb +0 -39
  45. data/spec/fixturama/load_fixture/_spec.rb +0 -53
  46. data/spec/fixturama/load_fixture/data.json +0 -5
  47. data/spec/fixturama/load_fixture/data.yaml +0 -3
  48. data/spec/fixturama/load_fixture/data.yml +0 -3
  49. data/spec/fixturama/seed_fixture/_spec.rb +0 -36
  50. data/spec/fixturama/seed_fixture/seed.yml +0 -16
  51. data/spec/fixturama/stub_fixture/_spec.rb +0 -120
  52. data/spec/fixturama/stub_fixture/stub.yml +0 -73
  53. data/spec/spec_helper.rb +0 -26
@@ -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
@@ -1,43 +0,0 @@
1
- class Fixturama::Stubs::Request
2
- class Response
3
- def to_h
4
- { status: status, body: body, headers: headers }.select { |_, val| val }
5
- end
6
-
7
- private
8
-
9
- def initialize(options)
10
- @options = options
11
- @options = with_error { Hash(options).transform_keys(&:to_sym) }
12
- end
13
-
14
- attr_reader :options
15
-
16
- def status
17
- with_error("status") { options[:status]&.to_i } || 200
18
- end
19
-
20
- def body
21
- with_error("body") do
22
- case options[:body]
23
- when NilClass then nil
24
- when Hash then JSON.dump(options[:body])
25
- else options[:body].to_s
26
- end
27
- end
28
- end
29
-
30
- def headers
31
- with_error("headers") do
32
- Hash(options[:headers]).map { |k, v| [k.to_s, v.to_s] }.to_h
33
- end
34
- end
35
-
36
- def with_error(part = nil)
37
- yield
38
- rescue RuntimeError
39
- text = ["Cannot extract a response", part, "from #{options}"].join(" ")
40
- raise ArgumentError, text, __FILE__, __LINE__ - 1
41
- end
42
- end
43
- end
@@ -1,20 +0,0 @@
1
- class Fixturama::Stubs::Request
2
- class Responses
3
- def next
4
- list.count > @count ? list[@count].tap { @count += 1 } : list.last
5
- end
6
-
7
- private
8
-
9
- def initialize(list)
10
- @count = 0
11
- list ||= [{ status: 200 }]
12
- @list = case list
13
- when Array then list.map { |item| Response.new(item).to_h }
14
- else [Response.new(list).to_h]
15
- end
16
- end
17
-
18
- attr_reader :list
19
- end
20
- end
@@ -1,39 +0,0 @@
1
- module Fixturama
2
- module Utils
3
- module_function
4
-
5
- def symbolize(item)
6
- item.to_s.to_sym
7
- end
8
-
9
- def symbolize_hash(data)
10
- Hash(data).transform_keys { |key| symbolize(key)}
11
- end
12
-
13
- def symbolize_array(data)
14
- Array(data).map { |item| symbolize(item) }
15
- end
16
-
17
- def constantize(item)
18
- Kernel.const_get(item.to_s)
19
- end
20
-
21
- def clone(item)
22
- item.respond_to?(:dup) ? item.dup : item
23
- end
24
-
25
- def array(list)
26
- case list
27
- when NilClass then []
28
- when Array then list
29
- else [list]
30
- end
31
- end
32
-
33
- def matched_hash_args?(actual, expected)
34
- return unless actual.is_a?(Hash) && expected.is_a?(Hash)
35
-
36
- expected.all? { |key, val| actual[key] == val }
37
- end
38
- end
39
- end
@@ -1,53 +0,0 @@
1
- RSpec.describe "load_fixture" do
2
- let(:expected) { { "foo" => { "bar" => 42 } } }
3
-
4
- context "YAML" do
5
- subject { load_fixture("#{__dir__}/data.yaml", id: 42) }
6
-
7
- it { is_expected.to eq expected }
8
- end
9
-
10
- context "YML" do
11
- subject { load_fixture("#{__dir__}/data.yml", id: 42) }
12
-
13
- it { is_expected.to eq expected }
14
- end
15
-
16
- context "YAML with ruby object" do
17
- subject { load_fixture("#{__dir__}/data.yaml", id: foobar) }
18
-
19
- before { class Test::Foobar; end }
20
-
21
- let(:foobar) { Test::Foobar.new }
22
- let(:expected) { { "foo" => { "bar" => foobar } } }
23
-
24
- it { is_expected.to eq expected }
25
- end
26
-
27
- context "JSON" do
28
- subject { load_fixture("#{__dir__}/data.json", id: 42) }
29
-
30
- it { is_expected.to eq expected }
31
- end
32
-
33
- context "JSON with ruby object" do
34
- subject { load_fixture("#{__dir__}/data.json", id: foobar) }
35
-
36
- before { class Test::Foobar; end }
37
-
38
- let(:foobar) { Test::Foobar.new }
39
- let(:expected) { { "foo" => { "bar" => foobar } } }
40
-
41
- it { is_expected.to eq expected }
42
- end
43
-
44
- context "with RSpec argument matchers" do
45
- subject { load_fixture("#{__dir__}/data.yaml", id: kind_of(Numeric)) }
46
-
47
- it "loads the matcher", aggregate_failures: true do
48
- expect("foo" => { "bar" => 42 }).to include subject
49
- expect("foo" => { "bar" => 99 }).to include subject
50
- expect("foo" => { "bar" => :a }).not_to include subject
51
- end
52
- end
53
- end
@@ -1,5 +0,0 @@
1
- {
2
- "foo": {
3
- "bar": <%= id %>
4
- }
5
- }
@@ -1,3 +0,0 @@
1
- ---
2
- foo:
3
- bar: <%= id %>
@@ -1,3 +0,0 @@
1
- ---
2
- foo:
3
- bar: <%= id %>
@@ -1,36 +0,0 @@
1
- RSpec.describe "seed_fixture" do
2
- subject { seed_fixture "#{__dir__}/seed.yml" }
3
-
4
- before do
5
- FactoryBot.define do
6
- factory :foo, class: Hash do
7
- transient do
8
- bar { 0 }
9
- baz { 0 }
10
- qux { 0 }
11
- end
12
-
13
- trait :bar do
14
- bar { 99 }
15
- end
16
-
17
- trait :baz do
18
- baz { 77 }
19
- end
20
-
21
- skip_create
22
- initialize_with { { bar: bar, baz: baz, qux: qux } }
23
- end
24
- end
25
- end
26
-
27
- it "runs the factory", aggregate_failures: true do
28
- expect(FactoryBot).to receive(:create_list).with(:foo, 1, :baz, qux: 42)
29
- expect(FactoryBot).to receive(:create_list) do |*args, **opts|
30
- expect(args).to eq [:foo, 3, :bar]
31
- expect(opts).to be_empty
32
- end
33
-
34
- subject
35
- end
36
- end
@@ -1,16 +0,0 @@
1
- ---
2
- - type: foo
3
- traits:
4
- - baz
5
- params:
6
- qux: 42
7
-
8
- - type: foo
9
- count: 3
10
- traits:
11
- - bar
12
-
13
- - type: foo
14
- count: 0
15
- traits:
16
- - baz
@@ -1,120 +0,0 @@
1
- RSpec.describe "stub_fixture" do
2
- subject { arguments.map { |argument| Payment.new.pay(argument) } }
3
-
4
- before do
5
- class Payment
6
- def pay(_)
7
- 5
8
- end
9
- end
10
- end
11
-
12
- context "without stubbing" do
13
- let(:arguments) { [0] }
14
-
15
- it { is_expected.to eq [5] }
16
- end
17
-
18
- context "when message chain stubbed" do
19
- before { stub_fixture "#{__dir__}/stub.yml" }
20
-
21
- context "with a :raise option" do
22
- let(:arguments) { [0] }
23
-
24
- it "raises an exception" do
25
- expect { subject }.to raise_error ArgumentError
26
- end
27
- end
28
-
29
- context "with a :return option" do
30
- let(:arguments) { [1] }
31
-
32
- it "returns stubbed value" do
33
- expect(subject).to eq [8]
34
- end
35
- end
36
-
37
- context "with several actions" do
38
- let(:arguments) { [2] * 4 }
39
-
40
- it "calls the consecutive actions and then repeates the last one" do
41
- expect(subject).to eq [4, 2, 0, 0]
42
- end
43
- end
44
-
45
- context "with multi-count actions" do
46
- let(:arguments) { [3] * 4 }
47
-
48
- it "repeats the action a specified number of times" do
49
- expect(subject).to eq [6, 6, 0, 0]
50
- end
51
- end
52
-
53
- context "with several arguments" do
54
- let(:arguments) { [2, 3, 2, 3, 2, 3] }
55
-
56
- it "counts actions for every stub in isolation from the others" do
57
- expect(subject).to eq [4, 6, 2, 6, 0, 0]
58
- end
59
- end
60
-
61
- context "with partially defined options" do
62
- subject { Payment.new.pay(10, overdraft: true, notiy: true) }
63
-
64
- it "uses the stub" do
65
- expect(subject).to eq(-5)
66
- end
67
- end
68
-
69
- context "when options differ" do
70
- subject { Payment.new.pay(10, overdraft: false) }
71
-
72
- it "uses universal stub" do
73
- expect(subject).to eq(-1)
74
- end
75
- end
76
-
77
- context "with unspecified argument" do
78
- let(:arguments) { [4] }
79
-
80
- it "uses universal stub" do
81
- expect(subject).to eq [-1]
82
- end
83
- end
84
- end
85
-
86
- context "when constant stubbed" do
87
- before do
88
- TIMEOUT = 20
89
- stub_fixture "#{__dir__}/stub.yml"
90
- end
91
-
92
- it "stubs the constant" do
93
- expect(TIMEOUT).to eq 10
94
- end
95
- end
96
-
97
- context "when http request stubbed" do
98
- before { stub_fixture "#{__dir__}/stub.yml" }
99
-
100
- it "stubs the request properly" do
101
- req = Net::HTTP::Get.new("/foo")
102
- res = Net::HTTP.start("www.example.com") { |http| http.request(req) }
103
-
104
- expect(res.code).to eq "200"
105
- expect(res.body).to eq "foo"
106
- expect(res["Content-Length"]).to eq "3"
107
- end
108
-
109
- def delete_request
110
- req = Net::HTTP::Delete.new("/foo")
111
- Net::HTTP.start("www.example.com") { |http| http.request(req) }
112
- end
113
-
114
- it "stubs repetitive requests properly" do
115
- expect(delete_request.code).to eq "200"
116
- expect(delete_request.code).to eq "404"
117
- expect(delete_request.code).to eq "404"
118
- end
119
- end
120
- end