pacto 0.3.0.pre → 0.3.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 (111) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rubocop-todo.yml +0 -27
  4. data/.rubocop.yml +9 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +4 -5
  8. data/CONTRIBUTING.md +112 -0
  9. data/Gemfile +5 -0
  10. data/Guardfile +18 -13
  11. data/README.md +157 -101
  12. data/Rakefile +3 -3
  13. data/features/configuration/strict_matchers.feature +97 -0
  14. data/features/evolve/README.md +11 -0
  15. data/features/evolve/existing_services.feature +82 -0
  16. data/features/generate/README.md +5 -0
  17. data/features/generate/generation.feature +28 -0
  18. data/features/steps/pacto_steps.rb +75 -0
  19. data/features/stub/README.md +2 -0
  20. data/features/stub/templates.feature +46 -0
  21. data/features/support/env.rb +11 -5
  22. data/features/validate/README.md +1 -0
  23. data/features/validate/body_only.feature +85 -0
  24. data/features/{journeys/validation.feature → validate/meta_validation.feature} +41 -24
  25. data/features/validate/validation.feature +36 -0
  26. data/lib/pacto.rb +61 -33
  27. data/lib/pacto/contract.rb +18 -15
  28. data/lib/pacto/contract_factory.rb +14 -11
  29. data/lib/pacto/contract_files.rb +17 -0
  30. data/lib/pacto/contract_list.rb +17 -0
  31. data/lib/pacto/contract_validator.rb +29 -0
  32. data/lib/pacto/core/configuration.rb +19 -17
  33. data/lib/pacto/core/contract_registry.rb +43 -0
  34. data/lib/pacto/core/{callback.rb → hook.rb} +3 -3
  35. data/lib/pacto/core/modes.rb +33 -0
  36. data/lib/pacto/core/validation_registry.rb +45 -0
  37. data/lib/pacto/erb_processor.rb +0 -1
  38. data/lib/pacto/extensions.rb +18 -4
  39. data/lib/pacto/generator.rb +34 -49
  40. data/lib/pacto/generator/filters.rb +41 -0
  41. data/lib/pacto/hooks/erb_hook.rb +4 -3
  42. data/lib/pacto/logger.rb +4 -2
  43. data/lib/pacto/meta_schema.rb +4 -2
  44. data/lib/pacto/rake_task.rb +28 -25
  45. data/lib/pacto/request_clause.rb +43 -0
  46. data/lib/pacto/request_pattern.rb +8 -0
  47. data/lib/pacto/response_clause.rb +15 -0
  48. data/lib/pacto/rspec.rb +102 -0
  49. data/lib/pacto/stubs/uri_pattern.rb +23 -0
  50. data/lib/pacto/stubs/webmock_adapter.rb +69 -0
  51. data/lib/pacto/stubs/webmock_helper.rb +71 -0
  52. data/lib/pacto/ui.rb +7 -0
  53. data/lib/pacto/uri.rb +9 -0
  54. data/lib/pacto/validation.rb +57 -0
  55. data/lib/pacto/validators/body_validator.rb +41 -0
  56. data/lib/pacto/validators/request_body_validator.rb +23 -0
  57. data/lib/pacto/validators/response_body_validator.rb +23 -0
  58. data/lib/pacto/validators/response_header_validator.rb +49 -0
  59. data/lib/pacto/validators/response_status_validator.rb +24 -0
  60. data/lib/pacto/version.rb +1 -1
  61. data/pacto.gemspec +33 -29
  62. data/resources/contract_schema.json +8 -176
  63. data/resources/draft-03.json +174 -0
  64. data/spec/integration/data/strict_contract.json +2 -2
  65. data/spec/integration/e2e_spec.rb +22 -31
  66. data/spec/integration/rspec_spec.rb +94 -0
  67. data/spec/integration/templating_spec.rb +9 -12
  68. data/{lib → spec}/pacto/server.rb +0 -0
  69. data/{lib → spec}/pacto/server/dummy.rb +11 -8
  70. data/{lib → spec}/pacto/server/playback_servlet.rb +1 -1
  71. data/spec/spec_helper.rb +2 -0
  72. data/spec/unit/hooks/erb_hook_spec.rb +15 -15
  73. data/spec/unit/pacto/configuration_spec.rb +2 -10
  74. data/spec/unit/pacto/contract_factory_spec.rb +16 -13
  75. data/spec/unit/pacto/contract_files_spec.rb +42 -0
  76. data/spec/unit/pacto/contract_list_spec.rb +35 -0
  77. data/spec/unit/pacto/contract_spec.rb +43 -44
  78. data/spec/unit/pacto/contract_validator_spec.rb +85 -0
  79. data/spec/unit/pacto/core/configuration_spec.rb +4 -11
  80. data/spec/unit/pacto/core/contract_registry_spec.rb +119 -0
  81. data/spec/unit/pacto/core/modes_spec.rb +18 -0
  82. data/spec/unit/pacto/core/validation_registry_spec.rb +76 -0
  83. data/spec/unit/pacto/core/validation_spec.rb +60 -0
  84. data/spec/unit/pacto/extensions_spec.rb +14 -23
  85. data/spec/unit/pacto/generator/filters_spec.rb +99 -0
  86. data/spec/unit/pacto/generator_spec.rb +34 -73
  87. data/spec/unit/pacto/meta_schema_spec.rb +46 -6
  88. data/spec/unit/pacto/pacto_spec.rb +17 -15
  89. data/spec/unit/pacto/{request_spec.rb → request_clause_spec.rb} +32 -44
  90. data/spec/unit/pacto/request_pattern_spec.rb +22 -0
  91. data/spec/unit/pacto/response_clause_spec.rb +54 -0
  92. data/spec/unit/pacto/stubs/uri_pattern_spec.rb +28 -0
  93. data/spec/unit/pacto/stubs/webmock_adapter_spec.rb +205 -0
  94. data/spec/unit/pacto/stubs/webmock_helper_spec.rb +20 -0
  95. data/spec/unit/pacto/uri_spec.rb +20 -0
  96. data/spec/unit/pacto/validators/body_validator_spec.rb +105 -0
  97. data/spec/unit/pacto/validators/response_header_validator_spec.rb +94 -0
  98. data/spec/unit/pacto/validators/response_status_validator_spec.rb +20 -0
  99. metadata +230 -146
  100. data/features/generation/generation.feature +0 -25
  101. data/lib/pacto/core/contract_repository.rb +0 -44
  102. data/lib/pacto/hash_merge_processor.rb +0 -14
  103. data/lib/pacto/request.rb +0 -57
  104. data/lib/pacto/response.rb +0 -63
  105. data/lib/pacto/response_adapter.rb +0 -24
  106. data/lib/pacto/stubs/built_in.rb +0 -57
  107. data/spec/unit/pacto/core/contract_repository_spec.rb +0 -133
  108. data/spec/unit/pacto/hash_merge_processor_spec.rb +0 -20
  109. data/spec/unit/pacto/response_adapter_spec.rb +0 -25
  110. data/spec/unit/pacto/response_spec.rb +0 -201
  111. data/spec/unit/pacto/stubs/built_in_spec.rb +0 -168
