pacto 0.2.5 → 0.3.0.pre
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.
- data/.gitignore +3 -0
- data/.rspec +0 -2
- data/.rubocop-todo.yml +51 -0
- data/.rubocop.yml +1 -0
- data/.travis.yml +4 -2
- data/Guardfile +28 -14
- data/README.md +81 -51
- data/Rakefile +24 -11
- data/features/generation/generation.feature +25 -0
- data/features/journeys/validation.feature +74 -0
- data/features/support/env.rb +16 -0
- data/lib/pacto.rb +63 -34
- data/lib/pacto/contract.rb +25 -11
- data/lib/pacto/contract_factory.rb +13 -44
- data/lib/pacto/core/callback.rb +11 -0
- data/lib/pacto/core/configuration.rb +34 -0
- data/lib/pacto/core/contract_repository.rb +44 -0
- data/lib/pacto/erb_processor.rb +18 -0
- data/lib/pacto/exceptions/invalid_contract.rb +10 -1
- data/lib/pacto/extensions.rb +2 -2
- data/lib/pacto/generator.rb +75 -0
- data/lib/pacto/hash_merge_processor.rb +14 -0
- data/lib/pacto/hooks/erb_hook.rb +17 -0
- data/lib/pacto/logger.rb +42 -0
- data/lib/pacto/meta_schema.rb +17 -0
- data/lib/pacto/rake_task.rb +75 -12
- data/lib/pacto/request.rb +3 -4
- data/lib/pacto/response.rb +27 -19
- data/lib/pacto/server.rb +2 -0
- data/lib/pacto/server/dummy.rb +45 -0
- data/lib/pacto/server/playback_servlet.rb +21 -0
- data/lib/pacto/stubs/built_in.rb +57 -0
- data/lib/pacto/version.rb +1 -1
- data/pacto.gemspec +8 -2
- data/resources/contract_schema.json +216 -0
- data/spec/coveralls_helper.rb +10 -0
- data/spec/integration/data/strict_contract.json +33 -0
- data/spec/integration/data/templating_contract.json +25 -0
- data/spec/integration/e2e_spec.rb +40 -7
- data/spec/integration/templating_spec.rb +55 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/unit/data/simple_contract.json +22 -0
- data/spec/unit/hooks/erb_hook_spec.rb +51 -0
- data/spec/unit/pacto/configuration_spec.rb +51 -0
- data/spec/unit/pacto/contract_factory_spec.rb +4 -35
- data/spec/unit/pacto/contract_spec.rb +59 -31
- data/spec/unit/pacto/core/configuration_spec.rb +28 -0
- data/spec/unit/pacto/core/contract_repository_spec.rb +133 -0
- data/spec/unit/pacto/erb_processor_spec.rb +23 -0
- data/spec/unit/pacto/extensions_spec.rb +11 -11
- data/spec/unit/pacto/generator_spec.rb +142 -0
- data/spec/unit/pacto/hash_merge_processor_spec.rb +20 -0
- data/spec/unit/pacto/logger_spec.rb +44 -0
- data/spec/unit/pacto/meta_schema_spec.rb +70 -0
- data/spec/unit/pacto/pacto_spec.rb +32 -58
- data/spec/unit/pacto/request_spec.rb +83 -34
- data/spec/unit/pacto/response_adapter_spec.rb +9 -11
- data/spec/unit/pacto/response_spec.rb +68 -68
- data/spec/unit/pacto/server/playback_servlet_spec.rb +24 -0
- data/spec/unit/pacto/stubs/built_in_spec.rb +168 -0
- metadata +291 -147
- data/.rspec_integration +0 -4
- data/.rspec_unit +0 -4
- data/lib/pacto/file_pre_processor.rb +0 -12
- data/lib/pacto/instantiated_contract.rb +0 -62
- data/spec/integration/spec_helper.rb +0 -1
- data/spec/integration/utils/dummy_server.rb +0 -34
- data/spec/unit/pacto/file_pre_processor_spec.rb +0 -13
- data/spec/unit/pacto/instantiated_contract_spec.rb +0 -224
- data/spec/unit/spec_helper.rb +0 -5
    
        data/spec/spec_helper.rb
    CHANGED
    
    | @@ -1 +1,18 @@ | |
| 1 | 
            +
            require 'coveralls_helper'
         | 
| 1 2 | 
             
            require 'pacto'
         | 
