fake_braintree 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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