@@ -21,8 +21,8 @@
21
21
  "items": {
22
22
  "type": "string",
23
23
  "required": true,
24
- "default": "/dev/<%= device_id %>",
25
- "pattern": "^/dev/[^/]+(/[^/]+)*$"
24
+ "default": "/dev/<%= values[:device_id].tap do values[:device_id] = values[:device_id] + 1 end %>",
25
+ "pattern": "^/dev/[\\d]+$"
26
26
  },
27
27
  "required": true,
28
28
  "uniqueItems": true
@@ -17,23 +17,18 @@ describe 'Pacto' do
17
17
  end
18
18
 
19
19
  it 'verifies the contract against a producer' do
20
- contract = Pacto.build_from_file(contract_path, 'http://localhost:8000')
21
- expect(contract.validate).to be_empty
20
+ contract = Pacto.load_contracts(contract_path, 'http://localhost:8000')
21
+ expect(contract.validate_all.flatten).to eq([])
22
22
  end
23
23
  end
24
24
 
25
- context 'Stub generation' do
26
- it 'generates a stub to be used by a consumer' do
27
- contract = Pacto.build_from_file(contract_path, 'http://dummyprovider.com')
28
- Pacto.register_contract(contract, 'my_tag')
29
- Pacto.use('my_tag')
30
- expect(response.keys).to eq ['message']
31
- expect(response['message']).to be_kind_of(String)
32
- end
25
+ context 'Stubbing a collection of contracts' do
26
+ it 'generates a server that stubs the contract for consumers' do
27
+ contracts = Pacto.load_contracts(contract_path, 'http://dummyprovider.com')
28
+ contracts.stub_all
33
29
 