| 3 | 
            +
            require 'pacto/server'
         | 
| 4 | 
            +
            require 'stringio'
         | 
| 5 | 
            +
            require 'should_not/rspec'
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            RSpec.configure do |config|
         | 
| 8 | 
            +
              config.expect_with :rspec do |c|
         | 
| 9 | 
            +
                c.syntax = :expect
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
              config.before(:each) do
         | 
| 12 | 
            +
                provider = Pacto.configuration.provider
         | 
| 13 | 
            +
                unless provider.respond_to? :reset!
         | 
| 14 | 
            +
                  provider.stub(:reset!)
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
                Pacto.clear!
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
            {
         | 
| 2 | 
            +
              "request": {
         | 
| 3 | 
            +
                "method": "GET",
         | 
| 4 | 
            +
                "path": "/hello",
         | 
| 5 | 
            +
                "headers": {
         | 
| 6 | 
            +
                  "Accept": "application/json"
         | 
| 7 | 
            +
                },
         | 
| 8 | 
            +
                "params": {}
         | 
| 9 | 
            +
              },
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              "response": {
         | 
| 12 | 
            +
                "status": 200,
         | 
| 13 | 
            +
                "headers": { "Content-Type": "application/json" },
         | 
| 14 | 
            +
                "body": {
         | 
| 15 | 
            +
                  "type": "object",
         | 
| 16 | 
            +
                  "required": true,
         | 
| 17 | 
            +
                  "properties": {
         | 
| 18 | 
            +
                    "message": { "type": "string", "required": true }
         | 
| 19 | 
            +
                  }
         | 
| 20 | 
            +
                }
         | 
| 21 | 
            +
              }
         | 
| 22 | 
            +
            }
         | 
| @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            describe Pacto::Hooks::ERBHook do
         | 
| 2 | 
            +
              describe '#process' do
         | 
| 3 | 
            +
                let(:req) {
         | 
| 4 | 
            +
                  OpenStruct.new({:headers => {'User-Agent' => 'abcd'}})
         | 
| 5 | 
            +
                }
         | 
| 6 | 
            +
                let(:converted_req) {
         | 
| 7 | 
            +
                  {'HEADERS' => {'User-Agent' => 'abcd'}}
         | 
| 8 | 
            +
                }
         | 
| 9 | 
            +
                let(:res) {
         | 
| 10 | 
            +
                  OpenStruct.new({:body => 'before'})
         | 
| 11 | 
            +
                }
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                before do
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                context 'no matching contracts' do
         | 
| 17 | 
            +
                  it 'binds the request' do
         | 
| 18 | 
            +
                    contracts = Set.new
         | 
| 19 | 
            +
                    mock_erb({ :req => converted_req })
         | 
| 20 | 
            +
                    described_class.new.process contracts, req, res
         | 
| 21 | 
            +
                    expect(res.body).to eq('after')
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                context 'one matching contract' do
         | 
| 26 | 
            +
                  it 'binds the request and the contract\'s values' do
         | 
| 27 | 
            +
                    contract = OpenStruct.new({:values => {:max => 'test'}})
         | 
| 28 | 
            +
                    contracts = Set.new([contract])
         | 
| 29 | 
            +
                    mock_erb({ :req => converted_req, :max => 'test'})
         | 
| 30 | 
            +
                    described_class.new.process contracts, req, res
         | 
| 31 | 
            +
                    expect(res.body).to eq('after')
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                context 'multiple matching contracts' do
         | 
| 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'})
         | 
| 41 | 
            +
                    contracts = Set.new([contract1, contract2])
         | 
| 42 | 
            +
                    described_class.new.process contracts, req, res
         | 
| 43 | 
            +
                    expect(res.body).to eq('after')
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
              def mock_erb(hash)
         | 
| 49 | 
            +
                Pacto::ERBProcessor.any_instance.should_receive(:process).with('before', hash).and_return('after')
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
            end
         | 
| @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            module Pacto
         | 
| 2 | 
            +
              describe Configuration do
         | 
| 3 | 
            +
                subject(:configuration) { Configuration.new }
         | 
| 4 | 
            +
                let(:contracts_path) { 'path_to_contracts' }
         | 
| 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
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                it 'sets strict matchers by default to true' do
         | 
| 19 | 
            +
                  expect(configuration.strict_matchers).to be_true
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                it 'sets contracts path by default to nil' do
         | 
