fake_braintree 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gimme_brains.gemspec
4
+ gemspec
@@ -0,0 +1,6 @@
1
+ # fake\_braintree, a Braintree fake
2
+
3
+ Currently in alpha. Needs complete test coverage, then more functionality can
4
+ be added.
5
+
6
+ Call FakeBraintree.activate! to make it go.
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ desc "Run specs"
8
+ task :default => [:spec]
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "fake_braintree/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "fake_braintree"
7
+ s.version = FakeBraintree::VERSION
8
+ s.authors = ["thoughtbot, inc."]
9
+ s.email = ["gabe@thoughtbot.com", "ben@thoughtbot.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{A fake Braintree that you can run integration tests against}
12
+ s.description = %q{A fake Braintree that you can run integration tests against}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency 'sham_rack'
20
+ s.add_dependency 'activesupport'
21
+ s.add_dependency 'i18n'
22
+ s.add_dependency 'sinatra'
23
+ s.add_dependency 'braintree', '~> 2.5'
24
+
25
+ s.add_development_dependency 'rspec', '~> 2.6.0'
26
+ s.add_development_dependency 'mocha', '~> 0.9.12'
27
+ end
@@ -0,0 +1,163 @@
1
+ require 'braintree'
2
+ require 'sham_rack'
3
+
4
+ require 'fake_braintree/sinatra_app'
5
+ require 'fake_braintree/version'
6
+
7
+ Braintree::Configuration.logger = Logger.new("tmp/log")
8
+
9
+ module FakeBraintree
10
+ class << self
11
+ @customers = {}
12
+ @subscriptions = {}
13
+ @failures = {}
14
+ @transaction = {}
15
+
16
+ @decline_all_cards = false
17
+ attr_accessor :customers, :subscriptions, :failures, :transaction, :decline_all_cards
18
+ end
19
+
20
+ def self.activate!
21
+ Braintree::Configuration.environment = :production
22
+ Braintree::Configuration.merchant_id = "xxx"
23
+ Braintree::Configuration.public_key = "xxx"
24
+ Braintree::Configuration.private_key = "xxx"
25
+ clear!
26
+ ShamRack.mount(FakeBraintree::SinatraApp, "www.braintreegateway.com", 443)
27
+ end
28
+
29
+ def self.clear!
30
+ self.customers = {}
31
+ self.subscriptions = {}
32
+ self.failures = {}
33
+ self.transaction = {}
34
+ self.decline_all_cards = false
35
+ end
36
+
37
+ def self.failure?(card_number)
38
+ self.failures.include?(card_number)
39
+ end
40
+
41
+ def self.failure_response(card_number)
42
+ failure = self.failures[card_number]
43
+ failure["errors"] ||= { "errors" => [] }
44
+
45
+ { "message" => failure["message"],
46
+ "verification" => { "status" => failure["status"],
47
+ "processor_response_text" => failure["message"],
48
+ "processor_response_code" => failure["code"],
49
+ "gateway_rejection_reason" => "cvv",
50
+ "cvv_response_code" => failure["code"] },
51
+ "errors" => failure["errors"],
52
+ "params" => {}}
53
+ end
54
+
55
+ def self.create_failure
56
+ { "message" => "Do Not Honor",
57
+ "verification" => { "status" => "processor_declined",
58
+ "processor_response_text" => "Do Not Honor",
59
+ "processor_response_code" => '2000' },
60
+ "errors" => { 'errors' => [] },
61
+ "params" => {} }
62
+ end
63
+
64
+ def self.decline_all_cards!
65
+ self.decline_all_cards = true
66
+ end
67
+
68
+ def self.decline_all_cards?
69
+ self.decline_all_cards
70
+ end
71
+
72
+ def self.credit_card_from_token(token)
73
+ self.customers.values.detect do |customer|
74
+ next unless customer.key?("credit_cards")
75
+
76
+ card = customer["credit_cards"].detect {|card| card["token"] == token }
77
+ return card if card
78
+ end
79
+ end
80
+
81
+ def self.generated_transaction
82
+ {"status_history"=>[{"timestamp"=>Time.now,
83
+ "amount"=>FakeBraintree.transaction[:amount],
84
+ "transaction_source"=>"CP",
85
+ "user"=>"copycopter",
86
+ "status"=>"authorized"},
87
+ {"timestamp"=>Time.now,
88
+ "amount"=>FakeBraintree.transaction[:amount],
89
+ "transaction_source"=>"CP",
90
+ "user"=>"copycopter",
91
+ "status"=>FakeBraintree.transaction[:status]}],
92
+ "created_at"=>(FakeBraintree.transaction[:created_at] || Time.now),
93
+ "currency_iso_code"=>"USD",
94
+ "settlement_batch_id"=>nil,
95
+ "processor_authorization_code"=>"ZKB4VJ",
96
+ "avs_postal_code_response_code"=>"I",
97
+ "order_id"=>nil,
98
+ "updated_at"=>Time.now,
99
+ "refunded_transaction_id"=>nil,
100
+ "amount"=>FakeBraintree.transaction[:amount],
101
+ "credit_card"=>{"last_4"=>"1111",
102
+ "card_type"=>"Visa",
103
+ "token"=>"8yq7",
104
+ "customer_location"=>"US",
105
+ "expiration_year"=>"2013",
106
+ "expiration_month"=>"02",
107
+ "bin"=>"411111",
108
+ "cardholder_name"=>"Chad Lee Pytel"
109
+ },
110
+ "refund_id"=>nil,
111
+ "add_ons"=>[],
112
+ "shipping"=>{"region"=>nil,
113
+ "company"=>nil,
114
+ "country_name"=>nil,
115
+ "extended_address"=>nil,
116
+ "postal_code"=>nil,
117
+ "id"=>nil,
118
+ "street_address"=>nil,
119
+ "country_code_numeric"=>nil,
120
+ "last_name"=>nil,
121
+ "locality"=>nil,
122
+ "country_code_alpha2"=>nil,
123
+ "country_code_alpha3"=>nil,
124
+ "first_name"=>nil},
125
+ "id"=>"49sbx6",
126
+ "merchant_account_id"=>"Thoughtbot",
127
+ "type"=>"sale",
128
+ "cvv_response_code"=>"I",
129
+ "subscription_id"=>FakeBraintree.transaction[:subscription_id],
130
+ "custom_fields"=>"\n",
131
+ "discounts"=>[],
132
+ "billing"=>{"region"=>nil,
133
+ "company"=>nil,
134
+ "country_name"=>nil,
135
+ "extended_address"=>nil,
136
+ "postal_code"=>nil,
137
+ "id"=>nil,
138
+ "street_address"=>nil,
139
+ "country_code_numeric"=>nil,
140
+ "last_name"=>nil,
141
+ "locality"=>nil,
142
+ "country_code_alpha2"=>nil,
143
+ "country_code_alpha3"=>nil,
144
+ "first_name"=>nil},
145
+ "processor_response_code"=>"1000",
146
+ "refund_ids"=>[],
147
+ "customer"=>{"company"=>nil,
148
+ "id"=>"108427",
149
+ "last_name"=>nil,
150
+ "fax"=>nil,
151
+ "phone"=>nil,
152
+ "website"=>nil,
153
+ "first_name"=>nil,
154
+ "email"=>"cpytel@thoughtbot.com" },
155
+ "avs_error_response_code"=>nil,
156
+ "processor_response_text"=>"Approved",
157
+ "avs_street_address_response_code"=>"I",
158
+ "status"=>FakeBraintree.transaction[:status],
159
+ "gateway_rejection_reason"=>nil}
160
+ end
161
+ end
162
+
163
+ FakeBraintree.activate!
@@ -0,0 +1,147 @@
1
+ require 'digest/md5'
2
+ require 'sinatra'
3
+ require 'active_support'
4
+ require 'active_support/core_ext'
5
+
6
+ module FakeBraintree
7
+ class SinatraApp < Sinatra::Base
8
+ set :show_exceptions, false
9
+ set :dump_errors, true
10
+ set :raise_errors, true
11
+ disable :logging
12
+
13
+ helpers do
14
+ def gzip(content)
15
+ ActiveSupport::Gzip.compress(content)
16
+ end
17
+
18
+ def gzipped_response(status_code, uncompressed_content)
19
+ [status_code, { "Content-Encoding" => "gzip" }, gzip(uncompressed_content)]
20
+ end
21
+ end
22
+
23
+ post "/merchants/:merchant_id/customers" do
24
+ customer = Hash.from_xml(request.body).delete("customer")
25
+ if FakeBraintree.failure?(customer["credit_card"]["number"])
26
+ gzipped_response(422, FakeBraintree.failure_response(customer["credit_card"]["number"]).to_xml(:root => 'api_error_response'))
27
+ else
28
+ customer["id"] ||= Digest::MD5.hexdigest("#{params[:merchant_id]}#{Time.now.to_f}")
29
+ customer["merchant-id"] = params[:merchant_id]
30
+ if customer["credit_card"] && customer["credit_card"].is_a?(Hash)
31
+ customer["credit_card"].delete("__content__")
32
+ if !customer["credit_card"].empty?
33
+ customer["credit_card"]["last_4"] = customer["credit_card"].delete("number")[-4..-1]
34
+ customer["credit_card"]["token"] = Digest::MD5.hexdigest("#{customer['merchant_id']}#{customer['id']}#{Time.now.to_f}")
35
+ expiration_date = customer["credit_card"].delete("expiration_date")
36
+ customer["credit_card"]["expiration_month"] = expiration_date.split('/')[0]
37
+ customer["credit_card"]["expiration_year"] = expiration_date.split('/')[1]
38
+
39
+ credit_card = customer.delete("credit_card")
40
+ customer["credit_cards"] = [credit_card]
41
+ end
42
+ end
43
+ FakeBraintree.customers[customer["id"]] = customer
44
+ gzipped_response(201, customer.to_xml(:root => 'customer'))
45
+ end
46
+ end
47
+
48
+ get "/merchants/:merchant_id/customers/:id" do
49
+ customer = FakeBraintree.customers[params[:id]]
50
+ gzipped_response(200, customer.to_xml(:root => 'customer'))
51
+ end
52
+
53
+ put "/merchants/:merchant_id/customers/:id" do
54
+ customer = Hash.from_xml(request.body).delete("customer")
55
+ if !FakeBraintree.failure?(customer["credit_card"]["number"])
56
+ customer["id"] = params[:id]
57
+ customer["merchant-id"] = params[:merchant_id]
58
+ if customer["credit_card"] && customer["credit_card"].is_a?(Hash)
59
+ customer["credit_card"].delete("__content__")
60
+ if !customer["credit_card"].empty?
61
+ customer["credit_card"]["last_4"] = customer["credit_card"].delete("number")[-4..-1]
62
+ customer["credit_card"]["token"] = Digest::MD5.hexdigest("#{customer['merchant_id']}#{customer['id']}#{Time.now.to_f}")
63
+ credit_card = customer.delete("credit_card")
64
+ customer["credit_cards"] = [credit_card]
65
+ end
66
+ end
67
+ FakeBraintree.customers[params["id"]] = customer
68
+ gzipped_response(200, customer.to_xml(:root => 'customer'))
69
+ else
70
+ gzipped_response(422, FakeBraintree.failure_response(customer["credit_card"]["number"]).to_xml(:root => 'api_error_response'))
71
+ end
72
+ end
73
+
74
+ delete "/merchants/:merchant_id/customers/:id" do
75
+ FakeBraintree.customers[params["id"]] = nil
76
+ gzipped_response(200, "")
77
+ end
78
+
79
+ post "/merchants/:merchant_id/subscriptions" do
80
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<subscription>\n <plan-id type=\"integer\">2</plan-id>\n <payment-method-token>b22x</payment-method-token>\n</subscription>\n"
81
+ subscription = Hash.from_xml(request.body).delete("subscription")
82
+ subscription["id"] ||= Digest::MD5.hexdigest("#{subscription["payment_method_token"]}#{Time.now.to_f}")
83
+ subscription["transactions"] = []
84
+ subscription["add_ons"] = []
85
+ subscription["discounts"] = []
86
+ subscription["next_billing_date"] = 1.month.from_now
87
+ subscription["status"] = Braintree::Subscription::Status::Active
88
+ FakeBraintree.subscriptions[subscription["id"]] = subscription
89
+ gzipped_response(201, subscription.to_xml(:root => 'subscription'))
90
+ end
91
+
92
+ get "/merchants/:merchant_id/subscriptions/:id" do
93
+ subscription = FakeBraintree.subscriptions[params[:id]]
94
+ gzipped_response(200, subscription.to_xml(:root => 'subscription'))
95
+ end
96
+
97
+ put "/merchants/:merchant_id/subscriptions/:id" do
98
+ subscription = Hash.from_xml(request.body).delete("subscription")
99
+ subscription["transactions"] = []
100
+ subscription["add_ons"] = []
101
+ subscription["discounts"] = []
102
+ FakeBraintree.subscriptions[params["id"]] = subscription
103
+ gzipped_response(200, subscription.to_xml(:root => 'subscription'))
104
+ end
105
+
106
+ # Braintree::Transaction.search
107
+ post "/merchants/:merchant_id/transactions/advanced_search_ids" do
108
+ # "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<search>\n <created-at>\n <min type=\"datetime\">2011-01-10T14:14:26Z</min>\n </created-at>\n</search>\n"
109
+ gzipped_response(200, "<search-results>\n <page-size type=\"integer\">50</page-size>\n <ids type=\"array\">\n <item>49sbx6</item>\n </ids>\n</search-results>\n")
110
+ end
111
+
112
+ # Braintree::Transaction.search
113
+ post "/merchants/:merchant_id/transactions/advanced_search" do
114
+ # "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<search>\n <ids type=\"array\">\n <item>49sbx6</item>\n </ids>\n <created-at>\n <min type=\"datetime\">2011-01-10T14:14:26Z</min>\n </created-at>\n</search>\n"
115
+ gzipped_response(200, FakeBraintree.generated_transaction.to_xml)
116
+ end
117
+
118
+ get "/merchants/:merchant_id/payment_methods/:credit_card_token" do
119
+ credit_card = FakeBraintree.credit_card_from_token(params[:credit_card_token])
120
+ gzipped_response(200, credit_card.to_xml(:root => "credit_card"))
121
+ end
122
+
123
+ # Braintree::Transaction.sale
124
+ # Braintree::CreditCard.sale
125
+ post "/merchants/:merchant_id/transactions" do
126
+ transaction = Hash.from_xml(request.body)["transaction"]
127
+ transaction_id = Digest::MD5.hexdigest("#{params[:merchant_id]}#{Time.now.to_f}")
128
+ transaction_response = {"id" => transaction_id, "amount" => transaction["amount"]}
129
+
130
+ if FakeBraintree.decline_all_cards?
131
+ gzipped_response(422, FakeBraintree.create_failure.to_xml(:root => 'api_error_response'))
132
+ else
133
+ FakeBraintree.transaction.replace(transaction_response)
134
+ gzipped_response(200, transaction_response.to_xml(:root => "transaction"))
135
+ end
136
+ end
137
+
138
+ # Braintree::Transaction.find
139
+ get "/merchants/:merchant_id/transactions/:transaction_id" do
140
+ if FakeBraintree.transaction["id"] == params[:transaction_id]
141
+ gzipped_response(200, FakeBraintree.transaction.to_xml(:root => "transaction"))
142
+ else
143
+ gzipped_response(404, {})
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,3 @@
1
+ module FakeBraintree
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ module FakeBraintree
4
+ describe SinatraApp, "Braintree::CreditCard.find" do
5
+ let(:cc_number) { %w(4111 1111 1111 9876).join }
6
+ let(:expiration_date) { "04/2016" }
7
+ let(:token) { braintree_credit_card_token(cc_number, expiration_date) }
8
+
9
+ it "gets the correct credit card" do
10
+ credit_card = Braintree::CreditCard.find(token)
11
+
12
+ credit_card.last_4.should == "9876"
13
+ credit_card.expiration_year.should == "2016"
14
+ credit_card.expiration_month.should == "04"
15
+ end
16
+ end
17
+
18
+ describe SinatraApp, "Braintree::CreditCard.sale" do
19
+ let(:cc_number) { %w(4111 1111 1111 9876).join }
20
+ let(:expiration_date) { "04/2016" }
21
+ let(:token) { braintree_credit_card_token(cc_number, expiration_date) }
22
+ let(:amount) { 10.00 }
23
+
24
+ it "successfully creates a sale" do
25
+ result = Braintree::CreditCard.sale(token, amount: amount, options: {submit_for_settlement: true})
26
+ result.should be_success
27
+
28
+ Braintree::Transaction.find(result.transaction.id).should be
29
+ lambda { Braintree::Transaction.find("foo") }.should raise_error(Braintree::NotFoundError)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,65 @@
1
+ require 'spec_helper'
2
+
3
+ describe FakeBraintree, ".credit_card_from_token" do
4
+ let(:cc_number) { %w(4111 1111 1111 9876).join }
5
+ let(:cc_number_2) { %w(4111 1111 1111 2222).join }
6
+ let(:expiration_date) { "04/2016" }
7
+ let(:expiration_date_2) { "05/2019" }
8
+ let(:token) { braintree_credit_card_token(cc_number, expiration_date) }
9
+ let(:token_2) { braintree_credit_card_token(cc_number_2, expiration_date_2) }
10
+
11
+ it "looks up the credit card based on a CC token" do
12
+ credit_card = FakeBraintree.credit_card_from_token(token)
13
+ credit_card["last_4"].should == "9876"
14
+ credit_card["expiration_year"].should == "2016"
15
+ credit_card["expiration_month"].should == "04"
16
+
17
+ credit_card = FakeBraintree.credit_card_from_token(token_2)
18
+ credit_card["last_4"].should == "2222"
19
+ credit_card["expiration_year"].should == "2019"
20
+ credit_card["expiration_month"].should == "05"
21
+ end
22
+ end
23
+
24
+ describe FakeBraintree, ".decline_all_cards!" do
25
+ let(:cc_number) { %w(4111 1111 1111 9876).join }
26
+ let(:expiration_date) { "04/2016" }
27
+ let(:token) { braintree_credit_card_token(cc_number, expiration_date) }
28
+ let(:amount) { 10.00 }
29
+
30
+ before do
31
+ FakeBraintree.decline_all_cards!
32
+ end
33
+
34
+ it "declines all cards" do
35
+ result = Braintree::CreditCard.sale(token, amount: amount)
36
+ result.should_not be_success
37
+ end
38
+
39
+ it "stops declining cards after clear! is called" do
40
+ FakeBraintree.clear!
41
+ result = Braintree::CreditCard.sale(token, amount: amount)
42
+ result.should be_success
43
+ end
44
+ end
45
+
46
+ describe "configuration variables" do
47
+ subject { Braintree::Configuration }
48
+
49
+ it "sets the environment to production" do
50
+ subject.environment.should == :production
51
+ end
52
+
53
+ it "sets some fake API credentials" do
54
+ subject.merchant_id.should == "xxx"
55
+ subject.public_key.should == "xxx"
56
+ subject.private_key.should == "xxx"
57
+ end
58
+
59
+ its(:logger) { should be_a Logger }
60
+
61
+ it "does not log to STDOUT" do
62
+ STDOUT.expects(:write).with("Logger test\n").never
63
+ subject.logger.info('Logger test')
64
+ end
65
+ end
@@ -0,0 +1,16 @@
1
+ # Requires supporting ruby files with custom matchers and macros, etc,
2
+ # in spec/support/ and its subdirectories.
3
+ require 'rspec'
4
+ require 'fake_braintree'
5
+ Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each {|f| require f}
6
+
7
+ Dir.mkdir('tmp') unless Dir.exist?('tmp')
8
+ File.new('tmp/braintree_log', 'w').close
9
+
10
+ RSpec.configure do |config|
11
+ config.mock_with :mocha
12
+
13
+ config.include BraintreeHelpers
14
+
15
+ config.before { FakeBraintree.clear! }
16
+ end
@@ -0,0 +1,15 @@
1
+ module BraintreeHelpers
2
+ def create_braintree_customer(cc_number, expiration_date)
3
+ Braintree::Customer.create(
4
+ email: "me@example.com",
5
+ credit_card: {
6
+ number: cc_number,
7
+ expiration_date: expiration_date
8
+ }
9
+ ).customer
10
+ end
11
+
12
+ def braintree_credit_card_token(cc_number, expiration_date)
13
+ create_braintree_customer(cc_number, expiration_date).credit_cards[0].token
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,139 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fake_braintree
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - thoughtbot, inc.
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-08 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sham_rack
16
+ requirement: &2162481680 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2162481680
25
+ - !ruby/object:Gem::Dependency
26
+ name: activesupport
27
+ requirement: &2162481240 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2162481240
36
+ - !ruby/object:Gem::Dependency
37
+ name: i18n
38
+ requirement: &2162480820 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *2162480820
47
+ - !ruby/object:Gem::Dependency
48
+ name: sinatra
49
+ requirement: &2162480400 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *2162480400
58
+ - !ruby/object:Gem::Dependency
59
+ name: braintree
60
+ requirement: &2162479900 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: '2.5'
66
+ type: :runtime
67
+ prerelease: false
68
+ version_requirements: *2162479900
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: &2162479400 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: 2.6.0
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *2162479400
80
+ - !ruby/object:Gem::Dependency
81
+ name: mocha
82
+ requirement: &2162478940 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ~>
86
+ - !ruby/object:Gem::Version
87
+ version: 0.9.12
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: *2162478940
91
+ description: A fake Braintree that you can run integration tests against
92
+ email:
93
+ - gabe@thoughtbot.com
94
+ - ben@thoughtbot.com
95
+ executables: []
96
+ extensions: []
97
+ extra_rdoc_files: []
98
+ files:
99
+ - .gitignore
100
+ - Gemfile
101
+ - README.md
102
+ - Rakefile
103
+ - fake_braintree.gemspec
104
+ - lib/fake_braintree.rb
105
+ - lib/fake_braintree/sinatra_app.rb
106
+ - lib/fake_braintree/version.rb
107
+ - spec/fake_braintree/sinatra_app_spec.rb
108
+ - spec/fake_braintree_spec.rb
109
+ - spec/spec_helper.rb
110
+ - spec/support/braintree_helpers.rb
111
+ homepage: ''
112
+ licenses: []
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ none: false
119
+ requirements:
120
+ - - ! '>='
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 1.8.8
132
+ signing_key:
133
+ specification_version: 3
134
+ summary: A fake Braintree that you can run integration tests against
135
+ test_files:
136
+ - spec/fake_braintree/sinatra_app_spec.rb
137
+ - spec/fake_braintree_spec.rb
138
+ - spec/spec_helper.rb
139
+ - spec/support/braintree_helpers.rb