34
- let :response do
35
- raw_response = HTTParty.get('http://dummyprovider.com/hello', headers: {'Accept' => 'application/json' })
36
- MultiJson.load(raw_response.body)
30
+ response = get_json('http://dummyprovider.com/hello')
31
+ expect(response['message']).to eq 'bar'
37
32
  end
38
33
  end
39
34
 
@@ -41,31 +36,27 @@ describe 'Pacto' do
41
36
  it 'stubs multiple services with a single use' do
42
37
  Pacto.configure do |c|
43
38
  c.strict_matchers = false
44
- c.postprocessor = Pacto::ERBProcessor.new
45
- c.preprocessor = nil
46
- c.register_callback Pacto::Hooks::ERBHook.new
47
- end
48
-
49
- # Preprocessor must be off before building!
50
- login_contract = Pacto.build_from_file(contract_path, 'http://dummyprovider.com')
51
- contract = Pacto.build_from_file(strict_contract_path, 'http://dummyprovider.com')
52
- Pacto.configure do |c|
53
- c.register_contract login_contract, :default
54
- c.register_contract contract, :devices
39
+ c.register_hook Pacto::Hooks::ERBHook.new
55
40
  end
56
41
 
57
- Pacto.use(:devices, {:device_id => 42})
42
+ contracts = Pacto.load_contracts 'spec/integration/data/', 'http://dummyprovider.com'
43
+ contracts.stub_all(:device_id => 42)
58
44
 
59
- raw_response = HTTParty.get('http://dummyprovider.com/hello', headers: {'Accept' => 'application/json' })
60
- login_response = MultiJson.load(raw_response.body)
45
+ login_response = get_json('http://dummyprovider.com/hello')
61
46
  expect(login_response.keys).to eq ['message']
62
47
  expect(login_response['message']).to be_kind_of(String)
63
48
 
64
- devices_response = HTTParty.get('http://dummyprovider.com/strict', headers: {'Accept' => 'application/json' })
65
- devices_response = MultiJson.load(devices_response.body)
49
+ devices_response = get_json('http://dummyprovider.com/strict')
66
50
  expect(devices_response['devices']).to have(2).items
67
- expect(devices_response['devices'][0]).to eq '/dev/42'
68
- # devices_response['devices'][1].should == '/dev/43'
51
+ expect(devices_response['devices'][0]).to eq('/dev/42')
52
+ expect(devices_response['devices'][1]).to eq('/dev/43')
53
+ end
54
+ end
55
+
56
+ def get_json(url)
57
+ response = Faraday.get(url) do |req|
58
+ req.headers = {'Accept' => 'application/json' }
69
59
  end
60
+ MultiJson.load(response.body)
70
61
  end
71
62
  end