| 23 | 
            +
                  expect(configuration.contracts_path).to be_nil
         | 
| 24 | 
            +
                end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                it 'sets logger by default to Logger' do
         | 
| 27 | 
            +
                  expect(configuration.logger).to be_kind_of Logger
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                context 'about logging' do
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  context 'when PACTO_DEBUG is enabled' do
         | 
| 33 | 
            +
                    around do |example|
         | 
| 34 | 
            +
                      ENV['PACTO_DEBUG'] = 'true'
         | 
| 35 | 
            +
                      example.run
         | 
| 36 | 
            +
                      ENV.delete 'PACTO_DEBUG'
         | 
| 37 | 
            +
                    end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                    it 'sets the log level to debug' do
         | 
| 40 | 
            +
                      expect(configuration.logger.level).to eq :debug
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  context 'when PACTO_DEBUG is disabled' do
         | 
| 45 | 
            +
                    it 'sets the log level to default' do
         | 
| 46 | 
            +
                      expect(configuration.logger.level).to eq :error
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
            end
         | 
| @@ -4,49 +4,18 @@ module Pacto | |
| 4 4 | 
             
                let(:contract_name)      { 'contract' }
         | 
| 5 5 | 
             
                let(:contract_path)      { File.join('spec', 'unit', 'data', "#{contract_name}.json") }
         | 
| 6 6 | 
             
                let(:file_pre_processor) { double('file_pre_processor') }
         | 
| 7 | 
            -
                let(:file_content)       { File.read(contract_path)}
         | 
| 7 | 
            +
                let(:file_content)       { File.read(contract_path) }
         | 
| 8 8 |  | 
| 9 9 | 
             
                describe '.build_from_file' do
         | 
| 10 | 
            -
                  it ' | 
| 10 | 
            +
                  it 'builds a contract given a JSON file path and a host' do
         | 
| 11 11 | 
             
                    file_pre_processor.stub(:process).and_return(file_content)
         | 
| 12 | 
            -
                    described_class.build_from_file(contract_path, host, file_pre_processor).
         | 
| 13 | 
            -
                      should be_a_kind_of(Pacto::Contract)
         | 
| 12 | 
            +
                    expect(described_class.build_from_file(contract_path, host, file_pre_processor)).to be_a_kind_of(Pacto::Contract)
         | 
| 14 13 | 
             
                  end
         | 
| 15 14 |  | 
| 16 | 
            -
                  it ' | 
| 15 | 
            +
                  it 'processes files using File Pre Processor module' do
         | 
| 17 16 | 
             
                    file_pre_processor.should_receive(:process).with(file_content).and_return(file_content)
         | 
| 18 17 | 
             
                    described_class.build_from_file(contract_path, host, file_pre_processor)
         | 
| 19 18 | 
             
                  end
         | 
| 20 19 | 
             
                end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                describe '.validate_contract' do
         | 
| 23 | 
            -
                  it 'should not raise error if contract is correct' do
         | 
| 24 | 
            -
                    expect {
         | 
| 25 | 
            -
                      definition = {
         | 
| 26 | 
            -
                        'request' => {
         | 
| 27 | 
            -
                          'method' => 'GET',
         | 
| 28 | 
            -
                          'path' => '/a/path',
         | 
| 29 | 
            -
                          'params' => {},
         | 
| 30 | 
            -
                          'headers' => {}
         | 
| 31 | 
            -
                        },
         | 
| 32 | 
            -
                        'response' => {
         | 
| 33 | 
            -
                          'status' => 200,
         | 
| 34 | 
            -
                          'headers' => {},
         | 
| 35 | 
            -
                          'body' => {
         | 
| 36 | 
            -
                            'type' => 'string',
         | 
| 37 | 
            -
                            'required' => true
         | 
| 38 | 
            -
                          }
         | 
| 39 | 
            -
                        }
         | 
| 40 | 
            -
                      }
         | 
| 41 | 
            -
                      described_class.validate_contract(definition, contract_path)
         | 
| 42 | 
            -
                    }.not_to raise_error
         | 
| 43 | 
            -
                  end
         | 
| 44 | 
            -
                  
         | 
| 45 | 
            -
                  it 'should raise InvalidContract if contract do not contain a Request' do
         | 
| 46 | 
            -
                    expect {
         | 
| 47 | 
            -
                      described_class.validate_contract({}, contract_path)
         | 
| 48 | 
            -
                    }.to raise_error(InvalidContract)
         | 
