[
  {
    "path": ".gitignore",
    "content": "*.gem\n*.log\n*.pid\n*.rbc\n.bundle\n.config\n.yardoc\nGemfile.lock\nInstalledFiles\n_yardoc\ncoverage\ndoc/\nlib/bundler/man\npkg\nrdoc\nspec/reports\ntest/tmp\ntest/version_tmp\ntmp\n*.swp\n*.swo\n.idea/\n.floo*\n.sublime*\ntags\npacto.log\n.polytrix/\n"
  },
  {
    "path": ".rspec",
    "content": "--colour\n--require spec_helper\n"
  },
  {
    "path": ".rubocop.yml",
    "content": "require: rubocop-rspec\n\nDocumentation:\n  Enabled: false\n\nDotPosition:\n  Enabled: false\n\nLineLength:\n  Enabled: false\n\nMethodLength:\n  Max: 20\n\nStyle/Encoding:\n  EnforcedStyle: when_needed\n\nAllCops:\n  Include:\n    - Guardfile\n    - '**/Rakefile'\n    - pacto*.gemspec\n  Exclude:\n    - bin/**/*\n    - tmp/**/*\nRSpec/DescribeClass:\n  Exclude:\n    - samples/**/*\n    - spec/integration/**/*\nRSpec/MultipleDescribes:\n  Exclude:\n    - samples/**/*\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: ruby\nrvm:\n  - 2.1.0\n  - 2.0.0\n  - 1.9.3\n  # There is a bug in jruby-1.7.15\n  # that is blocking testing\n  - jruby\nbefore_script:\n  - gem install foreman\n  - foreman start &\nmatrix:\n  allow_failures:\n    - rvm: jruby\n\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing\n\nYou are welcome to contribute to Pacto and this guide will help you to:\n\n- [Setup](#setup) all the needed dependencies in order to start hacking.\n- Follow [conventions](#code-conventions) agreed among the project \ncontributors.\n- Follow Pacto's suggested [workflow](#workflow).\n- [Submit](#submit-code) new code to the project.\n- Run the automated suite of [tests](#run-tests) that is bundled with Pacto.\n- Find easily code annotations for [technical debt](#technical-debt) (TODOs,\nFIXMEs, etc)\n- Be aware of some [troubleshooting tips](#troubleshooting) when running issues\nwith Pacto.\n\n## <a name=\"workflow\"></a>Development (suggested) workflow\n\nPacto comes with [`guard`](https://github.com/guard/guard) enabled, this means\nthat guard will trigger the tests after any change is made on the source code.\nWe try to keep the feedback loop as fast as we can, so you can be able to run\nall the tests everytime you make a change on the project. If you want to follow\nthis workflow just run:\n\n`bundle exec guard`\n\nGuard will run first the static analysis and then will run the unit test related\nwith the file that was changed, later the integration test and last the user\njourney tests.\n\n## <a name=\"submit-code\"></a>Submit code\n\nAny contribution has to come from a Pull Request via GitHub, to do it just\nfollow these steps:\n\n1. Fork it (`git clone git@github.com:thoughtworks/pacto.git`).\n2. Create your feature branch (`git checkout -b my-new-feature`).\n3. Commit your changes (`git commit -am 'Add some feature'`).\n4. Verify that the tests are passing (`bundle exec rake`).\n5. Push to the branch (`git push origin my-new-feature`).\n6. Create new Pull Request.\n\n## <a name=\"setup\"></a>Setting up\n\nYou will need to have installed:\n\n- Ruby 1.9.3 or greater installed.\n- Bundler gem installed (`gem install bundler`).\n- Install all the dependencies (`bundle install`).\n\n## <a name=\"code-conventions\"></a>Coding conventions\n\n### Style guide\n\nContributing in a project among several authors could lead to different styles\nof writting code. In order to create some basic baseline on the source code\nPacto comes with an static code analyzer that will enforce the code to follow\nthe [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide). To execute\nthe analyzer just run:\n\n`bundle exec rubocop`\n\n### Writing tests\n\nPacto unit tests and integration test are written in RSpec and the user journey\ntests are written in Cucumber. For the RSpec tests we suggest to follow the\n[Better Specs](http://betterspecs.org/) guideline.\n\n## <a name=\"run-tests\"></a>Running tests\n\nPacto comes with a set of automated tests. All the tests are runnable via rake\ntasks:\n\n- Unit tests (`bundle exec rake unit`).\n- Integration tests (`bundle exec rake integration`).\n- User journey tests (`bundle exec rake journeys`).\n\nIt is also possible run specific tests:\n\n- Unit tests (`bundle exec rspec spec/unit/[file_path]`\n- Integration tests  (`bundle exec rspec spec/integration/[file_path]`)\n- User journey tests (`bundle exec cucumber features/[file_path] -r features/support/env.rb`)\n\n### Checking that all is green\n\nTo know that both tests and static analysis is working fine you just have to\nrun:\n\n`bundle exec rake`\n\n## <a name=\"technical-debt\"></a>Technical Debt\n\nSome of the code in Pacto is commented with the anotations TODO or\nFIXME that might point to some potencial technical debt on the source code. If\nyou are interested to list where are all these, just run:\n\n`bundle exec notes`\n\n## <a name=\"troubleshooting\"></a>Troubleshooting\n\n### Debugging pacto\n\nIf you run into some strange behaviour that Pacto might have, you can take\nadvantage of the debugging capabilities of Pacto. Running the tests with the\nenvironment variable PACTO_DEBUG=true will show (on the standard output) more\ndetails what Pacto is doing behind the scenes.\n\n### Gemfile.lock\n\nBecause Pacto is a gem we don't include the Gemfile.lock into the repository\n([here is the reason](http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/)).\nThis could lead to some problems in your daily job as contributor specially\nwhen there is an upgrade in any of the gems that Pacto depends upon. That is\nwhy we recomend you to remove the Gemfile.lock and generate it\n(`bundle install`) everytime there are changes on the dependencies.\n\n"
  },
  {
    "path": "Gemfile",
    "content": "source 'https://rubygems.org'\n\n# Specify your gem's dependencies in pacto.gemspec\ngemspec name: 'pacto'\ngemspec name: 'pacto-server'\n\n# This is only used by Relish tests.  Putting it here let's travis\n# pre-install so we can speed up the test with `bundle install --local`,\n# avoiding Aruba timeouts.\ngem 'excon'\ngem 'octokit'\n\ngroup :samples do\n  gem 'grape'\n  gem 'grape-swagger'\n  gem 'puma'\n  gem 'rake'\n  gem 'pry'\n  gem 'rack'\nend\n"
  },
  {
    "path": "Guardfile",
    "content": "# vim: syntax=ruby filetype=ruby\n\nguard :rubocop, all_on_start: false do\n  watch(/.+\\.rb$/)\n  watch(/\\.gemspec$/)\n  watch('Guardfile')\n  watch('Rakefile')\n  watch('.rubocop.yml')      { '.' }\n  watch('.rubocop-todo.yml') { '.' }\nend\n\ngroup :tests, halt_on_fail: true do\n  guard :rspec, cmd: 'bundle exec rspec' do\n    # Unit tests\n    watch(%r{^spec/unit/.+_spec\\.rb$})\n    watch(/^lib\\/(.+)\\.rb$/)             { |_m| 'spec/unit/#{m[1]}_spec.rb' }\n    watch('spec/spec_helper.rb')         { 'spec/unit' }\n    watch('spec/unit/spec_helper.rb')    { 'spec/unit' }\n    watch(%r{^spec/unit/data/.+\\.json$}) { 'spec/unit' }\n\n    # Integration tests\n    watch(%r{^spec/integration/.+_spec\\.rb$})\n    watch(%r{^spec/integration/utils/.+\\.rb$})  { 'spec/integration' }\n    watch(/^lib\\/.+\\.rb$/)                       { 'spec/integration' }\n    watch('spec/spec_helper.rb')                { 'spec/integration' }\n    watch('spec/integration/spec_helper.rb')    { 'spec/integration' }\n    watch(%r{^spec/integration/data/.+\\.json$}) { 'spec/integration' }\n  end\n\n  guard :cucumber, cmd: 'bundle exec cucumber', all_on_start: false do\n    watch(/^features\\/.+\\.feature$/)\n    watch(%r{^features/support/.+$})                      { 'features' }\n    watch(%r{^features/step_definitions/(.+)_steps\\.rb$}) { |_m| Dir[File.join('**/#{m[1]}.feature')][0] || 'features' }\n  end\nend\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "Copyright (c) 2013 ThoughtWorks Brasil & Abril Midia\n\nMIT License\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "Procfile",
    "content": "sample_apis: sh -c 'bundle exec rackup -s puma -o localhost -p $PORT sample_apis/config.ru'\n"
  },
  {
    "path": "README.md",
    "content": "[![Gem Version](https://badge.fury.io/rb/pacto.png)](http://badge.fury.io/rb/pacto)\n[![Build Status](https://travis-ci.org/thoughtworks/pacto.png)](https://travis-ci.org/thoughtworks/pacto)\n[![Code Climate](https://codeclimate.com/github/thoughtworks/pacto.png)](https://codeclimate.com/github/thoughtworks/pacto)\n[![Dependency Status](https://gemnasium.com/thoughtworks/pacto.png)](https://gemnasium.com/thoughtworks/pacto)\n[![Coverage Status](https://coveralls.io/repos/thoughtworks/pacto/badge.png)](https://coveralls.io/r/thoughtworks/pacto)\n\n**Pacto is currently INACTIVE. Unfortunately none of the maintainers have had enough time to maintain it. While we feel that Pacto had good ideas, we also feel that a lot has changed since Pacto was first conceived (including the [OpenAPIs initiative](https://openapis.org/)) and that too much work would be required to maintain & update Pacto. Instead, we encourage others to use other projects that have focused on Consumer-Driven Contracts, like [Pact](https://github.com/realestate-com-au/pact), or to write their own Pacto-inspired project.**\n\n# [INACTIVE] Pacto\n\nPacto is a judge that arbitrates contract disputes between a **service provider** and one or more **consumers**.  In other words, it is a framework for [Integration Contract Testing](http://martinfowler.com/bliki/IntegrationContractTest.html), and helps guide service evolution patterns like [Consumer-Driven Contracts](http://thoughtworks.github.io/pacto/patterns/cdc/) or [Documentation-Driven Contracts](http://thoughtworks.github.io/pacto/patterns/documentation_driven/).\n\nPacto considers two major terms in order decide if there has been a breach of contract: the **request clause** and the **response clause**.\n\nThe **request clause** defines what information must be sent by the **consumer** to the **provider** in order to compel them to render a service.  The request clause often describes the required HTTP request headers like `Content-Type`, the required parameters, and the required request body (defined in [json-schema](http://json-schema.org/)) when applicable.  Providers are not held liable for failing to deliver services for invalid requests.\n\nThe **response clause** defines what information must be returned by the **provider** to the **consumer** in order to successfully complete the transaction.  This commonly includes HTTP response headers like `Location` as well as the required response body (also defined in [json-schema](http://json-schema.org/)).\n\n## Test Doubles\n\nThe consumer may also enter into an agreement with **test doubles** like [WebMock](http://robots.thoughtbot.com/how-to-stub-external-services-in-tests), [vcr](https://github.com/vcr/vcr) or [mountebank](http://www.mbtest.org/).  The services delivered by the **test doubles** for the purposes of development and testing will be held to the same conditions as the service the final services rendered by the parent **provider**.  This prevents misrepresentation of sample services as realistic, leading to damages during late integration.\n\nPacto can provide a [**test double**](#stubbing) if you cannot afford your own.\n\n## Due Diligence\n\nPacto usually makes it clear if the **consumer** or **provider** is at fault, but if a contract is too vague Pacto cannot assign blame, and if it is too specific the matter may become litigious.\n\nPacto can provide a [**contract writer**](#generating) that tries to strike a balance, but you may still need to adjust the terms.\n\n## Implied Terms\n\n- Pacto only arbitrates contracts for JSON services.\n- Pacto requires Ruby 1.9.3 or newer, though you can use [Polyglot Testing](http://thoughtworks.github.io/pacto/patterns/polyglot/) techniques to support older Rubies and non-Ruby projects.\n\n## Roadmap\n\n- The **test double** provided by Pacto is only semi-competent.  It handles simple cases, but we expect to find a more capable replacement in the near future.\n- Pacto will provide additional Contract Writers for converting from apiblueprint, WADL, or other documentation formats in the future.  It's part of our goal to support [Documentation-Driven Contracts](http://thoughtworks.github.io/pacto/patterns/documentation_driven/)\n- Pacto reserves the right to consider other clauses in the future, like security and compliance to industry specifications.\n\n## Usage\n\n**See also: http://thoughtworks.github.io/pacto/usage/**\n\nPacto can perform three activities: generating, validating, or stubbing services.  You can do each of these activities against either live or stubbed services.\n\nYou can also use [Pacto Server](#pacto-server-non-ruby-usage) if you are working with non-Ruby projects.\n\n### Configuration\n\nIn order to start with Pacto, you just need to require it and optionally customize the default [Configuration](docs/configuration.md).  For example:\n\n```ruby\nrequire 'pacto'\n\nPacto.configure do |config|\n  config.contracts_path = 'contracts'\nend\n```\n\n### Generating\n\nThe easiest way to get started with Pacto is to run a suite of live tests and tell Pacto to generate the contracts:\n\n```ruby\nPacto.generate!\n# run your tests\n```\n\nIf you're using the same configuration as above, this will produce Contracts in the contracts/ folder.\n\nWe know we cannot generate perfect Contracts, especially if we only have one sample request.  So we do our best to give you a good starting point, but you will likely want to customize the contract so the validation is more strict in some places and less strict in others.\n\n### Contract Lists\n\nIn order to stub or validate a group of contracts you need to create a ContractList.\nA ContractList represent a collection of endpoints attached to the same host.\n\n```ruby\nrequire 'pacto'\n\ndefault_contracts = Pacto.load_contracts('contracts/services', 'http://example.com')\nauthentication_contracts = Pacto.load_contracts('contracts/auth', 'http://example.com')\nlegacy_contracts = Pacto.load_contracts('contracts/legacy', 'http://example.com')\n```\n\n### Validating\n\nOnce you have a ContractList, you can validate all the contracts against the live host.\n\n```ruby\ncontracts = Pacto.load_contracts('contracts/services', 'http://example.com')\ncontracts.simulate_consumers\n```\n\nThis method will hit the real endpoint, with a request created based on the request part of the contract.  \nThe response will be compared against the response part of the contract and any structural difference will\ngenerate a validation error.\n\nRunning this in your build pipeline will ensure that your contracts actually match the real world, and that\nyou can run your acceptance tests against the contract stubs without worries.\n\n### Stubbing\n\nTo generate stubs based on a ContractList you can run:\n\n```ruby\ncontracts = Pacto.load_contracts('contracts/services', 'http://example.com')\ncontracts.stub_providers\n```\n\nThis method uses webmock to ensure that whenever you make a request against one of contracts you actually get a stubbed response,\nbased on the default values specified on the contract, instead of hitting the real provider.\n\nYou can override any default value on the contracts by providing a hash of optional values to the stub_providers method. This\nwill override the keys for every contract in the list\n\n```ruby\ncontracts = Pacto.load_contracts('contracts/services', 'http://example.com')\ncontracts.stub_providers(request_id: 14, name: \"Marcos\")\n```\n\n## Pacto Server (non-Ruby usage)\n\n**See also: http://thoughtworks.github.io/pacto/patterns/polyglot/**\n\nWe've bundled a small server that embeds pacto so you can use it for non-Ruby projects.  If you want to take advantage of the full features, you'll still need to use Ruby (usually rspec) to drive your API testing.  You can run just the server in order to stub or to write validation issues to a log, but you won't have access to the full API fail your tests if there were validation problems.\n\n### Command-line\n\nThe command-line version of the server will show you all the options.  These same options are used when you launch the server from within rspec.  In order to see the options:\n`bundle exec pacto-server --help`\n\nSome examples:\n```sh\n$ bundle exec pacto-server -sv --generate\n# Runs a server that will generate Contracts for each request received\n$ bundle exec pacto-server -sv --stub --validate\n# Runs the server that provides stubs and checks them against Contracts\n$ bundle exec pacto-server -sv --live --validate --host\n# Runs the server that acts as a proxy to http://example.com, validating each request/response against a Contract\n```\n\n### RSpec test helper\n\nYou can also launch a server from within an rspec test.  The server does start up an external port and runs asynchronously so it doens't block your main test thread from kicking off your consumer code.  This gives you an externally accessable server that non-Ruby clients can hit, but still gives you the full Pacto API in order to validate and spy on HTTP interactions.\n\nExample usage of the rspec test helper:\n```ruby\nrequire 'rspec'\nrequire 'pacto/rspec'\nrequire 'pacto/test_helper'\n\ndescribe 'my consumer' do\n  include Pacto::TestHelper\n\n  it 'calls a service' do\n    with_pacto(\n      :port => 5000,\n      :directory => '../spec/integration/data',\n      :stub => true) do |pacto_endpoint|\n      # call your code\n      system \"curl #{pacto_endpoint}/echo\"\n      # check results\n      expect(Pacto).to have_validated(:get, 'https://localhost/echo')\n    end\n  end\nend\n```\n\n## Rake Tasks\n\nPacto includes a few Rake tasks to help with common tasks.  If you want to use these tasks, just add this top your Rakefile:\n\n```ruby\nrequire 'pacto/rake_task'\n```\n\nThis should add several new tasks to you project:\n```sh\nrake pacto:generate[input_dir,output_dir,host]  # Generates contracts from partial contracts\nrake pacto:meta_validate[dir]                   # Validates a directory of contract definitions\nrake pacto:validate[host,dir]                   # Validates all contracts in a given directory against a given host\n```\n\nThe pacto:generate task will take partially defined Contracts and generate the missing pieces.  See [Generate](docs/generation.md) for more details.\n\nThe pacto:meta_validate task makes sure that your Contracts are valid.  It only checks the Contracts, not the services that implement them.\n\nThe pacto:validate task sends a request to an actual provider and ensures their response complies with the Contract.\n\n## Contracts\n\nPacto works by associating a service with a Contract.  The Contract is a JSON description of the service that uses json-schema to describe the response body.  You don't need to write your contracts by hand.  In fact, we recommend generating a Contract from your documentation or a service.\n\nA contract is composed of a request that has:\n\n- Method: the method of the HTTP request (e.g. GET, POST, PUT, DELETE);\n- Path: the relative path (without host) of the provider's endpoint;\n- Headers: headers sent in the HTTP request;\n- Params: any data or parameters of the HTTP request (e.g. query string for GET, body for POST).\n\nAnd a response has that has:\n\n- Status: the HTTP response status code (e.g. 200, 404, 500);\n- Headers: the HTTP response headers;\n- Body: a JSON Schema defining the expected structure of the HTTP response body.\n\nBelow is an example contract for a GET request\nto the /hello_world endpoint of a provider:\n\n```json\n{\n  \"request\": {\n    \"method\": \"GET\",\n    \"path\": \"/hello_world\",\n    \"headers\": {\n      \"Accept\": \"application/json\"\n    },\n    \"params\": {}\n  },\n\n  \"response\": {\n    \"status\": 200,\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"body\": {\n      \"description\": \"A simple response\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"message\": {\n          \"type\": \"string\"\n        }\n      }\n    }\n  }\n}\n```\n\n## Constraints\n\n- Pacto only works with JSON services\n- Pacto requires Ruby 1.9.3 or newer (though you can older Rubies or non-Ruby projects with a [Pacto Server](#pacto-server-non-ruby-usage))\n- Pacto cannot currently specify multiple acceptable status codes (e.g. 200 or 201)\n\n## Contributing\n\nRead the [CONTRIBUTING.md](CONTRIBUTING.md) file.\n"
  },
  {
    "path": "Rakefile",
    "content": "require 'rspec/core/rake_task'\nrequire 'cucumber'\nrequire 'cucumber/rake/task'\nrequire 'coveralls/rake/task'\nrequire 'rubocop/rake_task'\nrequire 'rake/notes/rake_task'\nrequire 'rake/packagetask'\nDir.glob('tasks/*.rake').each { |r| import r }\nCoveralls::RakeTask.new\n\nrequire 'pacto/rake_task' # FIXME: This require turns on WebMock\nWebMock.allow_net_connect!\n\nRuboCop::RakeTask.new(:rubocop) do |task|\n  task.fail_on_error = true\nend\n\nCucumber::Rake::Task.new(:journeys) do |t|\n  t.cucumber_opts = 'features --format progress'\nend\n\nRSpec::Core::RakeTask.new(:unit) do |t|\n  t.pattern = 'spec/unit/**/*_spec.rb'\nend\n\nRSpec::Core::RakeTask.new(:integration) do |t|\n  t.pattern = 'spec/integration/**/*_spec.rb'\nend\n\ntask default: [:unit, :integration, :journeys, :samples, :rubocop, 'coveralls:push']\n\n%w(unit integration journeys samples).each do |taskname|\n  task taskname => 'smoke_test_services'\nend\n\ndesc 'Run the samples'\ntask :samples do\n  FileUtils.rm_rf('samples/tmp')\n  sh 'bundle exec polytrix exec --solo=samples --solo-glob=\"*.{rb,sh}\"'\n  sh 'bundle exec polytrix generate code2doc --solo=samples --solo-glob=\"*.{rb,sh}\"'\nend\n\ndesc 'Build gems into the pkg directory'\ntask :build do\n  FileUtils.rm_rf('pkg')\n  Dir['*.gemspec'].each do |gemspec|\n    system \"gem build #{gemspec}\"\n  end\n  FileUtils.mkdir_p('pkg')\n  FileUtils.mv(Dir['*.gem'], 'pkg')\nend\n\nRake::PackageTask.new('pacto_docs', Pacto::VERSION) do |p|\n  p.need_zip = true\n  p.need_tar = true\n  p.package_files.include('docs/**/*')\nend\n\ndef changelog\n  changelog = File.read('CHANGELOG').split(\"\\n\\n\\n\", 2).first\n  confirm 'Does the CHANGELOG look correct? ', changelog\nend\n\ndef confirm(question, data)\n  puts 'Please confirm...'\n  puts data\n  print question\n  abort 'Aborted' unless $stdin.gets.strip == 'y'\n  puts 'Confirmed'\n  data\nend\n\ndesc 'Make sure the sample services are running'\ntask :smoke_test_services do\n  require 'faraday'\n  begin\n    retryable(tries: 5, sleep: 1) do\n      Faraday.get('http://localhost:5000/api/ping')\n    end\n  rescue\n    abort 'Could not connect to the demo services, please start them with `foreman start`'\n  end\nend\n\n# Retries a given block a specified number of times in the\n# event the specified exception is raised. If the retries\n# run out, the final exception is raised.\n#\n# This code is slightly adapted from https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/util/retryable.rb,\n# which is in turn adapted slightly from the following blog post:\n# http://blog.codefront.net/2008/01/14/retrying-code-blocks-in-ruby-on-exceptions-whatever/\ndef retryable(opts = nil)\n  opts   = { tries: 1, on: Exception }.merge(opts || {})\n\n  begin\n    return yield\n  rescue *opts[:on] => e\n    if (opts[:tries] -= 1) > 0\n      $stderr.puts(\"Retryable exception raised: #{e.inspect}\")\n\n      sleep opts[:sleep].to_f if opts[:sleep]\n      retry\n    end\n    raise\n  end\nend\n"
  },
  {
    "path": "TODO.md",
    "content": "# TODO\n\n# v0.4\n\n## Thor\n- Kill rake tasks, replace w/ pacto binary\n- Split Pacto server to separate repo??\n\n## Swagger converter\n- Legacy contracts -> Swagger\n\n## Swagger concepts not yet supported by Pacto\n- Support schemes (multiple)\n- Support multiple report types\n- Validate parameters\n- Support Swagger formats/serializations\n- Support Swagger examples, or extension for examples\n\n## Documentation\n\n- Polytrix samples -> docs\n\n# v0.5\n\n## Swagger\n- Support multiple media types (not just JSON)\n- Extension: templates for more advanced stubbing\n- Patterns: detect creation, auto-delete\n- Configure multiple producers: pacto server w/ multiple ports\n\n# v0.6\n\n## Nice to have\n\n\n# Someday\n\n- Pretty output for hash difference (using something like [hashdiff](https://github.com/liufengyun/hashdiff)).\n- A default header in the response marking the response as \"mocked\"\n\n## Assumptions\n\n- JSON Schema references are stored in the 'definitions' attribute, in the schema's root element.\n"
  },
  {
    "path": "appveyor.yml",
    "content": "version: 0.0.{build}\r\ninit:\r\n- choco install openssl.light\r\n- gem install bundler --quiet --no-ri --no-rdoc\r\n- gem install foreman --quiet --no-ri --no-rdoc\r\ninstall:\r\n- bundle install\r\nbuild: off\r\ntest_script:\r\n- START /B foreman start\r\n- bundle exec rake\r\n\r\n"
  },
  {
    "path": "bin/pacto",
    "content": "#!/usr/bin/env ruby\nrequire 'pacto/cli'\n\nPacto::CLI::Main.start\n"
  },
  {
    "path": "bin/pacto-server",
    "content": "#!/usr/bin/env ruby\nrequire 'pacto/server/cli'\n\nPacto::Server::CLI.start\n"
  },
  {
    "path": "changelog.md",
    "content": "## 0.3.2\n\n  *New Features:*\n    - #105: Add pacto-server for non-ruby tests.  Use the pacto-server gem.\n\n  *Breaking Changes:*\n    \n    - #107: Change default URI pattern to be less greedy.\n      /magazine will now not match also /magazine/last_edition.\n      query parameters after ? are still a match (ie /magazine?lastest=true)\n\n  *Bug Fixes:*\n    \n    - #106: Remove dead, undocumented tag feature\n\n\n## 0.3.1\n\n  *Enhancements:*\n    \n    - #103: Display file URI instead of meaningless schema identifier in messages\n\n  *Bug Fixes:*\n    \n    - #102: - Fix rake pacto:generate task\n\n\n## 0.3.0\n\n  First stable release\n"
  },
  {
    "path": "docs/configuration.md",
    "content": "Just require pacto to add it to your project.\n\n```rb\nrequire 'pacto'\n```\n\nPacto will disable live connections, so you will get an error if\nyour code unexpectedly calls an service that was not stubbed.  If you\nwant to re-enable connections, run `WebMock.allow_net_connect!`\n\n```rb\nWebMock.allow_net_connect!\n```\n\nPacto can be configured via a block:\n\n```rb\nPacto.configure do |c|\n```\n\nPath for loading/storing contracts.\n\n```rb\n  c.contracts_path = 'contracts'\n```\n\nIf the request matching should be strict (especially regarding HTTP Headers).\n\n```rb\n  c.strict_matchers = true\n```\n\nYou can set the Ruby Logger used by Pacto.\n\n```rb\n  c.logger = Pacto::Logger::SimpleLogger.instance\n```\n\n(Deprecated) You can specify a callback for post-processing responses.  Note that only one hook\ncan be active, and specifying your own will disable ERB post-processing.\n\n```rb\n  c.register_hook do |_contracts, request, _response|\n    puts \"Received #{request}\"\n  end\n```\n\nOptions to pass to the [json-schema-generator](https://github.com/maxlinc/json-schema-generator) while generating contracts.\n\n```rb\n  c.generator_options = { schema_version: 'draft3' }\nend\n```\n\nYou can also do inline configuration.  This example tells the json-schema-generator to store default values in the schema.\n\n```rb\nPacto.configuration.generator_options = { defaults: true }\n```\n\nIf you're using Pacto's rspec matchers you might want to configure a reset between each scenario\n\n```rb\nrequire 'pacto/rspec'\nRSpec.configure do |c|\n  c.after(:each)  { Pacto.clear! }\nend\n```\n\n"
  },
  {
    "path": "docs/consumer.md",
    "content": "\n```rb\nrequire 'pacto'\nPacto.load_contracts 'contracts', 'http://localhost:5000'\nWebMock.allow_net_connect!\n\ninteractions = Pacto.simulate_consumer :my_client do\n  request 'Ping'\n  request 'Echo', body: ->(body) { body.reverse },\n                  headers: (proc do |headers|\n                    headers['Content-Type'] = 'text/json'\n                    headers['Accept'] = 'none'\n                    headers\n                  end)\nend\nputs interactions\n```\n\n"
  },
  {
    "path": "docs/cops.md",
    "content": "\n```rb\nrequire 'pacto'\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\nPacto.validate!\n```\n\nYou can create a custom cop that investigates the request/response and sees if it complies with a\ncontract. The cop should return a list of citations if it finds any problems.\n\n```rb\nclass MyCustomCop\n  def investigate(_request, _response, contract)\n    citations = []\n    citations << 'Contract must have a request schema' if contract.request.schema.empty?\n    citations << 'Contract must have a response schema' if contract.response.schema.empty?\n    citations\n  end\nend\n\nPacto::Cops.active_cops << MyCustomCop.new\n\ncontracts = Pacto.load_contracts('contracts', 'http://localhost:5000')\ncontracts.stub_providers\nputs contracts.simulate_consumers\n```\n\nOr you can completely replace the default set of validators\n\n```rb\nPacto::Cops.registered_cops.clear\nPacto::Cops.register_cop Pacto::Cops::ResponseBodyCop\n\ncontracts = Pacto.load_contracts('contracts', 'http://localhost:5000')\nputs contracts.simulate_consumers\n```\n\n"
  },
  {
    "path": "docs/forensics.md",
    "content": "Pacto has a few RSpec matchers to help you ensure a **consumer** and **producer** are\ninteracting properly. First, let's setup the rspec suite.\n\n```rb\nrequire 'rspec/autorun' # Not generally needed\nrequire 'pacto/rspec'\nWebMock.allow_net_connect!\nPacto.validate!\nPacto.load_contracts('contracts', 'http://localhost:5000').stub_providers\n```\n\nIt's usually a good idea to reset Pacto between each scenario. `Pacto.reset` just clears the\ndata and metrics about which services were called. `Pacto.clear!` also resets all configuration\nand plugins.\n\n```rb\nRSpec.configure do |c|\n  c.after(:each)  { Pacto.reset }\nend\n```\n\nPacto provides some RSpec matchers related to contract testing, like making sure\nPacto didn't received any unrecognized requests (`have_unmatched_requests`) and that\nthe HTTP requests matched up with the terms of the contract (`have_failed_investigations`).\n\n```rb\ndescribe Faraday do\n  let(:connection) { described_class.new(url: 'http://localhost:5000') }\n\n  it 'passes contract tests' do\n    connection.get '/api/ping'\n    expect(Pacto).to_not have_failed_investigations\n    expect(Pacto).to_not have_unmatched_requests\n  end\nend\n```\n\nThere are also some matchers for collaboration testing, so you can make sure each scenario is\ncalling the expected services and sending the right type of data.\n\n```rb\ndescribe Faraday do\n  let(:connection) { described_class.new(url: 'http://localhost:5000') }\n  before(:each) do\n    connection.get '/api/ping'\n\n    connection.post do |req|\n      req.url '/api/echo'\n      req.headers['Content-Type'] = 'application/json'\n      req.body = '{\"foo\": \"bar\"}'\n    end\n  end\n\n  it 'calls the ping service' do\n    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping').against_contract('Ping')\n  end\n\n  it 'sends data to the echo service' do\n    expect(Pacto).to have_investigated('Ping').with_response(body: hash_including('ping' => 'pong - from the example!'))\n    expect(Pacto).to have_investigated('Echo').with_request(body: hash_including('foo' => 'bar'))\n    echoed_body = { 'foo' => 'bar' }\n    expect(Pacto).to have_investigated('Echo').with_request(body: echoed_body).with_response(body: echoed_body)\n  end\nend\n```\n\n"
  },
  {
    "path": "docs/generation.md",
    "content": "Some generation related [configuration](configuration.rb).\n\n```rb\nrequire 'pacto'\nWebMock.allow_net_connect!\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\nWebMock.allow_net_connect!\n```\n\nOnce we call `Pacto.generate!`, Pacto will record contracts for all requests it detects.\n\n```rb\nPacto.generate!\n```\n\nNow, if we run any code that makes an HTTP call (using an\n[HTTP library supported by WebMock](https://github.com/bblimke/webmock#supported-http-libraries))\nthen Pacto will generate a Contract based on the HTTP request/response.\n\nThis code snippet will generate a Contract and save it to `contracts/samples/contracts/localhost/api/ping.json`.\n\n```rb\nrequire 'faraday'\nconn = Faraday.new(url: 'http://localhost:5000')\nresponse = conn.get '/api/ping'\n```\n\nWe're getting back real data from GitHub, so this should be the actual file encoding.\n\n```rb\nputs response.body\n```\n\nThe generated contract will contain expectations based on the request/response we observed,\nincluding a best-guess at an appropriate json-schema.  Our heuristics certainly aren't foolproof,\nso you might want to customize schema!\nHere's another sample that sends a post request.\n\n```rb\nconn.post do |req|\n  req.url '/api/echo'\n  req.headers['Content-Type'] = 'application/json'\n  req.body = '{\"red fish\": \"blue fish\"}'\nend\n```\n\nYou can provide hints to Pacto to help it generate contracts. For example, Pacto doesn't have\na good way to know a good name and correct URI template for the service. That means that Pacto\nwill not know if two similar requests are for the same service or two different services, and\nwill be forced to give names based on the URI that are not good display names.\nThe hint below tells Pacto that requests to http://localhost:5000/album/1/cover and http://localhost:5000/album/2/cover\nare both going to the same service, which is known as \"Get Album Cover\". This hint will cause Pacto to\ngenerate a Contract for \"Get Album Cover\" and save it to `contracts/get_album_cover.json`, rather than two\ncontracts that are stored at `contracts/localhost/album/1/cover.json` and `contracts/localhost/album/2/cover.json`.\n\n```rb\nPacto::Generator.configure do |c|\n  c.hint 'Get Album Cover', http_method: :get, host: 'http://localhost:5000', path: '/api/album/{id}/cover'\nend\nconn.get '/api/album/1/cover'\nconn.get '/api/album/2/cover'\n```\n\n"
  },
  {
    "path": "docs/rake_tasks.md",
    "content": "# Rake tasks\n## This is a test!\n[That](www.google.com) markdown works\n\n```sh\nbundle exec rake pacto:meta_validate['contracts']\n\nbundle exec rake pacto:validate['http://localhost:5000','contracts']\n```\n\n"
  },
  {
    "path": "docs/rspec.md",
    "content": ""
  },
  {
    "path": "docs/samples.md",
    "content": "# Overview\nWelcome to the Pacto usage samples!\nThis document gives a quick overview of the main features.\n\nYou can browse the Table of Contents (upper right corner) to view additional samples.\n\nIn addition to this document, here are some highlighted samples:\n<ul>\n  <li><a href=\"configuration\">Configuration</a>: Shows all available configuration options</li>\n  <li><a href=\"generation\">Generation</a>: More details on generation</li>\n  <li><a href=\"rspec\">RSpec</a>: More samples for RSpec expectations</li>\n</ul>\nYou can also find other samples using the Table of Content (upper right corner), including sample contracts.\n# Getting started\nOnce you've installed the Pacto gem, you just require it.  If you want, you can also require the Pacto rspec expectations.\n\n```rb\nrequire 'pacto'\nrequire 'pacto/rspec'\n```\n\nPacto will disable live connections, so you will get an error if\nyour code unexpectedly calls an service that was not stubbed.  If you\nwant to re-enable connections, run `WebMock.allow_net_connect!`\n\n```rb\nWebMock.allow_net_connect!\n```\n\nPacto can be configured via a block.  The `contracts_path` option tells Pacto where it should load or save contracts.  See the [Configuration](configuration.html) for all the available options.\n\n```rb\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\n```\n\n# Generating a Contract\nCalling `Pacto.generate!` enables contract generation.\nPacto.generate!\nNow, if we run any code that makes an HTTP call (using an\n[HTTP library supported by WebMock](https://github.com/bblimke/webmock#supported-http-libraries))\nthen Pacto will generate a Contract based on the HTTP request/response.\n\nWe're using the sample APIs in the sample_apis directory.\n\n```rb\nrequire 'faraday'\nconn = Faraday.new(url: 'http://localhost:5000')\nresponse = conn.get '/api/ping'\n```\n\nThis is the real request, so you should see {\"ping\":\"pong\"}\n\n```rb\nputs response.body\n```\n\n# Testing providers by simulating consumers\nThe generated contract will contain expectations based on the request/response we observed,\nincluding a best-guess at an appropriate json-schema.  Our heuristics certainly aren't foolproof,\nso you might want to modify the output!\nWe can load the contract and validate it, by sending a new request and making sure\nthe response matches the JSON schema.  Obviously it will pass since we just recorded it,\nbut if the service has made a change, or if you alter the contract with new expectations,\nthen you will see a contract investigation message.\n\n```rb\ncontracts = Pacto.load_contracts('contracts', 'http://localhost:5000')\ncontracts.simulate_consumers\n```\n\n# Stubbing providers for consumer testing\nWe can also use Pacto to stub the service based on the contract.\n\n```rb\ncontracts.stub_providers\n```\n\nThe stubbed data won't be very realistic, the default behavior is to return the simplest data\nthat complies with the schema.  That basically means that you'll have \"bar\" for every string.\n\n```rb\nresponse = conn.get '/api/ping'\n```\n\nYou're now getting stubbed data.  You should see {\"ping\":\"bar\"} unless you recorded with\nthe `defaults` option enabled, in which case you will still seee {\"ping\":\"pong\"}.\n\n```rb\nputs response.body\n```\n\n# Collaboration tests with RSpec\nPacto comes with rspec matchers\n\n```rb\nrequire 'pacto/rspec'\n```\n\nIt's probably a good idea to reset Pacto between each rspec scenario\n\n```rb\nRSpec.configure do |c|\n  c.after(:each)  { Pacto.clear! }\nend\n```\n\nLoad your contracts, and stub them if you'd like.\n\n```rb\nPacto.load_contracts('contracts', 'http://localhost:5000').stub_providers\n```\n\nYou can turn on investigation mode so Pacto will detect and validate HTTP requests.\n\n```rb\nPacto.validate!\n\ndescribe 'my_code' do\n  it 'calls a service' do\n    conn = Faraday.new(url: 'http://localhost:5000')\n    response = conn.get '/api/ping'\n```\n\nThe have_validated matcher makes sure that Pacto received and successfully validated a request\n\n```rb\n    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping')\n  end\nend\n```\n\n"
  },
  {
    "path": "docs/server.md",
    "content": "\n```rb\nrequire 'pacto/rspec'\nrequire 'pacto/test_helper'\n\ndescribe 'ping service' do\n  include Pacto::TestHelper\n\n  it 'pongs' do\n    with_pacto(\n      port: 6000,\n      backend_host: 'http://localhost:5000',\n      live: true,\n      stub: false,\n      generate: false,\n      directory: 'contracts'\n      ) do |pacto_endpoint|\n```\n\ncall your code\n\n```rb\n      system \"curl #{pacto_endpoint}/api/ping\"\n    end\n```\n\ncheck citations\n\n```rb\n    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping')\n  end\nend\n```\n\n"
  },
  {
    "path": "docs/server_cli.md",
    "content": "# Standalone server\nYou can run Pacto as a server in order to test non-Ruby projects. In order to get the full set\nof options, run:\n\n```sh\nbundle exec pacto-server -h\n```\n\nYou probably want to run with the -sv option, which will display verbose output to stdout. You can\nrun server that proxies to a live endpoint:\n\n```sh\nbundle exec pacto-server -sv --port 9000 --live http://example.com &\nbundle exec pacto-server -sv --port 9001 --stub &\n\npkill -f pacto-server\n```\n\n"
  },
  {
    "path": "docs/stenographer.md",
    "content": "\n```rb\nrequire 'pacto'\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\ncontracts = Pacto.load_contracts('contracts', 'http://localhost:5000')\ncontracts.stub_providers\n\nPacto.simulate_consumer do\n  request 'Echo', values: nil, response: { status: 200 } # 0 contract violations\n  request 'Ping', values: nil, response: { status: 200 } # 0 contract violations\n  request 'Unknown (http://localhost:8000/404)', values: nil, response: { status: 500 } # 0 contract violations\nend\n\nPacto.simulate_consumer :my_consumer do\n  playback 'pacto_stenographer.log'\nend\n```\n\n"
  },
  {
    "path": "features/configuration/strict_matchers.feature",
    "content": "Feature: Strict Matching\n\n  By default, Pacto matches requests to contracts (and stubs) using exact request paths, parameters, and headers.  This strict behavior is useful for Consumer-Driven Contracts.\n\n  You can use less strict matching so the same contract can match multiple similar requests.  This is useful for matching contracts with resource identifiers in the path.  Any placeholder in the path (like :id in /beers/:id) is considered a resource identifier and will match any alphanumeric combination.\n\n  You can change the default behavior to the behavior that allows placeholders and ignores headers or request parameters by setting the strict_matchers configuration option:\n\n  ```ruby\n    Pacto.configure do |config|\n      config.strict_matchers = false\n    end\n  ```\n\n  Background:\n    Given a file named \"contracts/hello_contract.json\" with:\n      \"\"\"json\n      {\n        \"request\": {\n          \"http_method\": \"GET\",\n          \"path\": \"/hello/{id}\",\n          \"headers\": {\n            \"Accept\": \"application/json\"\n          },\n          \"params\": {}\n        },\n\n        \"response\": {\n          \"status\": 200,\n          \"headers\": { \"Content-Type\": \"application/json\" },\n          \"schema\": {\n            \"type\": \"object\",\n            \"required\": true,\n            \"properties\": {\n              \"message\": { \"type\": \"string\", \"required\": true, \"default\": \"Hello, world!\" }\n            }\n          }\n        }\n      }\n      \"\"\"\n\n    Given a file named \"requests.rb\" with:\n      \"\"\"ruby\n      require 'pacto'\n\n      strict = ARGV[0] == \"true\"\n      puts \"Pacto.configuration.strict_matchers = #{strict}\"\n      puts\n\n      Pacto.configure do |config|\n        config.strict_matchers = strict\n      end\n      Pacto.load_contracts('contracts', 'http://dummyprovider.com').stub_providers\n\n      def response url, headers\n        begin\n          response = Faraday.get(url) do |req|\n            req.headers = headers[:headers]\n          end\n          response.body\n        rescue WebMock::NetConnectNotAllowedError => e\n          e.class\n        end\n      end\n\n      print 'Exact: '\n      puts response URI.encode('http://dummyprovider.com/hello/{id}'), headers: {'Accept' => 'application/json' }\n\n      print 'Wrong headers: '\n      puts response 'http://dummyprovider.com/hello/123', headers: {'Content-Type' => 'application/json' }\n\n      print 'ID placeholder: '\n      puts response 'http://dummyprovider.com/hello/123', headers: {'Accept' => 'application/json' }\n      \"\"\"\n\n  Scenario: Default (strict) behavior\n    When I run `bundle exec ruby requests.rb true`\n    Then the stdout should contain:\n      \"\"\"\n      Pacto.configuration.strict_matchers = true\n\n      Exact: {\"message\":\"Hello, world!\"}\n      Wrong headers: WebMock::NetConnectNotAllowedError\n      ID placeholder: {\"message\":\"Hello, world!\"}\n\n      \"\"\"\n\n  Scenario: Non-strict matching\n    When I run `bundle exec ruby requests.rb false`\n    Then the stdout should contain:\n      \"\"\"\n      Pacto.configuration.strict_matchers = false\n\n      Exact: {\"message\":\"Hello, world!\"}\n      Wrong headers: {\"message\":\"Hello, world!\"}\n      ID placeholder: {\"message\":\"Hello, world!\"}\n      \"\"\"\n"
  },
  {
    "path": "features/evolve/README.md",
    "content": "## Consumer-Driven Contract Recommendations\n\nIf you are using Pacto for Consumer-Driven Contracts, we recommend avoiding the advanced features so you'll test with the strictest Contract possible.  We recommend:\n\n- Do not use templating, let Pacto use the json-generator\n- Use strict request matching\n- Use multiple contracts for the same service to capture attributes that are required in some situations but not others\n\nThe host address is intentionally left out of the request specification so that we can validate a contract against any provider.\nIt also reinforces the fact that a contract defines the expectation of a consumer, and not the implementation of any specific provider.\n\n"
  },
  {
    "path": "features/evolve/existing_services.feature",
    "content": "Feature: Existing services journey\n\n  Scenario: Generating the contracts\n    Given I have a Rakefile\n    Given an existing set of services\n    When I execute:\n    \"\"\"ruby\n    require 'pacto'\n\n    Pacto.configure do | c |\n      c.contracts_path = 'contracts'\n    end\n\n    Pacto.generate!\n\n    Faraday.get 'http://www.example.com/service1'\n    Faraday.get 'http://www.example.com/service2'\n    \"\"\"\n    Then the following files should exist:\n    | contracts/www.example.com/service1.json |\n    | contracts/www.example.com/service2.json |\n\n  @no-clobber\n  Scenario: Ensuring all contracts are valid\n    When I successfully run `bundle exec rake pacto:meta_validate['contracts']`\n    Then the stdout should contain exactly:\n    \"\"\"\n       validated  contracts/www.example.com/service1.json\n       validated  contracts/www.example.com/service2.json\n    All contracts successfully meta-validated\n\n    \"\"\"\n\n  # TODO: find where Webmock is being called with and an empty :with\n  # and update it, to not use with so we can upgrade Webmock past 1.20.2\n  @no-clobber\n  Scenario: Stubbing with the contracts\n    Given a file named \"test.rb\" with:\n    \"\"\"ruby\n    require 'pacto'\n\n    Pacto.configure do | c |\n      c.contracts_path = 'contracts'\n    end\n\n    contracts = Pacto.load_contracts('contracts/www.example.com/', 'http://www.example.com')\n    contracts.stub_providers\n\n    puts Faraday.get('http://www.example.com/service1').body\n    puts Faraday.get('http://www.example.com/service2').body\n    \"\"\"\n    When I successfully run `bundle exec ruby test.rb`\n    Then the stdout should contain exactly:\n    \"\"\"\n    {\"thoughtworks\":\"pacto\"}\n    {\"service2\":[\"thoughtworks\",\"pacto\"]}\n\n    \"\"\"\n\n  @no-clobber\n  Scenario: Expecting a change\n    When I make replacements in \"contracts/www.example.com/service1.json\":\n    | pattern | replacement |\n    | string  | integer     |\n    When I execute:\n    \"\"\"ruby\n    require 'pacto'\n\n    Pacto.stop_generating!\n\n    Pacto.configure do | c |\n      c.contracts_path = 'contracts'\n    end\n\n    Pacto.load_contracts('contracts', 'http://www.example.com').stub_providers\n    Pacto.validate!\n\n    Faraday.get 'http://www.example.com/service1'\n    Faraday.get 'http://www.example.com/service2'\n    \"\"\"\n    Then the stdout should contain exactly:\n    \"\"\"\n\n    \"\"\"\n"
  },
  {
    "path": "features/generate/README.md",
    "content": "We know - json-schema can get pretty verbose!  It's a powerful tool, but writing the entire Contract by hand for a complex service is a painstaking task.  We've created a simple generator to speed this process up.  You can invoke it programmatically, or with the provided rake task.\n\nThe basic generate we've bundled with Pacto completes partially defined Contracts - Contracts that have a request defined but no response.  We haven't bundled any other generates, but you could use the API to generate from other sources, like existing [VCR](https://github.com/vcr/vcr) cassettes, [apiblueprint](http://apiblueprint.org/), or [WADL](https://wadl.java.net/).  If you want some help or ideas, try the [pacto mailing-list](https://groups.google.com/forum/#!forum/pacto-gem).\n\nNote: Request headers are only recorded if they are in the response's [Vary header](http://www.subbu.org/blog/2007/12/vary-header-for-restful-applications), so make sure your services return a proper Vary for best results!"
  },
  {
    "path": "features/generate/generation.feature",
    "content": "@needs_server\nFeature: Contract Generation\n\n  We know - json-schema can get pretty verbose!  It's a powerful tool, but writing the entire Contract by hand for a complex service is a painstaking task.  We've created a simple generator to speed this process up.  You can invoke it programmatically, or with the provided rake task.\n\n  You just need to create a partial Contract that only describes the request.  The generator will then execute the request, and use the response to generate a full Contract.\n\n  Remember, we only record request headers if they are in the response's [Vary header](http://www.subbu.org/blog/2007/12/vary-header-for-restful-applications), so make sure your services return a proper Vary for best results!\n\n  Background:\n    Given a file named \"requests/my_contract.json\" with:\n    \"\"\"\n      {\n        \"request\": {\n          \"http_method\": \"GET\",\n          \"path\": \"/api/ping\",\n          \"headers\": {\n            \"Accept\": \"application/json\"\n          }\n        },\n        \"response\": {\n          \"status\": 200,\n          \"schema\": {\n            \"required\": true\n          }\n        }\n      }\n    \"\"\"\n\n  Scenario: Generating a contract using the rake task\n    Given a directory named \"contracts\"\n    When I successfully run `bundle exec rake pacto:generate['tmp/aruba/requests','tmp/aruba/contracts','http://localhost:5000']`\n    Then the stdout should contain \"Successfully generated all contracts\"\n\n  Scenario: Generating a contract programmatically\n    Given a file named \"generate.rb\" with:\n    \"\"\"ruby\n    require 'pacto'\n    Pacto.configuration.generator_options[:no_examples] = true\n\n    WebMock.allow_net_connect!\n    generator = Pacto::Generator.contract_generator\n    contract = generator.generate_from_partial_contract('requests/my_contract.json', 'http://localhost:5000')\n    puts contract\n    \"\"\"\n    When I successfully run `bundle exec ruby generate.rb`\n    Then the stdout should match this contract:\n    \"\"\"json\n    {\n      \"name\": \"/api/ping\",\n      \"request\": {\n        \"headers\": {\n        },\n        \"http_method\": \"get\",\n        \"path\": \"/api/ping\"\n      },\n      \"response\": {\n        \"headers\": {\n          \"Content-Type\": \"application/json\"\n        },\n        \"status\": 200,\n        \"schema\": {\n          \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n          \"description\": \"Generated from requests/my_contract.json with shasum 210fa3b144ef2db8d1c160c4d9e8d8bf738ed851\",\n          \"type\": \"object\",\n          \"required\": true,\n          \"properties\": {\n            \"ping\": {\n              \"type\": \"string\",\n              \"required\": true\n            }\n          }\n        }\n      }\n    }\n\n    \"\"\"\n"
  },
  {
    "path": "features/steps/pacto_steps.rb",
    "content": "# -*- encoding : utf-8 -*-\nGiven(/^Pacto is configured with:$/) do |string|\n  steps %(\n    Given a file named \"pacto_config.rb\" with:\n    \"\"\"ruby\n    #{string}\n    \"\"\"\n  )\nend\n\nGiven(/^I have a Rakefile$/) do\n  steps %(\n    Given a file named \"Rakefile\" with:\n    \"\"\"ruby\n    require 'pacto/rake_task'\n    \"\"\"\n  )\nend\n\nWhen(/^I request \"(.*?)\"$/) do |url|\n  steps %{\n    Given a file named \"request.rb\" with:\n    \"\"\"ruby\n    require 'pacto'\n    require_relative 'pacto_config'\n    require 'faraday'\n\n    resp = Faraday.get('#{url}') do |req|\n      req.headers = { 'Accept' => 'application/json' }\n    end\n    puts resp.body\n    \"\"\"\n    When I run `bundle exec ruby request.rb`\n  }\nend\n\nGiven(/^an existing set of services$/) do\n  WebMock.stub_request(:get, 'www.example.com/service1').to_return(body: { 'thoughtworks' => 'pacto' }.to_json)\n  WebMock.stub_request(:post, 'www.example.com/service1').with(body: 'thoughtworks').to_return(body: 'pacto')\n  WebMock.stub_request(:get, 'www.example.com/service2').to_return(body: { 'service2' => %w(thoughtworks pacto) }.to_json)\n  WebMock.stub_request(:post, 'www.example.com/service2').with(body: 'thoughtworks').to_return(body: 'pacto')\nend\n\nWhen(/^I execute:$/) do |script|\n  FileUtils.mkdir_p 'tmp/aruba'\n  Dir.chdir 'tmp/aruba' do\n    begin\n      script = <<-eof\n      require 'stringio'\n      begin $stdout = StringIO.new\n        #{ script }\n        $stdout.string\n      ensure\n        $stdout = STDOUT\n      end\neof\n      eval(script) # rubocop:disable Eval\n    # It's just for testing...\n\n    rescue SyntaxError => e\n      raise e\n    end\n  end\nend\n\nWhen(/^I make replacements in \"([^\"]*)\":$/) do |file_name, replacements|\n  Dir.chdir 'tmp/aruba' do\n    content = File.read file_name\n    replacements.rows.each do | pattern, replacement |\n      content.gsub! Regexp.new(pattern), replacement\n    end\n\n    File.open(file_name, 'w') { |file| file.write content }\n  end\nend\n\nThen(/^the stdout should match this contract:$/) do |expected_contract|\n  actual_contract = all_stdout\n  expect(actual_contract).to be_json_eql(expected_contract).excluding('description')\nend\n"
  },
  {
    "path": "features/stub/README.md",
    "content": "You can write your own stubs and use Pacto to [validate](https://www.relishapp.com/maxlinc/pacto/docs/validate) them, or you can just let Pacto create stubs for you.\n\n"
  },
  {
    "path": "features/stub/templates.feature",
    "content": "Feature: Templating\n\n  If you want to create more dynamic stubs, you can use Pacto templating.  Currently the only supported templating mechanism is to use ERB in the \"default\" attributes of the json-schema.\n\n  Background:\n    Given Pacto is configured with:\n      \"\"\"ruby\n      Pacto.configure do |c|\n        c.register_hook Pacto::Hooks::ERBHook.new\n      end\n      Pacto.load_contracts('contracts', 'http://example.com').stub_providers\n      \"\"\"\n    Given a file named \"contracts/template.json\" with:\n      \"\"\"json\n      {\n        \"request\": {\n          \"http_method\": \"GET\",\n          \"path\": \"/hello\",\n          \"headers\": {\n            \"Accept\": \"application/json\"\n          },\n          \"params\": {}\n        },\n\n        \"response\": {\n          \"status\": 200,\n          \"headers\": { \"Content-Type\": \"application/json\" },\n          \"schema\": {\n            \"type\": \"object\",\n            \"required\": true,\n            \"properties\": {\n              \"message\": { \"type\": \"string\", \"required\": true,\n                \"default\": \"<%= 'Hello, world!'.reverse %>\"\n              }\n            }\n          }\n        }\n      }\n      \"\"\"\n\n  Scenario: ERB Template\n    When I request \"http://example.com/hello\"\n    Then the stdout should contain:\n      \"\"\"\n      {\"message\":\"!dlrow ,olleH\"}\n      \"\"\"\n"
  },
  {
    "path": "features/support/env.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire_relative '../../spec/coveralls_helper'\nrequire 'aruba'\nrequire 'aruba/cucumber'\nrequire 'json_spec/cucumber'\nrequire 'aruba/jruby' if RUBY_PLATFORM == 'java'\nrequire 'pacto/test_helper'\n\nPacto.configuration.hide_deprecations = true\n\nBefore do\n  # Given I successfully run `bundle install` can take a while.\n  @aruba_timeout_seconds = RUBY_PLATFORM == 'java' ? 60 : 10\nend\n\nclass PactoWorld\n  include Pacto::TestHelper\nend\n\nWorld do\n  PactoWorld.new\nend\n\nAround do | _scenario, block |\n  WebMock.allow_net_connect!\n  world = self || PactoWorld.new\n  world.with_pacto(port: 8000, live: true, backend_host: 'http://localhost:5000') do\n    block.call\n  end\nend\n"
  },
  {
    "path": "features/validate/README.md",
    "content": "You can use Pacto to do Integration Contract Testing - making sure your service and any test double that simulates the service are similar.  If you generate your Contracts from documentation, you can be fairly confident that all three - live services, test doubles, and documentation - are in sync."
  },
  {
    "path": "features/validate/meta_validation.feature",
    "content": "Feature: Meta-validation\n\n  Meta-validation ensures that a Contract file matches the Contract format.  It does not validation actual responses, just the Contract itself.\n\n  You can easily do meta-validation with the Rake task pacto:meta_validate, or programmatically.\n\n  Background:\n    Given a file named \"contracts/my_contract.json\" with:\n      \"\"\"\n          {\n          \"request\": {\n            \"http_method\": \"GET\",\n            \"path\": \"/hello_world\",\n            \"headers\": {\n              \"Accept\": \"application/json\"\n            },\n            \"params\": {}\n          },\n\n          \"response\": {\n            \"status\": 200,\n            \"headers\": {\n              \"Content-Type\": \"application/json\"\n            },\n            \"schema\": {\n              \"description\": \"A simple response\",\n              \"type\": \"object\",\n              \"required\": [\"message\"],\n              \"properties\": {\n                \"message\": {\n                  \"type\": \"string\"\n                }\n              }\n            }\n          }\n        }\n      \"\"\"\n\n  Scenario: Meta-validation via a rake task\n    When I successfully run `bundle exec rake pacto:meta_validate['tmp/aruba/contracts/my_contract.json']`\n    Then the stdout should contain \"All contracts successfully meta-validated\"\n\n# The tests from here down should probably be specs instead of relish\n\n  Scenario: Meta-validation of an invalid contract\n    Given a file named \"contracts/my_contract.json\" with:\n    \"\"\"\n    {\"request\": \"yes\"}\n    \"\"\"\n    When I run `bundle exec rake pacto:meta_validate['tmp/aruba/contracts/my_contract.json']`\n    Then the exit status should be 1\n    And the stdout should contain \"did not match the following type\"\n\n\n  Scenario: Meta-validation of a contract with empty request and response\n    Given a file named \"contracts/my_contract.json\" with:\n    \"\"\"\n    {\"request\": {}, \"response\": {}}\n    \"\"\"\n    When I run `bundle exec rake pacto:meta_validate['tmp/aruba/contracts/my_contract.json']`\n    Then the exit status should be 1\n    And the stdout should contain \"did not contain a required property\"\n\n  Scenario: Meta-validation of a contracts response body\n    Given a file named \"contracts/my_contract.json\" with:\n    \"\"\"\n        {\n        \"request\": {\n          \"http_method\": \"GET\",\n          \"path\": \"/hello_world\"\n        },\n\n        \"response\": {\n          \"status\": 200,\n          \"schema\": {\n            \"required\": \"anystring\"\n            }\n          }\n        }\n    \"\"\"\n    When I run `bundle exec rake pacto:meta_validate['tmp/aruba/contracts/my_contract.json']`\n    Then the exit status should be 1\n    And the stdout should contain \"did not match the following type\"\n"
  },
  {
    "path": "features/validate/validation.feature",
    "content": "Feature: Validation\n\n  Validation ensures that a external service conform to a Contract.\n\n  Scenario: Validation via a rake task\n    Given a file named \"contracts/simple_contract.json\" with:\n      \"\"\"\n          {\n          \"request\": {\n            \"http_method\": \"GET\",\n            \"path\": \"/api/hello\",\n            \"headers\": { \"Accept\": \"application/json\" },\n            \"params\": {}\n          },\n\n          \"response\": {\n            \"status\": 200,\n            \"headers\": { \"Content-Type\": \"application/json\" },\n            \"schema\": {\n              \"description\": \"A simple response\",\n              \"type\": \"object\",\n              \"properties\": {\n                \"message\": { \"type\": \"string\" }\n              }\n            }\n          }\n        }\n      \"\"\"\n      When I successfully run `bundle exec rake pacto:validate['http://localhost:5000','tmp/aruba/contracts/simple_contract.json']`\n      Then the stdout should contain:\n        \"\"\"\"\n        Validating contracts against host http://localhost:5000\n                 OK!  simple_contract.json\n        1 valid contract\n        \"\"\"\n"
  },
  {
    "path": "lib/pacto/actor.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Actor\n  end\nend\n"
  },
  {
    "path": "lib/pacto/actors/from_examples.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Actors\n    class FirstExampleSelector\n      def self.select(examples, _values)\n        Hashie::Mash.new examples.values.first\n      end\n    end\n    class RandomExampleSelector\n      def self.select(examples, _values)\n        Hashie::Mash.new examples.values.sample\n      end\n    end\n    class NamedExampleSelector\n      def self.select(examples, values)\n        name = values[:example_name]\n        if name.nil?\n          RandomExampleSelector.select(examples, values)\n        else\n          Hashie::Mash.new examples[name]\n        end\n      end\n    end\n    class FromExamples < Actor\n      def initialize(fallback_actor = JSONGenerator.new, selector = Pacto::Actors::FirstExampleSelector)\n        @fallback_actor = fallback_actor\n        @selector = selector\n      end\n\n      def build_request(contract, values = {})\n        request_values = (values || {}).dup\n        if contract.examples?\n          example = @selector.select(contract.examples, values)\n          data = contract.request.to_hash\n          request_values.merge! example_uri_values(contract)\n          data['uri'] = contract.request.uri(request_values)\n          data['body'] = example.request.body\n          data['method'] = contract.request.http_method\n          Pacto::PactoRequest.new(data)\n        else\n          @fallback_actor.build_request contract, values\n        end\n      end\n\n      def build_response(contract, values = {})\n        if contract.examples?\n          example = @selector.select(contract.examples, values)\n          data = contract.response.to_hash\n          data['body'] = example.response.body\n          Pacto::PactoResponse.new(data)\n        else\n          @fallback_actor.build_response contract, values\n        end\n      end\n\n      def example_uri_values(contract)\n        uri_template = contract.request.pattern.uri_template\n        if contract.examples && contract.examples.values.first[:request][:uri]\n          example_uri = contract.examples.values.first[:request][:uri]\n          uri_template.extract example_uri\n        else\n          {}\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/actors/json_generator.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Actors\n    class JSONGenerator < Actor\n      def build_request(contract, values = {})\n        data = contract.request.to_hash\n        data['uri'] = contract.request.uri(values)\n        data['body'] = JSON::Generator.generate(data['schema']) if data['schema']\n        data['method'] = contract.request.http_method\n        Pacto::PactoRequest.new(data)\n      end\n\n      def build_response(contract, _values = {})\n        data = contract.response.to_hash\n        data['body'] = JSON::Generator.generate(data['schema'])\n        Pacto::PactoResponse.new(data)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/body_parsing.rb",
    "content": "# -*- encoding : utf-8 -*-\n\nmodule Pacto\n  module Handlers\n    autoload :JSONHandler, 'pacto/handlers/json_handler'\n    autoload :TextHandler, 'pacto/handlers/text_handler'\n    autoload :XMLHandler,  'pacto/handlers/xml_handler'\n  end\n  module BodyParsing\n    def raw_body\n      return nil if body.nil?\n      return body if body.respond_to? :to_str\n\n      body_handler.raw(body)\n    end\n\n    def parsed_body\n      return nil if body.nil?\n\n      body_handler.parse(body)\n    end\n\n    def content_type\n      headers['Content-Type']\n    end\n\n    def body_handler\n      case content_type\n      when /\\bjson$/\n        Pacto::Handlers::JSONHandler\n      when /\\btext$/\n        Pacto::Handlers::TextHandler\n      # No XML support - yet\n      # when /\\bxml$/\n      #   XMLHandler\n      else\n        # JSON is still the default\n        Pacto::Handlers::JSONHandler\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/cli/helpers.rb",
    "content": "module Pacto\n  module CLI\n    module Helpers\n      def each_contract(*contracts)\n        [*contracts].each do |contract|\n          if File.file? contract\n            yield contract\n          else # Should we assume it's a dir, or also support glob patterns?\n            contracts = Dir[File.join(contract, '**/*{.json.erb,.json}')]\n            fail Pacto::UI.colorize(\"No contracts found in directory #{contract}\", :yellow) if contracts.empty?\n\n            contracts.sort.each do |contract_file|\n              yield contract_file\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/cli.rb",
    "content": "require 'thor'\nrequire 'pacto'\nrequire 'pacto/cli/helpers'\n\nmodule Pacto\n  module CLI\n    class Main < Thor\n      include Pacto::CLI::Helpers\n\n      desc 'meta_validate [CONTRACTS...]', 'Validates a directory of contract definitions'\n      def meta_validate(*contracts)\n        invalid = []\n        each_contract(*contracts) do |contract_file|\n          begin\n            Pacto.validate_contract(contract_file)\n            say_status :validated, contract_file\n          rescue InvalidContract => exception\n            invalid << contract_file\n            shell.say_status :invalid, contract_file, :red\n            exception.errors.each do |error|\n              say set_color(\"  Error: #{error}\", :red)\n            end\n          end\n        end\n        abort \"The following contracts were invalid: #{invalid.join(',')}\" unless invalid.empty?\n        say 'All contracts successfully meta-validated'\n      end\n\n      desc 'validate [CONTRACTS...]', 'Validates all contracts in a given directory against a given host'\n      method_option :host, type: :string, desc: 'Override host in contracts for validation'\n      def validate(*contracts)\n        host = options[:host]\n        WebMock.allow_net_connect!\n        banner = 'Validating contracts'\n        banner << \" against host #{host}\" unless host.nil?\n        say banner\n\n        invalid_contracts = []\n        tested_contracts = []\n        each_contract(*contracts) do |contract_file|\n          tested_contracts << contract_file\n          invalid_contracts << contract_file unless contract_is_valid?(contract_file, host)\n        end\n\n        validation_summary(tested_contracts, invalid_contracts)\n      end\n\n      private\n\n      def validation_summary(contracts, invalid_contracts)\n        if invalid_contracts.empty?\n          say set_color(\"#{contracts.size} valid contract#{contracts.size > 1 ? 's' : nil}\", :green)\n        else\n          abort set_color(\"#{invalid_contracts.size} of #{contracts.size} failed. Check output for detailed error messages.\", :red)\n        end\n      end\n\n      def contract_is_valid?(contract_file, host)\n        name = File.split(contract_file).last\n        contract = Pacto.load_contract(contract_file, host)\n        investigation = contract.simulate_request\n\n        if investigation.successful?\n          say_status 'OK!', name\n          true\n        else\n          say_status 'FAILED!', name, :red\n          say set_color(investigation.summary, :red)\n          say set_color(investigation.to_s, :red)\n          false\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/consumer/faraday_driver.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Consumer\n    class FaradayDriver\n      include Pacto::Logger\n      # Sends a Pacto::PactoRequest\n      def execute(req)\n        conn_options = { url: req.uri.site }\n        conn_options[:proxy] = Pacto.configuration.proxy if Pacto.configuration.proxy\n        conn = Faraday.new(conn_options) do |faraday|\n          faraday.response :logger if Pacto.configuration.logger.level == :debug\n          faraday.adapter Faraday.default_adapter\n        end\n\n        response = conn.send(req.method) do |faraday_request|\n          faraday_request.url(req.uri.path, req.uri.query_values)\n          faraday_request.headers = req.headers\n          faraday_request.body = req.raw_body\n        end\n\n        faraday_to_pacto_response response\n      end\n\n      private\n\n      # This belongs in an adapter\n      def faraday_to_pacto_response(faraday_response)\n        data = {\n          status: faraday_response.status,\n          headers: faraday_response.headers,\n          body: faraday_response.body\n        }\n        Pacto::PactoResponse.new(data)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/consumer.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  def self.consumers\n    @consumers ||= {}\n  end\n\n  def self.simulate_consumer(consumer_name = :consumer, &block)\n    consumers[consumer_name] ||= Consumer.new(consumer_name)\n    consumers[consumer_name].simulate(&block)\n  end\n\n  class Consumer\n    include Logger\n    include Resettable\n\n    def initialize(name = :consumer)\n      @name = name\n    end\n\n    def simulate(&block)\n      instance_eval(&block)\n    end\n\n    def playback(stenographer_script)\n      script = File.read(stenographer_script)\n      instance_eval script, stenographer_script\n    end\n\n    def self.reset!\n      Pacto.consumers.clear\n    end\n\n    def actor\n      @actor ||= Pacto::Actors::FromExamples.new\n    end\n\n    def actor=(actor)\n      fail ArgumentError, 'The actor must respond to :build_request' unless actor.respond_to? :build_request\n      @actor = actor\n    end\n\n    def request(contract, data = {})\n      contract = Pacto.contract_registry.find_by_name(contract) if contract.is_a? String\n      logger.info \"Sending request to #{contract.name.inspect}\"\n      logger.info \"  with #{data.inspect}\"\n      reenact(contract, data)\n    rescue ContractNotFound => e\n      logger.warn \"Ignoring request: #{e.message}\"\n    end\n\n    def reenact(contract, data = {})\n      request = build_request contract, data\n      response = driver.execute request\n      [request, response]\n    end\n\n    # Returns the current driver\n    def driver\n      @driver ||= Pacto::Consumer::FaradayDriver.new\n    end\n\n    # Changes the driver\n    def driver=(driver)\n      fail ArgumentError, 'The driver must respond to :execute' unless driver.respond_to? :execute\n      @driver = driver\n    end\n\n    # @api private\n    def build_request(contract, data = {})\n      actor.build_request(contract, data[:values]).tap do |request|\n        if data[:headers] && data[:headers].respond_to?(:call)\n          request.headers = data[:headers].call(request.headers)\n        end\n        if data[:body] && data[:body].respond_to?(:call)\n          request.body = data[:body].call(request.body)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/contract.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Contract\n    include Logger\n\n    attr_reader :id\n    attr_reader :file\n    attr_reader :request\n    attr_reader :response\n    attr_reader :values\n    attr_reader :examples\n    attr_reader :name\n    attr_writer :adapter\n    attr_writer :consumer\n    attr_writer :provider\n\n    def adapter\n      @adapter ||= Pacto.configuration.adapter\n    end\n\n    def consumer\n      @consumer ||= Pacto.configuration.default_consumer\n    end\n\n    def provider\n      @provider ||= Pacto.configuration.default_provider\n    end\n\n    def examples?\n      examples && !examples.empty?\n    end\n\n    def stub_contract!(values = {})\n      self.values = values\n      adapter.stub_request!(self)\n    end\n\n    def simulate_request\n      pacto_request, pacto_response = execute\n      validate_response pacto_request, pacto_response\n    end\n\n    # Should this be deprecated?\n    def validate_response(request, response)\n      Pacto::Cops.perform_investigation request, response, self\n    end\n\n    def matches?(request_signature)\n      request_pattern.matches? request_signature\n    end\n\n    def request_pattern\n      request.pattern\n    end\n\n    def response_for(pacto_request)\n      provider.response_for self, pacto_request\n    end\n\n    def execute(additional_values = {})\n      # FIXME: Do we really need to store on the Contract, or just as a param for #stub_contact! and #execute?\n      full_values = values.merge(additional_values)\n      consumer.reenact(self, full_values)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/contract_factory.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class ContractFactory\n    include Singleton\n    include Logger\n\n    def initialize\n      @factories = {}\n    end\n\n    def add_factory(format, factory)\n      @factories[format.to_sym] = factory\n    end\n\n    def remove_factory(format)\n      @factories.delete format\n    end\n\n    def build(contract_files, host, format = :legacy)\n      factory = @factories[format.to_sym]\n      fail \"No Contract factory registered for #{format}\" if factory.nil?\n\n      contract_files.map { |file| factory.build_from_file(file, host) }.flatten\n    end\n\n    def load_contracts(contracts_path, host, format = :legacy)\n      factory = @factories[format.to_sym]\n      files = factory.files_for(contracts_path)\n      contracts = ContractFactory.build(files, host, format)\n      contracts\n    end\n\n    class << self\n      extend Forwardable\n      def_delegators :instance, *ContractFactory.instance_methods(false)\n    end\n  end\nend\n\nrequire 'pacto/formats/legacy/contract_factory'\nrequire 'pacto/formats/swagger/contract_factory'\n"
  },
  {
    "path": "lib/pacto/contract_files.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pathname'\nmodule Pacto\n  class ContractFiles\n    def self.for(path)\n      full_path = Pathname.new(path).realpath\n\n      if  full_path.directory?\n        all_json_files = \"#{full_path}/**/*.json\"\n        Dir.glob(all_json_files).map do |f|\n          Pathname.new(f)\n        end\n      else\n        [full_path]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/contract_set.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class ContractSet < Set\n    def stub_providers(values = {})\n      each { |contract| contract.stub_contract!(values) }\n    end\n\n    def simulate_consumers\n      map(&:simulate_request)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/cops/body_cop.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class BodyCop\n      KNOWN_CLAUSES = [:request, :response]\n\n      def self.validates(clause)\n        fail ArgumentError, \"Unknown clause: #{clause}\" unless KNOWN_CLAUSES.include? clause\n        @clause = clause\n      end\n\n      def self.investigate(request, response, contract)\n        # eval \"is a security risk\" and local_variable_get is ruby 2.1+ only, so...\n        body = { request: request, response: response }[@clause].body\n        schema = contract.send(@clause).schema\n        if schema && !schema.empty?\n          schema['id'] = contract.file unless schema.key? 'id'\n          JSON::Validator.fully_validate(schema, body, version: :draft3)\n        end || []\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/cops/request_body_cop.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class RequestBodyCop < BodyCop\n      validates :request\n    end\n  end\nend\n\nPacto::Cops.register_cop Pacto::Cops::RequestBodyCop\n"
  },
  {
    "path": "lib/pacto/cops/response_body_cop.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class ResponseBodyCop < BodyCop\n      validates :response\n    end\n  end\nend\n\nPacto::Cops.register_cop Pacto::Cops::ResponseBodyCop\n"
  },
  {
    "path": "lib/pacto/cops/response_header_cop.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class ResponseHeaderCop\n      def self.investigate(_request, response, contract)\n        expected_headers = contract.response.headers\n        actual_headers = response.headers\n        actual_headers = Pacto::Extensions.normalize_header_keys actual_headers\n        headers_to_validate = Pacto::Extensions.normalize_header_keys expected_headers\n\n        headers_to_validate.map do |expected_header, expected_value|\n          if actual_headers.key? expected_header\n            actual_value = actual_headers[expected_header]\n            HeaderValidatorMap[expected_header].call(expected_value, actual_value)\n          else\n            \"Missing expected response header: #{expected_header}\"\n          end\n        end.compact\n      end\n\n      private\n\n      HeaderValidatorMap = Hash.new do |_map, key|\n        proc do |expected_value, actual_value|\n          unless expected_value.eql? actual_value\n            \"Invalid response header #{key}: expected #{expected_value.inspect} but received #{actual_value.inspect}\"\n          end\n        end\n      end\n\n      HeaderValidatorMap['Location'] = proc do |expected_value, actual_value|\n        location_template = Addressable::Template.new(expected_value)\n        if location_template.match(Addressable::URI.parse(actual_value))\n          nil\n        else\n          \"Invalid response header Location: expected URI #{actual_value} to match URI Template #{location_template.pattern}\"\n        end\n      end\n    end\n  end\nend\n\nPacto::Cops.register_cop Pacto::Cops::ResponseHeaderCop\n"
  },
  {
    "path": "lib/pacto/cops/response_status_cop.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    class ResponseStatusCop\n      def self.investigate(_request, response, contract)\n        expected_status = contract.response.status\n        actual_status = response.status\n        errors = []\n        if expected_status != actual_status\n          errors << \"Invalid status: expected #{expected_status} but got #{actual_status}\"\n        end\n        errors\n      end\n    end\n  end\nend\n\nPacto::Cops.register_cop Pacto::Cops::ResponseStatusCop\n"
  },
  {
    "path": "lib/pacto/cops.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    extend Pacto::Resettable\n\n    class << self\n      def reset!\n        @active_cops = nil\n      end\n\n      def register_cop(cop)\n        fail TypeError \"#{cop} does not respond to investigate\" unless cop.respond_to? :investigate\n        registered_cops << cop\n      end\n\n      def registered_cops\n        @registered_cops ||= Set.new\n      end\n\n      def active_cops\n        @active_cops ||= registered_cops.dup\n      end\n\n      def investigate(request_signature, pacto_response)\n        return unless Pacto.validating?\n\n        contract = Pacto.contracts_for(request_signature).first\n        if contract\n          investigation = perform_investigation request_signature, pacto_response, contract\n        else\n          investigation = Investigation.new request_signature, pacto_response\n        end\n\n        Pacto::InvestigationRegistry.instance.register_investigation investigation\n      end\n\n      def perform_investigation(request, response, contract)\n        citations = []\n        active_cops.map do | cop |\n          citations.concat cop.investigate(request, response, contract)\n        end\n        Investigation.new(request, response, contract, citations.compact)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/core/configuration.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Configuration\n    attr_accessor :adapter, :strict_matchers,\n                  :contracts_path, :logger, :generator_options,\n                  :hide_deprecations, :default_consumer, :default_provider,\n                  :stenographer_log_file, :color, :proxy\n    attr_reader :hook\n\n    def initialize # rubocop:disable Metrics/MethodLength\n      @middleware = Pacto::Core::HTTPMiddleware.new\n      @middleware.add_observer Pacto::Cops, :investigate\n      @generator = Pacto::Generator.contract_generator\n      @middleware.add_observer @generator, :generate\n      @default_consumer = Pacto::Consumer.new\n      @default_provider = Pacto::Provider.new\n      @adapter = Stubs::WebMockAdapter.new(@middleware)\n      @strict_matchers = true\n      @contracts_path = '.'\n      @hook = Hook.new {}\n      @generator_options = { schema_version: 'draft3' }\n      @color = $stdout.tty?\n      @proxy = ENV['PACTO_PROXY']\n    end\n\n    def logger\n      @logger ||= new_simple_logger\n    end\n\n    def stenographer_log_file\n      @stenographer_log_file ||= File.expand_path('pacto_stenographer.log')\n    end\n\n    def register_hook(hook = nil, &block)\n      if block_given?\n        @hook = Hook.new(&block)\n      else\n        fail 'Expected a Pacto::Hook' unless hook.is_a? Hook\n        @hook = hook\n      end\n    end\n\n    private\n\n    def new_simple_logger\n      Logger::SimpleLogger.instance.tap do | logger |\n        if ENV['PACTO_DEBUG']\n          logger.level = :debug\n        else\n          logger.level = :default\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/core/contract_registry.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class ContractNotFound < StandardError; end\n\n  class ContractRegistry < Set\n    include Logger\n\n    def register(contract)\n      fail ArgumentError, 'expected a Pacto::Contract' unless contract.is_a? Contract\n      logger.debug \"Registering #{contract.request_pattern} as #{contract.name}\"\n      add contract\n    end\n\n    def find_by_name(name)\n      contract = select { |c| c.name == name }.first\n      fail ContractNotFound, \"No contract found for #{name}\" unless contract\n      contract\n    end\n\n    def contracts_for(request_signature)\n      select { |c| c.matches? request_signature }\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/core/hook.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Hook\n    def initialize(&block)\n      @hook = block\n    end\n\n    def process(contracts, request_signature, response)\n      @hook.call contracts, request_signature, response\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/core/http_middleware.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'observer'\n\nmodule Pacto\n  module Core\n    class HTTPMiddleware\n      include Logger\n      include Observable\n\n      def process(request, response)\n        contracts = Pacto.contracts_for request\n        Pacto.configuration.hook.process contracts, request, response\n\n        changed\n        begin\n          notify_observers request, response\n        rescue StandardError => e\n          logger.error Pacto::Errors.formatted_trace(e)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/core/investigation_registry.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class InvestigationRegistry\n    include Singleton\n    include Logger\n    include Resettable\n    attr_reader :investigations\n\n    def initialize\n      @investigations = []\n    end\n\n    def self.reset!\n      instance.reset!\n    end\n\n    def reset!\n      @investigations.clear\n      @stenographer = nil\n    end\n\n    def validated?(request_pattern)\n      matched_investigations = @investigations.select do |investigation|\n        request_pattern.matches? investigation.request\n      end\n      matched_investigations unless matched_investigations.empty?\n    end\n\n    def register_investigation(investigation)\n      @investigations << investigation\n      stenographer.log_investigation investigation\n      logger.info \"Detected #{investigation.summary}\"\n      logger.debug(investigation.to_s) unless investigation.successful?\n      investigation\n    end\n\n    def unmatched_investigations\n      @investigations.select do |investigation|\n        investigation.contract.nil?\n      end\n    end\n\n    def failed_investigations\n      @investigations.select do |investigation|\n        !investigation.successful?\n      end\n    end\n\n    protected\n\n    def stenographer\n      @stenographer ||= create_stenographer\n    end\n\n    def create_stenographer\n      stenographer_log = File.open(Pacto.configuration.stenographer_log_file, 'a+')\n      Pacto::Observers::Stenographer.new stenographer_log\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/core/modes.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class << self\n    def generate!\n      modes << :generate\n    end\n\n    def stop_generating!\n      modes.delete :generate\n    end\n\n    def generating?\n      modes.include? :generate\n    end\n\n    def validate!\n      modes << :validate\n    end\n\n    def stop_validating!\n      modes.delete :validate\n    end\n\n    def validating?\n      modes.include? :validate\n    end\n\n    private\n\n    def modes\n      @modes ||= []\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/core/pacto_request.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'hashie/mash'\n\nmodule Pacto\n  class PactoRequest\n    # FIXME: Need case insensitive header lookup, but case-sensitive storage\n    attr_accessor :headers, :body, :method, :uri\n\n    include BodyParsing\n\n    def initialize(data)\n      mash = Hashie::Mash.new data\n      @headers = mash.headers.nil? ? {} : mash.headers\n      @body    = mash.body\n      @method  = mash[:method]\n      @uri     = mash.uri\n      normalize\n    end\n\n    def to_hash\n      {\n        method: method,\n        uri: uri,\n        headers: headers,\n        body: body\n      }\n    end\n\n    def to_s\n      string = Pacto::UI.colorize_method(method)\n      string << \" #{relative_uri}\"\n      string << \" with body (#{raw_body.bytesize} bytes)\" if raw_body\n      string\n    end\n\n    def relative_uri\n      uri.to_s.tap do |s|\n        s.slice!(uri.normalized_site)\n      end\n    end\n\n    def normalize\n      @method = @method.to_s.downcase.to_sym\n      @uri = @uri.normalize if @uri\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/core/pacto_response.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class PactoResponse\n    # FIXME: Need case insensitive header lookup, but case-sensitive storage\n    attr_accessor :headers, :body, :status, :parsed_body\n    attr_reader :parsed_body\n\n    include BodyParsing\n\n    def initialize(data)\n      mash = Hashie::Mash.new data\n      @headers = mash.headers.nil? ? {} : mash.headers\n      @body = mash.body\n      @status  = mash.status.to_i\n    end\n\n    def to_hash\n      {\n        status: status,\n        headers: headers,\n        body: body\n      }\n    end\n\n    def to_s\n      string = \"STATUS: #{status}\"\n      string << \" with body (#{raw_body.bytesize} bytes)\" if raw_body\n      string\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/dash.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'hashie'\n\nmodule Pacto\n  class Dash < Hashie::Dash\n    include Hashie::Extensions::Coercion\n    include Hashie::Extensions::Dash::IndifferentAccess\n  end\nend\n"
  },
  {
    "path": "lib/pacto/erb_processor.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class ERBProcessor\n    include Logger\n    def process(contract, values = {})\n      erb = ERB.new(contract)\n      erb_result = erb.result hash_binding(values)\n      logger.debug \"Processed contract: #{erb_result.inspect}\"\n      erb_result\n    end\n\n    private\n\n    def hash_binding(values)\n      namespace = OpenStruct.new(values)\n      namespace.instance_eval { binding }\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/errors.rb",
    "content": "module Pacto\n  class InvalidContract < ArgumentError\n    attr_reader :errors\n\n    def initialize(errors)\n      @errors = errors\n    end\n\n    def message\n      @errors.join \"\\n\"\n    end\n  end\n\n  module Errors\n    # Creates an array of strings, representing a formatted exception,\n    # containing backtrace and nested exception info as necessary, that can\n    # be viewed by a human.\n    #\n    # For example:\n    #\n    #     ------Exception-------\n    #     Class: Crosstest::StandardError\n    #     Message: Failure starting the party\n    #     ---Nested Exception---\n    #     Class: IOError\n    #     Message: not enough directories for a party\n    #     ------Backtrace-------\n    #     nil\n    #     ----------------------\n    #\n    # @param exception [::StandardError] an exception\n    # @return [Array<String>] a formatted message\n    def self.formatted_trace(exception)\n      arr = formatted_exception(exception).dup\n      last = arr.pop\n      if exception.respond_to?(:original) && exception.original\n        arr += formatted_exception(exception.original, 'Nested Exception')\n        last = arr.pop\n      end\n      arr += ['Backtrace'.center(22, '-'), exception.backtrace, last].flatten\n      arr\n    end\n\n    # Creates an array of strings, representing a formatted exception that\n    # can be viewed by a human. Thanks to MiniTest for the inspiration\n    # upon which this output has been designed.\n    #\n    # For example:\n    #\n    #     ------Exception-------\n    #     Class: Crosstest::StandardError\n    #     Message: I have failed you\n    #     ----------------------\n    #\n    # @param exception [::StandardError] an exception\n    # @param title [String] a custom title for the message\n    #   (default: `\"Exception\"`)\n    # @return [Array<String>] a formatted message\n    def self.formatted_exception(exception, title = 'Exception')\n      [\n        title.center(22, '-'),\n        \"Class: #{exception.class}\",\n        \"Message: #{exception.message}\",\n        ''.center(22, '-')\n      ]\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/extensions.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Extensions\n    # Adapted from Faraday\n    HeaderKeyMap = Hash.new do |map, key|\n      split_char = key.to_s.include?('-') ? '-' : '_'\n      map[key] = key.to_s.split(split_char).     # :user_agent => %w(user agent)\n          each(&:capitalize!).   # => %w(User Agent)\n          join('-')                     # => \"User-Agent\"\n    end\n    HeaderKeyMap[:etag] = 'ETag'\n\n    def self.normalize_header_keys(headers)\n      headers.each_with_object({}) do |(key, value), normalized|\n        normalized[HeaderKeyMap[key]] = value\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/forensics/investigation_filter.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Forensics\n    class FilterExhaustedError < StandardError\n      attr_reader :suspects\n\n      def initialize(msg, filter, suspects = [])\n        @suspects = suspects\n        if filter.respond_to? :description\n          msg = \"#{msg} #{filter.description}\"\n        else\n          msg = \"#{msg} #{filter}\"\n        end\n        super(msg)\n      end\n    end\n\n    class InvestigationFilter\n      # CaseEquality makes sense for some of the rspec matchers and compound matching behavior\n      # rubocop:disable Style/CaseEquality\n      attr_reader :investigations, :filtered_investigations\n\n      def initialize(investigations, track_suspects = true)\n        investigations ||= []\n        @investigations = investigations.dup\n        @filtered_investigations = @investigations.dup\n        @track_suspects = track_suspects\n      end\n\n      def with_name(contract_name)\n        @filtered_investigations.keep_if do |investigation|\n          return false if investigation.contract.nil?\n\n          contract_name === investigation.contract.name\n        end\n        self\n      end\n\n      def with_request(request_constraints)\n        return self if request_constraints.nil?\n        [:headers, :body].each do |section|\n          filter_request_section(section, request_constraints[section])\n        end\n        self\n      end\n\n      def with_response(response_constraints)\n        return self if response_constraints.nil?\n        [:headers, :body].each do |section|\n          filter_response_section(section, response_constraints[section])\n        end\n        self\n      end\n\n      def successful_investigations\n        @filtered_investigations.select(&:successful?)\n      end\n\n      def unsuccessful_investigations\n        @filtered_investigations - successful_investigations\n      end\n\n      protected\n\n      def filter_request_section(section, filter)\n        suspects = []\n        section = :parsed_body if section == :body\n        @filtered_investigations.keep_if do |investigation|\n          candidate = investigation.request.send(section)\n          suspects << candidate if @track_suspects\n          filter === candidate\n        end if filter\n        fail FilterExhaustedError.new(\"no requests matched #{section}\", filter, suspects) if @filtered_investigations.empty?\n      end\n\n      def filter_response_section(section, filter)\n        section = :parsed_body if section == :body\n        suspects = []\n        @filtered_investigations.keep_if do |investigation|\n          candidate = investigation.response.send(section)\n          suspects << candidate if @track_suspects\n          filter === candidate\n        end if filter\n        fail FilterExhaustedError.new(\"no responses matched #{section}\", filter, suspects) if @filtered_investigations.empty?\n      end\n\n      # rubocop:enable Style/CaseEquality\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/forensics/investigation_matcher.rb",
    "content": "# -*- encoding : utf-8 -*-\nRSpec::Matchers.define :have_investigated do |service_name|\n  match do\n    investigations = Pacto::InvestigationRegistry.instance.investigations\n    @service_name = service_name\n\n    begin\n      @investigation_filter = Pacto::Forensics::InvestigationFilter.new(investigations)\n      @investigation_filter.with_name(@service_name)\n        .with_request(@request_constraints)\n        .with_response(@response_constraints)\n\n      @matched_investigations = @investigation_filter.filtered_investigations\n      @unsuccessful_investigations = @investigation_filter.unsuccessful_investigations\n\n      !@matched_investigations.empty? && (@allow_citations || @unsuccessful_investigations.empty?)\n    rescue Pacto::Forensics::FilterExhaustedError => e\n      @filter_error = e\n      false\n    end\n  end\n\n  def describe(obj)\n    obj.respond_to?(:description) ? obj.description : obj.to_s\n  end\n\n  description do\n    buffer = StringIO.new\n    buffer.puts \"to have investigated #{@service_name}\"\n    if @request_constraints\n      buffer.puts '  with request matching'\n      @request_constraints.each do |k, v|\n        buffer.puts \"    #{k}: #{describe(v)}\"\n      end\n    end\n    buffer.puts '  and' if @request_constraints && @response_constraints\n    if @response_constraint\n      buffer.puts '  with response matching'\n      @request_constraints.each do |k, v|\n        buffer.puts \"    #{k}: #{describe(v)}\"\n      end\n    end\n    buffer.string\n  end\n\n  chain :with_request do |request_constraints|\n    @request_constraints = request_constraints\n  end\n\n  chain :with_response do |response_constraints|\n    @response_constraints = response_constraints\n  end\n\n  chain :allow_citations do\n    @allow_citations = true\n  end\n\n  failure_message do | group |\n    buffer = StringIO.new\n    buffer.puts \"expected #{group} \" + description\n    if @filter_error\n      buffer.puts \"but #{@filter_error.message}\"\n      unless @filter_error.suspects.empty?\n        buffer.puts '  suspects:'\n        @filter_error.suspects.each do |suspect|\n          buffer.puts \"    #{suspect}\"\n        end\n      end\n    elsif @matched_investigations.empty?\n      investigated_services = @investigation_filter.investigations.map(&:contract).compact.map(&:name).uniq\n      buffer.puts \"but it was not among the services investigated: #{investigated_services}\"\n    elsif @unsuccessful_investigations\n      buffer.puts 'but investigation errors were found:'\n      @unsuccessful_investigations.each do |investigation|\n        buffer.puts \"  #{investigation}\"\n      end\n    end\n    buffer.string\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/legacy/contract.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto/formats/legacy/request_clause'\nrequire 'pacto/formats/legacy/response_clause'\n\nmodule Pacto\n  module Formats\n    module Legacy\n      class Contract < Pacto::Dash\n        include Pacto::Contract\n\n        property :id\n        property :file\n        property :request,  required: true\n        # Although I'd like response to be required, it complicates\n        # the partial contracts used the rake generation task...\n        # yet another reason I'd like to deprecate that feature\n        property :response # , required: true\n        property :values, default: {}\n        # Gotta figure out how to use test doubles w/ coercion\n        coerce_key :request,  RequestClause\n        coerce_key :response, ResponseClause\n        property :examples\n        property :name, required: true\n        property :adapter, default: proc { Pacto.configuration.adapter }\n        property :consumer, default: proc { Pacto.configuration.default_consumer }\n        property :provider, default: proc { Pacto.configuration.default_provider }\n\n        def initialize(opts)\n          skip_freeze = opts.delete(:skip_freeze)\n\n          if opts[:file]\n            opts[:file] = Addressable::URI.convert_path(File.expand_path(opts[:file])).to_s\n            opts[:name] ||= opts[:file]\n          end\n          opts[:id] ||= (opts[:summary] || opts[:file])\n          super\n          freeze unless skip_freeze\n        end\n\n        def freeze\n          (keys.map(&:to_sym) - [:values, :adapter, :consumer, :provider]).each do | key |\n            send(key).freeze\n          end\n          self\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/legacy/contract_builder.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      class ContractBuilder < Hashie::Dash # rubocop:disable Metrics/ClassLength\n        extend Forwardable\n        attr_accessor :source\n\n        def initialize(options = {})\n          @schema_generator = options[:schema_generator] ||= JSON::SchemaGenerator\n          @filters = options[:filters] ||= Generator::Filters.new\n          @data = { request: {}, response: {}, examples: {} }\n          @source = 'Pacto' # Currently used by JSONSchemaGeneator, but not really useful\n        end\n\n        def name=(name)\n          @data[:name] = name\n        end\n\n        def add_example(name, pacto_request, pacto_response)\n          @data[:examples][name] ||= {}\n          @data[:examples][name][:request] = clean(pacto_request.to_hash)\n          @data[:examples][name][:response] = clean(pacto_response.to_hash)\n          self\n        end\n\n        def infer_all\n          # infer_file # The target file is being chosen inferred by the Generator\n          infer_name\n          infer_schemas\n        end\n\n        def infer_name\n          if @data[:examples].empty?\n            @data[:name] = @data[:request][:path] if @data[:request]\n            return self\n          end\n\n          example, hint = example_and_hint\n          @data[:name] = hint.nil? ? PactoRequest.new(example[:request]).uri.path : hint.service_name\n          self\n        end\n\n        def infer_schemas\n          return self if @data[:examples].empty?\n\n          # TODO: It'd be awesome if we could infer across all examples\n          example, _hint = example_and_hint\n          sample_request_body = example[:request][:body]\n          sample_response_body = example[:response][:body]\n          @data[:request][:schema] = generate_schema(sample_request_body) if sample_request_body && !sample_request_body.empty?\n          @data[:response][:schema] = generate_schema(sample_response_body) if sample_response_body && !sample_response_body.empty?\n          self\n        end\n\n        def without_examples\n          @export_examples = false\n          self\n        end\n\n        def generate_contract(request, response)\n          generate_request(request, response)\n          generate_response(request, response)\n          infer_all\n          self\n        end\n\n        def generate_request(request, response)\n          hint = hint_for(request)\n          request = clean(\n                            headers: @filters.filter_request_headers(request, response),\n                            http_method: request.method,\n                            params: request.uri.query_values,\n                            path: hint.nil? ? request.uri.path : hint.path\n                          )\n          @data[:request] = request\n          self\n        end\n\n        def generate_response(request, response)\n          response = clean(\n                             headers: @filters.filter_response_headers(request, response),\n                             status: response.status\n                           )\n          @data[:response] = response\n          self\n        end\n\n        def build_hash\n          instance_eval(&block) if block_given?\n          @final_data = @data.dup\n          @final_data.delete(:examples) if exclude_examples?\n          clean(@final_data)\n        end\n\n        def build(&block)\n          Contract.new build_hash(&block)\n        end\n\n        protected\n\n        def example_and_hint\n          example = @data[:examples].values.first\n          example_request = PactoRequest.new example[:request]\n          [example, Pacto::Generator.hint_for(example_request)]\n        end\n\n        def exclude_examples?\n          @export_examples == false\n        end\n\n        def generate_schema(body, generator_options = Pacto.configuration.generator_options)\n          return if body.nil? || body.empty?\n\n          body_schema = @schema_generator.generate @source, body, generator_options\n          MultiJson.load(body_schema)\n        end\n\n        def clean(data)\n          data.delete_if { |_k, v| v.nil? }\n        end\n\n        def hint_for(pacto_request)\n          Pacto::Generator.hint_for(pacto_request)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/legacy/contract_factory.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto/formats/legacy/contract'\n\nmodule Pacto\n  module Formats\n    module Legacy\n      # Builds {Pacto::Formats::Legacy::Contract} instances from Pacto's legacy Contract format.\n      class ContractFactory\n        attr_reader :schema\n\n        def initialize(options = {})\n          @schema = options[:schema] || MetaSchema.new\n        end\n\n        def build_from_file(contract_path, host)\n          contract_definition = File.read(contract_path)\n          definition = JSON.parse(contract_definition)\n          schema.validate definition\n          definition['request'].merge!('host' => host)\n          body_to_schema(definition, 'request', contract_path)\n          body_to_schema(definition, 'response', contract_path)\n          method_to_http_method(definition, contract_path)\n          request = RequestClause.new(definition['request'])\n          response = ResponseClause.new(definition['response'])\n          Contract.new(request: request, response: response, file: contract_path, name: definition['name'], examples: definition['examples'])\n        end\n\n        def files_for(contracts_dir)\n          full_path = Pathname.new(contracts_dir).realpath\n\n          if  full_path.directory?\n            all_json_files = \"#{full_path}/**/*.json\"\n            Dir.glob(all_json_files).map do |f|\n              Pathname.new(f)\n            end\n          else\n            [full_path]\n          end\n        end\n\n        private\n\n        def body_to_schema(definition, section, file)\n          schema = definition[section].delete 'body'\n          return nil unless schema\n\n          Pacto::UI.deprecation \"Contract format deprecation: #{section}:body will be moved to #{section}:schema (#{file})\"\n          definition[section]['schema'] = schema\n        end\n\n        def method_to_http_method(definition, file)\n          method = definition['request'].delete 'method'\n          return nil unless method\n\n          Pacto::UI.deprecation \"Contract format deprecation: request:method will be moved to request:http_method (#{file})\"\n          definition['request']['http_method'] = method\n        end\n\n        Pacto::ContractFactory.add_factory(:legacy, ContractFactory.new)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/legacy/contract_generator.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'json/schema_generator'\nrequire 'pacto/formats/legacy/contract_builder'\nrequire 'pacto/formats/legacy/generator/filters'\n\nmodule Pacto\n  module Formats\n    module Legacy\n      class ContractGenerator\n        include Logger\n\n        def initialize(_schema_version = 'draft3',\n          schema_generator = JSON::SchemaGenerator,\n          validator = Pacto::MetaSchema.new,\n          filters = Generator::Filters.new,\n          consumer = Pacto::Consumer.new)\n          @contract_builder = ContractBuilder.new(schema_generator: schema_generator, filters: filters)\n          @consumer = consumer\n          @validator = validator\n        end\n\n        def generate(pacto_request, pacto_response)\n          return unless Pacto.generating?\n          logger.debug(\"Generating Contract for #{pacto_request}, #{pacto_response}\")\n          begin\n            contract_file = load_contract_file(pacto_request)\n\n            unless File.exist? contract_file\n              uri = URI(pacto_request.uri)\n              FileUtils.mkdir_p(File.dirname contract_file)\n              raw_contract = save(uri, pacto_request, pacto_response)\n              File.write(contract_file, raw_contract)\n              logger.debug(\"Generating #{contract_file}\")\n\n              Pacto.load_contract contract_file, uri.host\n            end\n          rescue => e\n            raise StandardError, \"Error while generating Contract #{contract_file}: #{e.message}\", e.backtrace\n          end\n        end\n\n        def generate_from_partial_contract(request_file, host)\n          contract = Pacto.load_contract request_file, host\n          request, response = @consumer.request(contract)\n          save(request_file, request, response)\n        end\n\n        def save(source, request, response)\n          @contract_builder.source = source\n          # TODO: Get rid of the generate_contract call, just use add_example/infer_all\n          @contract_builder.add_example('default', request, response).generate_contract(request, response) # .infer_all\n          @contract_builder.without_examples if Pacto.configuration.generator_options[:no_examples]\n          contract = @contract_builder.build_hash\n          pretty_contract = MultiJson.encode(contract, pretty: true)\n          # This is because of a discrepency w/ jruby vs MRI pretty json\n          pretty_contract.gsub!(/^$\\n/, '')\n          @validator.validate pretty_contract\n          pretty_contract\n        end\n\n        private\n\n        def load_contract_file(pacto_request)\n          hint = Pacto::Generator.hint_for(pacto_request)\n          if hint.nil?\n            uri = URI(pacto_request.uri)\n            path = uri.path\n            basename = File.basename(path, '.json') + '.json'\n            File.join(Pacto.configuration.contracts_path, uri.host, File.dirname(path), basename)\n          else\n            File.expand_path(hint.target_file, Pacto.configuration.contracts_path)\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/legacy/generator/filters.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      module Generator\n        class Filters\n          CONNECTION_CONTROL_HEADERS = %w(\n            Via\n            Server\n            Connection\n            Transfer-Encoding\n            Content-Length\n          )\n\n          FRESHNESS_HEADERS =\n          %w(\n            Date\n            Last-Modified\n            ETag\n          )\n\n          HEADERS_TO_FILTER = CONNECTION_CONTROL_HEADERS + FRESHNESS_HEADERS\n\n          def filter_request_headers(request, response)\n            # FIXME: Do we need to handle all these cases in real situations, or just because of stubbing?\n            vary_headers = response.headers['vary'] || response.headers['Vary'] || []\n            vary_headers = [vary_headers] if vary_headers.is_a? String\n            vary_headers = vary_headers.map do |h|\n              h.split(',').map(&:strip)\n            end.flatten\n\n            request.headers.select do |header|\n              vary_headers.map(&:downcase).include? header.downcase\n            end\n          end\n\n          def filter_response_headers(_request, response)\n            Pacto::Extensions.normalize_header_keys(response.headers).reject do |header|\n              (HEADERS_TO_FILTER.include? header) || (header.start_with?('X-'))\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/legacy/generator_hint.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      class GeneratorHint < Pacto::Dash\n        extend Forwardable\n\n        property :request_clause\n        coerce_key :request_clause, RequestClause\n        property :service_name, required: true\n        property :target_file\n\n        def_delegators :request_clause, *RequestClause::Data.properties.map(&:to_sym)\n\n        def initialize(data)\n          data[:request_clause] = RequestClause::Data.properties.each_with_object({}) do | prop, hash |\n            hash[prop] = data.delete prop\n          end\n          super\n          self.target_file ||= \"#{slugify(service_name)}.json\"\n        end\n\n        def matches?(pacto_request)\n          return false if pacto_request.nil?\n          Pacto::RequestPattern.for(request_clause).matches?(pacto_request)\n        end\n\n        private\n\n        def slugify(path)\n          path.downcase.gsub(' ', '_')\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/legacy/request_clause.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      class RequestClause < Pacto::Dash\n        include Pacto::RequestClause\n        extend Forwardable\n        attr_reader :data\n        def_delegators :data, :to_hash\n        def_delegators :data, :host, :http_method, :schema, :path, :headers, :params\n        def_delegators :data, :host=, :http_method=, :schema=, :path=, :headers=, :params=\n\n        class Data < Pacto::Dash\n          property :host # required?\n          property :http_method, required: true\n          property :schema, default: {}\n          property :path, default: '/'\n          property :headers, default: {}\n          property :params, default: {}\n        end\n\n        def initialize(data)\n          skip_freeze = data.delete(:skip_freeze)\n          mash = Hashie::Mash.new data\n          mash['http_method'] = normalize(mash['http_method'])\n          @data = Data.new(mash)\n          freeze unless skip_freeze\n          super({})\n          @pattern = Pacto::RequestPattern.for(self)\n        end\n\n        def freeze\n          @data.freeze\n          self\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/legacy/response_clause.rb",
    "content": "module Pacto\n  module Formats\n    module Legacy\n      class ResponseClause\n        include Pacto::ResponseClause\n        extend Forwardable\n        attr_reader :data\n        def_delegators :data, :to_hash\n        def_delegators :data, :status, :headers, :schema\n        def_delegators :data, :status=, :headers=, :schema=\n\n        class Data < Pacto::Dash\n          property :status\n          property :headers, default: {}\n          property :schema, default: {}\n        end\n\n        def initialize(data)\n          skip_freeze = data.delete(:skip_freeze)\n          @data = Data.new(data)\n          freeze unless skip_freeze\n        end\n\n        def freeze\n          @data.freeze\n          self\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/swagger/contract.rb",
    "content": "# -*- encoding : utf-8 -*-\n\nrequire 'pacto/formats/swagger/request_clause'\nrequire 'pacto/formats/swagger/response_clause'\n\nmodule Pacto\n  module Formats\n    module Swagger\n      class Contract < Pacto::Dash\n        include Pacto::Contract\n\n        attr_reader :swagger_api_operation\n\n        property :id\n        property :file\n        property :request,  required: true\n        # Although I'd like response to be required, it complicates\n        # the partial contracts used the rake generation task...\n        # yet another reason I'd like to deprecate that feature\n        property :response # , required: true\n        property :values, default: {}\n        # Gotta figure out how to use test doubles w/ coercion\n        coerce_key :request,  RequestClause\n        coerce_key :response, ResponseClause\n        property :examples\n        property :name, required: true\n        property :adapter, default: proc { Pacto.configuration.adapter }\n        property :consumer, default: proc { Pacto.configuration.default_consumer }\n        property :provider, default: proc { Pacto.configuration.default_provider }\n\n        def initialize(swagger_api_operation, base_data = {}) # rubocop:disable Metrics/MethodLength\n          if base_data[:file]\n            base_data[:file] = Addressable::URI.convert_path(File.expand_path(base_data[:file])).to_s\n            base_data[:name] ||= base_data[:file]\n          end\n          base_data[:id] ||= (base_data[:summary] || base_data[:file])\n\n          @swagger_api_operation = swagger_api_operation\n          host = base_data.delete(:host) || swagger_api_operation.host\n          default_response = swagger_api_operation.default_response\n          request_clause = Pacto::Formats::Swagger::RequestClause.new(swagger_api_operation, host: host)\n\n          if default_response.nil?\n            logger.warn(\"No response defined for #{swagger_api_operation.full_name}\")\n            response_clause = ResponseClause.new(status: 200)\n          else\n            response_clause = ResponseClause.new(default_response)\n          end\n\n          examples = build_examples(default_response)\n          super base_data.merge(\n                  id: swagger_api_operation.operationId,\n                  name: swagger_api_operation.full_name,\n                  request: request_clause, response: response_clause,\n                  examples: examples\n                )\n        end\n\n        private\n\n        def build_examples(response)\n          return nil if response.nil? || response.examples.nil? || response.examples.empty?\n\n          if response.examples.empty?\n            response_body = nil\n          else\n            response_body = response.examples.values.first\n          end\n\n          {\n            default: {\n              request: {}, # Swagger doesn't have a clear way to capture request examples\n              response: {\n                body: response_body\n              }\n            }\n          }\n        rescue => e # FIXME: Only parsing errors?\n          logger.warn(\"Error while trying to parse response example for #{swagger_api_operation.full_name}\")\n          logger.debug(\"  Error details: #{e.inspect}\")\n          nil\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/swagger/contract_factory.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'swagger'\nrequire 'pacto/formats/swagger/contract'\n\nmodule Pacto\n  module Formats\n    module Swagger\n      # Builds {Pacto::Formats::Swagger::Contract} instances from Swagger documents\n      class ContractFactory\n        include Logger\n\n        def load_hints(_contract_path, _host = nil)\n          fail NotImplementedError, 'Contract generation from hints is not currently supported for Swagger'\n        end\n\n        def build_from_file(contract_path, host = nil)\n          app = ::Swagger.load(contract_path)\n          app.operations.map do |op|\n            Contract.new(op,\n                         file: contract_path,\n                         host: host\n            )\n          end\n        rescue ArgumentError => e\n          logger.error(e)\n          raise \"Could not load #{contract_path}: #{e.message}\"\n        end\n\n        def files_for(contracts_dir)\n          full_path = Pathname.new(contracts_dir).realpath\n\n          if  full_path.directory?\n            all_json_files = \"#{full_path}/**/*.{json,yaml,yml}\"\n            Dir.glob(all_json_files).map do |f|\n              Pathname.new(f)\n            end\n          else\n            [full_path]\n          end\n        end\n      end\n      Pacto::ContractFactory.add_factory(:swagger, ContractFactory.new)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/swagger/request_clause.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Swagger\n      class RequestClause\n        include Pacto::RequestClause\n\n        extend Forwardable\n        attr_writer :host\n        attr_reader :swagger_api_operation\n        def_delegator :swagger_api_operation, :verb, :http_method\n        def_delegators :swagger_api_operation, :path\n\n        def initialize(swagger_api_operation, base_data = {})\n          @swagger_api_operation = swagger_api_operation\n          @host = base_data[:host] || swagger_api_operation.host\n          @pattern = Pacto::RequestPattern.for(self)\n        end\n\n        def schema\n          return nil if body_parameter.nil?\n          return nil if body_parameter.schema.nil?\n          body_parameter.schema.parse\n        end\n\n        def params\n          return {} if swagger_api_operation.parameters.nil?\n\n          swagger_api_operation.parameters.select { |p| p.in == 'query' }\n        end\n\n        def headers\n          return {} if swagger_api_operation.parameters.nil?\n\n          swagger_api_operation.parameters.select { |p| p.in == 'header' }\n        end\n\n        def to_hash\n          [:http_method, :schema, :path, :headers, :params].each_with_object({}) do | key, hash |\n            hash[key.to_s] = send key\n          end\n        end\n\n        private\n\n        def body_parameter\n          return nil if swagger_api_operation.parameters.nil?\n          swagger_api_operation.parameters.find { |p| p.in == 'body' }\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/formats/swagger/response_clause.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Swagger\n      class ResponseClause\n        extend Forwardable\n        include Pacto::ResponseClause\n        attr_reader :swagger_response\n\n        def_delegators :swagger_response, :schema\n\n        def initialize(swagger_response, _base_data = {})\n          @swagger_response = swagger_response\n        end\n\n        def status\n          swagger_response.status_code || 200\n        end\n\n        def headers\n          swagger_response.headers || {}\n        end\n\n        def schema\n          return nil unless swagger_response.schema\n          swagger_response.schema.parse\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/generator.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto/formats/legacy/contract_generator'\nrequire 'pacto/formats/legacy/generator_hint'\n\nmodule Pacto\n  module Generator\n    include Logger\n\n    class << self\n      # Factory method to return the active contract generator implementation\n      def contract_generator\n        Pacto::Formats::Legacy::ContractGenerator.new\n      end\n\n      # Factory method to return the active contract generator implementation\n      def schema_generator\n        JSON::SchemaGenerator\n      end\n\n      def configuration\n        @configuration ||= Configuration.new\n      end\n\n      def configure\n        yield(configuration)\n      end\n\n      def hint_for(pacto_request)\n        configuration.hints.find { |hint| hint.matches? pacto_request }\n      end\n    end\n\n    class Configuration\n      attr_reader :hints\n\n      def initialize\n        @hints = Set.new\n      end\n\n      def hint(name, hint_data)\n        @hints << Formats::Legacy::GeneratorHint.new(hint_data.merge(service_name: name))\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/handlers/json_handler.rb",
    "content": "require 'json'\n\nmodule Pacto\n  module Handlers\n    module JSONHandler\n      class << self\n        def raw(body)\n          JSON.dump(body)\n        end\n\n        def parse(body)\n          JSON.parse(body)\n        end\n\n        # TODO: Something like validate(contract, body)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/handlers/text_handler.rb",
    "content": "module Pacto\n  module Handlers\n    module TextHandler\n      class << self\n        def raw(body)\n          body.to_s\n        end\n\n        def parse(body)\n          body.to_s\n        end\n\n        # TODO: Something like validate(contract, body)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/hooks/erb_hook.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire_relative '../erb_processor'\n\nmodule Pacto\n  module Hooks\n    class ERBHook < Pacto::Hook\n      def initialize\n        @processor = ERBProcessor.new\n      end\n\n      def process(contracts, request_signature, response)\n        bound_values = contracts.empty? ? {} : contracts.first.values\n        bound_values.merge!(req: { 'HEADERS' => request_signature.headers })\n        response.body = @processor.process response.body, bound_values\n        response.body\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/investigation.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Investigation\n    include Logger\n    attr_reader :request, :response, :contract, :citations\n\n    def initialize(request, response, contract = nil, citations = nil)\n      @request = request\n      @response = response\n      @contract = contract\n      @citations = citations || []\n    end\n\n    def successful?\n      @citations.empty?\n    end\n\n    def against_contract?(contract_pattern)\n      return nil if @contract.nil?\n\n      case contract_pattern\n      when String\n        @contract if @contract.file.eql? contract_pattern\n      when Regexp\n        @contract if @contract.file =~ contract_pattern\n      end\n    end\n\n    def to_s\n      contract_name = @contract.nil? ? 'nil' : contract.name\n      citation_string = Pacto::UI.colorize(@citations.join(\"\\n\\t\\t\"), :red)\n      ''\"\n      Investigation:\n      \\tContract: #{contract_name}\n      \\tRequest: #{@request}\n      \\tCitations: \\n\\t\\t#{citation_string}\n      \"''\n    end\n\n    def summary\n      if @contract.nil?\n        \"Missing contract for services provided by #{@request.uri.host}\"\n      else\n        status = successful? ? 'successful' : 'unsuccessful'\n        \"#{status} investigation of #{@contract.name}\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/logger.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'forwardable'\n\nmodule Pacto\n  module Logger\n    def logger\n      Pacto.configuration.logger\n    end\n\n    class SimpleLogger\n      include Singleton\n      extend Forwardable\n\n      def_delegators :@log, :debug, :info, :warn, :error, :fatal\n\n      def initialize\n        log ::Logger.new STDOUT\n      end\n\n      def log(log)\n        @log = log\n        @log.level = default_level\n        @log.progname = 'Pacto'\n      end\n\n      def level=(level)\n        @log.level = log_levels.fetch(level, default_level)\n      end\n\n      def level\n        log_levels.key @log.level\n      end\n\n      private\n\n      def default_level\n        ::Logger::ERROR\n      end\n\n      def log_levels\n        {\n          debug: ::Logger::DEBUG,\n          info:  ::Logger::INFO,\n          warn:  ::Logger::WARN,\n          error: ::Logger::ERROR,\n          fatal: ::Logger::FATAL\n        }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/meta_schema.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class MetaSchema\n    attr_accessor :schema, :engine\n\n    def initialize(engine = JSON::Validator)\n      @schema = File.join(File.dirname(File.expand_path(__FILE__)), '../../resources/contract_schema.json')\n      base_schemas = ['../../resources/draft-03.json', '../../resources/draft-04.json']\n      validatable = false\n      base_schemas.each do |base_schema|\n        base_schema_file = File.join(File.dirname(File.expand_path(__FILE__)), base_schema)\n        # This has a side-effect of caching local schemas, so we don't\n        # look up json-schemas over HTTP.\n        validatable ||= JSON::Validator.validate(base_schema_file, @schema)\n      end\n      fail 'Could not validate metaschema against any known version of json-schema' unless validatable\n      @engine = engine\n    end\n\n    def validate(definition)\n      errors = engine.fully_validate(schema, definition)\n      fail InvalidContract, errors unless errors.empty?\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/observers/stenographer.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Observers\n    class Stenographer\n      def initialize(output)\n        @output = output\n      end\n\n      def log_investigation(investigation)\n        return if @output.nil?\n\n        contract = investigation.contract\n        request = investigation.request\n        response = investigation.response\n        name = name_for(contract, request)\n        values = values_for(contract, request)\n\n        msg = \"request #{name.inspect}, values: #{values.inspect}, response: {status: #{response.status}} # #{number_of_citations(investigation)} contract violations\"\n        @output.puts msg\n        @output.flush\n      end\n\n      protected\n\n      def name_for(contract, request)\n        return \"Unknown (#{request.uri})\" if contract.nil?\n        contract.name\n      end\n\n      def number_of_citations(investigation)\n        return 0 if investigation.nil?\n        return 0 if investigation.citations.nil?\n        investigation.citations.size.to_s\n      end\n\n      def values_for(_contract, request)\n        # FIXME: Extract vars w/ URI::Template\n        request.uri.query_values\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/provider.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  def self.providers\n    @providers ||= {}\n  end\n\n  class Provider\n    include Resettable\n\n    def self.reset!\n      Pacto.providers.clear\n    end\n\n    def actor\n      @actor ||= Pacto::Actors::FromExamples.new\n    end\n\n    def actor=(actor)\n      fail ArgumentError, 'The actor must respond to :build_response' unless actor.respond_to? :build_response\n      @actor = actor\n    end\n\n    def response_for(contract, data = {})\n      actor.build_response contract, data\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/rake_task.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nrequire 'thor'\nrequire 'pacto/cli'\nrequire 'pacto/cli/helpers'\n\n# FIXME: RakeTask is a huge class, refactor this please\n# rubocop:disable ClassLength\nmodule Pacto\n  class RakeTask\n    extend Forwardable\n    include Thor::Actions\n    include Rake::DSL\n    include Pacto::CLI::Helpers\n\n    def initialize\n      @exit_with_error = false\n      @cli = Pacto::CLI::Main.new\n    end\n\n    def run(task, args, opts = {})\n      Pacto::CLI::Main.new([], opts).public_send(task, *args)\n    end\n\n    def install\n      desc 'Tasks for Pacto gem'\n      namespace :pacto do\n        validate_task\n        generate_task\n        meta_validate\n      end\n    end\n\n    def validate_task\n      desc 'Validates all contracts in a given directory against a given host'\n      task :validate, :host, :dir do |_t, args|\n        opts = args.to_hash\n        dir = opts.delete :dir\n        run(:validate, dir, opts)\n      end\n    end\n\n    def generate_task\n      desc 'Generates contracts from partial contracts'\n      task :generate, :input_dir, :output_dir, :host do |_t, args|\n        if args.to_a.size < 3\n          fail Pacto::UI.colorize('USAGE: rake pacto:generate[<request_contract_dir>, <output_dir>, <record_host>]', :yellow)\n        end\n\n        generate_contracts(args[:input_dir], args[:output_dir], args[:host])\n      end\n    end\n\n    def meta_validate\n      desc 'Validates a directory of contract definitions'\n      task :meta_validate, :dir do |_t, args|\n        run(:meta_validate, *args)\n      end\n    end\n\n    # rubocop:enable MethodLength\n\n    # FIXME: generate_contracts is a big method =(. Needs refactoring\n    # rubocop:disable MethodLength\n    def generate_contracts(input_dir, output_dir, host)\n      WebMock.allow_net_connect!\n      generator = Pacto::Generator.contract_generator\n      puts \"Generating contracts from partial contracts in #{input_dir} and recording to #{output_dir}\\n\\n\"\n\n      failed_contracts = []\n      each_contract(input_dir) do |contract_file|\n        begin\n          contract = generator.generate_from_partial_contract(contract_file, host)\n          output_file = File.expand_path(File.basename(contract_file), output_dir)\n          output_file = File.open(output_file, 'wb')\n          output_file.write contract\n          output_file.flush\n          output_file.close\n        rescue InvalidContract => e\n          failed_contracts << contract_file\n          puts Pacto::UI.colorize(e.message, :red)\n        end\n      end\n\n      if failed_contracts.empty?\n        puts Pacto::UI.colorize('Successfully generated all contracts', :green)\n      else\n        fail Pacto::UI.colorize(\"The following contracts could not be generated: #{failed_contracts.join ','}\", :red)\n      end\n    end\n    # rubocop:enable MethodLength\n  end\nend\n# rubocop:enable ClassLength\n\nPacto::RakeTask.new.install\n"
  },
  {
    "path": "lib/pacto/request_clause.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module RequestClause\n    include Logger\n    attr_reader :host\n    attr_reader :http_method\n    attr_reader :schema\n    attr_reader :path\n    attr_reader :headers\n    attr_reader :params\n    attr_reader :pattern\n\n    def http_method=(method)\n      normalize(method)\n    end\n\n    def uri(values = {})\n      values ||= {}\n      uri_template = pattern.uri_template\n      missing_keys = uri_template.keys.map(&:to_sym) - values.keys.map(&:to_sym)\n      values[:scheme] = 'http' if missing_keys.delete(:scheme)\n      values[:server] = 'localhost' if missing_keys.delete(:server)\n      logger.warn \"Missing keys for building a complete URL: #{missing_keys.inspect}\" unless missing_keys.empty?\n      Addressable::URI.heuristic_parse(uri_template.expand(values)).tap do |uri|\n        uri.query_values = params unless params.nil? || params.empty?\n      end\n    end\n\n    private\n\n    def normalize(method)\n      method.to_s.downcase.to_sym\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/request_pattern.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class RequestPattern < WebMock::RequestPattern\n    attr_accessor :uri_template\n\n    def self.for(base_request)\n      new(base_request.http_method, UriPattern.for(base_request))\n    end\n\n    def initialize(http_method, uri_template)\n      @uri_template = uri_template\n      super\n    end\n\n    def to_s\n      string = Pacto::UI.colorize_method(@method_pattern.to_s)\n      string << \" #{@uri_pattern}\"\n      # WebMock includes this info, but I don't think we should. Pacto should match on URIs only and then validate the rest...\n      # string << \" with body #{@body_pattern.to_s}\" if @body_pattern\n      # string << \" with headers #{@headers_pattern.to_s}\" if @headers_pattern\n      # string << \" with given block\" if @with_block\n      string\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/resettable.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  # Included this module so that Pacto::Resettable.reset_all will call your class/module's self.reset! method.\n  module Resettable\n    def self.resettables\n      @resettables ||= []\n    end\n\n    def self.extended(base)\n      resettables << base\n    end\n\n    def self.included(base)\n      resettables << base\n    end\n\n    def self.reset_all\n      resettables.each(&:reset!)\n      true\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/response_clause.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module ResponseClause\n    attr_reader :status\n    attr_reader :headers\n    attr_reader :schema\n  end\nend\n"
  },
  {
    "path": "lib/pacto/rspec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\n\nbegin\n  require 'rspec/core'\n  require 'rspec/expectations'\nrescue LoadError\n  raise 'pacto/rspec requires rspec 2 or later'\nend\n\nrequire 'pacto/forensics/investigation_filter'\nrequire 'pacto/forensics/investigation_matcher'\n\nRSpec::Matchers.define :have_unmatched_requests do |_method, _uri|\n  match do\n    @unmatched_investigations = Pacto::InvestigationRegistry.instance.unmatched_investigations\n    !@unmatched_investigations.empty?\n  end\n\n  failure_message do\n    'Expected Pacto to have not matched all requests to a Contract, but all requests were matched.'\n  end\n\n  failure_message_when_negated do\n    unmatched_requests = @unmatched_investigations.map(&:request).join(\"\\n  \")\n    \"Expected Pacto to have matched all requests to a Contract, but the following requests were not matched: \\n  #{unmatched_requests}\"\n  end\nend\n\nRSpec::Matchers.define :have_failed_investigations do |_method, _uri|\n  match do\n    @failed_investigations = Pacto::InvestigationRegistry.instance.failed_investigations\n    !@failed_investigations.empty?\n  end\n\n  failure_message do\n    'Expected Pacto to have found investigation problems, but none were found.'\n  end\n\n  failure_message_when_negated do\n    \"Expected Pacto to have successfully validated all requests, but the following issues were found: #{@failed_investigations}\"\n  end\nend\n\nRSpec::Matchers.define :have_validated do |method, uri|\n  match do\n    @request_pattern = Pacto::RequestPattern.new(method, uri)\n    @request_pattern.with(@options) if @options\n    validated? @request_pattern\n  end\n\n  chain :against_contract do |contract|\n    @contract = contract\n  end\n\n  chain :with do |options|\n    @options = options\n  end\n\n  def validated?(_request_pattern)\n    @matching_investigations = Pacto::InvestigationRegistry.instance.validated? @request_pattern\n    validated = !@matching_investigations.nil?\n    validated && successfully? && contract_matches?\n  end\n\n  def investigation_citations\n    @investigation_citations ||= @matching_investigations.map(&:citations).flatten.compact\n  end\n\n  def successfully?\n    @matching_investigations.map(&:successful?).uniq.eql? [true]\n  end\n\n  def contract_matches?\n    if @contract\n      validated_contracts = @matching_investigations.map(&:contract).compact\n      # Is there a better option than case equality for string & regex support?\n      validated_contracts.any? do |contract|\n        @contract === contract.file || @contract === contract.name # rubocop:disable CaseEquality\n      end\n    else\n      true\n    end\n  end\n\n  failure_message do\n    buffer = StringIO.new\n    buffer.puts \"expected Pacto to have validated #{@request_pattern}\"\n    if @matching_investigations.nil? || @matching_investigations.empty?\n      buffer.puts '  but no matching request was received'\n      buffer.puts '    received:'\n      buffer.puts \"#{WebMock::RequestRegistry.instance}\"\n    elsif @matching_investigations.map(&:contract).compact.empty?\n      buffer.puts '  but a matching Contract was not found'\n    elsif !successfully?\n      buffer.puts '  but investigation errors were found:'\n      buffer.print '    '\n      buffer.puts investigation_citations.join \"\\n    \"\n      # investigation_citations.each do |investigation_result|\n      #   buffer.puts \"    #{investigation_result}\"\n      # end\n    elsif @contract\n      validated_against = @matching_investigations.map { |v| v.against_contract? @contract }.compact.join ','\n      buffer.puts \"  against Contract #{@contract}\"\n      buffer.puts \"    but it was validated against #{validated_against}\"\n    end\n    buffer.string\n  end\nend\n"
  },
  {
    "path": "lib/pacto/server/cli.rb",
    "content": "require 'thor'\nrequire 'pacto/server'\n\nmodule Pacto\n  module Server\n    class CLI < Thor\n      class << self\n        DEFAULTS = {\n          stdout: true,\n          log_file: 'pacto.log',\n          # :config => 'pacto/config/pacto_server.rb',\n          strict: false,\n          stub: true,\n          live: false,\n          generate: false,\n          verbose: true,\n          validate: true,\n          directory: File.join(Dir.pwd, 'contracts'),\n          port: 9000,\n          format: :legacy,\n          stenographer_log_file: File.expand_path('pacto_stenographer.log', Dir.pwd),\n          strip_port: true\n        }\n\n        def server_options\n          method_option :port, default: 4567, desc: 'The port to run the server on'\n          method_option :directory, default: DEFAULTS[:directory], desc: 'The directory containing contracts'\n          method_option :strict, default: DEFAULTS[:strict], desc: 'Whether Pacto should use strict matching or not'\n          method_option :format, default: DEFAULTS[:format], desc: 'The contract format to use'\n          method_option :strip_port, default: DEFAULTS[:strip_port], desc: 'If pacto should remove the port from URLs before forwarding'\n        end\n      end\n\n      desc 'stub [CONTRACTS...]', 'Launches a stub server for a set of contracts'\n      method_option :port, type: :numeric, desc: 'The port to listen on', default: 3000\n      method_option :spy, type: :boolean, desc: 'Display traffic received by Pacto'\n      server_options\n      def stub(*_contracts)\n        setup_interrupt\n        server_options = @options.dup\n        server_options[:stub] = true\n        Pacto::Server::HTTP.run('0.0.0.0', options.port, server_options)\n      end\n\n      desc 'proxy [CONTRACTS...]', 'Launches an intercepting proxy server for a set of contracts'\n      method_option :to, type: :string, desc: 'The target host for forwarded requests'\n      method_option :port, type: :numeric, desc: 'The port to listen on', default: 3000\n      method_option :spy, type: :boolean, desc: 'Display traffic received by Pacto'\n      def proxy(*_contracts)\n        setup_interrupt\n        server_options = @options.dup\n        server_options[:live] = true\n        Pacto::Server::HTTP.run('0.0.0.0', options.port, server_options)\n      end\n\n      private\n\n      def setup_interrupt\n        trap('INT') do\n          say 'Exiting...'\n          exit\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/server/config.rb",
    "content": "# -*- encoding : utf-8 -*-\nPacto::Server::Settings::OptionHandler.new(port, logger, config).handle(options)\n"
  },
  {
    "path": "lib/pacto/server/proxy.rb",
    "content": "module Pacto\n  module Server\n    module Proxy\n      def proxy_request(pacto_request)\n        prepare_to_forward(pacto_request)\n        pacto_response = forward(pacto_request)\n        prepare_to_respond(pacto_response)\n        pacto_response.body = rewrite(pacto_response.body)\n        pacto_response\n      end\n\n      def prepare_to_forward(pacto_request)\n        host = host_for(pacto_request)\n        fail 'Could not determine request host' if host.nil?\n        host.gsub!('.dev', '.com') if settings[:strip_dev]\n        scheme, host = host.split('://')\n        host, scheme = scheme, host if host.nil?\n        host, _port = host.split(':')\n        scheme ||= 'https'\n        pacto_request.uri = Addressable::URI.heuristic_parse(\"#{scheme}://#{host}#{pacto_request.uri}\")\n        # FIXME: We're stripping accept-encoding and transfer-encoding rather than dealing with the encodings\n        pacto_request.headers.delete_if { |k, _v| %w(host content-length accept-encoding transfer-encoding).include? k.downcase }\n      end\n\n      def rewrite(body)\n        return body unless settings[:strip_dev]\n        # FIXME: This is pretty hacky and needs to be rethought, but here to support hypermedia APIs\n        # This rewrites the response body so that URLs that may link to other services are rewritten\n        # to also passs through the Pacto server.\n        body.gsub('.com', \".dev:#{settings[:port]}\").gsub(/https\\:([\\w\\-\\.\\\\\\/]+).dev/, 'http:\\1.dev')\n      end\n\n      def forward(pacto_request)\n        Pacto::Consumer::FaradayDriver.new.execute(pacto_request)\n      end\n\n      def prepare_to_respond(pacto_response)\n        pacto_response.headers.delete_if { |k, _v| %w(connection content-encoding content-length transfer-encoding).include? k.downcase }\n      end\n\n      private\n\n      def host_for(pacto_request)\n        # FIXME: Need case insensitive fetch for headers\n        pacto_request.uri.site || pacto_request.headers.find { |key, _| key.downcase == 'host' }[1]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/server/settings.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Server\n    module Settings\n      def options_parser(opts, options) # rubocop:disable MethodLength\n        options[:format] ||= :legacy\n        options[:strict] ||= false\n        options[:directory] ||= File.expand_path('contracts', @original_pwd)\n        options[:config] ||= File.expand_path('../config.rb', __FILE__)\n        options[:stenographer_log_file] ||= File.expand_path('pacto_stenographer.log', @original_pwd)\n        options[:strip_port] ||= true\n\n        opts.on('-l', '--live', 'Send requests to live services (instead of stubs)') { |_val| options[:live] = true }\n        opts.on('-f', '--format FORMAT', 'Contract format') { |val| options[:format] = val }\n        opts.on('--stub', 'Stub responses based on contracts') { |_val| options[:stub] = true }\n        opts.on('-g', '--generate', 'Generate Contracts from requests') { |_val| options[:generate] = true }\n        opts.on('-V', '--validate', 'Validate requests/responses against Contracts') { |_val| options[:validate] = true }\n        opts.on('-m', '--match-strict', 'Enforce strict request matching rules') { |_val| options[:strict] = true }\n        opts.on('-x', '--contracts_dir DIR', 'Directory that contains the contracts to be registered') { |val| options[:directory] = File.expand_path(val, @original_pwd) }\n        opts.on('-H', '--host HOST', 'Host of the real service, for generating or validating live requests') { |val| options[:backend_host] = val }\n        opts.on('-r', '--recursive-loading', 'Load contracts from folders named after the host to be stubbed') { |_val| options[:recursive_loading] = true }\n        opts.on('--strip-port', 'Strip the port from the request URI to build the proxied URI') { |_val| options[:strip_port] = true }\n        opts.on('--strip-dev', 'Strip .dev from the request domain to build the proxied URI') { |_val| options[:strip_dev] = true }\n        opts.on('--stenographer-log-file', 'Location for the stenographer log file') { |val| options[:stenographer_log_file] = val }\n        opts.on('--log-level [LEVEL]', [:debug, :info, :warn, :error, :fatal], 'Pacto log level ( debug, info, warn, error or fatal)') { |val| options[:pacto_log_level] = val }\n      end\n\n      class OptionHandler\n        attr_reader :port, :logger, :config, :options\n\n        def initialize(port, logger, config = {})\n          @port, @logger, @config = port, logger, config\n        end\n\n        def token_map\n          if File.readable? '.tokens.json'\n            MultiJson.load(File.read '.tokens.json')\n          else\n            {}\n          end\n        end\n\n        def prepare_contracts(contracts)\n          contracts.stub_providers if options[:stub]\n        end\n\n        def handle(options) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity\n          @options = options\n          config[:backend_host] = options[:backend_host]\n          config[:strip_port] = options[:strip_port]\n          config[:strip_dev] = options[:strip_dev]\n          config[:port] = port\n          contracts_path = options[:directory] || File.expand_path('contracts', Dir.pwd)\n          Pacto.configure do |pacto_config|\n            pacto_config.logger = options[:pacto_logger] || logger\n            pacto_config.loggerl.log_level = config[:pacto_log_level] if config[:pacto_log_level]\n            pacto_config.contracts_path = contracts_path\n            pacto_config.strict_matchers = options[:strict]\n            pacto_config.generator_options = {\n              schema_version: :draft3,\n              token_map: token_map\n            }\n            pacto_config.stenographer_log_file = options[:stenographer_log_file]\n          end\n\n          if options[:generate]\n            Pacto.generate!\n            logger.info 'Pacto generation mode enabled'\n          end\n\n          if options[:recursive_loading]\n            Dir[\"#{contracts_path}/*\"].each do |host_dir|\n              host = File.basename host_dir\n              prepare_contracts Pacto.load_contracts(host_dir, \"https://#{host}\", options[:format])\n            end\n          else\n            host_pattern = options[:backend_host] || '{scheme}://{server}'\n            if File.exist? contracts_path\n              prepare_contracts Pacto.load_contracts(contracts_path, host_pattern, options[:format])\n            end\n          end\n\n          Pacto.validate! if options[:validate]\n\n          if options[:live]\n            #  WebMock.reset!\n            WebMock.allow_net_connect!\n          end\n\n          config\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/server.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'reel'\nrequire 'pacto'\nrequire_relative 'server/settings'\nrequire_relative 'server/proxy'\n\nmodule Pacto\n  module Server\n    class HTTP < Reel::Server::HTTP\n      attr_reader :settings, :logger\n      include Proxy\n\n      def initialize(host = '127.0.0.1', port = 3000, options = {})\n        @logger = options[:pacto_logger] || Pacto.configuration.logger\n        @settings = Settings::OptionHandler.new(port, @logger).handle(options)\n        logger.info \"Pacto Server starting on #{host}:#{port}\"\n        super(host, port, spy: options[:spy], &method(:on_connection))\n      end\n\n      def on_connection(connection)\n        # Support multiple keep-alive requests per connection\n        connection.each_request do |reel_request|\n          begin\n            pacto_request = # exclusive do\n              Pacto::PactoRequest.new(\n                headers: reel_request.headers, body: reel_request.read,\n                method: reel_request.method, uri: Addressable::URI.heuristic_parse(reel_request.uri)\n              )\n            # end\n\n            pacto_response = proxy_request(pacto_request)\n            reel_response = ::Reel::Response.new(pacto_response.status, pacto_response.headers, pacto_response.body)\n            reel_request.respond(reel_response)\n          rescue WebMock::NetConnectNotAllowedError, Faraday::ConnectionFailed => e\n            reel_request.respond 502, e.message\n          rescue => e\n            reel_request.respond 500, Pacto::Errors.formatted_trace(e)\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/stubs/uri_pattern.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class UriPattern\n    class << self\n      def for(request, strict = Pacto.configuration.strict_matchers)\n        fail_deprecations(request)\n\n        build_template_uri_pattern(request, strict)\n      end\n\n      def build_template_uri_pattern(request, strict)\n        path = request.path.respond_to?(:pattern) ? request.path.pattern : request.path\n        host = request.host\n        host ||= '{server}'\n        scheme, host = host.split('://') if host.include?('://')\n        scheme ||= '{scheme}'\n\n        if strict\n          Addressable::Template.new(\"#{scheme}://#{host}#{path}\")\n        else\n          Addressable::Template.new(\"#{scheme}://#{host}#{path}{?anyvars*}\")\n        end\n      end\n\n      def fail_deprecations(request)\n        return if request.path.is_a? Addressable::Template\n        return if request.path == (corrected_path = request.path.gsub(/\\/:(\\w+)/, '/{\\\\1}'))\n\n        fail \"please change path #{request.path} to uri template: #{corrected_path} - old syntax no longer supported\"\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/stubs/webmock_adapter.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Adapters\n    module WebMock\n      class PactoRequest < Pacto::PactoRequest\n        extend Forwardable\n        def_delegators :@webmock_request_signature, :headers, :method, :body, :uri, :to_s, :inspect\n\n        def initialize(webmock_request_signature)\n          @webmock_request_signature = webmock_request_signature\n        end\n\n        def params\n          @webmock_request_signature.uri.query_values\n        end\n\n        def path\n          @webmock_request_signature.uri.path\n        end\n      end\n\n      class PactoResponse < Pacto::PactoResponse\n        extend Forwardable\n        def_delegators :@webmock_response, :body, :body=, :headers=, :status=, :to_s, :inspect\n\n        def initialize(webmock_response)\n          @webmock_response = webmock_response\n        end\n\n        def headers\n          @webmock_response.headers || {}\n        end\n\n        def status\n          status, _ = @webmock_response.status\n          status\n        end\n      end\n    end\n  end\n  module Stubs\n    class WebMockAdapter\n      include Resettable\n\n      def initialize(middleware)\n        @middleware = middleware\n\n        WebMock.after_request do |webmock_request_signature, webmock_response|\n          process_hooks webmock_request_signature, webmock_response\n        end\n      end\n\n      def stub_request!(contract)\n        request_clause = contract.request\n        uri_pattern = UriPattern.for(request_clause)\n        stub = WebMock.stub_request(request_clause.http_method, uri_pattern)\n\n        if Pacto.configuration.strict_matchers\n          with_opts = strict_details(request_clause)\n          stub.request_pattern.with(with_opts) unless with_opts.empty?\n        end\n\n        stub.to_return do |request|\n          pacto_request = Pacto::Adapters::WebMock::PactoRequest.new request\n          response = contract.response_for pacto_request\n          {\n            status: response.status,\n            headers: response.headers,\n            body: format_body(response.body)\n          }\n        end\n      end\n\n      def self.reset!\n        WebMock.reset!\n        WebMock.reset_callbacks\n      end\n\n      def process_hooks(webmock_request_signature, webmock_response)\n        pacto_request = Pacto::Adapters::WebMock::PactoRequest.new webmock_request_signature\n        pacto_response = Pacto::Adapters::WebMock::PactoResponse.new webmock_response\n        @middleware.process pacto_request, pacto_response\n      end\n\n      private\n\n      def format_body(body)\n        if body.is_a?(Hash) || body.is_a?(Array)\n          body.to_json\n        else\n          body\n        end\n      end\n\n      def strict_details(request)\n        {}.tap do |details|\n          details[webmock_params_key(request)] = request.params unless request.params.empty?\n          details[:headers] = request.headers unless request.headers.empty?\n        end\n      end\n\n      def webmock_params_key(request)\n        request.http_method == :get ? :query : :body\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/test_helper.rb",
    "content": "# -*- encoding : utf-8 -*-\nbegin\n  require 'pacto'\n  require 'pacto/server'\nrescue LoadError\n  raise 'pacto/test_helper requires the pacto-server gem'\nend\n\nmodule Pacto\n  module TestHelper\n    DEFAULT_ARGS = {\n      stdout: true,\n      log_file: 'pacto.log',\n      # :config => 'pacto/config/pacto_server.rb',\n      strict: false,\n      stub: true,\n      live: false,\n      generate: false,\n      verbose: true,\n      validate: true,\n      directory: File.join(Dir.pwd, 'contracts'),\n      port: 9000,\n      format: :legacy,\n      stenographer_log_file: File.expand_path('pacto_stenographer.log', Dir.pwd),\n      strip_port: true\n    }\n\n    def with_pacto(args = {})\n      start_index = ::Pacto::InvestigationRegistry.instance.investigations.size\n      ::Pacto::InvestigationRegistry.instance.investigations.clear\n      args = DEFAULT_ARGS.merge(args)\n      args[:spy] = args[:verbose]\n      server = Pacto::Server::HTTP.supervise('0.0.0.0', args[:port], args)\n      yield \"http://localhost:#{args[:port]}\"\n      ::Pacto::InvestigationRegistry.instance.investigations[start_index, -1]\n    ensure\n      server.terminate unless server.nil?\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/ui.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'thor'\n\nmodule Pacto\n  module UI\n    # Colors for HTTP Methods, intended to match colors of Swagger-UI (as close as possible with ANSI Colors)\n    METHOD_COLORS = {\n      'POST' => :green,\n      'PUT'  => :yellow,\n      'DELETE' => :red,\n      'GET' => :blue,\n      'PATCH' => :yellow,\n      'HEAD' => :green\n    }\n\n    def self.shell\n      @shell ||= Thor::Shell::Color.new\n    end\n\n    def self.deprecation(msg)\n      $stderr.puts colorize(msg, :yellow) unless Pacto.configuration.hide_deprecations\n    end\n\n    def self.colorize(msg, color)\n      return msg unless Pacto.configuration.color\n\n      shell.set_color(msg, color)\n    end\n\n    def self.colorize_method(method)\n      method_string = method.to_s.upcase\n\n      color = METHOD_COLORS[method_string] || :red # red for unknown methods\n      colorize(method_string, color)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/uri.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class URI\n    def self.for(host, path, params = {})\n      Addressable::URI.heuristic_parse(\"#{host}#{path}\").tap do |uri|\n        uri.query_values = params unless params.nil? || params.empty?\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/pacto/version.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  VERSION = '0.4.0.rc3'\nend\n"
  },
  {
    "path": "lib/pacto.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto/version'\n\nrequire 'addressable/template'\nrequire 'swagger'\nrequire 'middleware'\nrequire 'faraday'\nrequire 'multi_json'\nrequire 'json-schema'\nrequire 'json-generator'\nrequire 'webmock'\nrequire 'ostruct'\nrequire 'erb'\nrequire 'logger'\n\n# FIXME: There's soo much stuff here! I'd both like to re-roganize and to use autoloading.\nrequire 'pacto/errors'\nrequire 'pacto/dash'\nrequire 'pacto/resettable'\nrequire 'pacto/logger'\nrequire 'pacto/ui'\nrequire 'pacto/request_pattern'\nrequire 'pacto/core/http_middleware'\nrequire 'pacto/consumer/faraday_driver'\nrequire 'pacto/actor'\nrequire 'pacto/consumer'\nrequire 'pacto/provider'\nrequire 'pacto/actors/json_generator'\nrequire 'pacto/actors/from_examples'\nrequire 'pacto/body_parsing'\nrequire 'pacto/core/pacto_request'\nrequire 'pacto/core/pacto_response'\nrequire 'pacto/core/contract_registry'\nrequire 'pacto/core/investigation_registry'\nrequire 'pacto/core/configuration'\nrequire 'pacto/core/modes'\nrequire 'pacto/core/hook'\nrequire 'pacto/extensions'\nrequire 'pacto/request_clause'\nrequire 'pacto/response_clause'\nrequire 'pacto/stubs/webmock_adapter'\nrequire 'pacto/stubs/uri_pattern'\nrequire 'pacto/contract'\nrequire 'pacto/cops'\nrequire 'pacto/meta_schema'\nrequire 'pacto/contract_factory'\nrequire 'pacto/investigation'\nrequire 'pacto/hooks/erb_hook'\nrequire 'pacto/observers/stenographer'\nrequire 'pacto/generator'\nrequire 'pacto/contract_files'\nrequire 'pacto/contract_set'\nrequire 'pacto/uri'\n\n# Cops\nrequire 'pacto/cops/body_cop'\nrequire 'pacto/cops/request_body_cop'\nrequire 'pacto/cops/response_body_cop'\nrequire 'pacto/cops/response_status_cop'\nrequire 'pacto/cops/response_header_cop'\n\nmodule Pacto\n  class << self\n    def configuration\n      @configuration ||= Configuration.new\n    end\n\n    def contract_registry\n      @registry ||= ContractRegistry.new\n    end\n\n    # Resets data and metrics only. It usually makes sense to call this between test scenarios.\n    def reset\n      Pacto::InvestigationRegistry.instance.reset!\n      # Pacto::Resettable.reset_all\n    end\n\n    # Resets but also clears configuration, loaded contracts, and plugins.\n    def clear!\n      Pacto::Resettable.reset_all\n      @modes = nil\n      @configuration = nil\n      @registry = nil\n    end\n\n    def configure\n      yield(configuration)\n    end\n\n    def contracts_for(request_signature)\n      contract_registry.contracts_for(request_signature)\n    end\n\n    # @throws Pacto::InvalidContract\n    def validate_contract(contract)\n      Pacto::MetaSchema.new.validate contract\n      true\n    end\n\n    def load_contract(contract_path, host, format = :legacy)\n      load_contracts(contract_path, host, format).first\n    end\n\n    def load_contracts(contracts_path, host, format = :legacy)\n      contracts = ContractFactory.load_contracts(contracts_path, host, format)\n      contracts.each do |contract|\n        contract_registry.register(contract)\n      end\n      ContractSet.new(contracts)\n    end\n  end\nend\n"
  },
  {
    "path": "pacto-server.gemspec",
    "content": "lib = File.expand_path('../lib', __FILE__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire 'pacto/version'\n\nGem::Specification.new do |gem|\n  gem.name          = 'pacto-server'\n  gem.version       = Pacto::VERSION\n  gem.authors       = ['ThoughtWorks']\n  gem.email         = ['pacto-gem@googlegroups.com']\n  gem.description   = \"Pacto Server let's you run Pacto as a standalone server to arbitrate contract disputes between a service provider and one or more consumers in any programming language. It's Pacto beyond Ruby\"\n  gem.summary       = 'Polyglot Integration Contract Testing server'\n  gem.homepage      = 'http://thoughtworks.github.io/pacto/'\n  gem.license       = 'MIT'\n\n  gem.files         = `git ls-files -- bin/pacto-server lib/pacto/server.rb lib/pacto/server`.split($/) # rubocop:disable SpecialGlobalVars\n  gem.executables   = gem.files.grep(/^bin\\//).map { |f| File.basename(f) }\n  gem.test_files    = gem.files.grep(/^(test|spec|features)\\//)\n  gem.require_paths = ['lib']\n\n  gem.add_dependency 'pacto', Pacto::VERSION\n  gem.add_dependency 'reel', '~> 0.5'\nend\n"
  },
  {
    "path": "pacto.gemspec",
    "content": "lib = File.expand_path('../lib', __FILE__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire 'pacto/version'\n\nplugin_files = Dir['pacto-*.gemspec'].map do |gemspec|\n  eval(File.read(gemspec)).files # rubocop:disable Eval\nend.flatten.uniq\n\nGem::Specification.new do |gem|\n  gem.name          = 'pacto'\n  gem.version       = Pacto::VERSION\n  gem.authors       = ['ThoughtWorks & Abril']\n  gem.email         = ['pacto-gem@googlegroups.com']\n  gem.description   = 'Pacto is a judge that arbitrates contract disputes between a service provider and one or more consumers. In other words, it is a framework for Integration Contract Testing, and helps guide service evolution patterns like Consumer-Driven Contracts or Documentation-Driven Contracts.'\n  gem.summary       = 'Integration Contract Testing framework'\n  gem.homepage      = 'http://thoughtworks.github.io/pacto/'\n  gem.license       = 'MIT'\n\n  gem.files         = `git ls-files`.split($/) - plugin_files # rubocop:disable SpecialGlobalVars\n  gem.executables   = gem.files.grep(/^bin\\//).map { |f| File.basename(f) }\n  gem.test_files    = gem.files.grep(/^(test|spec|features)\\//)\n  gem.require_paths = ['lib']\n\n  gem.add_dependency 'webmock', '~> 1.18'\n  gem.add_dependency 'swagger-core', '~> 0.2', '>= 0.2.1'\n  gem.add_dependency 'middleware', '~> 0.1'\n  gem.add_dependency 'multi_json', '~> 1.8'\n  gem.add_dependency 'json-schema', '~> 2.0'\n  gem.add_dependency 'json-generator', '~> 0.0', '>= 0.0.5'\n  gem.add_dependency 'hashie', '~> 3.0'\n  gem.add_dependency 'faraday', '~> 0.9'\n  gem.add_dependency 'addressable', '~> 2.3'\n  gem.add_dependency 'json-schema-generator', '~> 0.0', '>= 0.0.7'\n  gem.add_dependency 'thor', '~> 0.19'\n\n  gem.add_development_dependency 'polytrix', '~> 0.1', '>= 0.1.4'\n  gem.add_development_dependency 'coveralls', '~> 0'\n  gem.add_development_dependency 'fabrication', '~> 2.11'\n  gem.add_development_dependency 'rake', '~> 10.0'\n  gem.add_development_dependency 'rake-notes', '~> 0'\n  gem.add_development_dependency 'rspec', '~> 3.0'\n  gem.add_development_dependency 'aruba', '~> 0'\n  gem.add_development_dependency 'json_spec', '~> 1.0'\n  # Only required to push documentation, and not easily installed on Windows\n  # gem.add_development_dependency 'relish'\n  gem.add_development_dependency 'guard-rspec', '~> 4.2'\n  # FIXME: Rubocop upgrade needed... rubocop -a will do most of the work\n  gem.add_development_dependency 'rubocop', '~> 0.23', '< 0.27.0'\n  gem.add_development_dependency 'rubocop-rspec', '~> 1.0.rc3'\n  gem.add_development_dependency 'guard-rubocop', '~> 1.0'\n  gem.add_development_dependency 'guard-cucumber', '~> 1.4'\n  gem.add_development_dependency 'rb-fsevent', '~> 0' if RUBY_PLATFORM =~ /darwin/i\n  gem.add_development_dependency 'terminal-notifier-guard', '~> 1.5' if RUBY_PLATFORM =~ /darwin/i\nend\n"
  },
  {
    "path": "resources/contract_schema.json",
    "content": "{\n  \"title\": \"Example Schema\",\n  \"type\": \"object\",\n  \"required\": [\"request\", \"response\"],\n  \"definitions\": {\n    \"subschema\": {\n      \"anyOf\": [\n        { \"$ref\": \"http://json-schema.org/draft-03/schema#\" },\n        { \"$ref\": \"http://json-schema.org/draft-04/schema#\" }\n      ]\n    }\n  },\n  \"properties\": {\n    \"name\": {\n      \"type\": \"string\"\n    },\n    \"request\": {\n      \"type\": \"object\",\n      \"required\": [\"path\"],\n      \"properties\": {\n        \"method\": {\n          \"_deprecated\": true,\n          \"type\": \"string\"\n        },\n        \"http_method\": {\n          \"type\": \"string\"\n        },\n        \"path\": {\n          \"type\": \"string\"\n        },\n        \"headers\": {\n          \"type\": \"object\"\n        },\n        \"params\": {\n          \"type\": \"object\"\n        },\n        \"body\": {\n          \"description\": \"body is deprecated, use schema\",\n          \"$ref\": \"#/definitions/subschema\"\n        },\n        \"schema\": {\n          \"$ref\": \"#/definitions/subschema\"\n        }\n      }\n    },\n    \"response\": {\n      \"type\": \"object\",\n      \"required\": [\"status\"],\n      \"properties\": {\n        \"status\":{\n          \"type\": \"integer\"\n        },\n        \"body\": {\n          \"description\": \"body is deprecated, use schema\",\n          \"$ref\": \"#/definitions/subschema\"\n        },\n        \"schema\": {\n          \"$ref\": \"#/definitions/subschema\"\n        }\n      }\n    },\n    \"examples\": {\n      \"type\": \"object\",\n      \"additionalProperties\": {\n        \"type\": \"object\",\n        \"required\": [\"request\", \"response\"],\n        \"properties\": {\n          \"request\": {\n          },\n          \"response\": {\n          }\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "resources/draft-03.json",
    "content": "{\n  \"$schema\" : \"http://json-schema.org/draft-03/schema#\",\n  \"id\" : \"http://json-schema.org/draft-03/schema#\",\n  \"type\" : \"object\",\n  \n  \"properties\" : {\n    \"type\" : {\n      \"type\" : [\"string\", \"array\"],\n      \"items\" : {\n        \"type\" : [\"string\", {\"$ref\" : \"#\"}]\n      },\n      \"uniqueItems\" : true,\n      \"default\" : \"any\"\n    },\n    \n    \"properties\" : {\n      \"type\" : \"object\",\n      \"additionalProperties\" : {\"$ref\" : \"#\"},\n      \"default\" : {}\n    },\n    \n    \"patternProperties\" : {\n      \"type\" : \"object\",\n      \"additionalProperties\" : {\"$ref\" : \"#\"},\n      \"default\" : {}\n    },\n    \n    \"additionalProperties\" : {\n      \"type\" : [{\"$ref\" : \"#\"}, \"boolean\"],\n      \"default\" : {}\n    },\n    \n    \"items\" : {\n      \"type\" : [{\"$ref\" : \"#\"}, \"array\"],\n      \"items\" : {\"$ref\" : \"#\"},\n      \"default\" : {}\n    },\n    \n    \"additionalItems\" : {\n      \"type\" : [{\"$ref\" : \"#\"}, \"boolean\"],\n      \"default\" : {}\n    },\n    \n    \"required\" : {\n      \"type\" : \"boolean\",\n      \"default\" : false\n    },\n    \n    \"dependencies\" : {\n      \"type\" : \"object\",\n      \"additionalProperties\" : {\n        \"type\" : [\"string\", \"array\", {\"$ref\" : \"#\"}],\n        \"items\" : {\n          \"type\" : \"string\"\n        }\n      },\n      \"default\" : {}\n    },\n    \n    \"minimum\" : {\n      \"type\" : \"number\"\n    },\n    \n    \"maximum\" : {\n      \"type\" : \"number\"\n    },\n    \n    \"exclusiveMinimum\" : {\n      \"type\" : \"boolean\",\n      \"default\" : false\n    },\n    \n    \"exclusiveMaximum\" : {\n      \"type\" : \"boolean\",\n      \"default\" : false\n    },\n    \n    \"minItems\" : {\n      \"type\" : \"integer\",\n      \"minimum\" : 0,\n      \"default\" : 0\n    },\n    \n    \"maxItems\" : {\n      \"type\" : \"integer\",\n      \"minimum\" : 0\n    },\n    \n    \"uniqueItems\" : {\n      \"type\" : \"boolean\",\n      \"default\" : false\n    },\n    \n    \"pattern\" : {\n      \"type\" : \"string\",\n      \"format\" : \"regex\"\n    },\n    \n    \"minLength\" : {\n      \"type\" : \"integer\",\n      \"minimum\" : 0,\n      \"default\" : 0\n    },\n    \n    \"maxLength\" : {\n      \"type\" : \"integer\"\n    },\n    \n    \"enum\" : {\n      \"type\" : \"array\",\n      \"minItems\" : 1,\n      \"uniqueItems\" : true\n    },\n    \n    \"default\" : {\n      \"type\" : \"any\"\n    },\n    \n    \"title\" : {\n      \"type\" : \"string\"\n    },\n    \n    \"description\" : {\n      \"type\" : \"string\"\n    },\n    \n    \"format\" : {\n      \"type\" : \"string\"\n    },\n    \n    \"divisibleBy\" : {\n      \"type\" : \"number\",\n      \"minimum\" : 0,\n      \"exclusiveMinimum\" : true,\n      \"default\" : 1\n    },\n    \n    \"disallow\" : {\n      \"type\" : [\"string\", \"array\"],\n      \"items\" : {\n        \"type\" : [\"string\", {\"$ref\" : \"#\"}]\n      },\n      \"uniqueItems\" : true\n    },\n    \n    \"extends\" : {\n      \"type\" : [{\"$ref\" : \"#\"}, \"array\"],\n      \"items\" : {\"$ref\" : \"#\"},\n      \"default\" : {}\n    },\n    \n    \"id\" : {\n      \"type\" : \"string\",\n      \"format\" : \"uri\"\n    },\n    \n    \"$ref\" : {\n      \"type\" : \"string\",\n      \"format\" : \"uri\"\n    },\n    \n    \"$schema\" : {\n      \"type\" : \"string\",\n      \"format\" : \"uri\"\n    }\n  },\n  \n  \"dependencies\" : {\n    \"exclusiveMinimum\" : \"minimum\",\n    \"exclusiveMaximum\" : \"maximum\"\n  },\n  \n  \"default\" : {}\n}"
  },
  {
    "path": "resources/draft-04.json",
    "content": "{\n    \"id\": \"http://json-schema.org/draft-04/schema#\",\n    \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n    \"description\": \"Core schema meta-schema\",\n    \"definitions\": {\n        \"schemaArray\": {\n            \"type\": \"array\",\n            \"minItems\": 1,\n            \"items\": { \"$ref\": \"#\" }\n        },\n        \"positiveInteger\": {\n            \"type\": \"integer\",\n            \"minimum\": 0\n        },\n        \"positiveIntegerDefault0\": {\n            \"allOf\": [ { \"$ref\": \"#/definitions/positiveInteger\" }, { \"default\": 0 } ]\n        },\n        \"simpleTypes\": {\n            \"enum\": [ \"array\", \"boolean\", \"integer\", \"null\", \"number\", \"object\", \"string\" ]\n        },\n        \"stringArray\": {\n            \"type\": \"array\",\n            \"items\": { \"type\": \"string\" },\n            \"minItems\": 1,\n            \"uniqueItems\": true\n        }\n    },\n    \"type\": \"object\",\n    \"properties\": {\n        \"id\": {\n            \"type\": \"string\",\n            \"format\": \"uri\"\n        },\n        \"$schema\": {\n            \"type\": \"string\",\n            \"format\": \"uri\"\n        },\n        \"title\": {\n            \"type\": \"string\"\n        },\n        \"description\": {\n            \"type\": \"string\"\n        },\n        \"default\": {},\n        \"multipleOf\": {\n            \"type\": \"number\",\n            \"minimum\": 0,\n            \"exclusiveMinimum\": true\n        },\n        \"maximum\": {\n            \"type\": \"number\"\n        },\n        \"exclusiveMaximum\": {\n            \"type\": \"boolean\",\n            \"default\": false\n        },\n        \"minimum\": {\n            \"type\": \"number\"\n        },\n        \"exclusiveMinimum\": {\n            \"type\": \"boolean\",\n            \"default\": false\n        },\n        \"maxLength\": { \"$ref\": \"#/definitions/positiveInteger\" },\n        \"minLength\": { \"$ref\": \"#/definitions/positiveIntegerDefault0\" },\n        \"pattern\": {\n            \"type\": \"string\",\n            \"format\": \"regex\"\n        },\n        \"additionalItems\": {\n            \"anyOf\": [\n                { \"type\": \"boolean\" },\n                { \"$ref\": \"#\" }\n            ],\n            \"default\": {}\n        },\n        \"items\": {\n            \"anyOf\": [\n                { \"$ref\": \"#\" },\n                { \"$ref\": \"#/definitions/schemaArray\" }\n            ],\n            \"default\": {}\n        },\n        \"maxItems\": { \"$ref\": \"#/definitions/positiveInteger\" },\n        \"minItems\": { \"$ref\": \"#/definitions/positiveIntegerDefault0\" },\n        \"uniqueItems\": {\n            \"type\": \"boolean\",\n            \"default\": false\n        },\n        \"maxProperties\": { \"$ref\": \"#/definitions/positiveInteger\" },\n        \"minProperties\": { \"$ref\": \"#/definitions/positiveIntegerDefault0\" },\n        \"required\": { \"$ref\": \"#/definitions/stringArray\" },\n        \"additionalProperties\": {\n            \"anyOf\": [\n                { \"type\": \"boolean\" },\n                { \"$ref\": \"#\" }\n            ],\n            \"default\": {}\n        },\n        \"definitions\": {\n            \"type\": \"object\",\n            \"additionalProperties\": { \"$ref\": \"#\" },\n            \"default\": {}\n        },\n        \"properties\": {\n            \"type\": \"object\",\n            \"additionalProperties\": { \"$ref\": \"#\" },\n            \"default\": {}\n        },\n        \"patternProperties\": {\n            \"type\": \"object\",\n            \"additionalProperties\": { \"$ref\": \"#\" },\n            \"default\": {}\n        },\n        \"dependencies\": {\n            \"type\": \"object\",\n            \"additionalProperties\": {\n                \"anyOf\": [\n                    { \"$ref\": \"#\" },\n                    { \"$ref\": \"#/definitions/stringArray\" }\n                ]\n            }\n        },\n        \"enum\": {\n            \"type\": \"array\",\n            \"minItems\": 1,\n            \"uniqueItems\": true\n        },\n        \"type\": {\n            \"anyOf\": [\n                { \"$ref\": \"#/definitions/simpleTypes\" },\n                {\n                    \"type\": \"array\",\n                    \"items\": { \"$ref\": \"#/definitions/simpleTypes\" },\n                    \"minItems\": 1,\n                    \"uniqueItems\": true\n                }\n            ]\n        },\n        \"allOf\": { \"$ref\": \"#/definitions/schemaArray\" },\n        \"anyOf\": { \"$ref\": \"#/definitions/schemaArray\" },\n        \"oneOf\": { \"$ref\": \"#/definitions/schemaArray\" },\n        \"not\": { \"$ref\": \"#\" }\n    },\n    \"dependencies\": {\n        \"exclusiveMaximum\": [ \"maximum\" ],\n        \"exclusiveMinimum\": [ \"minimum\" ]\n    },\n    \"default\": {}\n}"
  },
  {
    "path": "sample_apis/album/cover_api.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule AlbumServices\n  class Cover < Grape::API\n    format :json\n    desc 'Ping'\n    namespace :album do\n      get ':id/cover' do\n        { cover: 'image' }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "sample_apis/config.ru",
    "content": "require 'grape'\nrequire 'grape-swagger'\nrequire 'json'\nDir[File.expand_path('../**/*_api.rb', __FILE__)].each do |f|\n    puts \"Requiring #{f}\"\n  require f\nend\n\nmodule DummyServices\n  class API < Grape::API\n    prefix 'api'\n    format :json\n    mount DummyServices::Hello\n    mount DummyServices::Ping\n    mount DummyServices::Echo\n    mount DummyServices::Files\n    mount DummyServices::Reverse\n    mount AlbumServices::Cover\n    add_swagger_documentation # api_version: 'v1'\n  end\nend\nDummyServices::API.routes.each do |route|\n  p route\nend\nrun DummyServices::API\n"
  },
  {
    "path": "sample_apis/echo_api.rb",
    "content": "# -*- encoding : utf-8 -*-\n# This illustrates simple get w/ params and post w/ body services\n# It also illustrates having two services w/ the same endpoint (just different HTTP methods)\nmodule DummyServices\n  class Echo < Grape::API\n    format :json\n    content_type :txt, 'text/plain'\n\n    helpers do\n      def echo(message)\n        error!('Bad Request', 400) unless message\n        message\n      end\n    end\n\n    # curl localhost:5000/api/echo --get --data-urlencode 'msg={\"one fish\": \"two fish\"}' -vv\n    get '/echo' do\n      echo params[:msg]\n    end\n\n    # curl localhost:5000/api/echo -H 'Content-Type: text/plain' -d '{\"red fish\": \"blue fish\"}' -vv\n    post '/echo' do\n      echo env['api.request.body']\n    end\n  end\nend\n"
  },
  {
    "path": "sample_apis/files_api.rb",
    "content": "# -*- encoding : utf-8 -*-\n# This example should illustrate\n#   - Authentication\n#   - Expect: 100-continue\n#   - Binary data\n#   - Content negotiation\n#   - Etags\n#   - Collections\nmodule DummyServices\n  class PartialRequestException < StandardError\n    attr_reader :http_status, :msg\n    def initialize(http_status, msg)\n      @http_status = http_status\n      @msg = msg\n    end\n  end\n\n  class Files < Grape::API\n    format :json\n    content_type :binary, 'application/octet-stream'\n    content_type :pdf, 'application/pdf'\n\n    before do\n      error!('Unauthorized', 401) unless env['HTTP_X_AUTH_TOKEN'] == '12345'\n\n      if env['HTTP_EXPECT'] == '100-continue'\n        # Can't use Content-Type because Grape tries to handle it, causing problems\n        case env['CONTENT_TYPE']\n        when 'application/pdf'\n          fail DummyServices::PartialRequestException.new(100, 'Continue')\n        when 'application/webm'\n          fail DummyServices::PartialRequestException.new(415, 'Unsupported Media Type')\n        else\n          fail DummyServices::PartialRequestException.new(417, 'Expectation Failed')\n        end\n      end\n    end\n\n    rescue_from DummyServices::PartialRequestException do |e|\n      Rack::Response.new([], e.http_status, {}).finish\n    end\n\n    namespace '/files' do\n      # curl localhost:5000/api/files/myfile.txt -H 'X-Auth-Token: 12345' -d @myfile.txt -vv\n      put ':name' do\n        params[:name]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "sample_apis/hello_api.rb",
    "content": "# -*- encoding : utf-8 -*-\n#  This illustrates a simple get service\nmodule DummyServices\n  class Hello < Grape::API\n    format :json\n    content_type :json, 'application/json'\n\n    desc 'Hello'\n    get '/hello' do\n      header 'Vary', 'Accept'\n      { message: 'Hello World!' }\n    end\n  end\nend\n"
  },
  {
    "path": "sample_apis/ping_api.rb",
    "content": "# -*- encoding : utf-8 -*-\n#  This illustrates a simple get service\nmodule DummyServices\n  class Ping < Grape::API\n    format :json\n    desc 'Ping'\n    get '/ping' do\n      { ping: 'pong' }\n    end\n  end\nend\n"
  },
  {
    "path": "sample_apis/reverse_api.rb",
    "content": "# -*- encoding : utf-8 -*-\n# This illustrates simple get w/ params and post w/ body services\n# It also illustrates having two services w/ the same endpoint (just different HTTP methods)\nmodule DummyServices\n  class Reverse < Grape::API\n    format :txt\n\n    helpers do\n      def echo(message)\n        error!('Bad Request', 400) unless message\n        message\n      end\n    end\n\n    # curl localhost:5000/api/echo -H 'Content-Type: application/json' -d '{\"red fish\": \"blue fish\"}' -vv\n    post '/reverse' do\n      echo(env['api.request.body']).reverse\n    end\n  end\nend\n"
  },
  {
    "path": "sample_apis/user_api.rb",
    "content": "# -*- encoding : utf-8 -*-\n# A siple JSON service to demonstrate request/response bodies\n\nrequire 'securerandom'\n\nmodule DummyServices\n  class Echo < Grape::API\n    format :json\n\n    post '/users' do\n      user = env['api.request.body']\n      user[:id] = SecureRandom.uuid\n      user\n    end\n  end\nend\n"
  },
  {
    "path": "samples/README.md",
    "content": "Welcome to the Pacto usage samples!\n\nWe have a listing of [sample contracts](contracts/README.html).\n\nHighlighted samples:\n\n- *[Configuration](configuration.html)*: Shows the available Pacto configuration\n- *[Generation](generation.html)*: Shows how to generate Contracts\n- *[RSpec](rspec.html)*: Shows the usage of RSpec expectations for collaboration tests\n\nSee the Table of Contents (upper right corner) for a full list of available samples.\n"
  },
  {
    "path": "samples/Rakefile",
    "content": "require 'pacto/rake_task' # FIXME: This require turns on WebMock\nWebMock.allow_net_connect!\n"
  },
  {
    "path": "samples/configuration.rb",
    "content": "# -*- encoding : utf-8 -*-\n# Just require pacto to add it to your project.\nrequire 'pacto'\n# Pacto will disable live connections, so you will get an error if\n# your code unexpectedly calls an service that was not stubbed.  If you\n# want to re-enable connections, run `WebMock.allow_net_connect!`\nWebMock.allow_net_connect!\n\n# Pacto can be configured via a block:\nPacto.configure do |c|\n  # Path for loading/storing contracts.\n  c.contracts_path = 'contracts'\n  # If the request matching should be strict (especially regarding HTTP Headers).\n  c.strict_matchers = true\n  # You can set the Ruby Logger used by Pacto.\n  c.logger = Pacto::Logger::SimpleLogger.instance\n  # (Deprecated) You can specify a callback for post-processing responses.  Note that only one hook\n  # can be active, and specifying your own will disable ERB post-processing.\n  c.register_hook do |_contracts, request, _response|\n    puts \"Received #{request}\"\n  end\n  # Options to pass to the [json-schema-generator](https://github.com/maxlinc/json-schema-generator) while generating contracts.\n  c.generator_options = { schema_version: 'draft3' }\nend\n\n# You can also do inline configuration.  This example tells the json-schema-generator to store default values in the schema.\nPacto.configuration.generator_options = { defaults: true }\n\n# If you're using Pacto's rspec matchers you might want to configure a reset between each scenario\nrequire 'pacto/rspec'\nRSpec.configure do |c|\n  c.after(:each)  { Pacto.clear! }\nend\n"
  },
  {
    "path": "samples/consumer.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nPacto.load_contracts 'contracts', 'http://localhost:5000'\nWebMock.allow_net_connect!\n\ninteractions = Pacto.simulate_consumer :my_client do\n  request 'Ping'\n  request 'Echo', body: ->(body) { body.reverse },\n                  headers: (proc do |headers|\n                    headers['Content-Type'] = 'text/json'\n                    headers['Accept'] = 'none'\n                    headers\n                  end)\nend\nputs interactions\n"
  },
  {
    "path": "samples/contracts/README.md",
    "content": "This folder contains sample contracts.\n"
  },
  {
    "path": "samples/contracts/contract.js",
    "content": "// Pacto Contracts describe the constraints we want to put on interactions between a consumer and a provider.  It sets some expectations about the headers expected for both the request and response, the expected response status code.  It also uses [json-schema](http://json-schema.org/) to define the allowable request body (if one should exist) and response body.\n{\n  // The Request section comes first.  In this case, we're just describing a simple get request that does not require any parameters or a request body.\n  \"request\": {\n    \"headers\": {\n      // A request must exactly match these headers for Pacto to believe the request matches the contract, unless `Pacto.configuration.strict_matchers` is false.\n      \"Accept\": \"application/vnd.github.beta+json\",\n      \"Accept-Encoding\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\"\n    },\n    // The `method` and `path` are required.  The `path` may be an [rfc6570 URI template](http://tools.ietf.org/html/rfc6570) for more flexible matching.\n    \"method\": \"get\",\n    \"path\": \"/repos/thoughtworks/pacto/readme\"\n  },\n  \"response\": {\n    \"headers\": {\n      \"Content-Type\": \"application/json; charset=utf-8\",\n      \"Status\": \"200 OK\",\n      \"Cache-Control\": \"public, max-age=60, s-maxage=60\",\n      \"Etag\": \"\\\"fc8e78b0a9694de66d47317768b20820\\\"\",\n      \"Vary\": \"Accept, Accept-Encoding\",\n      \"Access-Control-Allow-Credentials\": \"true\",\n      \"Access-Control-Expose-Headers\": \"ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval\",\n      \"Access-Control-Allow-Origin\": \"*\"\n    },\n    \"status\": 200,\n    \"body\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"description\": \"Generated from https://api.github.com/repos/thoughtworks/pacto/readme with shasum 3ae59164c6d9f84c0a81f21fb63e17b3b8ce6894\",\n      \"type\": \"object\",\n      \"required\": true,\n      \"properties\": {\n        \"name\": {\n          \"type\": \"string\",\n          \"required\": true\n        },\n        \"path\": {\n          \"type\": \"string\",\n          \"required\": true\n        },\n        \"sha\": {\n          \"type\": \"string\",\n          \"required\": true\n        },\n        \"size\": {\n          \"type\": \"integer\",\n          \"required\": true\n        },\n        \"url\": {\n          \"type\": \"string\",\n          \"required\": true\n        },\n        \"html_url\": {\n          \"type\": \"string\",\n          \"required\": true\n        },\n        \"git_url\": {\n          \"type\": \"string\",\n          \"required\": true\n        },\n        \"type\": {\n          \"type\": \"string\",\n          \"required\": true\n        },\n        \"content\": {\n          \"type\": \"string\",\n          \"required\": true\n        },\n        \"encoding\": {\n          \"type\": \"string\",\n          \"required\": true\n        },\n        \"_links\": {\n          \"type\": \"object\",\n          \"required\": true,\n          \"properties\": {\n            \"self\": {\n              \"type\": \"string\",\n              \"required\": true\n            },\n            \"git\": {\n              \"type\": \"string\",\n              \"required\": true\n            },\n            \"html\": {\n              \"type\": \"string\",\n              \"required\": true\n            }\n          }\n        }\n      }\n    }\n  }\n}"
  },
  {
    "path": "samples/contracts/get_album_cover.json",
    "content": "{\n  \"request\": {\n    \"headers\": {\n    },\n    \"http_method\": \"get\",\n    \"path\": \"/api/album/{id}/cover\"\n  },\n  \"response\": {\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"status\": 200,\n    \"schema\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"description\": \"Generated from http://localhost:5000/api/album/1/cover with shasum db640385d2b346db760dbfd78058101663197bcf\",\n      \"type\": \"object\",\n      \"required\": true,\n      \"properties\": {\n        \"cover\": {\n          \"type\": \"string\",\n          \"required\": true\n        }\n      }\n    }\n  },\n  \"examples\": {\n    \"default\": {\n      \"request\": {\n        \"method\": \"get\",\n        \"uri\": \"http://localhost:5000/api/album/1/cover\",\n        \"headers\": {\n          \"User-Agent\": \"Faraday v0.9.0\",\n          \"Accept-Encoding\": \"gzip;q=1.0,deflate;q=0.6,identity;q=0.3\",\n          \"Accept\": \"*/*\"\n        }\n      },\n      \"response\": {\n        \"status\": 200,\n        \"headers\": {\n          \"Content-Type\": \"application/json\",\n          \"Content-Length\": \"17\"\n        },\n        \"body\": \"{\\\"cover\\\":\\\"image\\\"}\"\n      }\n    }\n  },\n  \"name\": \"Get Album Cover\"\n}"
  },
  {
    "path": "samples/contracts/localhost/api/echo.json",
    "content": "{\n  \"name\": \"Echo\",\n  \"request\": {\n    \"headers\": {\n      \"Content-Type\": \"text/plain\"\n    },\n    \"http_method\": \"post\",\n    \"path\": \"/api/echo\",\n    \"schema\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"oneOf\": [\n        { \"type\": \"string\", \"required\": true },\n        { \"type\": \"object\", \"required\": true }\n      ]\n    }\n  },\n  \"response\": {\n    \"status\": 201,\n    \"schema\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"oneOf\": [\n        { \"type\": \"string\", \"required\": true },\n        { \"type\": \"object\", \"required\": true }\n      ]\n    }\n  },\n  \"examples\": {\n    \"foo\": {\n      \"request\": {\n        \"body\": \"foo\"\n      },\n      \"response\": {\n        \"body\": \"foo\"\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "samples/contracts/localhost/api/ping.json",
    "content": "{\n  \"name\": \"Ping\",\n  \"request\": {\n    \"headers\": {\n    },\n    \"http_method\": \"get\",\n    \"path\": \"/api/ping\"\n  },\n  \"response\": {\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"status\": 200,\n    \"schema\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"description\": \"Generated from http://localhost:9292/api/ping with shasum 2cf3478c18e3ce877fb823ed435cb75b4a801aaa\",\n      \"type\": \"object\",\n      \"required\": true,\n      \"properties\": {\n        \"ping\": {\n          \"type\": \"string\",\n          \"required\": true\n        }\n      }\n    }\n  },\n  \"examples\": {\n    \"default\": {\n      \"request\": {\n      },\n      \"response\": {\n        \"body\": {\n          \"ping\": \"pong - from the example!\"\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "samples/contracts/user.json",
    "content": "{\n  \"name\": \"User\",\n  \"request\": {\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"http_method\": \"post\",\n    \"path\": \"/api/users\",\n    \"schema\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"firstName\": {\"type\": \"string\", \"required\": true},\n        \"lastName\": {\"type\": \"string\", \"required\": true}\n      }\n    }\n  },\n  \"response\": {\n    \"status\": 201,\n    \"schema\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"id\": { \"type\": \"string\", \"required\": true },\n        \"firstName\": {\"type\": \"string\", \"required\": true},\n        \"lastName\": {\"type\": \"string\", \"required\": true}\n      }\n    }\n  },\n  \"examples\": {\n    \"max\": {\n      \"request\": {\n        \"headers\": {\n          \"Content-Type\": \"application/json\"\n        },\n        \"body\": {\n          \"firstName\": \"Max\",\n          \"lastName\": \"Lincoln\"\n        }\n      },\n      \"response\": {\n        \"body\": {\n          \"id\": \"026ed411-6d12-4a76-a3c7-19758a872455\",\n          \"firstName\": \"Max\",\n          \"lastName\": \"Lincoln\"\n        }\n      }\n    }\n  }\n}\n\n"
  },
  {
    "path": "samples/cops.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'rspec'\nrequire 'rspec/autorun'\nrequire 'pacto'\n\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\nPacto.validate!\n\n# You can create a custom cop that investigates the request/response and sees if it complies with a\n# contract. The cop should return a list of citations if it finds any problems.\nclass MyCustomCop\n  def investigate(_request, _response, contract)\n    citations = []\n    citations << 'Contract must have a request schema' if contract.request.schema.empty?\n    citations << 'Contract must have a response schema' if contract.response.schema.empty?\n    citations\n  end\nend\n\nPacto::Cops.active_cops << MyCustomCop.new\n\ncontracts = Pacto.load_contracts('contracts', 'http://localhost:5000')\ncontracts.stub_providers\nputs contracts.simulate_consumers\n\n# Or you can completely replace the default set of validators\nPacto::Cops.registered_cops.clear\nPacto::Cops.register_cop Pacto::Cops::ResponseBodyCop\n\ncontracts = Pacto.load_contracts('contracts', 'http://localhost:5000')\nputs contracts.simulate_consumers\n"
  },
  {
    "path": "samples/forensics.rb",
    "content": "# -*- encoding : utf-8 -*-\n# Pacto has a few RSpec matchers to help you ensure a **consumer** and **producer** are\n# interacting properly. First, let's setup the rspec suite.\nrequire 'rspec/autorun' # Not generally needed\nrequire 'pacto/rspec'\nWebMock.allow_net_connect!\nPacto.validate!\nPacto.load_contracts('contracts', 'http://localhost:5000').stub_providers\n\n# It's usually a good idea to reset Pacto between each scenario. `Pacto.reset` just clears the\n# data and metrics about which services were called. `Pacto.clear!` also resets all configuration\n# and plugins.\nRSpec.configure do |c|\n  c.after(:each)  { Pacto.reset }\nend\n\n# Pacto provides some RSpec matchers related to contract testing, like making sure\n# Pacto didn't received any unrecognized requests (`have_unmatched_requests`) and that\n# the HTTP requests matched up with the terms of the contract (`have_failed_investigations`).\ndescribe Faraday do\n  let(:connection) { described_class.new(url: 'http://localhost:5000') }\n\n  it 'passes contract tests' do\n    connection.get '/api/ping'\n    expect(Pacto).to_not have_failed_investigations\n    expect(Pacto).to_not have_unmatched_requests\n  end\nend\n\n# There are also some matchers for collaboration testing, so you can make sure each scenario is\n# calling the expected services and sending the right type of data.\ndescribe Faraday do\n  let(:connection) { described_class.new(url: 'http://localhost:5000') }\n  before(:each) do\n    connection.get '/api/ping'\n\n    connection.post do |req|\n      req.url '/api/echo'\n      req.headers['Content-Type'] = 'application/json'\n      req.body = '{\"foo\": \"bar\"}'\n    end\n  end\n\n  it 'calls the ping service' do\n    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping').against_contract('Ping')\n  end\n\n  it 'sends data to the echo service' do\n    expect(Pacto).to have_investigated('Ping').with_response(body: hash_including('ping' => 'pong - from the example!'))\n    expect(Pacto).to have_investigated('Echo').with_request(body: hash_including('foo' => 'bar'))\n    echoed_body = { 'foo' => 'bar' }\n    expect(Pacto).to have_investigated('Echo').with_request(body: echoed_body).with_response(body: echoed_body)\n  end\nend\n"
  },
  {
    "path": "samples/generation.rb",
    "content": "# -*- encoding : utf-8 -*-\n# Some generation related [configuration](configuration.rb).\nrequire 'pacto'\nWebMock.allow_net_connect!\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\nWebMock.allow_net_connect!\n\n# Once we call `Pacto.generate!`, Pacto will record contracts for all requests it detects.\nPacto.generate!\n\n# Now, if we run any code that makes an HTTP call (using an\n# [HTTP library supported by WebMock](https://github.com/bblimke/webmock#supported-http-libraries))\n# then Pacto will generate a Contract based on the HTTP request/response.\n#\n# This code snippet will generate a Contract and save it to `contracts/samples/contracts/localhost/api/ping.json`.\nrequire 'faraday'\nconn = Faraday.new(url: 'http://localhost:5000')\nresponse = conn.get '/api/ping'\n# We're getting back real data from GitHub, so this should be the actual file encoding.\nputs response.body\n\n# The generated contract will contain expectations based on the request/response we observed,\n# including a best-guess at an appropriate json-schema.  Our heuristics certainly aren't foolproof,\n# so you might want to customize schema!\n\n# Here's another sample that sends a post request.\nconn.post do |req|\n  req.url '/api/echo'\n  req.headers['Content-Type'] = 'application/json'\n  req.body = '{\"red fish\": \"blue fish\"}'\nend\n\n# You can provide hints to Pacto to help it generate contracts. For example, Pacto doesn't have\n# a good way to know a good name and correct URI template for the service. That means that Pacto\n# will not know if two similar requests are for the same service or two different services, and\n# will be forced to give names based on the URI that are not good display names.\n\n# The hint below tells Pacto that requests to http://localhost:5000/album/1/cover and http://localhost:5000/album/2/cover\n# are both going to the same service, which is known as \"Get Album Cover\". This hint will cause Pacto to\n# generate a Contract for \"Get Album Cover\" and save it to `contracts/get_album_cover.json`, rather than two\n# contracts that are stored at `contracts/localhost/album/1/cover.json` and `contracts/localhost/album/2/cover.json`.\nPacto::Generator.configure do |c|\n  c.hint 'Get Album Cover', http_method: :get, host: 'http://localhost:5000', path: '/api/album/{id}/cover'\nend\nconn.get '/api/album/1/cover'\nconn.get '/api/album/2/cover'\n"
  },
  {
    "path": "samples/rake_tasks.sh",
    "content": "# # Rake tasks\n\n# ## This is a test!\n# [That](www.google.com) markdown works\nbundle exec rake pacto:meta_validate['contracts']\n\nbundle exec rake pacto:validate['http://localhost:5000','contracts']\n"
  },
  {
    "path": "samples/rspec.rb",
    "content": "# -*- encoding : utf-8 -*-\n"
  },
  {
    "path": "samples/samples.rb",
    "content": "# -*- encoding : utf-8 -*-\n# # Overview\n# Welcome to the Pacto usage samples!\n# This document gives a quick overview of the main features.\n#\n# You can browse the Table of Contents (upper right corner) to view additional samples.\n#\n# In addition to this document, here are some highlighted samples:\n# <ul>\n#   <li><a href=\"configuration\">Configuration</a>: Shows all available configuration options</li>\n#   <li><a href=\"generation\">Generation</a>: More details on generation</li>\n#   <li><a href=\"rspec\">RSpec</a>: More samples for RSpec expectations</li>\n# </ul>\n\n# You can also find other samples using the Table of Content (upper right corner), including sample contracts.\n\n# # Getting started\n# Once you've installed the Pacto gem, you just require it.  If you want, you can also require the Pacto rspec expectations.\nrequire 'pacto'\nrequire 'pacto/rspec'\n# Pacto will disable live connections, so you will get an error if\n# your code unexpectedly calls an service that was not stubbed.  If you\n# want to re-enable connections, run `WebMock.allow_net_connect!`\nWebMock.allow_net_connect!\n\n# Pacto can be configured via a block.  The `contracts_path` option tells Pacto where it should load or save contracts.  See the [Configuration](configuration.html) for all the available options.\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\n\n# # Generating a Contract\n\n# Calling `Pacto.generate!` enables contract generation.\n# Pacto.generate!\n\n# Now, if we run any code that makes an HTTP call (using an\n# [HTTP library supported by WebMock](https://github.com/bblimke/webmock#supported-http-libraries))\n# then Pacto will generate a Contract based on the HTTP request/response.\n#\n# We're using the sample APIs in the sample_apis directory.\nrequire 'faraday'\nconn = Faraday.new(url: 'http://localhost:5000')\nresponse = conn.get '/api/ping'\n# This is the real request, so you should see {\"ping\":\"pong\"}\nputs response.body\n\n# # Testing providers by simulating consumers\n\n# The generated contract will contain expectations based on the request/response we observed,\n# including a best-guess at an appropriate json-schema.  Our heuristics certainly aren't foolproof,\n# so you might want to modify the output!\n\n# We can load the contract and validate it, by sending a new request and making sure\n# the response matches the JSON schema.  Obviously it will pass since we just recorded it,\n# but if the service has made a change, or if you alter the contract with new expectations,\n# then you will see a contract investigation message.\ncontracts = Pacto.load_contracts('contracts', 'http://localhost:5000')\ncontracts.simulate_consumers\n\n# # Stubbing providers for consumer testing\n# We can also use Pacto to stub the service based on the contract.\ncontracts.stub_providers\n# The stubbed data won't be very realistic, the default behavior is to return the simplest data\n# that complies with the schema.  That basically means that you'll have \"bar\" for every string.\nresponse = conn.get '/api/ping'\n# You're now getting stubbed data.  You should see {\"ping\":\"bar\"} unless you recorded with\n# the `defaults` option enabled, in which case you will still seee {\"ping\":\"pong\"}.\nputs response.body\n\n# # Collaboration tests with RSpec\n\n# Pacto comes with rspec matchers\nrequire 'pacto/rspec'\n\n# It's probably a good idea to reset Pacto between each rspec scenario\nRSpec.configure do |c|\n  c.after(:each)  { Pacto.clear! }\nend\n\n# Load your contracts, and stub them if you'd like.\nPacto.load_contracts('contracts', 'http://localhost:5000').stub_providers\n# You can turn on investigation mode so Pacto will detect and validate HTTP requests.\nPacto.validate!\n\ndescribe 'my_code' do\n  it 'calls a service' do\n    conn = Faraday.new(url: 'http://localhost:5000')\n    response = conn.get '/api/ping'\n    # The have_validated matcher makes sure that Pacto received and successfully validated a request\n    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping')\n  end\nend\n"
  },
  {
    "path": "samples/scripts/bootstrap",
    "content": "#!/bin/bash\nbundle install\n"
  },
  {
    "path": "samples/scripts/wrapper",
    "content": "#!/bin/bash\n\n# Polytrix should probably support different wrappers for different langauges\nextension=\"${1##*.}\"\nif [ $extension = \"rb\" ];\nthen\n  bundle exec ruby \"$@\"\nelif [ $extension = \"sh\" ];\nthen\n  bash \"$@\"\nfi\n"
  },
  {
    "path": "samples/server.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto/rspec'\nrequire 'pacto/test_helper'\n\ndescribe 'ping service' do\n  include Pacto::TestHelper\n\n  it 'pongs' do\n    with_pacto(\n      port: 6000,\n      backend_host: 'http://localhost:5000',\n      live: true,\n      stub: false,\n      generate: false,\n      directory: 'contracts'\n      ) do |pacto_endpoint|\n      # call your code\n      system \"curl #{pacto_endpoint}/api/ping\"\n    end\n\n    # check citations\n    expect(Pacto).to have_validated(:get, 'http://localhost:5000/api/ping')\n  end\nend\n"
  },
  {
    "path": "samples/server_cli.sh",
    "content": "# # Standalone server\n\n# You can run Pacto as a server in order to test non-Ruby projects. In order to get the full set\n# of options, run:\nbundle exec pacto-server -h\n\n# You probably want to run with the -sv option, which will display verbose output to stdout. You can\n# run server that proxies to a live endpoint:\nbundle exec pacto proxy --port 9000 --to http://example.com &\nbundle exec pacto stub --port 9001 &\n\npkill -f 'pacto server'\n"
  },
  {
    "path": "samples/stenographer.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nPacto.configure do |c|\n  c.contracts_path = 'contracts'\nend\ncontracts = Pacto.load_contracts('contracts', 'http://localhost:5000')\ncontracts.stub_providers\n\nPacto.simulate_consumer do\n  request 'Echo', values: nil, response: { status: 200 } # 0 contract violations\n  request 'Ping', values: nil, response: { status: 200 } # 0 contract violations\n  request 'Unknown (http://localhost:8000/404)', values: nil, response: { status: 500 } # 0 contract violations\nend\n\nPacto.simulate_consumer :my_consumer do\n  playback 'pacto_stenographer.log'\nend\n"
  },
  {
    "path": "spec/coveralls_helper.rb",
    "content": "# -*- encoding : utf-8 -*-\nunless ENV['NO_COVERAGE']\n  require 'simplecov'\n  require 'coveralls'\n\n  SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[\n    SimpleCov::Formatter::HTMLFormatter,\n    Coveralls::SimpleCov::Formatter\n  ]\n  SimpleCov.start\nend\n"
  },
  {
    "path": "spec/fabricators/contract_fabricator.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nrequire 'hashie/mash'\n\n# Fabricators for contracts or parts of contracts\nunless defined? PACTO_DEFAULT_FORMAT\n  PACTO_DEFAULT_FORMAT = (ENV['PACTO_DEFAULT_FORMAT'] || 'legacy')\n  CONTRACT_CLASS = Pacto::Formats.const_get(PACTO_DEFAULT_FORMAT.capitalize).const_get('Contract')\n  REQUEST_CLAUSE_CLASS = Pacto::Formats.const_get(PACTO_DEFAULT_FORMAT.capitalize).const_get('RequestClause')\n  RESPONSE_CLAUSE_CLASS = Pacto::Formats.const_get(PACTO_DEFAULT_FORMAT.capitalize).const_get('ResponseClause')\nend\n\nFabricator(:contract, from: CONTRACT_CLASS) do\n  initialize_with { @_klass.new(to_hash.merge(skip_freeze: true)) } # Hash based initialization\n\n  transient example_count: 0\n  name { 'Dummy Contract' }\n  file { 'file:///does/not/exist/dummy_contract.json' }\n  request { Fabricate(:request_clause).to_hash }\n  response { Fabricate(:response_clause).to_hash }\n  examples do |attr|\n    example_count = attr[:example_count]\n    if example_count\n      examples = attr[:example_count].times.each_with_object({}) do |i, h|\n        name = i.to_s\n        h[name] = Fabricate(:an_example, name: name)\n      end\n      examples\n    else\n      nil\n    end\n  end\n\n  # after_save { | contract, _transients | contract.freeze }\nend\n\nFabricator(:partial_contract, from: CONTRACT_CLASS) do\n  initialize_with { @_klass.new(to_hash.merge(skip_freeze: true)) } # Hash based initialization\n  name { 'Dummy Contract' }\n  file { 'file:///does/not/exist/dummy_contract.json' }\n  request { Fabricate(:request_clause).to_hash }\nend\n\nFabricator(:request_clause, from: REQUEST_CLAUSE_CLASS) do\n  initialize_with { @_klass.new(to_hash.merge(skip_freeze: true)) } # Hash based initialization\n  host { 'example.com' }\n  http_method { 'GET' }\n  path { '/abcd' }\n  headers do\n    {\n      'Server' => ['example.com'],\n      'Connection' => ['Close'],\n      'Content-Length' => [1234],\n      'Via' => ['Some Proxy'],\n      'User-Agent' => ['rspec']\n    }\n  end\n  params {}\nend\n\nFabricator(:response_clause, from: RESPONSE_CLAUSE_CLASS) do\n  initialize_with { @_klass.new(to_hash.merge(skip_freeze: true)) } # Hash based initialization\n  status { 200 }\n  headers do\n    {\n      'Content-Type' => 'application/json'\n    }\n  end\n  schema { Fabricate(:schema).to_hash }\nend\n\nFabricator(:schema, from: Hashie::Mash) do\n  transient :version\n  initialize_with { @_klass.new to_hash } # Hash based initialization\n  type { 'object' }\n  required do |attrs|\n    attrs[:version] == :draft3 ? true : []\n  end\n  properties do\n    {\n      type: 'string'\n    }\n  end\nend\n\nFabricator(:an_example, from: Hashie::Mash) do\n  initialize_with { @_klass.new to_hash } # Hash based initialization\n  transient name: 'default'\n  request do |attr|\n    {\n      body: {\n        message: \"I am example request #{attr[:name]}\"\n      }\n    }\n  end\n  response do |attr|\n    {\n      body: {\n        message: \"I am example response #{attr[:name]}\"\n      }\n    }\n  end\nend\n"
  },
  {
    "path": "spec/fabricators/http_fabricator.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto'\nrequire 'hashie/mash'\n\n# Fabricators for Pacto objects representing HTTP transactions\n\nFabricator(:pacto_request, from: Pacto::PactoRequest) do\n  initialize_with { @_klass.new @_transient_attributes } # Hash based initialization\n  # These transient attributes turn into the URI\n  transient host: 'example.com'\n  transient path: '/abcd'\n  transient params: {}\n  method { :get }\n  uri do |attr|\n    Addressable::URI.heuristic_parse(attr[:host]).tap do |uri|\n      uri.path = attr[:path]\n      uri.query_values = attr[:params]\n    end\n  end\n  headers do\n    {\n      'Server' => ['example.com'],\n      'Connection' => ['Close'],\n      'Content-Length' => [1234],\n      'Via' => ['Some Proxy'],\n      'User-Agent' => ['rspec']\n    }\n  end\n  body do |attr|\n    case attr[:method]\n    when :get, :head, :options\n      nil\n    else\n      '{\"data\": \"something\"}'\n    end\n  end\nend\n\nFabricator(:pacto_response, from: Pacto::PactoResponse) do\n  initialize_with { @_klass.new to_hash } # Hash based initialization\n  status { 200 }\n  headers do\n    {\n      'Content-Type' => 'application/json'\n    }\n  end\n  body { '' }\nend\n"
  },
  {
    "path": "spec/fabricators/webmock_fabricator.rb",
    "content": "# -*- encoding : utf-8 -*-\n# Fabricators for WebMock objects\n\nFabricator(:webmock_request_signature, from: WebMock::RequestSignature) do\n  initialize_with do\n    uri = _transient_attributes[:uri]\n    method = _transient_attributes[:method]\n    uri = Addressable::URI.heuristic_parse(uri) unless uri.is_a? Addressable::URI\n    WebMock::RequestSignature.new method, uri\n  end\n  transient method: :get\n  transient uri: 'www.example.com'\nend\n\nFabricator(:webmock_request_pattern, from: Pacto::RequestPattern) do\n  initialize_with do\n    uri = _transient_attributes[:uri]\n    method = _transient_attributes[:method]\n    uri = Addressable::URI.heuristic_parse(uri) unless uri.is_a? Addressable::URI\n    Pacto::RequestPattern.new method, uri\n  end\n  transient method: :get\n  transient uri: 'www.example.com'\nend\n"
  },
  {
    "path": "spec/fixtures/contracts/deprecated/deprecated_contract.json",
    "content": "{\n  \"request\": {\n    \"method\": \"GET\",\n    \"path\": \"/hello/:id\",\n    \"headers\": {\n      \"Accept\": \"application/json\"\n    },\n    \"params\": {}\n  },\n\n  \"response\": {\n    \"status\": 200,\n    \"headers\": { \"Content-Type\": \"application/json\", \"Vary\": \"Accept\" },\n    \"body\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"type\": \"object\",\n      \"required\": true,\n      \"properties\": {\n        \"message\": { \"type\": \"string\", \"required\": true }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "spec/fixtures/contracts/legacy/contract.json",
    "content": "{\n  \"request\": {\n    \"http_method\": \"GET\",\n    \"path\": \"/hello_world\",\n    \"headers\": {\n      \"Accept\": \"application/json\"\n    },\n    \"params\": {}\n  },\n\n  \"response\": {\n    \"status\": 200,\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"schema\": {\n      \"description\": \"A simple response\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"message\": {\n          \"type\": \"string\"\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "spec/fixtures/contracts/legacy/contract_with_examples.json",
    "content": "{\n  \"request\": {\n    \"headers\": {\n    },\n    \"http_method\": \"get\",\n    \"path\": \"/api/echo\",\n    \"schema\": {\n      \"type\": \"object\",\n      \"required\": [\"message\"],\n      \"properties\": {\n        \"message\": {\n          \"type\": \"string\"\n        }\n      }\n    }\n  },\n  \"response\": {\n    \"headers\": {\n      \"Content-Type\": \"application/json\"\n    },\n    \"status\": 200,\n    \"schema\": {\n      \"type\": \"object\",\n      \"required\": [\"message\"],\n      \"properties\": {\n        \"message\": {\n          \"type\": \"string\"\n        }\n      }\n    }\n  },\n  \"examples\": {\n    \"max\": {\n      \"request\": {\n        \"body\": {\n          \"message\": \"max\"\n        }\n      },\n      \"response\": {\n        \"body\": {\n          \"message\": \"max\"\n        }\n      }\n    },\n    \"12345\": {\n      \"request\": {\n        \"body\": {\n          \"message\": 12345\n        }\n      },\n      \"response\": {\n        \"body\": {\n          \"message\": 12345\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "spec/fixtures/contracts/legacy/simple_contract.json",
    "content": "{\n  \"name\": \"Simple Contract\",\n  \"request\": {\n    \"http_method\": \"GET\",\n    \"path\": \"/api/hello\",\n    \"headers\": {\n      \"Accept\": \"application/json\"\n    },\n    \"params\": {}\n  },\n\n  \"response\": {\n    \"status\": 200,\n    \"headers\": { \"Content-Type\": \"application/json\", \"Vary\": \"Accept\" },\n    \"schema\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"type\": \"object\",\n      \"required\": true,\n      \"properties\": {\n        \"message\": { \"type\": \"string\", \"required\": true }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "spec/fixtures/contracts/legacy/strict_contract.json",
    "content": "{\n  \"name\": \"Strict Contract\",\n  \"request\": {\n    \"http_method\": \"GET\",\n    \"path\": \"/strict\",\n    \"headers\": {\n      \"Accept\": \"application/json\"\n    },\n    \"params\": {}\n  },\n\n  \"response\": {\n    \"status\": 200,\n    \"headers\": { \"Content-Type\": \"application/json\" },\n    \"schema\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"type\": \"object\",\n      \"required\": true,\n      \"properties\": {\n        \"devices\": {\n            \"type\": \"array\",\n            \"minItems\": 2,\n            \"items\": {\n              \"type\": \"string\",\n              \"required\": true,\n              \"default\": \"/dev/<%= values[:device_id].tap do values[:device_id] = values[:device_id] + 1 end %>\",\n              \"pattern\": \"^/dev/[\\\\d]+$\"\n            },\n            \"required\": true,\n            \"uniqueItems\": true\n        }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "spec/fixtures/contracts/legacy/templating_contract.json",
    "content": "{\n  \"request\": {\n    \"http_method\": \"GET\",\n    \"path\": \"/echo\",\n    \"headers\": {\n      \"Accept\": \"application/json\",\n      \"Custom-Auth-Token\": \"<%= auth_token %>\",\n      \"X-Message\": \"<%= key %>\"\n    },\n    \"params\": {\n    }\n  },\n\n  \"response\": {\n    \"status\": 200,\n    \"headers\": { \"Content-Type\": \"application/json\" },\n    \"schema\": {\n      \"$schema\": \"http://json-schema.org/draft-03/schema#\",\n      \"type\": \"object\",\n      \"required\": true,\n      \"properties\": {\n        \"message\": { \"type\": \"string\", \"default\": \"<%= req['HEADERS']['X-Message'].reverse %>\", \"required\": true }\n      }\n    }\n  }\n}\n"
  },
  {
    "path": "spec/fixtures/contracts/swagger/petstore.yaml",
    "content": "swagger: 2.0\ninfo:\n  version: 1.0.0\n  title: Swagger Petstore\n  license:\n    name: MIT\nhost: petstore.swagger.wordnik.com\nbasePath: /v1\nschemes:\n  - http\nconsumes:\n  - application/json\nproduces:\n  - application/json\npaths:\n  /pets:\n    get:\n      summary: List all pets\n      operationId: listPets\n      tags:\n        - pets\n      parameters:\n        - name: limit\n          in: query\n          description: How many items to return at one time (max 100)\n          required: false\n          type: integer\n          format: int32\n      responses:\n        200:\n          description: An paged array of pets\n          headers:\n            - x-next:\n              type: string\n              description: A link to the next page of responses\n          schema:\n            $ref: Pets\n        default:\n          description: unexpected error\n          schema:\n            $ref: Error\n    post:\n      summary: Create a pet\n      operationId: createPets\n      tags:\n        - pets\n      responses:\n        201:\n          description: Null response\n        default:\n          description: unexpected error\n          schema:\n            $ref: Error\n  /pets/{petId}:\n    get:\n      summary: Info for a specific pet\n      operationId: showPetById\n      tags:\n        - pets\n      parameters:\n        - name: petId\n          in: path\n          description: The id of the pet to retrieve\n          type: string\n      responses:\n        200:\n          description: Expected response to a valid request\n          schema:\n            $ref: Pets\n        default:\n          description: unexpected error\n          schema:\n            $ref: Error\ndefinitions:\n  Pet:\n    required:\n      - id\n      - name\n    properties:\n      id:\n        type: integer\n        format: int64\n      name:\n        type: string\n      tag:\n        type: string\n  Pets:\n    type: array\n    items:\n      $ref: Pet\n  Error:\n    required:\n      - code\n      - message\n    properties:\n      code:\n        type: integer\n        format: int32\n      message:\n        type: string\n\n"
  },
  {
    "path": "spec/integration/e2e_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\ndescribe Pacto do\n  let(:contract_path) { contract_file 'simple_contract' }\n  let(:strict_contract_path) { contract_file 'strict_contract' }\n\n  before :all do\n    WebMock.allow_net_connect!\n  end\n\n  context 'Contract investigation' do\n    xit 'verifies the contract against a producer' do\n      # FIXME: Does this really test what it says it does??\n      contract = described_class.load_contracts(contract_path, 'http://localhost:8000')\n      expect(contract.simulate_consumers.map(&:successful?).uniq).to eq([true])\n    end\n  end\n\n  context 'Stubbing a collection of contracts' do\n    it 'generates a server that stubs the contract for consumers' do\n      contracts = described_class.load_contracts(contract_path, 'http://dummyprovider.com')\n      contracts.stub_providers\n\n      response = get_json('http://dummyprovider.com/api/hello')\n      expect(response['message']).to eq 'bar'\n    end\n  end\n\n  context 'Journey' do\n    it 'stubs multiple services with a single use' do\n      described_class.configure do |c|\n        c.strict_matchers = false\n        c.register_hook Pacto::Hooks::ERBHook.new\n      end\n\n      contracts = described_class.load_contracts contracts_folder, 'http://dummyprovider.com'\n      contracts.stub_providers(device_id: 42)\n\n      login_response = get_json('http://dummyprovider.com/api/hello')\n      expect(login_response.keys).to eq ['message']\n      expect(login_response['message']).to be_kind_of(String)\n\n      devices_response = get_json('http://dummyprovider.com/strict')\n      expect(devices_response['devices'].size).to eq(2)\n      expect(devices_response['devices'][0]).to eq('/dev/42')\n      expect(devices_response['devices'][1]).to eq('/dev/43')\n    end\n  end\n\n  def get_json(url)\n    response = Faraday.get(url) do |req|\n      req.headers = { 'Accept' => 'application/json' }\n    end\n    MultiJson.load(response.body)\n  end\nend\n"
  },
  {
    "path": "spec/integration/forensics/integration_matcher_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto/rspec'\n\nmodule Pacto\n  describe '#have_investigated' do\n    let(:contract_path) { contract_file 'simple_contract' }\n    let(:strict_contract_path) { contract_file 'strict_contract' }\n\n    def expect_to_raise(message_pattern = nil, &blk)\n      expect { blk.call }.to raise_error(RSpec::Expectations::ExpectationNotMetError, message_pattern)\n    end\n\n    def json_response(url)\n      response = Faraday.get(url) do |req|\n        req.headers = { 'Accept' => 'application/json' }\n      end\n      MultiJson.load(response.body)\n    end\n\n    def play_bad_response\n      contracts.stub_providers(device_id: 1.5)\n      Faraday.get('http://dummyprovider.com/strict') do |req|\n        req.headers = { 'Accept' => 'application/json' }\n      end\n    end\n\n    context 'successful investigations' do\n      let(:contracts) do\n        Pacto.load_contracts contracts_folder, 'http://dummyprovider.com'\n      end\n\n      before(:each) do\n        Pacto.configure do |c|\n          c.strict_matchers = false\n          c.register_hook Pacto::Hooks::ERBHook.new\n        end\n\n        contracts.stub_providers(device_id: 42)\n        Pacto.validate!\n\n        Faraday.get('http://dummyprovider.com/api/hello') do |req|\n          req.headers = { 'Accept' => 'application/json' }\n        end\n      end\n\n      it 'performs successful assertions' do\n        # High level assertions\n        expect(Pacto).to_not have_unmatched_requests\n        expect(Pacto).to_not have_failed_investigations\n\n        # Increasingly strict assertions\n        expect(Pacto).to have_investigated('Simple Contract')\n        expect(Pacto).to have_investigated('Simple Contract').with_request(headers: hash_including('Accept' => 'application/json'))\n        expect(Pacto).to have_investigated('Simple Contract').with_request(http_method: :get, url: 'http://dummyprovider.com/api/hello')\n      end\n\n      it 'supports negative assertions' do\n        expect(Pacto).to_not have_investigated('Strict Contract')\n        Faraday.get('http://dummyprovider.com/strict') do |req|\n          req.headers = { 'Accept' => 'application/json' }\n        end\n        expect(Pacto).to have_investigated('Strict Contract')\n      end\n\n      it 'raises useful error messages' do\n        # Expected failures\n        header_matcher  = hash_including('Accept' => 'text/plain')\n        matcher_description = Regexp.quote(header_matcher.description)\n        expect_to_raise(/but no requests matched headers #{matcher_description}/) { expect(Pacto).to have_investigated('Simple Contract').with_request(headers: header_matcher) }\n      end\n\n      it 'displays Contract investigation problems' do\n        play_bad_response\n        expect_to_raise(/investigation errors were found:/) { expect(Pacto).to have_investigated('Strict Contract') }\n      end\n\n      it 'displays the Contract file' do\n        play_bad_response\n        schema_file_uri = Addressable::URI.convert_path(File.absolute_path strict_contract_path).to_s\n        expect_to_raise(/in schema #{schema_file_uri}/) { expect(Pacto).to have_investigated('Strict Contract') }\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/rspec_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'pacto/rspec'\n\ndescribe 'pacto/rspec' do\n  let(:contract_path) { contract_file 'simple_contract' }\n  let(:strict_contract_path) { contract_file 'strict_contract' }\n\n  around :each do |example|\n    with_pacto(port: 8000) do\n      example.run\n    end\n  end\n\n  def expect_to_raise(message_pattern = nil, &blk)\n    expect { blk.call }.to raise_error(RSpec::Expectations::ExpectationNotMetError, message_pattern)\n  end\n\n  def json_response(url)\n    response = Faraday.get(url) do |req|\n      req.headers = { 'Accept' => 'application/json' }\n    end\n    MultiJson.load(response.body)\n  end\n\n  def play_bad_response\n    contracts.stub_providers(device_id: 1.5)\n    Faraday.get('http://dummyprovider.com/strict') do |req|\n      req.headers = { 'Accept' => 'application/json' }\n    end\n  end\n\n  context 'successful investigations' do\n    let(:contracts) do\n      Pacto.load_contracts contracts_folder, 'http://dummyprovider.com'\n    end\n\n    before(:each) do\n      Pacto.configure do |c|\n        c.strict_matchers = false\n        c.register_hook Pacto::Hooks::ERBHook.new\n      end\n\n      contracts.stub_providers(device_id: 42)\n      Pacto.validate!\n\n      Faraday.get('http://dummyprovider.com/api/hello') do |req|\n        req.headers = { 'Accept' => 'application/json' }\n      end\n    end\n\n    it 'performs successful assertions' do\n      # High level assertions\n      expect(Pacto).to_not have_unmatched_requests\n      expect(Pacto).to_not have_failed_investigations\n\n      # Increasingly strict assertions\n      expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/api/hello')\n      expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/api/hello').with(headers: { 'Accept' => 'application/json' })\n      expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/api/hello').against_contract(/simple_contract.json/)\n    end\n\n    it 'supports negative assertions' do\n      expect(Pacto).to_not have_validated(:get, 'http://dummyprovider.com/strict')\n      Faraday.get('http://dummyprovider.com/strict') do |req|\n        req.headers = { 'Accept' => 'application/json' }\n      end\n      expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/strict')\n    end\n\n    it 'raises useful error messages' do\n      # High level error messages\n      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 }\n      expect_to_raise(/Expected Pacto to have found investigation problems, but none were found/) { expect(Pacto).to have_failed_investigations }\n\n      unmatched_url = 'http://localhost:8000/404'\n      Faraday.get unmatched_url\n      expect_to_raise(/the following requests were not matched.*#{Regexp.quote unmatched_url}/m) { expect(Pacto).to_not have_unmatched_requests }\n\n      # Expected failures\n      expect_to_raise(/no matching request was received/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/api/hello').with(headers: { 'Accept' => 'text/plain' }) }\n      # No support for with accepting a block\n      # expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/api/hello').with { |req| req.body == \"abc\" }\n      expect_to_raise(/but it was validated against/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/api/hello').against_contract(/strict_contract.json/) }\n      expect_to_raise(/but it was validated against/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/api/hello').against_contract('simple_contract.json') }\n      expect_to_raise(/but no matching request was received/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/strict') }\n    end\n\n    it 'displays Contract investigation problems' do\n      play_bad_response\n      expect_to_raise(/investigation errors were found:/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/strict') }\n      expect_to_raise(/but the following issues were found:/) { expect(Pacto).to_not have_failed_investigations }\n    end\n\n    it 'displays the Contract file' do\n      play_bad_response\n      schema_file_uri = Addressable::URI.convert_path(File.absolute_path strict_contract_path).to_s\n      expect_to_raise(/in schema #{schema_file_uri}/) { expect(Pacto).to have_validated(:get, 'http://dummyprovider.com/strict') }\n    end\n  end\nend\n"
  },
  {
    "path": "spec/integration/templating_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'securerandom'\n\ndescribe 'Templating' do\n  let(:contract_path) { contract_file 'templating_contract' }\n  let(:contracts) {  Pacto.load_contracts(contract_path, 'http://dummyprovider.com') }\n\n  let(:key) { SecureRandom.hex }\n  let(:auth_token) { SecureRandom.hex }\n\n  let :response do\n    contracts.stub_providers(key: key, auth_token: auth_token)\n\n    raw_response = Faraday.get('http://dummyprovider.com/echo') do |req|\n      req.headers = {\n        'Accept' => 'application/json',\n        'Custom-Auth-Token' => \"#{auth_token}\",\n        'X-Message' => \"#{key}\"\n      }\n    end\n    MultiJson.load(raw_response.body)\n  end\n\n  before :each do\n    Pacto.clear!\n  end\n\n  context 'No processing' do\n    it 'does not proccess erb tag' do\n      Pacto.configure do |c|\n        c.strict_matchers = false\n        c.register_hook do |_contracts, _req, res|\n          res\n        end\n      end\n\n      expect(response.keys).to eq ['message']\n      expect(response['message']).to eq(\"<%= req['HEADERS']['X-Message'].reverse %>\")\n    end\n  end\n\n  context 'Post processing' do\n    it 'processes erb on each request' do\n      Pacto.configure do |c|\n        c.strict_matchers = false\n        c.register_hook Pacto::Hooks::ERBHook.new\n      end\n\n      expect(response.keys).to eq ['message']\n      expect(response['message']).to eq(key.reverse)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'coveralls_helper'\nrequire 'webmock/rspec'\nrequire 'pacto'\nrequire 'pacto/test_helper'\nrequire 'fabrication'\nrequire 'stringio'\nrequire 'rspec'\n\n# Pre-load shared examples\nrequire_relative 'unit/pacto/actor_spec.rb'\n\nRSpec.configure do |config|\n  config.raise_errors_for_deprecations!\n  config.include Pacto::TestHelper\n  config.expect_with :rspec do |c|\n    c.syntax = :expect\n  end\n  config.after(:each) do\n    Pacto.clear!\n  end\nend\n\ndef default_pacto_format\n  ENV['PACTO_DEFAULT_FORMAT'] || 'legacy'\nend\n\ndef contracts_folder(format = default_pacto_format)\n  \"spec/fixtures/contracts/#{format}\"\nend\n\ndef contract_file(name, format = default_pacto_format)\n  file = Dir.glob(\"#{contracts_folder(format)}/#{name}.*\").first\n  fail \"Could not find a #{format} contract for #{name}\" if file.nil?\n  file\nend\n\ndef sample_contract\n  # Memoized for test speed\n  @sample_contract ||= Fabricate(:contract)\nend\n"
  },
  {
    "path": "spec/unit/actors/from_examples_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Actors\n    describe FromExamples do\n\n      let(:fallback) { double('fallback') }\n      subject(:generator) { described_class.new fallback }\n\n      context 'a contract without examples' do\n        let(:contract) { Fabricate(:contract) }\n\n        it_behaves_like 'an actor' do\n          before(:each) do\n            allow(fallback).to receive(:build_request).with(contract, {}).and_return(Fabricate(:pacto_request))\n            allow(fallback).to receive(:build_response).with(contract, {}).and_return(Fabricate(:pacto_response))\n          end\n          let(:contract) { Fabricate(:contract) }\n        end\n\n        it 'uses the fallback actor' do\n          expect(fallback).to receive(:build_request).with(contract, {})\n          expect(fallback).to receive(:build_response).with(contract, {})\n          generator.build_request contract\n          generator.build_response contract\n        end\n      end\n\n      context 'a contract with examples' do\n        let(:contract) { Fabricate(:contract, example_count: 3) }\n        let(:request) { generator.build_request contract }\n        let(:response) { generator.build_response contract }\n\n        it_behaves_like 'an actor' do\n          let(:contract) { Fabricate(:contract, example_count: 3) }\n        end\n\n        context 'no example specified' do\n          it 'uses the first example' do\n            expect(request.body).to eq(contract.examples.values.first.request.body)\n            expect(response.body).to eq(contract.examples.values.first.response.body)\n          end\n        end\n\n        context 'example specified' do\n          let(:name) { '1' }\n          subject(:generator) { described_class.new fallback, Pacto::Actors::NamedExampleSelector }\n          let(:request) { generator.build_request contract, example_name: name }\n          let(:response) { generator.build_response contract, example_name: name }\n\n          it 'uses the named example' do\n            expect(request.body).to eq(contract.examples[name].request.body)\n            expect(response.body).to eq(contract.examples[name].response.body)\n          end\n        end\n\n        context 'with randomized behavior' do\n          subject(:generator) { described_class.new fallback, Pacto::Actors::RandomExampleSelector }\n          it 'returns a randomly selected example' do\n            examples_requests = contract.examples.values.map(&:request)\n            examples_responses = contract.examples.values.map(&:response)\n            request_bodies = examples_requests.map(&:body)\n            response_bodies = examples_responses.map(&:body)\n            expect(request_bodies).to include request.body\n            expect(response_bodies).to include response.body\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/actors/json_generator_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nRSpec.shared_examples 'uses defaults' do\n  it 'uses the default values for the request' do\n    expect(request.body['foo']).to eq 'custom default value'\n  end\n\n  it 'uses the default values for the response' do\n    response = generator.build_response contract # , request\n    expect(response.body['foo']).to eq 'custom default value'\n  end\nend\n\nRSpec.shared_examples 'uses dumb values' do\n  it 'uses dumb values (request)' do\n    expect(request.body['foo']).to eq 'bar'\n  end\n\n  it 'uses dumb values (response)' do\n    response = generator.build_response contract # , request\n    expect(response.body['foo']).to eq 'bar'\n  end\nend\n\nmodule Pacto\n  module Actors\n    describe JSONGenerator do\n      subject(:generator) { described_class.new }\n      let(:request_clause) { Fabricate(:request_clause, schema: schema) }\n      let(:response_clause) { Fabricate(:response_clause, schema: schema) }\n      let(:contract) { Fabricate(:contract, request: request_clause, response: response_clause) }\n      let(:request) { generator.build_request contract }\n\n      context 'using default values from schema' do\n        context 'draft3' do\n          let(:schema) do\n            {\n              '$schema'  => 'http://json-schema.org/draft-03/schema#',\n              'type'     => 'object',\n              'required' => true,\n              'properties' => {\n                'foo' => {\n                  'type'     => 'string',\n                  'required' => true,\n                  'default'  => 'custom default value'\n                }\n              }\n            }\n          end\n          include_examples 'uses defaults'\n        end\n        context 'draft4' do\n          let(:schema) do\n            {\n              '$schema'  => 'http://json-schema.org/draft-04/schema#',\n              'type'     => 'object',\n              'required' => ['foo'],\n              'properties' => {\n                'foo' => {\n                  'type'     => 'string',\n                  'default'  => 'custom default value'\n                }\n              }\n            }\n          end\n          skip 'draft4 is not supported by JSONGenerator'\n          # include_examples 'uses defaults'\n        end\n      end\n      context 'using dumb values (no defaults)' do\n        context 'draft3' do\n          let(:schema) do\n            {\n              '$schema'  => 'http://json-schema.org/draft-03/schema#',\n              'type'     => 'object',\n              'required' => true,\n              'properties' => {\n                'foo' => {\n                  'type'     => 'string',\n                  'required' => true\n                }\n              }\n            }\n          end\n          include_examples 'uses dumb values'\n        end\n        context 'draft4' do\n          let(:schema) do\n            {\n              '$schema'  => 'http://json-schema.org/draft-04/schema#',\n              'type'     => 'object',\n              'required' => ['foo'],\n              'properties' => {\n                'foo' => {\n                  'type'     => 'string'\n                }\n              }\n            }\n          end\n          skip 'draft4 is not supported by JSONGenerator'\n          # include_examples 'uses dumb values'\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/actor_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nRSpec.shared_examples 'an actor' do\n  # let(:contract) { Fabricate(:contract) }\n  let(:data) do\n    {}\n  end\n\n  describe '#build_request' do\n    let(:request) { subject.build_request contract, data }\n    it 'creates a PactoRequest' do\n      expect(request).to be_an_instance_of Pacto::PactoRequest\n    end\n  end\n\n  describe '#build_response' do\n    # Shouldn't build response be building a response for a request?\n    # let(:request) { Fabricate :pacto_request }\n    let(:response) { subject.build_response contract, data }\n    it 'creates a PactoResponse' do\n      expect(response).to be_an_instance_of Pacto::PactoResponse\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/configuration_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe Configuration do\n    subject(:configuration) { described_class.new }\n    let(:contracts_path) { 'path_to_contracts' }\n\n    it 'sets the http adapter by default to WebMockAdapter' do\n      expect(configuration.adapter).to be_kind_of Stubs::WebMockAdapter\n    end\n\n    it 'sets strict matchers by default to true' do\n      expect(configuration.strict_matchers).to be true\n    end\n\n    it 'sets contracts path by default to .' do\n      expect(configuration.contracts_path).to eq('.')\n    end\n\n    it 'sets logger by default to Logger' do\n      expect(configuration.logger).to be_kind_of Logger::SimpleLogger\n    end\n\n    context 'about logging' do\n\n      context 'when PACTO_DEBUG is enabled' do\n        around do |example|\n          ENV['PACTO_DEBUG'] = 'true'\n          example.run\n          ENV.delete 'PACTO_DEBUG'\n        end\n\n        it 'sets the log level to debug' do\n          expect(configuration.logger.level).to eq :debug\n        end\n      end\n\n      context 'when PACTO_DEBUG is disabled' do\n        it 'sets the log level to default' do\n          expect(configuration.logger.level).to eq :error\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/consumer/faraday_driver_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  class Consumer\n    describe FaradayDriver do\n      subject(:strategy) { described_class.new }\n      let(:get_request)  { Fabricate(:pacto_request, method: :get,  host: 'http://localhost/', path: 'hello_world', params: { 'foo' => 'bar' }) }\n      let(:post_request) { Fabricate(:pacto_request, method: :post, host: 'http://localhost/', path: 'hello_world', params: { 'foo' => 'bar' }) }\n\n      describe '#execute' do\n\n        before do\n          WebMock.stub_request(:get, 'http://localhost/hello_world?foo=bar').\n            to_return(status: 200, body: '', headers: {})\n          WebMock.stub_request(:post, 'http://localhost/hello_world?foo=bar').\n            to_return(status: 200, body: '', headers: {})\n        end\n\n        context 'for any request' do\n          it 'returns the a Pacto::PactoResponse' do\n            expect(strategy.execute get_request).to be_a Pacto::PactoResponse\n          end\n        end\n\n        context 'for a GET request' do\n          it 'makes the request thru the http client' do\n            strategy.execute get_request\n            expect(WebMock).to have_requested(:get, 'http://localhost/hello_world?foo=bar')\n          end\n        end\n\n        context 'for a POST request' do\n          it 'makes the request thru the http client' do\n            strategy.execute post_request\n            expect(WebMock).to have_requested(:post, 'http://localhost/hello_world?foo=bar')\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/contract_factory_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe ContractFactory do\n    let(:host)                 { 'http://localhost' }\n    let(:contract_name)        { 'contract' }\n    let(:contract_path)        { File.join(contracts_folder, \"#{contract_name}.json\") }\n    let(:contract_files)       { [contract_path, contract_path] }\n    subject(:contract_factory) { described_class }\n\n    describe '#build' do\n      context 'default contract format' do\n        it 'builds contracts from a list of file paths and a host' do\n          contracts = contract_factory.build(contract_files, host)\n          contracts.each do |contract|\n            expect(contract).to be_a(Contract)\n          end\n        end\n      end\n\n      context 'custom format' do\n        let(:dummy_contract) { double }\n\n        class CustomContractFactory\n          def initialize(dummy_contract)\n            @dummy_contract = dummy_contract # rubocop:disable RSpec/InstanceVariable\n          end\n\n          def build_from_file(_contract_path, _host)\n            @dummy_contract # rubocop:disable RSpec/InstanceVariable\n          end\n        end\n\n        before do\n          subject.add_factory :custom, CustomContractFactory.new(dummy_contract)\n        end\n\n        it 'delegates to the registered factory' do\n          expect(contract_factory.build(contract_files, host, :custom)).to eq([dummy_contract, dummy_contract])\n        end\n      end\n\n      context 'flattening' do\n        let(:contracts_per_file) { 4 }\n\n        class MultiContractFactory\n          def initialize(contracts)\n            @contracts = contracts # rubocop:disable RSpec/InstanceVariable\n          end\n\n          def build_from_file(_contract_path, _host)\n            @contracts # rubocop:disable RSpec/InstanceVariable\n          end\n        end\n\n        before do\n          contracts = contracts_per_file.times.map do\n            double\n          end\n          subject.add_factory :multi, MultiContractFactory.new(contracts)\n        end\n\n        it 'delegates to the registered factory' do\n          loaded_contracts = contract_factory.build(contract_files, host, :multi)\n          expected_size = contracts_per_file * contract_files.size\n          # If the ContractFactory doesn't flatten returned contracts the size will be off. It needs\n          # to flatten because some factories load a single contract per file, others load multiple.\n          expect(loaded_contracts.size).to eq(expected_size)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/contract_files_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\nrequire 'fileutils'\n\nmodule Pacto\n  describe ContractFiles do\n    let(:test_dir) { File.join(File.dirname(__FILE__), 'temp') }\n    let(:contract_1) { Pathname.new(File.join(test_dir, 'contract_1.json')) }\n    let(:contract_2) { Pathname.new(File.join(test_dir, 'contract_2.json')) }\n    let(:contract_3) { Pathname.new(File.join(test_dir, 'nested', 'contract_3.json')) }\n\n    before do\n      Dir.mkdir(test_dir)\n      Dir.chdir(test_dir) do\n        Dir.mkdir('nested')\n        ['contract_1.json', 'contract_2.json', 'not_a_contract', 'nested/contract_3.json'].each do |file|\n          FileUtils.touch file\n        end\n      end\n    end\n\n    after do\n      FileUtils.rm_rf(test_dir)\n    end\n\n    describe 'for a dir' do\n      it 'returns a list with the full path of all json found recursively in that dir' do\n        files = ContractFiles.for(test_dir)\n        expect(files.size).to eq(3)\n        expect(files).to include(contract_1)\n        expect(files).to include(contract_2)\n        expect(files).to include(contract_3)\n      end\n    end\n\n    describe 'for a file' do\n      it 'returns a list containing only that file' do\n        files = ContractFiles.for(File.join(test_dir, 'contract_1.json'))\n        expect(files).to eq [contract_1]\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/contract_set_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe ContractSet do\n    let(:contract1) { Fabricate(:contract) }\n    let(:contract2) { Fabricate(:contract, request: Fabricate(:request_clause, host: 'www2.example.com')) }\n\n    it 'holds a list of contracts' do\n      list = ContractSet.new([contract1, contract2])\n      expect(list).to eq(Set.new([contract1, contract2]))\n    end\n\n    context 'when validating' do\n      it 'validates every contract on the list' do\n        expect(contract1).to receive(:simulate_request)\n        expect(contract2).to receive(:simulate_request)\n\n        list = ContractSet.new([contract1, contract2])\n        list.simulate_consumers\n      end\n    end\n\n    context 'when stubbing' do\n      let(:values) { Hash.new }\n\n      it 'stubs every contract on the list' do\n        expect(contract1).to receive(:stub_contract!).with(values)\n        expect(contract2).to receive(:stub_contract!).with(values)\n\n        list = ContractSet.new([contract1, contract2])\n        list.stub_providers(values)\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/contract_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nRSpec.shared_examples 'a contract' do\n  before do\n    Pacto.configuration.adapter = adapter\n    allow(consumer_driver).to receive(:respond_to?).with(:execute).and_return true\n    allow(provider_actor).to receive(:respond_to?).with(:build_response).and_return true\n    Pacto.configuration.default_consumer.driver = consumer_driver\n    Pacto.configuration.default_provider.actor = provider_actor\n  end\n\n  it 'is a type of Contract' do\n    expect(subject).to be_a_kind_of(Pacto::Contract)\n  end\n\n  describe '#stub_contract!' do\n    it 'register a stub for the contract' do\n      expect(adapter).to receive(:stub_request!).with(contract)\n      contract.stub_contract!\n    end\n  end\n\n  context 'investigations' do\n    let(:request) { Pacto.configuration.default_consumer.build_request contract }\n    let(:fake_response) { Fabricate(:pacto_response) } # double('fake response') }\n    let(:cop) { double 'cop' }\n    let(:investigation_citations) { [double('investigation result')] }\n\n    before do\n      Pacto::Cops.active_cops.clear\n      Pacto::Cops.active_cops << cop\n      allow(cop).to receive(:investigate).with(an_instance_of(Pacto::PactoRequest), fake_response, contract).and_return investigation_citations\n    end\n\n    describe '#simulate_request' do\n      before do\n        allow(consumer_driver).to receive(:execute).with(an_instance_of(Pacto::PactoRequest)).and_return fake_response\n      end\n\n      it 'generates the response' do\n        expect(consumer_driver).to receive(:execute).with(an_instance_of(Pacto::PactoRequest))\n        contract.simulate_request\n      end\n\n      it 'returns the result of the validating the generated response' do\n        expect(cop).to receive(:investigate).with(an_instance_of(Pacto::PactoRequest), fake_response, contract)\n        investigation = contract.simulate_request\n        expect(investigation.citations).to eq investigation_citations\n      end\n    end\n  end\n\n  describe '#matches?' do\n    let(:request_pattern)  { double('request_pattern') }\n    let(:request_signature)  { double('request_signature') }\n\n    it 'delegates to the request pattern' do\n      expect(Pacto::RequestPattern).to receive(:for).and_return(request_pattern)\n      expect(request_pattern).to receive(:matches?).with(request_signature)\n\n      contract.matches?(request_signature)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/cops/body_cop_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nRSpec.shared_examples 'a body cop' do | section_to_validate |\n  subject(:cop) { described_class }\n  let(:request_clause)  { Fabricate(:request_clause, schema: schema) }\n  let(:response_clause) { Fabricate(:response_clause, schema: schema) }\n  let(:contract)         do\n    Fabricate(:contract, file: 'file:///a.json', request: request_clause, response: response_clause)\n  end\n  let(:string_required)  { %w(#) }\n  let(:request)          { Fabricate(:pacto_request) }\n  let(:response)         { Fabricate(:pacto_response) }\n  let(:clause_to_validate) { contract.send section_to_validate }\n  let(:object_to_validate) { send section_to_validate }\n\n  describe '#validate' do\n    context 'when schema is not specified' do\n      let(:schema) { nil }\n\n      it 'gives no errors without validating body' do\n        expect(JSON::Validator).not_to receive(:fully_validate)\n        expect(cop.investigate(request, response, contract)).to be_empty\n      end\n    end\n\n    context 'when the expected body is a string' do\n      let(:schema) { { 'type' => 'string', 'required' => string_required } }\n\n      context 'if required' do\n        it 'does not return an error when body is a string' do\n          object_to_validate.body = 'asdf'\n          expect(cop.investigate(request, response, contract)).to eq([])\n        end\n\n        it 'returns an error when body is nil' do\n          object_to_validate.body = nil\n          expect(cop.investigate(request, response, contract).size).to eq 1\n        end\n      end\n\n      context 'if not required' do\n        let(:string_required) { %w() }\n\n        # Body can be empty but not nil if not required\n        # Not sure if this is an issue or not\n        skip 'does not return an error when body is a string' do\n          expect(cop.investigate(request, response, contract)).to be_empty\n        end\n\n        it 'does not return an error when body is empty' do\n          object_to_validate.body = ''\n          expect(cop.investigate(request, response, contract)).to be_empty\n        end\n      end\n\n      context 'if contains pattern' do\n        let(:schema) do\n          { type: 'string', required: string_required, pattern: 'a.c' }\n        end\n\n        context 'body matches pattern' do\n          it 'does not return an error' do\n            object_to_validate.body = 'abc'\n            expect(cop.investigate(request, response, contract)).to be_empty\n          end\n        end\n\n        context 'body does not match pattern' do\n          it 'returns an error' do\n            object_to_validate.body = 'acb' # This does not matches the pattern /a.c/\n            expect(cop.investigate(request, response, contract).size).to eq 1\n          end\n        end\n      end\n    end\n\n    context 'when the body is json' do\n      let(:schema) { { type: 'object' } }\n\n      context 'when body matches' do\n        it 'does not return any errors' do\n          expect(JSON::Validator).to receive(:fully_validate).and_return([])\n          expect(cop.investigate(request, response, contract)).to be_empty\n        end\n      end\n\n      context 'when body does not match' do\n        it 'returns a list of errors' do\n          errors = double 'some errors'\n          expect(JSON::Validator).to receive(:fully_validate).and_return(errors)\n          expect(cop.investigate(request, response, contract)).to eq(errors)\n        end\n      end\n    end\n  end\nend\n\nmodule Pacto\n  module Cops\n    describe RequestBodyCop do\n      it_behaves_like 'a body cop', :request\n    end\n\n    describe ResponseBodyCop do\n      it_behaves_like 'a body cop', :response\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/cops/response_header_cop_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    describe ResponseHeaderCop do\n      subject(:cop) { described_class }\n      let(:contract)         do\n        response_clause = Fabricate(:response_clause, headers: expected_headers)\n        Fabricate(:contract, response: response_clause)\n      end\n      let(:request)          { Fabricate(:pacto_request) }\n      let(:response)         { Fabricate(:pacto_response, headers: actual_headers) }\n      let(:expected_headers) do\n        {\n          'Content-Type' => 'application/json'\n        }\n      end\n      describe '#investigate' do\n        context 'when headers do not match' do\n          let(:actual_headers) do\n            { 'Content-Type' => 'text/html' }\n          end\n          it 'indicates the exact mismatches' do\n            expect(cop.investigate(request, response, contract)).\n              to eq ['Invalid response header Content-Type: expected \"application/json\" but received \"text/html\"']\n          end\n        end\n\n        context 'when headers are missing' do\n          let(:actual_headers) do\n            {}\n          end\n          let(:expected_headers) do\n            {\n              'Content-Type' => 'application/json',\n              'My-Cool-Header' => 'Whiskey Pie'\n            }\n          end\n          it 'lists the missing headers' do\n            expect(cop.investigate(request, response, contract)).\n              to eq [\n                'Missing expected response header: Content-Type',\n                'Missing expected response header: My-Cool-Header'\n              ]\n          end\n        end\n\n        context 'when Location Header is expected' do\n          before(:each) do\n            expected_headers.merge!('Location' => 'http://www.example.com/{foo}/bar')\n          end\n\n          context 'and no Location header is sent' do\n            let(:actual_headers) { { 'Content-Type' => 'application/json' } }\n            it 'returns a header error when no Location header is sent' do\n              expect(cop.investigate(request, response, contract)).to eq ['Missing expected response header: Location']\n            end\n          end\n\n          context 'but the Location header does not matches the pattern' do\n            let(:actual_headers) do\n              {\n                'Content-Type' => 'application/json',\n                'Location' => 'http://www.example.com/foo/bar/baz'\n              }\n            end\n\n            it 'returns a investigation error' do\n              response.headers = actual_headers\n              expect(cop.investigate(request, response, contract)).to eq [\"Invalid response header Location: expected URI #{actual_headers['Location']} to match URI Template #{expected_headers['Location']}\"]\n            end\n          end\n\n          context 'and the Location header matches pattern' do\n            let(:actual_headers) do\n              {\n                'Content-Type' => 'application/json',\n                'Location' => 'http://www.example.com/foo/bar'\n              }\n            end\n\n            it 'investigates successfully' do\n              expect(cop.investigate(request, response, contract)).to be_empty\n            end\n          end\n        end\n\n        context 'when headers are a subset of expected headers' do\n          let(:actual_headers) { { 'Content-Type' => 'application/json' } }\n\n          it 'does not return any errors' do\n            expect(cop.investigate(request, response, contract)).to be_empty\n          end\n        end\n\n        context 'when headers values match but keys have different case' do\n          let(:actual_headers) { { 'content-type' => 'application/json' } }\n\n          it 'does not return any errors' do\n            expect(cop.investigate(request, response, contract)).to be_empty\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/cops/response_status_cop_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Cops\n    describe ResponseStatusCop do\n      subject(:cop) { described_class }\n      let(:contract) { Fabricate(:contract) }\n      let(:request) { Fabricate(:pacto_request) }\n\n      describe '#investigate' do\n        context 'when status does not match' do\n          let(:response) { Fabricate(:pacto_response, status: 500) }\n          it 'returns a status error' do\n            expect(cop.investigate(request, response, contract)).to eq ['Invalid status: expected 200 but got 500']\n          end\n        end\n\n        context 'when the status matches' do\n          let(:response) { Fabricate(:pacto_response, status: 200) }\n          it 'returns nil' do\n            expect(cop.investigate(request, response, contract)).to be_empty\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/cops_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe Cops do\n    let(:investigation_errors) { ['some error', 'another error'] }\n\n    let(:expected_response) do\n      Fabricate(:response_clause)\n    end\n\n    let(:actual_response) do\n      # TODO: Replace this with a Fabrication for Pacto::PactoResponse (perhaps backed by WebMock)\n      Fabricate(:pacto_response)\n      # double(\n      #   status: 200,\n      #   headers: { 'Content-Type' => 'application/json', 'Age' => '60' },\n      #   body: { 'message' => 'response' }\n      # )\n    end\n\n    let(:actual_request) { Fabricate(:pacto_request) }\n\n    let(:expected_request) do\n      Fabricate(:request_clause)\n    end\n\n    let(:contract) do\n      Fabricate(\n        :contract,\n        request: expected_request,\n        response: expected_response\n      )\n    end\n\n    describe '#validate_contract' do\n      before do\n        allow(Pacto::Cops::RequestBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])\n        allow(Pacto::Cops::ResponseBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])\n      end\n\n      context 'default cops' do\n        let(:investigation) { described_class.perform_investigation actual_request, actual_response, contract }\n\n        it 'calls the RequestBodyCop' do\n          expect(Pacto::Cops::RequestBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return(investigation_errors)\n          expect(investigation.citations).to eq(investigation_errors)\n        end\n\n        it 'calls the ResponseStatusCop' do\n          expect(Pacto::Cops::ResponseStatusCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return(investigation_errors)\n          expect(investigation.citations).to eq(investigation_errors)\n        end\n\n        it 'calls the ResponseHeaderCop' do\n          expect(Pacto::Cops::ResponseHeaderCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return(investigation_errors)\n          expect(investigation.citations).to eq(investigation_errors)\n        end\n\n        it 'calls the ResponseBodyCop' do\n          expect(Pacto::Cops::ResponseBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return(investigation_errors)\n          expect(investigation.citations).to eq(investigation_errors)\n        end\n      end\n\n      context 'when headers and body match and the ResponseStatusCop reports no errors' do\n        it 'does not return any errors' do\n          expect(Pacto::Cops::RequestBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])\n          expect(Pacto::Cops::ResponseStatusCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])\n          expect(Pacto::Cops::ResponseHeaderCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])\n          expect(Pacto::Cops::ResponseBodyCop).to receive(:investigate).with(actual_request, actual_response, contract).and_return([])\n          expect(described_class.perform_investigation actual_request, actual_response, contract).to be_successful\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/core/configuration_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\ndescribe Pacto do\n  describe '.configure' do\n    let(:contracts_path) { 'path_to_contracts' }\n\n    it 'allows contracts_path manual configuration' do\n      expect(described_class.configuration.contracts_path).to eq('.')\n      described_class.configure do |c|\n        c.contracts_path = contracts_path\n      end\n      expect(described_class.configuration.contracts_path).to eq(contracts_path)\n    end\n\n    it 'register a Pacto Hook' do\n      hook_block = Pacto::Hook.new {}\n      described_class.configure do |c|\n        c.register_hook(hook_block)\n      end\n      expect(described_class.configuration.hook).to eq(hook_block)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/core/contract_registry_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire_relative '../../../../lib/pacto/core/contract_registry'\n\nmodule Pacto\n  describe ContractRegistry do\n    let(:contract) { Fabricate(:contract) }\n    let(:request_signature) { Fabricate(:webmock_request_signature) }\n\n    subject(:contract_registry) do\n      ContractRegistry.new\n    end\n\n    describe '.register' do\n      it 'registers the contract' do\n        contract_registry.register contract\n        expect(contract_registry).to include(contract)\n      end\n    end\n\n    describe '.contracts_for' do\n      before(:each) do\n        contract_registry.register contract\n      end\n\n      context 'when no contracts are found for a request' do\n        it 'returns an empty list' do\n          expect(contract).to receive(:matches?).with(request_signature).and_return false\n          expect(contract_registry.contracts_for request_signature).to be_empty\n        end\n      end\n\n      context 'when contracts are found for a request' do\n        it 'returns the matching contracts' do\n          expect(contract).to receive(:matches?).with(request_signature).and_return true\n          expect(contract_registry.contracts_for request_signature).to eq([contract])\n        end\n      end\n    end\n\n    def create_contracts(total, matches)\n      total.times.map do\n        double('contract',\n               :stub_contract! => double('request matcher'),\n               :matches? => matches)\n      end\n    end\n\n    def register_contracts(contracts)\n      contracts.each { |contract| contract_registry.register contract }\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/core/http_middleware_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Core\n    describe HTTPMiddleware do\n      subject(:middleware) { Pacto::Core::HTTPMiddleware.new }\n      let(:request) { double }\n      let(:response) { double }\n\n      class FailingObserver\n        def raise_error(_pacto_request, _pacto_response)\n          fail InvalidContract, ['The contract was missing things', 'and stuff']\n        end\n      end\n\n      describe '#process' do\n        it 'calls registered HTTP observers' do\n          observer1, observer2 = double, double\n          expect(observer1).to receive(:respond_to?).with(:do_something).and_return true\n          expect(observer2).to receive(:respond_to?).with(:do_something_else).and_return true\n          middleware.add_observer(observer1, :do_something)\n          middleware.add_observer(observer2, :do_something_else)\n          expect(observer1).to receive(:do_something).with(request, response)\n          expect(observer2).to receive(:do_something_else).with(request, response)\n          middleware.process request, response\n        end\n\n        pending 'logs rescues and logs failures'\n        pending 'calls the HTTP middleware'\n        pending 'calls the registered hook'\n        pending 'calls generate when generate is enabled'\n        pending 'calls validate when validate mode is enabled'\n        pending 'validates a WebMock request/response pair'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/core/investigation_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe Investigation do\n    let(:request) { double('request') }\n    let(:response) { double('response') }\n    let(:file) { 'foobar' }\n    let(:contract) { Fabricate(:contract, file: file) }\n    let(:investigation_citations) { [] }\n    let(:investigation_citations_with_errors) { ['an error occurred'] }\n\n    it 'stores the request, response, contract and citations' do\n      investigation = Pacto::Investigation.new request, response, contract, investigation_citations\n      expect(investigation.request).to eq request\n      expect(investigation.response).to eq response\n      expect(investigation.contract).to eq contract\n      expect(investigation.citations).to eq investigation_citations\n    end\n\n    context 'if there were investigation errors' do\n      subject(:investigation) do\n        Pacto::Investigation.new request, response, contract, investigation_citations_with_errors\n      end\n\n      describe '#successful?' do\n        it 'returns false' do\n          expect(investigation.successful?).to be_falsey\n        end\n      end\n    end\n\n    context 'if there were no investigation errors' do\n      subject(:investigation) do\n        Pacto::Investigation.new request, response, contract, investigation_citations\n      end\n\n      it 'returns false' do\n        expect(investigation.successful?).to be true\n      end\n    end\n\n    describe '#against_contract?' do\n      it 'returns nil if there was no contract' do\n        investigation = Pacto::Investigation.new request, response, nil, investigation_citations\n        expect(investigation.against_contract? 'a').to be_nil\n      end\n\n      it 'returns the contract with an exact string name match' do\n        investigation = Pacto::Investigation.new request, response, contract, investigation_citations\n        expect(investigation.against_contract? 'foobar').to eq(contract)\n        expect(investigation.against_contract? 'foo').to be_nil\n        expect(investigation.against_contract? 'bar').to be_nil\n      end\n\n      it 'returns the contract if there is a regex match' do\n        allow(contract).to receive(:file).and_return 'foobar'\n        investigation = Pacto::Investigation.new request, response, contract, investigation_citations\n        expect(investigation.against_contract?(/foo/)).to eq(contract)\n        expect(investigation.against_contract?(/bar/)).to eq(contract)\n        expect(investigation.against_contract?(/baz/)).to be_nil\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/core/modes_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\ndescribe Pacto do\n  modes = %w(generate validate)\n  modes.each do |mode|\n    enable_method = \"#{mode}!\".to_sym # generate!\n    query_method = \"#{mode[0..-2]}ing?\".to_sym # generating?\n    disable_method = \"stop_#{mode[0..-2]}ing!\".to_sym # stop_generating!\n    describe \".#{mode}!\" do\n      it \"tells the provider to enable #{mode} mode\" do\n        expect(subject.send query_method).to be_falsey\n        subject.send enable_method\n        expect(subject.send query_method).to be true\n\n        subject.send disable_method\n        expect(subject.send query_method).to be_falsey\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/erb_processor_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe ERBProcessor do\n    subject(:processor) { described_class.new }\n\n    describe '#process' do\n      let(:erb) { '2 + 2 = <%= 2 + 2 %>' }\n      let(:result) { '2 + 2 = 4' }\n\n      it 'returns the result of ERB' do\n        expect(processor.process(erb)).to eq result\n      end\n\n      it 'logs the erb processed' do\n        expect(Pacto.configuration.logger).to receive(:debug).with(\"Processed contract: \\\"#{result}\\\"\")\n        processor.process erb\n      end\n\n      it 'does not mess with pure JSONs' do\n        processor.process('{\"property\": [\"one\", \"two, null\"]}')\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/extensions_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe Extensions do\n    describe '#normalize_header_keys' do\n      it 'matches headers to the style in the RFC documentation' do\n        expect(Pacto::Extensions.normalize_header_keys(:'user-agent' => 'a')).to eq('User-Agent' => 'a') # rubocop:disable SymbolName\n        expect(Pacto::Extensions.normalize_header_keys(user_agent: 'a')).to eq('User-Agent' => 'a')\n        expect(Pacto::Extensions.normalize_header_keys('User-Agent' => 'a')).to eq('User-Agent' => 'a')\n        expect(Pacto::Extensions.normalize_header_keys('user-agent' => 'a')).to eq('User-Agent' => 'a')\n        expect(Pacto::Extensions.normalize_header_keys('user_agent' => 'a')).to eq('User-Agent' => 'a')\n        expect(Pacto::Extensions.normalize_header_keys('USER_AGENT' => 'a')).to eq('User-Agent' => 'a')\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/contract_builder_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      describe ContractBuilder do\n        let(:data) { subject.build_hash }\n        describe '#name' do\n          it 'sets the contract name' do\n            subject.name = 'foo'\n            expect(data).to include(name: 'foo')\n          end\n        end\n\n        describe '#add_example' do\n          let(:examples) { subject.build_hash[:examples] }\n          it 'adds named examples to the contract' do\n            subject.add_example 'foo', Fabricate(:pacto_request), Fabricate(:pacto_response)\n            subject.add_example 'bar', Fabricate(:pacto_request), Fabricate(:pacto_response)\n            expect(examples).to be_a(Hash)\n            expect(examples.keys).to include('foo', 'bar')\n            expect(examples['foo'][:response]).to include(status: 200)\n            expect(data)\n          end\n        end\n\n        context 'without examples' do\n          describe '#infer_schemas' do\n            it 'does not add schemas' do\n              subject.name = 'test'\n              subject.infer_schemas\n              expect(data[:request][:schema]).to be_nil\n              expect(data[:response][:schema]).to be_nil\n            end\n          end\n        end\n\n        context 'with examples' do\n          before(:each) do\n            subject.add_example 'success', Fabricate(:pacto_request), Fabricate(:pacto_response)\n            subject.add_example 'not found', Fabricate(:pacto_request), Fabricate(:pacto_response)\n          end\n\n          describe '#without_examples' do\n            it 'stops the builder from including examples in the final data' do\n              expect(subject.build_hash.keys).to include(:examples)\n              expect(subject.without_examples.build_hash.keys).to_not include(:examples)\n            end\n          end\n\n          describe '#infer_schemas' do\n            it 'adds schemas' do\n              subject.name = 'test'\n              subject.infer_schemas\n              contract = subject.build\n              expect(contract.request.schema).to_not be_nil\n              expect(contract.request.schema).to_not be_nil\n            end\n          end\n        end\n\n        context 'generating from interactions' do\n          let(:request) { Fabricate(:pacto_request) }\n          let(:response) { Fabricate(:pacto_response) }\n          let(:data) { subject.generate_response(request, response).build_hash }\n          let(:contract) { subject.generate_contract(request, response).build }\n\n          describe '#generate_response' do\n            it 'sets the response status' do\n              expect(data[:response]).to include(\n                                                   status: 200\n                                                 )\n            end\n\n            it 'sets response headers' do\n              expect(data[:response][:headers]).to be_a(Hash)\n            end\n          end\n\n          describe '#infer_schemas' do\n            it 'sets the schemas based on the examples' do\n              expect(contract.request.schema).to_not be_nil\n              expect(contract.request.schema).to_not be_nil\n            end\n          end\n        end\n\n        skip '#add_request_header'\n        skip '#add_response_header'\n        skip '#filter'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/contract_factory_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  module Formats\n    module Legacy\n      describe ContractFactory do\n        let(:host)                 { 'http://localhost' }\n        let(:contract_format)      { 'legacy' }\n        let(:contract_name)        { 'contract' }\n        let(:contract_path)        { contract_file(contract_name, contract_format) }\n        subject(:contract_factory) { described_class.new }\n\n        it 'builds a Contract given a JSON file path and a host' do\n          contract = contract_factory.build_from_file(contract_path, host)\n          expect(contract).to be_a(Pacto::Formats::Legacy::Contract)\n        end\n\n        context 'deprecated contracts' do\n          let(:contract_format)      { 'deprecated' }\n          let(:contract_name)        { 'deprecated_contract' }\n          it 'can no longer be loaded' do\n            expect { contract_factory.build_from_file(contract_path, host) }.to raise_error(/old syntax no longer supported/)\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/contract_generator_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      describe ContractGenerator do\n        let(:record_host) do\n          'http://example.com'\n        end\n        let(:request_clause) { Fabricate(:request_clause, params: { 'api_key' => \"<%= ENV['MY_API_KEY'] %>\" }) }\n        let(:response_adapter) do\n          Faraday::Response.new(\n            status: 200,\n            response_headers: {\n              'Date' => [Time.now],\n              'Server' => ['Fake Server'],\n              'Content-Type' => ['application/json'],\n              'Vary' => ['User-Agent']\n            },\n            body: 'dummy body' # body is just a string\n          )\n        end\n        let(:filtered_request_headers) { double('filtered_response_headers') }\n        let(:filtered_response_headers) { double('filtered_response_headers') }\n        let(:response_body_schema) { '{\"message\": \"dummy generated schema\"}' }\n        let(:version) { 'draft3' }\n        let(:schema_generator) { double('schema_generator') }\n        let(:validator) { double('validator') }\n        let(:filters) { double :filters }\n        let(:consumer) { double 'consumer' }\n        let(:request_file) { 'request.json' }\n        let(:generator) { described_class.new version, schema_generator, validator, filters, consumer }\n        let(:request_contract) do\n          Fabricate(:partial_contract, request: request_clause, file: request_file)\n        end\n        let(:request) do\n          Pacto.configuration.default_consumer.build_request request_contract\n        end\n\n        def pretty(obj)\n          MultiJson.encode(obj, pretty: true).gsub(/^$\\n/, '')\n        end\n\n        describe '#generate_from_partial_contract' do\n          # TODO: Deprecate partial contracts?\n          let(:generated_contract) { Fabricate(:contract) }\n          before do\n            expect(Pacto).to receive(:load_contract).with(request_file, record_host).and_return request_contract\n            expect(consumer).to receive(:request).with(request_contract).and_return([request, response_adapter])\n          end\n\n          it 'parses the request' do\n            expect(generator).to receive(:save).with(request_file, request, anything)\n            generator.generate_from_partial_contract request_file, record_host\n          end\n\n          it 'fetches a response' do\n            expect(generator).to receive(:save).with(request_file, anything, response_adapter)\n            generator.generate_from_partial_contract request_file, record_host\n          end\n\n          it 'saves the result' do\n            expect(generator).to receive(:save).with(request_file, request, response_adapter).and_return generated_contract\n            expect(generator.generate_from_partial_contract request_file, record_host).to eq(generated_contract)\n          end\n        end\n\n        describe '#save' do\n          before do\n            allow(filters).to receive(:filter_request_headers).with(request, response_adapter).and_return filtered_request_headers\n            allow(filters).to receive(:filter_response_headers).with(request, response_adapter).and_return filtered_response_headers\n          end\n          context 'invalid schema' do\n            it 'raises an error if schema generation fails' do\n              expect(schema_generator).to receive(:generate).and_raise ArgumentError.new('Could not generate schema')\n              expect { generator.save request_file, request, response_adapter }.to raise_error\n            end\n\n            it 'raises an error if the generated contract is invalid' do\n              expect(schema_generator).to receive(:generate).and_return response_body_schema\n              expect(validator).to receive(:validate).and_raise InvalidContract.new('dummy error')\n              expect { generator.save request_file, request, response_adapter }.to raise_error\n            end\n          end\n\n          context 'valid schema' do\n            let(:raw_contract) do\n              expect(schema_generator).to receive(:generate).with(request_file, response_adapter.body, Pacto.configuration.generator_options).and_return response_body_schema\n              expect(validator).to receive(:validate).and_return true\n              generator.save request_file, request, response_adapter\n            end\n            subject(:generated_contract) { JSON.parse raw_contract }\n\n            it 'sets the schema to the generated json-schema' do\n              expect(subject['response']['schema']).to eq(JSON.parse response_body_schema)\n            end\n\n            it 'sets the request attributes' do\n              generated_request = subject['request']\n              expect(generated_request['params']).to eq(request.uri.query_values)\n              expect(generated_request['path']).to eq(request.uri.path)\n            end\n\n            it 'preserves ERB in the request params' do\n              generated_request = subject['request']\n              expect(generated_request['params']).to eq('api_key' => \"<%= ENV['MY_API_KEY'] %>\")\n            end\n\n            it 'normalizes the request method' do\n              generated_request = subject['request']\n              expect(generated_request['http_method']).to eq(request.method.downcase.to_s)\n            end\n\n            it 'sets the response attributes' do\n              generated_response = subject['response']\n              expect(generated_response['status']).to eq(response_adapter.status)\n            end\n\n            it 'generates pretty JSON' do\n              expect(raw_contract).to eq(pretty(subject))\n            end\n          end\n\n          context 'with hints' do\n            let(:request1) { Fabricate(:pacto_request, host: 'example.com', path: '/album/5/cover') }\n            let(:request2) { Fabricate(:pacto_request, host: 'example.com', path: '/album/7/cover') }\n            let(:response1) { Fabricate(:pacto_response) }\n            let(:response2) { Fabricate(:pacto_response) }\n            let(:contracts_path) { Dir.mktmpdir }\n\n            before(:each) do\n              allow(filters).to receive(:filter_request_headers).with(request1, response1).and_return request1.headers\n              allow(filters).to receive(:filter_response_headers).with(request1, response1).and_return response1.headers\n              allow(filters).to receive(:filter_request_headers).with(request2, response2).and_return request2.headers\n              allow(filters).to receive(:filter_response_headers).with(request2, response2).and_return response2.headers\n              allow(schema_generator).to receive(:generate).with(request_file, response1.body, Pacto.configuration.generator_options).and_return response_body_schema\n              allow(schema_generator).to receive(:generate).with(request_file, response2.body, Pacto.configuration.generator_options).and_return response_body_schema\n              allow(validator).to receive(:validate).twice.and_return true\n              Pacto.configuration.contracts_path = contracts_path\n              Pacto::Generator.configure do |c|\n                c.hint 'Get Album Cover', http_method: :get, host: 'http://example.com', path: '/album/{id}/cover', target_file: 'album_services/get_album_cover.json'\n              end\n              Pacto.generate!\n            end\n\n            it 'names the contract based on the hint' do\n              contract1 = generator.generate request1, response1\n              expect(contract1.name).to eq('Get Album Cover')\n            end\n\n            it 'sets the path to match the hint' do\n              contract1 = generator.generate request1, response1\n              expect(contract1.request.path).to eq('/album/{id}/cover')\n            end\n\n            it 'sets the target file based on the hint' do\n              contract1 = generator.generate request1, response1\n              expected_path = File.expand_path('album_services/get_album_cover.json', contracts_path)\n              real_expected_path =  Pathname.new(expected_path).realpath.to_s\n              expected_file_uri = Addressable::URI.convert_path(real_expected_path).to_s\n              expect(contract1.file).to eq(expected_file_uri)\n            end\n\n            xit 'does not create duplicate contracts' do\n              contract1 = generator.generate request1, response1\n              contract2 = generator.generate request2, response2\n              expect(contract1).to eq(contract2)\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/contract_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'unit/pacto/contract_spec'\n\nmodule Pacto\n  module Formats\n    module Legacy\n      describe Contract do\n        let(:request_clause) do\n          Pacto::Formats::Legacy::RequestClause.new(\n            http_method: 'GET',\n            host: 'http://example.com',\n            path: '/',\n            schema:  {\n              type: 'object',\n              required: true # , :properties => double('body definition properties')\n            }\n          )\n        end\n\n        let(:response_clause) do\n          ResponseClause.new(status: 200)\n        end\n        let(:adapter) { double 'provider' }\n        let(:file) { contract_file 'contract', 'legacy' }\n        let(:consumer_driver) { double }\n        let(:provider_actor) { double }\n\n        subject(:contract) do\n          described_class.new(\n            request: request_clause,\n            response: response_clause,\n            file: file,\n            name: 'sample'\n          )\n        end\n\n        it_behaves_like 'a contract'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/generator/filters_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      module Generator\n        describe Filters do\n          let(:record_host) do\n            'http://example.com'\n          end\n          let(:request) do\n            RequestClause.new(\n              host: record_host,\n              http_method: 'GET',\n              path: '/abcd',\n              headers: {\n                'Server' => ['example.com'],\n                'Connection' => ['Close'],\n                'Content-Length' => [1234],\n                'Via' => ['Some Proxy'],\n                'User-Agent' => ['rspec']\n              },\n              params: {\n                'apikey' => \"<%= ENV['MY_API_KEY'] %>\"\n              }\n            )\n          end\n          let(:varies) { ['User-Agent'] }\n          let(:response) do\n            Faraday::Response.new(\n              status: 200,\n              response_headers: {\n                'Date' => Time.now.rfc2822,\n                'Last-Modified' => Time.now.rfc2822,\n                'ETag' => 'abc123',\n                'Server' => ['Fake Server'],\n                'Content-Type' => ['application/json'],\n                'Vary' => varies\n              },\n              body: double('dummy body')\n            )\n          end\n\n          describe '#filter_request_headers' do\n            subject(:filtered_request_headers) { described_class.new.filter_request_headers(request, response).keys.map(&:downcase) }\n            it 'keeps important request headers' do\n              expect(filtered_request_headers).to include 'user-agent'\n            end\n\n            it 'filters informational request headers' do\n              expect(filtered_request_headers).not_to include 'via'\n              expect(filtered_request_headers).not_to include 'date'\n              expect(filtered_request_headers).not_to include 'server'\n              expect(filtered_request_headers).not_to include 'content-length'\n              expect(filtered_request_headers).not_to include 'connection'\n            end\n\n            context 'multiple Vary elements' do\n              context 'as a single string' do\n                let(:varies) do\n                  ['User-Agent,Via']\n                end\n                it 'keeps each header' do\n                  expect(filtered_request_headers).to include 'user-agent'\n                  expect(filtered_request_headers).to include 'via'\n                end\n              end\n              context 'as multiple items' do\n                let(:varies) do\n                  %w(User-Agent Via)\n                end\n                it 'keeps each header' do\n                  expect(filtered_request_headers).to include 'user-agent'\n                  expect(filtered_request_headers).to include 'via'\n                end\n              end\n            end\n          end\n\n          describe '#filter_response_headers' do\n            subject(:filtered_response_headers) { described_class.new.filter_response_headers(request, response).keys.map(&:downcase) }\n            it 'keeps important response headers' do\n              expect(filtered_response_headers).to include 'content-type'\n            end\n\n            it 'filters connection control headers' do\n              expect(filtered_response_headers).not_to include 'content-length'\n              expect(filtered_response_headers).not_to include 'via'\n            end\n\n            it 'filters freshness headers' do\n              expect(filtered_response_headers).not_to include 'date'\n              expect(filtered_response_headers).not_to include 'last-modified'\n              expect(filtered_response_headers).not_to include 'eTag'\n            end\n\n            it 'filters x-* headers' do\n              expect(filtered_response_headers).not_to include 'x-men'\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/request_clause_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      describe RequestClause do\n        let(:host)           { 'http://localhost' }\n        let(:method)         { 'GET' }\n        let(:path)           { '/hello_world' }\n        let(:headers)        { { 'accept' => 'application/json' } }\n        let(:params)         { { 'foo' => 'bar' } }\n        let(:body)           { double :body }\n        let(:params_as_json) { \"{\\\"foo\\\":\\\"bar\\\"}\" }\n        let(:absolute_uri)   { \"#{host}#{path}\" }\n        subject(:request) do\n          req_hash = {\n            host: host,\n            'http_method'  => method,\n            'path'    => path,\n            'headers' => headers,\n            'params'  => params\n          }\n          # The default test is for missing keys, not explicitly nil keys\n          req_hash.merge!('schema' => body) if body\n          described_class.new(req_hash)\n        end\n\n        it 'has a host' do\n          expect(request.host).to eq host\n        end\n\n        describe '#http_method' do\n          it 'delegates to definition' do\n            expect(request.http_method).to eq :get\n          end\n\n          it 'downcases the method' do\n            expect(request.http_method).to eq request.http_method.downcase\n          end\n\n          it 'returns a symbol' do\n            expect(request.http_method).to be_kind_of Symbol\n          end\n        end\n\n        describe '#schema' do\n          it 'delegates to definition\\'s body' do\n            expect(request.schema).to eq body\n          end\n\n          describe 'when definition does not have a schema' do\n            let(:body) { nil }\n\n            it 'returns an empty empty hash' do\n              expect(request.schema).to eq({})\n            end\n          end\n        end\n\n        describe '#path' do\n          it 'delegates to definition' do\n            expect(request.path).to eq path\n          end\n        end\n\n        describe '#headers' do\n          it 'delegates to definition' do\n            expect(request.headers).to eq headers\n          end\n        end\n\n        describe '#params' do\n          it 'delegates to definition' do\n            expect(request.params).to eq params\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/formats/legacy/response_clause_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Legacy\n      describe ResponseClause do\n        let(:body_definition) do\n          Fabricate(:schema)\n        end\n\n        let(:definition) do\n          {\n            'status' => 200,\n            'headers' => {\n              'Content-Type' => 'application/json'\n            },\n            'schema' => body_definition\n          }\n        end\n\n        subject(:response) { described_class.new(definition) }\n\n        it 'has a status' do\n          expect(response.status).to eq(200)\n        end\n\n        it 'has a headers hash' do\n          expect(response.headers).to eq(\n            'Content-Type' => 'application/json'\n          )\n        end\n\n        it 'has a schema' do\n          expect(response.schema).to eq(body_definition)\n        end\n\n        it 'has a default value for the schema' do\n          definition.delete 'schema'\n          response = described_class.new(definition)\n          expect(response.schema).to eq(Hash.new)\n        end\n\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/formats/swagger/contract_factory_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Formats\n    module Swagger\n      describe ContractFactory do\n        let(:swagger_file) { contract_file('petstore', 'swagger') }\n        let(:expected_schema) do\n          {\n            'type' => 'array',\n            'items' => {\n              'required' => %w(id name),\n              'properties' => {\n                'id' => { 'type' => 'integer', 'format' => 'int64' },\n                'name' => { 'type' => 'string' },\n                'tag' => { 'type' => 'string' }\n              }\n            }\n          }\n        end\n        describe '#load_hints' do\n          pending 'loads hints from Swagger' do\n            hints = subject.load_hints(swagger_file)\n            expect(hints.size).to eq(3) # number of API operations\n            hints.each do | hint |\n              expect(hint).to be_a_kind_of(Pacto::Generator::Hint)\n              expect(hint.host).to eq('petstore.swagger.wordnik.com')\n              expect([:get, :post]).to include(hint.http_method)\n              expect(hint.path).to match(/\\/pets/)\n            end\n          end\n        end\n\n        describe '#build_from_file' do\n          it 'loads Contracts from Swagger' do\n            contracts = subject.build_from_file(swagger_file)\n            expect(contracts.size).to eq(3) # number of API operations\n            contracts.each do | contract |\n              expect(contract).to be_a(Pacto::Formats::Swagger::Contract)\n\n              request_clause = contract.request\n              expect(request_clause.host).to eq('petstore.swagger.wordnik.com')\n              expect([:get, :post]).to include(request_clause.http_method)\n              expect(request_clause.path).to match(/\\/pets/)\n\n              response_clause = contract.response\n              if request_clause.http_method == :get\n                expect(response_clause.status).to eq(200)\n              else\n                expect(response_clause.status).to eq(201)\n              end\n              expect(response_clause.schema).to eq(expected_schema) if response_clause.status == 200\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/formats/swagger/contract_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'unit/pacto/contract_spec'\n\nmodule Pacto\n  module Formats\n    module Swagger\n      describe Contract do\n        let(:swagger_yaml) do\n          ''\"\n          swagger: '2.0'\n          info:\n            title: Sample API\n            version: N/A\n          consumes:\n          - application/json\n          produces:\n          - application/json\n          paths:\n            /:\n              get:\n                operationId: sample\n                responses:\n                  200:\n                    description: |-\n                      Success.\n          \"''\n        end\n        let(:swagger_definition) do\n          ::Swagger.build(swagger_yaml, format: :yaml)\n        end\n        let(:api_operation) do\n          swagger_definition.operations.first\n        end\n        let(:adapter) { double 'provider' }\n        let(:file) { Tempfile.new(['swagger', '.yaml']).path }\n        let(:consumer_driver) { double }\n        let(:provider_actor) { double }\n\n        subject(:contract) do\n          described_class.new(api_operation, file: file)\n        end\n\n        it_behaves_like 'a contract'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/hooks/erb_hook_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\ndescribe Pacto::Hooks::ERBHook do\n  describe '#process' do\n    let(:req) do\n      OpenStruct.new(headers: { 'User-Agent' => 'abcd' })\n    end\n    let(:converted_req) do\n      { 'HEADERS' => { 'User-Agent' => 'abcd' } }\n    end\n    let(:res) do\n      Pacto::PactoResponse.new(\n        status: 200,\n        body: 'before'\n      )\n    end\n\n    before do\n    end\n\n    context 'no matching contracts' do\n      it 'binds the request' do\n        contracts = Set.new\n        mock_erb(req: converted_req)\n        described_class.new.process contracts, req, res\n        expect(res.body).to eq('after')\n      end\n    end\n\n    context 'one matching contract' do\n      it 'binds the request and the contract\\'s values' do\n        contract = OpenStruct.new(values: { max: 'test' })\n        contracts = Set.new([contract])\n        mock_erb(req: converted_req, max: 'test')\n        described_class.new.process contracts, req, res\n        expect(res.body).to eq('after')\n      end\n    end\n\n    context 'multiple matching contracts' do\n      it 'binds the request and the first contract\\'s values' do\n        contract1 = OpenStruct.new(values: { max: 'test' })\n        contract2 = OpenStruct.new(values: { mob: 'team' })\n        res = Pacto::PactoResponse.new(\n          status: 200,\n          body: 'before'\n        )\n        mock_erb(req: converted_req, max: 'test')\n        contracts = Set.new([contract1, contract2])\n        described_class.new.process contracts, req, res\n        expect(res.body).to eq('after')\n      end\n    end\n  end\n\n  def mock_erb(hash)\n    expect_any_instance_of(Pacto::ERBProcessor).to receive(:process).with('before', hash).and_return('after')\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/investigation_registry_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\ndescribe Pacto::InvestigationRegistry do\n  subject(:registry) { described_class.instance }\n  let(:request_pattern) { Fabricate(:webmock_request_pattern) }\n  let(:request_signature) { Fabricate(:webmock_request_signature) }\n  let(:pacto_response) { Fabricate(:pacto_response) }\n  let(:different_request_signature) { Fabricate(:webmock_request_signature, uri: 'www.thoughtworks.com') }\n  let(:investigation) { Pacto::Investigation.new(request_signature, pacto_response, nil, []) }\n  let(:investigation_for_a_similar_request) { Pacto::Investigation.new(request_signature, pacto_response, nil, []) }\n  let(:investigation_for_a_different_request) { Pacto::Investigation.new(different_request_signature, pacto_response, nil, []) }\n\n  before(:each) do\n    registry.reset!\n  end\n\n  describe 'reset!' do\n    before(:each) do\n      registry.register_investigation(investigation)\n    end\n\n    it 'cleans investigations' do\n      expect { registry.reset! }.to change { registry.validated? request_pattern }.from([investigation]).to(nil)\n    end\n  end\n\n  describe 'registering and reporting registered investigations' do\n    it 'returns registered investigation' do\n      expect(registry.register_investigation investigation).to eq(investigation)\n    end\n\n    it 'reports if investigation is not registered' do\n      expect(registry.validated? request_pattern).to be_falsey\n    end\n\n    it 'registers and returns matching investigations' do\n      registry.register_investigation(investigation)\n      registry.register_investigation(investigation_for_a_similar_request)\n      registry.register_investigation(investigation_for_a_different_request)\n      expect(registry.validated? request_pattern).to eq([investigation, investigation_for_a_similar_request])\n    end\n  end\n\n  describe '.unmatched_investigations' do\n    let(:contract) { Fabricate(:contract) }\n\n    it 'returns investigations with no contract' do\n      investigation_with_citations = Pacto::Investigation.new(different_request_signature, pacto_response, contract, [])\n      registry.register_investigation(investigation)\n      registry.register_investigation(investigation_for_a_similar_request)\n      registry.register_investigation(investigation_for_a_different_request)\n      registry.register_investigation(investigation_with_citations)\n\n      expect(registry.unmatched_investigations).to match_array([investigation, investigation_for_a_similar_request, investigation_for_a_different_request])\n    end\n  end\n\n  describe '.failed_investigations' do\n    let(:contract) { Fabricate(:contract, name: 'test') }\n    let(:citations2) { ['a sample citation'] }\n\n    it 'returns investigations with unsuccessful citations' do\n      investigation_with_successful_citations = Pacto::Investigation.new(request_signature, pacto_response, nil, ['error'])\n      investigation_with_unsuccessful_citations = Pacto::Investigation.new(request_signature, pacto_response, nil, %w(error2 error3))\n\n      # Twice because of debug statement...\n      expect(investigation_with_successful_citations).to receive(:successful?).twice.and_return true\n      expect(investigation_with_unsuccessful_citations).to receive(:successful?).twice.and_return false\n\n      registry.register_investigation(investigation)\n      registry.register_investigation(investigation_with_successful_citations)\n      registry.register_investigation(investigation_with_unsuccessful_citations)\n\n      expect(registry.failed_investigations).to match_array([investigation_with_unsuccessful_citations])\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/logger_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Logger\n    describe SimpleLogger do\n      before do\n        logger.log logger_lib\n      end\n\n      subject(:logger) { described_class.instance }\n      let(:logger_lib) { ::Logger.new(StringIO.new) }\n\n      it 'delegates debug to the logger lib' do\n        expect(logger_lib).to receive(:debug)\n        logger.debug\n      end\n\n      it 'delegates info to the logger lib' do\n        expect(logger_lib).to receive(:info)\n        logger.info\n      end\n\n      it 'delegates warn to the logger lib' do\n        expect(logger_lib).to receive(:warn)\n        logger.warn\n      end\n\n      it 'delegates error to the logger lib' do\n        expect(logger_lib).to receive(:error)\n        logger.error\n      end\n\n      it 'delegates fatal to the logger lib' do\n        expect(logger_lib).to receive(:error)\n        logger.error\n      end\n\n      it 'has the default log level as error' do\n        expect(logger.level).to eq :error\n      end\n\n      it 'provides access to the log level' do\n        logger.level = :info\n        expect(logger.level).to eq :info\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/meta_schema_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  describe MetaSchema do\n    let(:valid_contract) do\n      <<-EOF\n        {\n          \"request\": {\n            \"method\": \"GET\",\n            \"path\": \"/hello_world\",\n            \"headers\": {\n              \"Accept\": \"application/json\"\n            },\n            \"params\": {}\n          },\n\n          \"response\": {\n            \"status\": 200,\n            \"headers\": {\n              \"Content-Type\": \"application/json\"\n            },\n            \"schema\": {\n              \"description\": \"A simple response\",\n              \"type\": \"object\",\n              \"properties\": {\n                \"message\": {\n                  \"type\": \"string\"\n                }\n              }\n            }\n          }\n        }\n      EOF\n    end\n\n    let(:partial_contract) do\n      <<-EOF\n        {\n          \"request\": {\n            \"method\": \"GET\",\n            \"path\": \"/hello_world\",\n            \"headers\": {\n              \"Accept\": \"application/json\"\n            },\n            \"params\": {}\n          }\n\n        }\n      EOF\n    end\n\n    let(:invalid_contract) do\n      <<-EOF\n        {\n          \"request\": {\n            \"method\": \"GET\",\n            \"path\": \"/hello_world\",\n            \"headers\": {\n              \"Accept\": \"application/json\"\n            },\n            \"params\": {}\n          },\n\n          \"response\": {\n            \"status\": 200,\n            \"headers\": {\n              \"Content-Type\": \"application/json\"\n            },\n            \"schema\": {\n              \"description\": \"A simple response\",\n              \"required\": {},\n              \"type\": \"object\",\n              \"properties\": {\n                \"message\": {\n                  \"type\": \"string\"\n                }\n              }\n            }\n          }\n        }\n      EOF\n    end\n\n    subject(:schema) { described_class.new }\n\n    describe 'when validating a contract against the master schema' do\n      context 'with a valid contract structure' do\n        it 'does not raise any exceptions' do\n          expect do\n            schema.validate(valid_contract)\n          end.to_not raise_error\n        end\n      end\n\n      context 'with an partial contract structure' do\n        it 'raises InvalidContract exception' do\n          expect do\n            schema.validate(invalid_contract)\n          end.to raise_error(InvalidContract)\n        end\n      end\n\n      context 'with an invalid contract' do\n        it 'raises InvalidContract exception' do\n          expect do\n            schema.validate(invalid_contract)\n          end.to raise_error(InvalidContract)\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/pacto_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\ndescribe Pacto do\n  around(:each) do |example|\n    $stdout = StringIO.new\n    example.run\n    $stdout = STDOUT\n  end\n\n  def output\n    $stdout.string.strip\n  end\n\n  def mock_investigation(errors)\n    expect(JSON::Validator).to receive(:fully_validate).with(any_args).and_return errors\n  end\n\n  describe '.validate_contract' do\n    let(:contract_path) { contract_file 'contract' }\n\n    context 'valid' do\n      it 'returns true' do\n        mock_investigation []\n        success = described_class.validate_contract contract_path\n        expect(success).to be true\n      end\n    end\n\n    context 'invalid' do\n      it 'raises an InvalidContract error' do\n        mock_investigation ['Error 1']\n        expect { described_class.validate_contract contract_path }.to raise_error(Pacto::InvalidContract)\n      end\n    end\n  end\n\n  describe 'loading contracts' do\n    let(:contracts_path) { contracts_folder }\n    let(:host) { 'localhost' }\n\n    it 'instantiates a contract list' do\n      expect(Pacto::ContractSet).to receive(:new) do |contracts|\n        contracts.each { |contract| expect(contract).to be_a_kind_of(Pacto::Contract) }\n      end\n      described_class.load_contracts(contracts_path, host)\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/request_pattern_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe RequestPattern do\n    let(:http_method) { :get  }\n    let(:uri_pattern) { double }\n    let(:request_pattern) { double }\n    let(:request) { double(http_method: http_method) }\n\n    it 'returns a pattern that combines the contracts http_method and uri_pattern' do\n      expect(UriPattern).to receive(:for).\n        with(request).\n        and_return(uri_pattern)\n\n      expect(Pacto::RequestPattern).to receive(:new).\n        with(http_method, uri_pattern).\n        and_return(request_pattern)\n\n      expect(RequestPattern.for(request)).to eq request_pattern\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/stubs/observers/stenographer_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  module Observers\n    describe Stenographer do\n      let(:pacto_request) { Fabricate(:pacto_request) }\n      let(:pacto_response) { Fabricate(:pacto_response) }\n      let(:contract) { Fabricate(:contract) }\n      let(:citations) { %w(one two) }\n      let(:investigation) { Pacto::Investigation.new(pacto_request, pacto_response, contract, citations) }\n\n      subject(:stream) { StringIO.new }\n\n      subject { described_class.new stream }\n\n      it 'writes to the stenographer log stream' do\n        subject.log_investigation investigation\n        expected_log_line = \"request #{contract.name.inspect}, values: {}, response: {status: #{pacto_response.status}} # #{citations.size} contract violations\\n\"\n        expect(stream.string).to eq expected_log_line\n      end\n\n      context 'when the stenographer log stream is nil' do\n        let(:stream) { nil }\n\n        it 'does nothing' do\n          # Would raise an error if it tried to write to stream\n          subject.log_investigation investigation\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/stubs/uri_pattern_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe UriPattern do\n    context 'with non-strict matchers' do\n      before(:each) do\n        Pacto.configuration.strict_matchers = false\n      end\n\n      it 'appends host if path is an Addressable::Template' do\n        path_pattern = '/{account}/data{.format}{?page,per_page}'\n        path = Addressable::Template.new path_pattern\n        request = Fabricate(:request_clause, host: 'https://www.example.com', path: path)\n        expect(UriPattern.for(request).pattern).to include(Addressable::Template.new(\"https://www.example.com#{path_pattern}\").pattern)\n      end\n\n      it 'returns a URITemplate containing the host and path and wildcard vars' do\n        request = Fabricate(:request_clause, host: 'myhost.com', path: '/stuff')\n        uri_pattern = UriPattern.for(request)\n        expect(uri_pattern.pattern).to eql('{scheme}://myhost.com/stuff{?anyvars*}')\n      end\n\n      it 'fails if segment uses : syntax' do\n        expect do\n          Fabricate(:request_clause, host: 'myhost.com', path: '/:id')\n        end.to raise_error(/old syntax no longer supported/)\n      end\n\n      it 'creates a regex that does not allow additional path elements' do\n        request = Fabricate(:request_clause, host: 'myhost.com', path: '/{id}')\n        pattern = UriPattern.for(request)\n        expect(pattern).to match('http://myhost.com/foo')\n        expect(pattern).to_not match('http://myhost.com/foo/bar')\n      end\n\n      it 'creates a regex that does allow query parameters' do\n        request = Fabricate(:request_clause, host: 'myhost.com', path: '/{id}')\n        pattern = UriPattern.for(request)\n        expect(pattern.match('http://myhost.com/foo?a=b')). to be_truthy\n        expect(pattern.match('http://myhost.com/foo?a=b&c=d')).to be_truthy\n      end\n    end\n\n    # Strict/relaxed matching should be done against the full URI or path only\n    context 'with strict matchers', deprecated: true do\n      it 'returns a string with the host and path' do\n        Pacto.configuration.strict_matchers = true\n        request = Fabricate(:request_clause, host: 'myhost.com', path: '/stuff')\n        uri_pattern = UriPattern.for(request)\n        expect(uri_pattern.pattern).to eq('{scheme}://myhost.com/stuff')\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/stubs/webmock_adapter_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nmodule Pacto\n  module Stubs\n    # FIXME: Review this test and see which requests are Pacto vs WebMock, then use Fabricate\n    describe WebMockAdapter do\n      let(:middleware) { double('middleware') }\n\n      let(:request) do\n        Fabricate(:request_clause,\n                  host: 'http://localhost',\n                  http_method: http_method,\n                  path: '/hello_world',\n                  headers: { 'Accept' => 'application/json' },\n                  params: { 'foo' => 'bar' }\n        )\n      end\n\n      let(:http_method) { :get }\n\n      let(:response) do\n        Fabricate(\n          :response_clause,\n          status: 200,\n          headers: {},\n          schema: {\n            type: 'object',\n            required: ['message'],\n            properties: {\n              message: {\n                type: 'string',\n                default: 'foo'\n              }\n            }\n          }\n        )\n      end\n\n      let(:contract) do\n        Fabricate(:contract, request: request, response: response)\n      end\n\n      let(:body) do\n        { 'message' => 'foo' }\n      end\n\n      let(:stubbed_request) do\n        {\n          path: nil\n        }\n      end\n\n      let(:request_pattern) { double('request_pattern') }\n\n      subject(:adapter) { WebMockAdapter.new middleware }\n\n      before(:each) do\n        allow(stubbed_request).to receive(:to_return).with(no_args)\n        allow(stubbed_request).to receive(:request_pattern).and_return request_pattern\n      end\n\n      describe '#initialize' do\n        it 'sets up a hook' do\n          expect(WebMock).to receive(:after_request) do | _arg, &block |\n            expect(block.parameters.size).to eq(2)\n          end\n\n          Pacto.configuration.adapter # (rather than WebMockAdapter.new, to prevent rpec after block from creating a second instance\n        end\n      end\n\n      describe '#process_hooks' do\n        let(:request_signature) { double('request_signature') }\n\n        it 'calls the middleware for processing' do\n          expect(middleware).to receive(:process).with(a_kind_of(Pacto::PactoRequest), a_kind_of(Pacto::PactoResponse))\n          adapter.process_hooks request_signature, response\n        end\n      end\n\n      describe '#stub_request!' do\n        before(:each) do\n          expect(WebMock).to receive(:stub_request) do | _method, url |\n            stubbed_request[:path] = url\n            stubbed_request\n          end\n        end\n\n        context 'when the response body is an object' do\n          let(:body) do\n            { 'message' => 'foo' }\n          end\n\n          context 'a GET request' do\n            let(:http_method) { :get }\n\n            it 'uses WebMock to stub the request' do\n              expect(request_pattern).to receive(:with).\n                with(headers: request.headers, query: request.params).\n                and_return(stubbed_request)\n              adapter.stub_request! contract\n            end\n          end\n\n          context 'a POST request' do\n            let(:http_method) { :post }\n\n            it 'uses WebMock to stub the request' do\n              expect(request_pattern).to receive(:with).\n                with(headers: request.headers, body: request.params).\n                and_return(stubbed_request)\n              adapter.stub_request! contract\n            end\n          end\n\n          context 'a request with no headers' do\n            let(:request) do\n              Fabricate(:request_clause,\n                        host: 'http://localhost',\n                        http_method: :get,\n                        path: '/hello_world',\n                        headers: {},\n                        params: { 'foo' => 'bar' }\n              )\n            end\n\n            it 'uses WebMock to stub the request' do\n              expect(request_pattern).to receive(:with).\n                with(query: request.params).\n                and_return(stubbed_request)\n              adapter.stub_request! contract\n            end\n          end\n\n          context 'a request with no params' do\n            let(:request) do\n              Fabricate(:request_clause,\n                        host: 'http://localhost',\n                        http_method: :get,\n                        path: '/hello_world',\n                        headers: {},\n                        params: {}\n              )\n            end\n\n            it 'does not send parameter details to WebMock' do\n              expect(request_pattern).to_not receive(:with)\n              adapter.stub_request! contract\n            end\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/unit/pacto/uri_spec.rb",
    "content": "# -*- encoding : utf-8 -*-\nrequire 'spec_helper'\n\nmodule Pacto\n  describe URI do\n    it 'returns the path appended to the host' do\n      uri = URI.for('https://localtest.me', '/bla')\n      expect(uri.to_s).to eq 'https://localtest.me/bla'\n    end\n\n    it 'uses http as the default scheme for hosts' do\n      uri = URI.for('localtest.me', '/bla')\n      expect(uri.to_s).to eq 'http://localtest.me/bla'\n    end\n\n    it 'shows query parameters if initialized with params' do\n      uri = URI.for('localtest.me', '/bla', 'param1' => 'ble')\n      expect(uri.to_s).to eq 'http://localtest.me/bla?param1=ble'\n    end\n  end\nend\n"
  },
  {
    "path": "tasks/release.rake",
    "content": "require 'octokit'\n\ndef github\n  @client ||= Octokit::Client.new :access_token => ENV['GITHUB_TOKEN']\nend\n\ndef release_tag\n  \"v#{Pacto::VERSION}\"\nend\n\ndef release\n  @release ||= github.list_releases('thoughtworks/pacto').find{|r| r.name == release_tag }\nend\n\ndef changelog\n  changelog = File.read('changelog.md').split(\"\\n\\n\\n\", 2).first\n  confirm 'Does the CHANGELOG look correct? ', changelog\nend\n\ndef confirm(question, data)\n  puts 'Please confirm...'\n  puts data\n  print question\n  abort 'Aborted' unless $stdin.gets.strip == 'y'\n  puts 'Confirmed'\n  data\nend\n\ndesc 'Tags and pushes the gem'\ntask :release_gem do\n  sh 'git', 'tag', '-m', changelog, \"v#{Pacto::VERSION}\"\n  sh 'git push origin master'\n  sh \"git push origin v#{Pacto::VERSION}\"\n  sh 'ls pkg/*.gem | xargs -n 1 gem push'\nend\n\ndesc 'Releases to RubyGems and GitHub'\ntask :release => [:build, :release_gem, :samples, :package, :create_release, :upload_docs]\n\ndesc 'Preview the changelog'\ntask :changelog do\n  changelog\nend\n\ndesc 'Create a release on GitHub'\ntask :create_release do\n  github.create_release 'thoughtworks/pacto', release_tag, {:name => release_tag, :body => changelog}\nend\n\ndesc 'Upload docs to the GitHub release'\ntask :upload_docs do\n  Dir['pkg/pacto_docs*'].each do |file|\n    next if File.directory? file\n    puts \"Uploading #{file}\"\n    github.upload_asset release.url, file\n  end\nend\n"
  }
]