@@ -0,0 +1,94 @@
1
+ require 'pacto/rspec'
2
+
3
+ describe 'pacto/rspec' do
4
+ let(:contract_path) { 'spec/integration/data/simple_contract.json' }
5
+ let(:strict_contract_path) { 'spec/integration/data/strict_contract.json' }
6
+
7
+ before :all do
8
+ WebMock.allow_net_connect!
9
+ @server = Pacto::Server::Dummy.new 8000, '/hello', '{"message": "Hello World!"}'
10
+ @server.start
11
+ end
12
+
13
+ after :all do
14
+ @server.terminate
15
+ end
16
+
17
+ def expect_to_raise(message_pattern = nil, &blk)
18
+ expect { blk.call }.to raise_error(RSpec::Expectations::ExpectationNotMetError, message_pattern)
19
+ end
20
+
21
+ def json_response(url)
22
+ response = Faraday.get(url) do |req|
23
+ req.headers = {'Accept' => 'application/json' }
24
+ end
25
+ MultiJson.load(response.body)
26
+ end
27
+
28
+ context 'successful validations' do
29
+ let(:contracts) do
30
+ Pacto.load_contracts 'spec/integration/data/', 'http://dummyprovider.com'
31
+ end
32
+
33
+ before(:each) do
34
+ Pacto.configure do |c|
35
+ c.strict_matchers = false
36
+ c.register_hook Pacto::Hooks::ERBHook.new
37
+ end
38
+
39
+ contracts.stub_all(:device_id => 42)
40
+ Pacto.validate!
41
+
42
+ Faraday.get('http://dummyprovider.com/hello') do |req|
43
+ req.headers = {'Accept' => 'application/json' }
44
+ end
45
+ end
46
+
47
+ it 'performs successful assertions' do
48
+ # High level assertions
49
+ expect(Pacto).to_not have_unmatched_requests
50
+ expect(Pacto).to_not have_failed_validations
51
+
52
+ # Increasingly strict assertions
53
+ expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/hello')
54
+ expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/hello').with(:headers => {'Accept' => 'application/json'})
55
+ expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/hello').against_contract(/simple_contract.json/)
56
+ end
57
+
58
+ it 'supports negative assertions' do
59
+ expect(Pacto).to_not have_validated(:get, 'http://dummyprovider.com/strict')
60
+ Faraday.get('http://dummyprovider.com/strict') do |req|
61
+ req.headers = {'Accept' => 'application/json' }
62
+ end
63
+ expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/strict')
64
+ end
65
+
66
+ it 'raises useful error messages' do
67
+ # High level error messages
68
+ expect_to_raise(/Expected Pacto to have not matched all requests to a Contract, but all requests were matched/) { expect(Pacto).to have_unmatched_requests }
69
+ expect_to_raise(/Expected Pacto to have found validation problems, but none were found/) { expect(Pacto).to have_failed_validations }
70
+
71
+ unmatched_url = 'http://localhost:8000/404'
72
+ Faraday.get unmatched_url
73
+ expect_to_raise(/the following requests were not matched.*#{Regexp.quote unmatched_url}/m) { expect(Pacto).to_not have_unmatched_requests }
74
+
75
+ # Expected failures
76
+ expect_to_raise(/no matching request was received/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/hello').with(:headers => {'Accept' => 'text/plain'}) }
77
+ # No support for with accepting a block
78
+ # expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/hello').with { |req| req.body == "abc" }
79
+ expect_to_raise(/but it was validated against/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/hello').against_contract(/strict_contract.json/) }
80
+ expect_to_raise(/but it was validated against/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/hello').against_contract('simple_contract.json') }
81
+ expect_to_raise(/but no matching request was received/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/strict') }
82
+ end
83
+
84
+ it 'displays Contract validation problems' do
85
+ contracts.stub_all(:device_id => 1.5)
86
+ Faraday.get('http://dummyprovider.com/strict') do |req|
87
+ req.headers = {'Accept' => 'application/json' }
88
+ end
89
+ expect_to_raise(/validation errors were found:/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/strict') }
90
+
91
+ expect_to_raise(/but the following issues were found:/) { expect(Pacto).to_not have_failed_validations }
92
+ end
93
+ end
94
+ end
@@ -1,36 +1,34 @@
1
1
  require 'securerandom'
2
- require 'pacto/erb_processor'
3
2
 
4
3
  describe 'Templating' do
5
4
  let(:contract_path) { 'spec/integration/data/templating_contract.json' }
5
+ let(:contracts) { Pacto.load_contracts(contract_path, 'http://dummyprovider.com') }
6
6
 
7
7
  let(:key) { SecureRandom.hex }
8
8
  let(:auth_token) { SecureRandom.hex }
9
+
9
10
  let :response do
10
- contract = Pacto.build_from_file(contract_path, 'http://dummyprovider.com')
11
- Pacto.register_contract(contract, 'my_contract')
12
- Pacto.use('my_contract', {:key => key, :auth_token => auth_token})
11
+ contracts.stub_all(:key => key, :auth_token => auth_token)
13
12
 
14
- raw_response = HTTParty.get('http://dummyprovider.com/echo', headers: {
13
+ raw_response = Faraday.get('http://dummyprovider.com/echo') do |req|
14
+ req.headers = {
15
15
  'Accept' => 'application/json',
16
16
  'Custom-Auth-Token' => "#{auth_token}",
17
17
  'X-Message' => "#{key}"
18
18
  }
19
- )
19
+ end
20
20
  MultiJson.load(raw_response.body)
21
21
  end
22
22
 
23
23
  before :each do
24
- Pacto.unregister_all!
24
+ Pacto.clear!
25
25
  end
26
26
 
27
27
  context 'No processing' do
28
28
  it 'does not proccess erb tag' do
29
29
  Pacto.configure do |c|
30
- c.preprocessor = nil
31
- c.postprocessor = nil
32
30
  c.strict_matchers = false
33
- c.register_callback do |contracts, req, res|
31
+ c.register_hook do |contracts, req, res|
34
32
  res
35
33
  end
36
34
  end
@@ -43,9 +41,8 @@ describe 'Templating' do
43
41
  context 'Post processing' do
44
42
  it 'processes erb on each request' do
45
43
  Pacto.configure do |c|
46
- c.preprocessor = nil
47
44
  c.strict_matchers = false
48
- c.postprocessor = Pacto::ERBProcessor.new
45
+ c.register_hook Pacto::Hooks::ERBHook.new
49
46
  end
50
47
 
51
48
  expect(response.keys).to eq ['message']
File without changes
@@ -6,25 +6,25 @@ module Pacto
6
6
  class Servlet < WEBrick::HTTPServlet::AbstractServlet
7
7
  extend Forwardable
8
8
 
9
- def initialize server, json
9
+ def initialize(server, json)
10
10
  super(server)
11
11
 
12
- @doer = PlaybackServlet.new({
12
+ @doer = PlaybackServlet.new(
13
13
  status: 200,
14
- headers: {'Content-Type' => 'application/json'},
14
+ headers: {'Content-Type' => 'application/json', 'Vary' => 'Accept'},
15
15
  body: json
16
- })
16
+ )
17
17
  end
18
18
 
19
- def_delegator :@doer, :do_GET
19
+ def_delegator :@doer, :do_GET # rubocop:disable SymbolName
20
20
  end
21
21
 
22
22
  class Dummy
23
- def initialize port, path, response
23
+ def initialize(port, path, response)
24
24
  params = {
25
25
  :Port => port,
26
26
  :AccessLog => [],
27
- :Logger => WEBrick::Log::new('/dev/null', 7)
27
+ :Logger => WEBrick::Log.new('/dev/null', 7)
28
28
  }
29
29
  @server = WEBrick::HTTPServer.new params
30
30
  @server.mount path, Servlet, response
@@ -32,12 +32,15 @@ module Pacto
32
32
 
33
33
  def start
34
34
  @pid = Thread.new do
35
- trap 'INT' do @server.shutdown end
35
+ trap 'INT' do
36
+ @server.shutdown
37
+ end
36
38
  @server.start
37
39
  end
38
40
  end
39
41
 
40
42
  def terminate
43
+ @server.shutdown
41
44
  @pid.kill
42
45
  end
43
46
  end
@@ -9,7 +9,7 @@ module Pacto
9
9
  @body = attributes.fetch(:body, nil)
10
10
  end
11
11
 
12
- def do_GET(request, response)
12
+ def do_GET(request, response) # rubocop:disable MethodName
13
13
  response.status = status
14
14
  headers.each do |key, value|
15
15
  response[key] = value
@@ -1,7 +1,9 @@
1
1
  require 'coveralls_helper'
2
+ require 'webmock/rspec'
2
3
  require 'pacto'
3
4
  require 'pacto/server'
4
5
  require 'stringio'
6
+ require 'rspec'
5
7
  require 'should_not/rspec'
6
8
 
7
9
  RSpec.configure do |config|
@@ -1,14 +1,14 @@
1
1
  describe Pacto::Hooks::ERBHook do
2
2
  describe '#process' do
3
- let(:req) {
4
- OpenStruct.new({:headers => {'User-Agent' => 'abcd'}})
5
- }
6
- let(:converted_req) {
3
+ let(:req) do
4
+ OpenStruct.new(:headers => {'User-Agent' => 'abcd'})
5
+ end
6
+ let(:converted_req) do
7
7
  {'HEADERS' => {'User-Agent' => 'abcd'}}
8
- }
9
- let(:res) {
10
- OpenStruct.new({:body => 'before'})
11
- }
8
+ end
9
+ let(:res) do
10
+ OpenStruct.new(:body => 'before')
11
+ end
12
12
 
13
13
  before do
14
14
  end
@@ -16,7 +16,7 @@ describe Pacto::Hooks::ERBHook do
16
16
  context 'no matching contracts' do
17
17
  it 'binds the request' do
18
18
  contracts = Set.new
19
- mock_erb({ :req => converted_req })
19
+ mock_erb(:req => converted_req)
20
20
  described_class.new.process contracts, req, res
21
21
  expect(res.body).to eq('after')
22
22
  end
@@ -24,9 +24,9 @@ describe Pacto::Hooks::ERBHook do
24
24
 
25
25
  context 'one matching contract' do
26
26
  it 'binds the request and the contract\'s values' do
27
- contract = OpenStruct.new({:values => {:max => 'test'}})
27
+ contract = OpenStruct.new(:values => {:max => 'test'})
28
28
  contracts = Set.new([contract])
29
- mock_erb({ :req => converted_req, :max => 'test'})
29
+ mock_erb(:req => converted_req, :max => 'test')
30
30
  described_class.new.process contracts, req, res
31
31
  expect(res.body).to eq('after')
32
32
  end
@@ -34,10 +34,10 @@ describe Pacto::Hooks::ERBHook do
34
34
 
35
35
  context 'multiple matching contracts' do
36
36
  it 'binds the request and the first contract\'s values' do
37
- contract1 = OpenStruct.new({:values => {:max => 'test'}})
38
- contract2 = OpenStruct.new({:values => {:mob => 'team'}})
39
- res = OpenStruct.new({:body => 'before'})
40
- mock_erb({ :req => converted_req, :max => 'test'})
37
+ contract1 = OpenStruct.new(:values => {:max => 'test'})
38
+ contract2 = OpenStruct.new(:values => {:mob => 'team'})
39
+ res = OpenStruct.new(:body => 'before')
40
+ mock_erb(:req => converted_req, :max => 'test')
41
41
  contracts = Set.new([contract1, contract2])
42
42
  described_class.new.process contracts, req, res
43
43
  expect(res.body).to eq('after')
@@ -3,16 +3,8 @@ module Pacto
3
3
  subject(:configuration) { Configuration.new }
4
4
  let(:contracts_path) { 'path_to_contracts' }
5
5
 
6
- it 'sets the preprocessor by default to ERBProcessor' do
7
- expect(configuration.preprocessor).to be_kind_of ERBProcessor
8
- end
9
-
10
- it 'sets the postprocessor by default to HashMergeProcessor' do
11
- expect(configuration.postprocessor).to be_kind_of HashMergeProcessor
12
- end
13
-
14
- it 'sets the stub provider by default to BuiltIn' do
15
- expect(configuration.provider).to be_kind_of Stubs::BuiltIn
6
+ it 'sets the stub provider by default to WebMockAdapter' do
7
+ expect(configuration.provider).to be_kind_of Stubs::WebMockAdapter
16
8
  end
17
9
 
18
10
  it 'sets strict matchers by default to true' do
@@ -1,20 +1,23 @@
1
+ require 'spec_helper'
2
+
1
3
  module Pacto
2
4
  describe ContractFactory do
3
- let(:host) { 'http://localhost' }
4
- let(:contract_name) { 'contract' }
5
- let(:contract_path) { File.join('spec', 'unit', 'data', "#{contract_name}.json") }
6
- let(:file_pre_processor) { double('file_pre_processor') }
7
- let(:file_content) { File.read(contract_path) }
5
+ let(:host) { 'http://localhost' }
6
+ let(:contract_name) { 'contract' }
7
+ let(:contracts_path) { %w(spec unit data) }
8
+ let(:contract_path) { File.join(contracts_path, "#{contract_name}.json") }
9
+ subject(:contract_factory) { ContractFactory.new }
8
10
 
9
- describe '.build_from_file' do
10
- it 'builds a contract given a JSON file path and a host' do
11
- file_pre_processor.stub(:process).and_return(file_content)
12
- expect(described_class.build_from_file(contract_path, host, file_pre_processor)).to be_a_kind_of(Pacto::Contract)
13
- end
11
+ it 'builds a contract given a JSON file path and a host' do
12
+ contract = contract_factory.build_from_file(contract_path, host)
13
+ expect(contract).to be_a(Contract)
14
+ end
14
15
 
15
- it 'processes files using File Pre Processor module' do
16
- file_pre_processor.should_receive(:process).with(file_content).and_return(file_content)
17
- described_class.build_from_file(contract_path, host, file_pre_processor)
16
+ it 'builds contracts from a list of file paths and a host' do
17
+ contract_files = [contract_path, contract_path]
18
+ contracts = contract_factory.build(contract_files, host)
19
+ contracts.each do |contract|
20
+ expect(contract).to be_a(Contract)
18
21
  end
19
22
  end
20
23
  end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+
4
+ module Pacto
5
+ describe ContractFiles do
6
+ let(:test_dir) { File.join(File.dirname(__FILE__), 'temp') }
7
+ let(:contract_1) { Pathname.new(File.join(test_dir, 'contract_1.json')) }
8
+ let(:contract_2) { Pathname.new(File.join(test_dir, 'contract_2.json')) }
9
+ let(:contract_3) { Pathname.new(File.join(test_dir, 'nested', 'contract_3.json')) }
10
+
11
+ before do
12
+ Dir.mkdir(test_dir)
13
+ Dir.chdir(test_dir) do
14
+ Dir.mkdir('nested')
15
+ ['contract_1.json', 'contract_2.json', 'not_a_contract', 'nested/contract_3.json'].each do |file|
16
+ FileUtils.touch file
17
+ end
18
+ end
19
+ end
20
+
21
+ after do
22
+ FileUtils.rm_rf(test_dir)
23
+ end
24
+
25
+ describe 'for a dir' do
26
+ it 'returns a list with the full path of all json found recursively in that dir' do
27
+ files = ContractFiles.for(test_dir)
28
+ expect(files.size).to eq(3)
29
+ expect(files).to include(contract_1)
30
+ expect(files).to include(contract_2)
31
+ expect(files).to include(contract_3)
32
+ end
33
+ end
34
+
35
+ describe 'for a file' do
36
+ it 'returns a list containing only that file' do
37
+ files = ContractFiles.for(File.join(test_dir, 'contract_1.json'))
38
+ expect(files).to eq [contract_1]
39
+ end
40
+ end
41
+ end
42
+ end