| 49 | 
            -
                  end
         | 
| 50 | 
            -
                end
         | 
| 51 20 | 
             
              end
         | 
| 52 21 | 
             
            end
         | 
| @@ -1,49 +1,77 @@ | |
| 1 1 | 
             
            module Pacto
         | 
| 2 2 | 
             
              describe Contract do
         | 
| 3 | 
            -
                let(:request) | 
| 4 | 
            -
                let(: | 
| 3 | 
            +
                let(:request)  { double 'request' }
         | 
| 4 | 
            +
                let(:request_signature)  { double 'request_signature' }
         | 
| 5 | 
            +
                let(:response) { double 'response' }
         | 
| 6 | 
            +
                let(:provider) { double 'provider' }
         | 
| 7 | 
            +
                let(:instantiated_response) { double 'instantiated response' }
         | 
| 5 8 |  | 
| 6 | 
            -
                 | 
| 9 | 
            +
                subject(:contract) { described_class.new request, response }
         | 
| 7 10 |  | 
| 8 | 
            -
                 | 
| 9 | 
            -
                   | 
| 10 | 
            -
                   | 
| 11 | 
            +
                before do
         | 
| 12 | 
            +
                  response.stub(:instantiate => instantiated_response)
         | 
| 13 | 
            +
                  Pacto.configuration.provider = provider
         | 
| 14 | 
            +
                end
         | 
| 11 15 |  | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 16 | 
            +
                describe '#stub_contract!' do
         | 
| 17 | 
            +
                  it 'instantiates the response and registers a stub' do
         | 
| 18 | 
            +
                    response.should_receive :instantiate
         | 
| 19 | 
            +
                    provider.should_receive(:stub_request!).with request, instantiated_response
         | 
| 20 | 
            +
                    contract.stub_contract!
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 19 23 |  | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 24 | 
            +
                describe '#validate' do
         | 
| 25 | 
            +
                  before do
         | 
| 26 | 
            +
                    response.stub(:validate => validation_result)
         | 
| 27 | 
            +
                    request.stub(:execute => fake_response)
         | 
| 22 28 | 
             
                  end
         | 
| 23 29 |  | 
| 24 | 
            -
                   | 
| 25 | 
            -
             | 
| 30 | 
            +
                  let(:validation_result) { double 'validation result' }
         | 
| 31 | 
            +
                  let(:fake_response)     { double 'fake response' }
         | 
| 26 32 |  | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            +
                  it 'validates the generated response' do
         | 
| 34 | 
            +
                    response.should_receive(:validate).with(fake_response, {})
         | 
| 35 | 
            +
                    expect(contract.validate).to eq validation_result
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  it 'returns the result of the validation' do
         | 
| 39 | 
            +
                    expect(contract.validate).to eq validation_result
         | 
| 40 | 
            +
                  end
         | 
| 33 41 |  | 
| 34 | 
            -
             | 
| 42 | 
            +
                  it 'generates the response' do
         | 
| 43 | 
            +
                    request.should_receive :execute
         | 
| 44 | 
            +
                    contract.validate
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  context 'when response gotten is provided' do
         | 
| 48 | 
            +
                    it 'does not generate the response' do
         | 
| 49 | 
            +
                      request.should_not_receive :execute
         | 
| 50 | 
            +
                      contract.validate fake_response
         | 
| 35 51 | 
             
                    end
         | 
| 36 52 | 
             
                  end
         | 
| 37 53 | 
             
                end
         | 
| 38 54 |  | 
| 39 | 
            -
                describe '# | 
| 40 | 
            -
                  let(: | 
| 41 | 
            -
             | 
| 55 | 
            +
                describe '#matches?' do
         | 
| 56 | 
            +
                  let(:request_matcher) do
         | 
| 57 | 
            +
                    double('fake request matcher').tap do |matcher|
         | 
| 58 | 
            +
                      matcher.stub(:matches?) { |r| r == request_signature }
         | 
| 59 | 
            +
                    end
         | 
| 60 | 
            +
                  end
         | 
| 42 61 |  | 
| 43 | 
            -
                   | 
| 44 | 
            -
                     | 
| 45 | 
            -
             | 
| 46 | 
            -
                     | 
| 62 | 
            +
                  context 'when the contract is not stubbed' do
         | 
| 63 | 
            +
                    it 'returns false' do
         | 
| 64 | 
            +
                      expect(contract.matches? request_signature).to be_false
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  context 'when the contract is stubbed' do
         | 
| 69 | 
            +
                    it 'returns true if it matches the request' do
         | 
| 70 | 
            +
                      provider.should_receive(:stub_request!).with(request, instantiated_response).and_return(request_matcher)
         | 
| 71 | 
            +
                      contract.stub_contract!
         | 
| 72 | 
            +
                      expect(contract.matches? request_signature).to be_true
         | 
| 73 | 
            +
                      expect(contract.matches? :anything).to be_false
         | 
| 74 | 
            +
                    end
         | 
| 47 75 | 
             
                  end
         | 
| 48 76 | 
             
                end
         | 
| 49 77 | 
             
              end
         | 
| @@ -0,0 +1,28 @@ | |
| 1 | 
            +
            describe Pacto do
         | 
| 2 | 
            +
              describe '.configure' do
         | 
| 3 | 
            +
                let(:contracts_path) { 'path_to_contracts' }
         | 
| 4 | 
            +
                it 'allows preprocessor manual configuration' do
         | 
| 5 | 
            +
                  expect(Pacto.configuration.preprocessor).to_not be_nil
         | 
| 6 | 
            +
                  Pacto.configure do |c|
         | 
| 7 | 
            +
                    c.preprocessor = nil
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
                  expect(Pacto.configuration.preprocessor).to be_nil
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                it 'allows contracts_path manual configuration' do
         | 
| 13 | 
            +
                  expect(Pacto.configuration.contracts_path).to be_nil
         | 
| 14 | 
            +
                  Pacto.configure do |c|
         | 
| 15 | 
            +
                    c.contracts_path = contracts_path
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  expect(Pacto.configuration.contracts_path).to eq(contracts_path)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                it 'register a Pacto Callback' do
         | 
| 21 | 
            +
                  callback_block = Pacto::Callback.new { }
         | 
| 22 | 
            +
                  Pacto.configure do |c|
         | 
| 23 | 
            +
                    c.register_callback(callback_block)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                  expect(Pacto.configuration.callback).to eq(callback_block)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
            end
         | 
| @@ -0,0 +1,133 @@ | |
| 1 | 
            +
            describe Pacto do
         | 
| 2 | 
            +
              let(:tag) { 'contract_tag' }
         | 
| 3 | 
            +
              let(:another_tag) { 'another_tag' }
         | 
| 4 | 
            +
              let(:contract) { double('contract') }
         | 
| 5 | 
            +
              let(:another_contract) { double('another_contract') }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              after do
         | 
| 8 | 
            +
                described_class.unregister_all!
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              describe '.register' do
         | 
| 12 | 
            +
                context 'no tag' do
         | 
| 13 | 
            +
                  it 'registers the contract with the default tag' do
         | 
| 14 | 
            +
                    described_class.register_contract contract
         | 
| 15 | 
            +
                    expect(described_class.registered[:default]).to include(contract)
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                context 'one tag' do
         | 
| 20 | 
            +
                  it 'registers a contract under a given tag' do
         | 
| 21 | 
            +
                    described_class.register_contract(contract, tag)
         | 
| 22 | 
            +
                    expect(described_class.registered[tag]).to include(contract)
         | 
| 23 | 
            +
                  end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                  it 'does not duplicate a contract when it has already been registered with the same tag' do
         | 
| 26 | 
            +
                    described_class.register_contract(contract, tag)
         | 
| 27 | 
            +
                    described_class.register_contract(contract, tag)
         | 
| 28 | 
            +
                    expect(described_class.registered[tag]).to include(contract)
         | 
| 29 | 
            +
                    expect(described_class.registered[tag]).to have(1).items
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                context 'multiple tags' do
         | 
| 34 | 
            +
                  it 'registers a contract using different tags' do
         | 
| 35 | 
            +
                    described_class.register_contract(contract, tag, another_tag)
         | 
| 36 | 
            +
                    expect(described_class.registered[tag]).to include(contract)
         | 
| 37 | 
            +
                    expect(described_class.registered[another_tag]).to include(contract)
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  it 'registers a tag with different contracts ' do
         | 
| 41 | 
            +
                    described_class.register_contract(contract, tag)
         | 
| 42 | 
            +
                    described_class.register_contract(another_contract, tag)
         | 
| 43 | 
            +
                    expect(described_class.registered[tag]).to include(contract, another_contract)
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                context 'with a block' do
         | 
| 49 | 
            +
                  it 'has a compact syntax for registering multiple contracts' do
         | 
| 50 | 
            +
                    described_class.configure do |c|
         | 
| 51 | 
            +
                      c.register_contract 'new_api/create_item_v2', :item, :new
         | 
| 52 | 
            +
                      c.register_contract 'authentication', :default
         | 
| 53 | 
            +
                      c.register_contract 'list_items_legacy', :legacy
         | 
| 54 | 
            +
                      c.register_contract 'get_item_legacy', :legacy
         | 
| 55 | 
            +
                    end
         | 
| 56 | 
            +
                    expect(described_class.registered[:new]).to include('new_api/create_item_v2')
         | 
| 57 | 
            +
                    expect(described_class.registered[:default]).to include('authentication')
         | 
| 58 | 
            +
                    expect(described_class.registered[:legacy]).to include('list_items_legacy', 'get_item_legacy')
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              describe '.use' do
         | 
| 64 | 
            +
                before do
         | 
| 65 | 
            +
                  described_class.register_contract(contract, tag)
         | 
| 66 | 
            +
                  described_class.register_contract(another_contract, :default)
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                context 'when a contract has been registered' do
         | 
| 70 | 
            +
                  let(:response_body) { double('response_body') }
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                  it 'stubs a contract with default values' do
         | 
| 73 | 
            +
                    contract.should_receive(:stub_contract!)
         | 
| 74 | 
            +
                    another_contract.should_receive(:stub_contract!)
         | 
| 75 | 
            +
                    expect(described_class.use(tag)).to eq 2
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  it 'stubs default contract if unused tag' do
         | 
| 79 | 
            +
                    another_contract.should_receive(:stub_contract!)
         | 
| 80 | 
            +
                    expect(described_class.use(another_tag)).to eq 1
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                context 'when contract has not been registered' do
         | 
| 85 | 
            +
                  it 'raises an argument error' do
         | 
| 86 | 
            +
                    described_class.unregister_all!
         | 
| 87 | 
            +
                    expect { described_class.use('unregistered') }.to raise_error ArgumentError
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
                end
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              describe '.unregister_all!' do
         | 
| 93 | 
            +
                it 'unregisters all previously registered contracts' do
         | 
| 94 | 
            +
                  described_class.register_contract(contract, tag)
         | 
| 95 | 
            +
                  described_class.unregister_all!
         | 
| 96 | 
            +
                  expect(described_class.registered).to be_empty
         | 
| 97 | 
            +
                end
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              describe '.contract_for' do
         | 
| 101 | 
            +
                let(:request_signature) { double('request signature') }
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                context 'when no contracts are found for a request' do
         | 
| 104 | 
            +
                  it 'returns an empty list' do
         | 
| 105 | 
            +
                    expect(described_class.contract_for request_signature).to be_empty
         | 
| 106 | 
            +
                  end
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                context 'when contracts are found for a request' do
         | 
| 110 | 
            +
                  let(:contracts_that_match)      { create_contracts 2, true }
         | 
| 111 | 
            +
                  let(:contracts_that_dont_match) { create_contracts 3, false }
         | 
| 112 | 
            +
                  let(:all_contracts)             { contracts_that_match + contracts_that_dont_match }
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                  it 'returns the matching contracts' do
         | 
| 115 | 
            +
                    register_and_use all_contracts
         | 
| 116 | 
            +
                    expect(described_class.contract_for request_signature).to eq(contracts_that_match)
         | 
| 117 | 
            +
                  end
         | 
| 118 | 
            +
                end
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
              def create_contracts(total, matches)
         | 
| 122 | 
            +
                total.times.map do
         | 
| 123 | 
            +
                  double('contract',
         | 
| 124 | 
            +
                         :stub_contract! => double('request matcher'),
         | 
| 125 | 
            +
                         :matches? => matches)
         | 
| 126 | 
            +
                end.to_set
         | 
| 127 | 
            +
              end
         | 
| 128 | 
            +
             | 
| 129 | 
            +
              def register_and_use contracts
         | 
| 130 | 
            +
                contracts.each { |contract| described_class.register_contract contract }
         | 
| 131 | 
            +
                Pacto.use :default
         | 
| 132 | 
            +
              end
         | 
| 133 | 
            +
            end
         |