stripe 1.7.0 → 1.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.gitignore +2 -0
  2. data/.travis.yml +8 -0
  3. data/CONTRIBUTORS +3 -0
  4. data/Gemfile +2 -0
  5. data/Gemfile.lock +34 -0
  6. data/History.txt +68 -0
  7. data/LICENSE +21 -0
  8. data/README.rdoc +28 -0
  9. data/Rakefile +9 -0
  10. data/VERSION +1 -0
  11. data/gemfiles/default-with-activesupport.gemfile +3 -0
  12. data/gemfiles/default-with-activesupport.gemfile.lock +39 -0
  13. data/gemfiles/json.gemfile +4 -0
  14. data/gemfiles/json.gemfile.lock +41 -0
  15. data/gemfiles/yajl.gemfile +4 -0
  16. data/gemfiles/yajl.gemfile.lock +41 -0
  17. data/lib/stripe.rb +62 -500
  18. data/lib/stripe/account.rb +4 -0
  19. data/lib/stripe/api_operations/create.rb +16 -0
  20. data/lib/stripe/api_operations/delete.rb +11 -0
  21. data/lib/stripe/api_operations/list.rb +16 -0
  22. data/lib/stripe/api_operations/update.rb +15 -0
  23. data/lib/stripe/api_resource.rb +33 -0
  24. data/lib/stripe/charge.rb +29 -0
  25. data/lib/stripe/coupon.rb +7 -0
  26. data/lib/stripe/customer.rb +51 -0
  27. data/lib/stripe/errors/api_connection_error.rb +4 -0
  28. data/lib/stripe/errors/api_error.rb +4 -0
  29. data/lib/stripe/errors/authentication_error.rb +4 -0
  30. data/lib/stripe/errors/card_error.rb +11 -0
  31. data/lib/stripe/errors/invalid_request_error.rb +10 -0
  32. data/lib/stripe/errors/stripe_error.rb +20 -0
  33. data/lib/stripe/event.rb +5 -0
  34. data/lib/stripe/invoice.rb +16 -0
  35. data/lib/stripe/invoice_item.rb +8 -0
  36. data/lib/stripe/json.rb +21 -0
  37. data/lib/stripe/plan.rb +8 -0
  38. data/lib/stripe/singleton_api_resource.rb +20 -0
  39. data/lib/stripe/stripe_object.rb +150 -0
  40. data/lib/stripe/token.rb +5 -0
  41. data/lib/stripe/transfer.rb +16 -0
  42. data/lib/stripe/util.rb +103 -0
  43. data/lib/stripe/version.rb +1 -1
  44. data/stripe.gemspec +28 -0
  45. data/test/test_helper.rb +175 -0
  46. data/test/test_stripe.rb +472 -0
  47. data/test/test_stripe_with_active_support.rb +3 -0
  48. metadata +54 -7
@@ -0,0 +1,5 @@
1
+ module Stripe
2
+ class Token < APIResource
3
+ include Stripe::APIOperations::Create
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ module Stripe
2
+ class Transfer < APIResource
3
+ include Stripe::APIOperations::List
4
+
5
+ def transactions(params={})
6
+ response, api_key = Stripe.request(:get, transactions_url, @api_key, params)
7
+ Util.convert_to_stripe_object(response, api_key)
8
+ end
9
+
10
+ private
11
+
12
+ def transactions_url
13
+ url + '/transactions'
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,103 @@
1
+ module Stripe
2
+ module Util
3
+ def self.objects_to_ids(h)
4
+ case h
5
+ when APIResource
6
+ h.id
7
+ when Hash
8
+ res = {}
9
+ h.each { |k, v| res[k] = objects_to_ids(v) unless v.nil? }
10
+ res
11
+ when Array
12
+ h.map { |v| objects_to_ids(v) }
13
+ else
14
+ h
15
+ end
16
+ end
17
+
18
+ def self.convert_to_stripe_object(resp, api_key)
19
+ types = {
20
+ 'charge' => Charge,
21
+ 'customer' => Customer,
22
+ 'invoiceitem' => InvoiceItem,
23
+ 'invoice' => Invoice,
24
+ 'plan' => Plan,
25
+ 'coupon' => Coupon,
26
+ 'event' => Event,
27
+ 'transfer' => Transfer
28
+ }
29
+ case resp
30
+ when Array
31
+ resp.map { |i| convert_to_stripe_object(i, api_key) }
32
+ when Hash
33
+ # Try converting to a known object class. If none available, fall back to generic APIResource
34
+ if klass_name = resp[:object]
35
+ klass = types[klass_name]
36
+ end
37
+ klass ||= StripeObject
38
+ klass.construct_from(resp, api_key)
39
+ else
40
+ resp
41
+ end
42
+ end
43
+
44
+ def self.file_readable(file)
45
+ begin
46
+ File.open(file) { |f| }
47
+ rescue
48
+ false
49
+ else
50
+ true
51
+ end
52
+ end
53
+
54
+ def self.symbolize_names(object)
55
+ case object
56
+ when Hash
57
+ new = {}
58
+ object.each do |key, value|
59
+ key = (key.to_sym rescue key) || key
60
+ new[key] = symbolize_names(value)
61
+ end
62
+ new
63
+ when Array
64
+ object.map { |value| symbolize_names(value) }
65
+ else
66
+ object
67
+ end
68
+ end
69
+
70
+ def self.encode_key(key)
71
+ URI.escape(key.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
72
+ end
73
+
74
+ def self.flatten_params(params, parent_key=nil)
75
+ result = []
76
+ params.each do |key, value|
77
+ calculated_key = parent_key ? "#{parent_key}[#{encode_key(key)}]" : encode_key(key)
78
+ if value.is_a?(Hash)
79
+ result += flatten_params(value, calculated_key)
80
+ elsif value.is_a?(Array)
81
+ result += flatten_params_array(value, calculated_key)
82
+ else
83
+ result << [calculated_key, value]
84
+ end
85
+ end
86
+ result
87
+ end
88
+
89
+ def self.flatten_params_array(value, calculated_key)
90
+ result = []
91
+ value.each do |elem|
92
+ if elem.is_a?(Hash)
93
+ result += flatten_params(elem, calculated_key)
94
+ elsif elem.is_a?(Array)
95
+ result += flatten_params_array(elem, calculated_key)
96
+ else
97
+ result << ["#{calculated_key}[]", elem]
98
+ end
99
+ end
100
+ result
101
+ end
102
+ end
103
+ end
@@ -1,3 +1,3 @@
1
1
  module Stripe
2
- VERSION = '1.7.0'
2
+ VERSION = '1.7.1'
3
3
  end
data/stripe.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), 'lib'))
2
+
3
+ require 'stripe/version'
4
+
5
+ spec = Gem::Specification.new do |s|
6
+ s.name = 'stripe'
7
+ s.version = Stripe::VERSION
8
+ s.summary = 'Ruby bindings for the Stripe API'
9
+ s.description = 'Stripe is the easiest way to accept payments online. See https://stripe.com for details.'
10
+ s.authors = ['Ross Boucher', 'Greg Brockman']
11
+ s.email = ['boucher@stripe.com', 'gdb@stripe.com']
12
+ s.homepage = 'https://stripe.com/api'
13
+ s.executables = 'stripe-console'
14
+ s.require_paths = %w{lib}
15
+
16
+ s.add_dependency('rest-client', '~> 1.4')
17
+ s.add_dependency('multi_json', '~> 1.1')
18
+
19
+ s.add_development_dependency('mocha')
20
+ s.add_development_dependency('shoulda')
21
+ s.add_development_dependency('test-unit')
22
+ s.add_development_dependency('rake')
23
+
24
+ s.files = `git ls-files`.split("\n")
25
+ s.test_files = `git ls-files -- test/*`.split("\n")
26
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
27
+ s.require_paths = ['lib']
28
+ end
@@ -0,0 +1,175 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require 'stripe'
4
+ require 'mocha'
5
+ include Mocha
6
+
7
+ #monkeypatch request methods
8
+ module Stripe
9
+ @mock_rest_client = nil
10
+
11
+ def self.mock_rest_client=(mock_client)
12
+ @mock_rest_client = mock_client
13
+ end
14
+
15
+ def self.execute_request(opts)
16
+ get_params = (opts[:headers] || {})[:params]
17
+ post_params = opts[:payload]
18
+ case opts[:method]
19
+ when :get then @mock_rest_client.get opts[:url], get_params, post_params
20
+ when :post then @mock_rest_client.post opts[:url], get_params, post_params
21
+ when :delete then @mock_rest_client.delete opts[:url], get_params, post_params
22
+ end
23
+ end
24
+ end
25
+
26
+ def test_response(body, code=200)
27
+ # When an exception is raised, restclient clobbers method_missing. Hence we
28
+ # can't just use the stubs interface.
29
+ body = MultiJson.dump(body) if !(body.kind_of? String)
30
+ m = mock
31
+ m.instance_variable_set('@stripe_values', { :body => body, :code => code })
32
+ def m.body; @stripe_values[:body]; end
33
+ def m.code; @stripe_values[:code]; end
34
+ m
35
+ end
36
+
37
+ def test_customer(params={})
38
+ {
39
+ :subscription_history => [],
40
+ :bills => [],
41
+ :charges => [],
42
+ :livemode => false,
43
+ :object => "customer",
44
+ :id => "c_test_customer",
45
+ :active_card => {
46
+ :type => "Visa",
47
+ :last4 => "4242",
48
+ :exp_month => 11,
49
+ :country => "US",
50
+ :exp_year => 2012,
51
+ :id => "cc_test_card",
52
+ :object => "card"
53
+ },
54
+ :created => 1304114758
55
+ }.merge(params)
56
+ end
57
+
58
+ def test_customer_array
59
+ {:data => [test_customer, test_customer, test_customer]}
60
+ end
61
+
62
+ def test_charge(params={})
63
+ {
64
+ :refunded => false,
65
+ :paid => true,
66
+ :amount => 100,
67
+ :card => {
68
+ :type => "Visa",
69
+ :last4 => "4242",
70
+ :exp_month => 11,
71
+ :country => "US",
72
+ :exp_year => 2012,
73
+ :id => "cc_test_card",
74
+ :object => "card"
75
+ },
76
+ :id => "ch_test_charge",
77
+ :reason => "execute_charge",
78
+ :livemode => false,
79
+ :currency => "usd",
80
+ :object => "charge",
81
+ :created => 1304114826
82
+ }.merge(params)
83
+ end
84
+
85
+ def test_charge_array
86
+ {:data => [test_charge, test_charge, test_charge]}
87
+ end
88
+
89
+ def test_card(params={})
90
+ {
91
+ :type => "Visa",
92
+ :last4 => "4242",
93
+ :exp_month => 11,
94
+ :country => "US",
95
+ :exp_year => 2012,
96
+ :id => "cc_test_card",
97
+ :object => "card"
98
+ }.merge(params)
99
+ end
100
+
101
+ def test_coupon(params={})
102
+ {
103
+ :duration => 'repeating',
104
+ :duration_in_months => 3,
105
+ :percent_off => 25,
106
+ :id => "co_test_coupon",
107
+ :object => "coupon"
108
+ }.merge(params)
109
+ end
110
+
111
+ #FIXME nested overrides would be better than hardcoding plan_id
112
+ def test_subscription(plan_id="gold")
113
+ {
114
+ :current_period_end => 1308681468,
115
+ :status => "trialing",
116
+ :plan => {
117
+ :interval => "month",
118
+ :amount => 7500,
119
+ :trial_period_days => 30,
120
+ :object => "plan",
121
+ :identifier => plan_id
122
+ },
123
+ :current_period_start => 1308595038,
124
+ :start => 1308595038,
125
+ :object => "subscription",
126
+ :trial_start => 1308595038,
127
+ :trial_end => 1308681468,
128
+ :customer => "c_test_customer"
129
+ }
130
+ end
131
+
132
+ def test_invalid_api_key_error
133
+ {
134
+ "error" => {
135
+ "type" => "invalid_request_error",
136
+ "message" => "Invalid API Key provided: invalid"
137
+ }
138
+ }
139
+ end
140
+
141
+ def test_invalid_exp_year_error
142
+ {
143
+ "error" => {
144
+ "code" => "invalid_expiry_year",
145
+ "param" => "exp_year",
146
+ "type" => "card_error",
147
+ "message" => "Your card's expiration year is invalid"
148
+ }
149
+ }
150
+ end
151
+
152
+ def test_missing_id_error
153
+ {
154
+ :error => {
155
+ :param => "id",
156
+ :type => "invalid_request_error",
157
+ :message => "Missing id"
158
+ }
159
+ }
160
+ end
161
+
162
+ def test_api_error
163
+ {
164
+ :error => {
165
+ :type => "api_error"
166
+ }
167
+ }
168
+ end
169
+
170
+ def test_delete_discount_response
171
+ {
172
+ :deleted => true,
173
+ :id => "di_test_coupon"
174
+ }
175
+ end
@@ -0,0 +1,472 @@
1
+ # -*- coding: utf-8 -*-
2
+ require File.expand_path('../test_helper', __FILE__)
3
+ require 'test/unit'
4
+ require 'shoulda'
5
+ require 'mocha'
6
+ require 'pp'
7
+ require 'rest-client'
8
+ require 'cgi'
9
+ require 'uri'
10
+
11
+ class TestStripeRuby < Test::Unit::TestCase
12
+ include Mocha
13
+
14
+ context "Util" do
15
+ should "symbolize_names should convert names to symbols" do
16
+ start = {
17
+ 'foo' => 'bar',
18
+ 'array' => [{ 'foo' => 'bar' }],
19
+ 'nested' => {
20
+ 1 => 2,
21
+ :symbol => 9,
22
+ 'string' => nil
23
+ }
24
+ }
25
+ finish = {
26
+ :foo => 'bar',
27
+ :array => [{ :foo => 'bar' }],
28
+ :nested => {
29
+ 1 => 2,
30
+ :symbol => 9,
31
+ :string => nil
32
+ }
33
+ }
34
+
35
+ symbolized = Stripe::Util.symbolize_names(start)
36
+ assert_equal(finish, symbolized)
37
+ end
38
+ end
39
+
40
+ context "API Bindings" do
41
+ setup do
42
+ @mock = mock
43
+ Stripe.mock_rest_client = @mock
44
+ end
45
+
46
+ teardown do
47
+ Stripe.mock_rest_client = nil
48
+ end
49
+
50
+ should "creating a new APIResource should not fetch over the network" do
51
+ @mock.expects(:get).never
52
+ c = Stripe::Customer.new("someid")
53
+ end
54
+
55
+ should "creating a new APIResource from a hash should not fetch over the network" do
56
+ @mock.expects(:get).never
57
+ c = Stripe::Customer.construct_from({
58
+ :id => "somecustomer",
59
+ :card => {:id => "somecard", :object => "card"},
60
+ :object => "customer"
61
+ })
62
+ end
63
+
64
+ should "setting an attribute should not cause a network request" do
65
+ @mock.expects(:get).never
66
+ @mock.expects(:post).never
67
+ c = Stripe::Customer.new("test_customer");
68
+ c.card = {:id => "somecard", :object => "card"}
69
+ end
70
+
71
+ should "accessing id should not issue a fetch" do
72
+ @mock.expects(:get).never
73
+ c = Stripe::Customer.new("test_customer");
74
+ c.id
75
+ end
76
+
77
+ should "not specifying api credentials should raise an exception" do
78
+ Stripe.api_key = nil
79
+ assert_raises Stripe::AuthenticationError do
80
+ Stripe::Customer.new("test_customer").refresh
81
+ end
82
+ end
83
+
84
+ should "specifying invalid api credentials should raise an exception" do
85
+ Stripe.api_key = "invalid"
86
+ response = test_response(test_invalid_api_key_error, 401)
87
+ assert_raises Stripe::AuthenticationError do
88
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
89
+ Stripe::Customer.retrieve("failing_customer")
90
+ end
91
+ end
92
+
93
+ should "AuthenticationErrors should have an http status, http body, and JSON body" do
94
+ Stripe.api_key = "invalid"
95
+ response = test_response(test_invalid_api_key_error, 401)
96
+ begin
97
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 401))
98
+ Stripe::Customer.retrieve("failing_customer")
99
+ rescue Stripe::AuthenticationError => e
100
+ assert_equal(401, e.http_status)
101
+ assert_equal(true, !!e.http_body)
102
+ assert_equal(true, !!e.json_body[:error][:message])
103
+ assert_equal(test_invalid_api_key_error['error']['message'], e.json_body[:error][:message])
104
+ end
105
+ end
106
+
107
+ context "with valid credentials" do
108
+ setup do
109
+ Stripe.api_key="foo"
110
+ end
111
+
112
+ teardown do
113
+ Stripe.api_key=nil
114
+ end
115
+
116
+ should "a 400 should give an InvalidRequestError with http status, body, and JSON body" do
117
+ response = test_response(test_missing_id_error, 400)
118
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
119
+ begin
120
+ Stripe::Customer.retrieve("foo")
121
+ rescue Stripe::InvalidRequestError => e
122
+ assert_equal(400, e.http_status)
123
+ assert_equal(true, !!e.http_body)
124
+ assert_equal(true, e.json_body.kind_of?(Hash))
125
+ end
126
+ end
127
+
128
+ should "a 401 should give an AuthenticationError with http status, body, and JSON body" do
129
+ response = test_response(test_missing_id_error, 401)
130
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
131
+ begin
132
+ Stripe::Customer.retrieve("foo")
133
+ rescue Stripe::AuthenticationError => e
134
+ assert_equal(401, e.http_status)
135
+ assert_equal(true, !!e.http_body)
136
+ assert_equal(true, e.json_body.kind_of?(Hash))
137
+ end
138
+ end
139
+
140
+ should "a 402 should give a CardError with http status, body, and JSON body" do
141
+ response = test_response(test_missing_id_error, 402)
142
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
143
+ begin
144
+ Stripe::Customer.retrieve("foo")
145
+ rescue Stripe::CardError => e
146
+ assert_equal(402, e.http_status)
147
+ assert_equal(true, !!e.http_body)
148
+ assert_equal(true, e.json_body.kind_of?(Hash))
149
+ end
150
+ end
151
+
152
+ should "a 404 should give an InvalidRequestError with http status, body, and JSON body" do
153
+ response = test_response(test_missing_id_error, 404)
154
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
155
+ begin
156
+ Stripe::Customer.retrieve("foo")
157
+ rescue Stripe::InvalidRequestError => e
158
+ assert_equal(404, e.http_status)
159
+ assert_equal(true, !!e.http_body)
160
+ assert_equal(true, e.json_body.kind_of?(Hash))
161
+ end
162
+ end
163
+
164
+ should "setting a nil value for a param should exclude that param from the request" do
165
+ @mock.expects(:get).with do |url, api_key, params|
166
+ uri = URI(url)
167
+ query = CGI.parse(uri.query)
168
+ (url =~ %r{^https://api.stripe.com/v1/charges?} &&
169
+ query.keys.sort == ['offset', 'sad'])
170
+ end.returns(test_response({ :count => 1, :data => [test_charge] }))
171
+ c = Stripe::Charge.all(:count => nil, :offset => 5, :sad => false)
172
+
173
+ @mock.expects(:post).with('https://api.stripe.com/v1/charges', nil, { :amount => 50, :currency => 'usd', :card => {} }).returns(test_response({ :count => 1, :data => [test_charge] }))
174
+ c = Stripe::Charge.create(:amount => 50, :currency => 'usd', :card => { :number => nil })
175
+ end
176
+
177
+ should "requesting with a unicode ID should result in a request" do
178
+ response = test_response(test_missing_id_error, 404)
179
+ @mock.expects(:get).once.with("https://api.stripe.com/v1/customers/%E2%98%83", nil, nil).raises(RestClient::ExceptionWithResponse.new(response, 404))
180
+ c = Stripe::Customer.new("☃")
181
+ assert_raises(Stripe::InvalidRequestError) { c.refresh }
182
+ end
183
+
184
+ should "requesting with no ID should result in an InvalidRequestError with no request" do
185
+ c = Stripe::Customer.new
186
+ assert_raises(Stripe::InvalidRequestError) { c.refresh }
187
+ end
188
+
189
+ should "making a GET request with parameters should have a query string and no body" do
190
+ params = { :limit => 1 }
191
+ @mock.expects(:get).once.with("https://api.stripe.com/v1/charges?limit=1", nil, nil).returns(test_response([test_charge]))
192
+ c = Stripe::Charge.all(params)
193
+ end
194
+
195
+ should "making a POST request with parameters should have a body and no query string" do
196
+ params = { :amount => 100, :currency => 'usd', :card => 'sc_token' }
197
+ @mock.expects(:post).once.with { |url, get, post| get.nil? and post == params }.returns(test_response(test_charge))
198
+ c = Stripe::Charge.create(params)
199
+ end
200
+
201
+ should "loading an object should issue a GET request" do
202
+ @mock.expects(:get).once.returns(test_response(test_customer))
203
+ c = Stripe::Customer.new("test_customer")
204
+ c.refresh
205
+ end
206
+
207
+ should "using array accessors should be the same as the method interface" do
208
+ @mock.expects(:get).once.returns(test_response(test_customer))
209
+ c = Stripe::Customer.new("test_customer")
210
+ c.refresh
211
+ assert_equal c.created, c[:created]
212
+ assert_equal c.created, c['created']
213
+ c['created'] = 12345
214
+ assert_equal c.created, 12345
215
+ end
216
+
217
+ should "accessing a property other than id or parent on an unfetched object should fetch it" do
218
+ @mock.expects(:get).once.returns(test_response(test_customer))
219
+ c = Stripe::Customer.new("test_customer")
220
+ c.charges
221
+ end
222
+
223
+ should "updating an object should issue a POST request with only the changed properties" do
224
+ @mock.expects(:post).with("https://api.stripe.com/v1/customers/c_test_customer", nil, {:mnemonic => 'another_mn'}).once.returns(test_response(test_customer))
225
+ c = Stripe::Customer.construct_from(test_customer)
226
+ c.mnemonic = "another_mn"
227
+ c.save
228
+ end
229
+
230
+ should "updating should merge in returned properties" do
231
+ @mock.expects(:post).once.returns(test_response(test_customer))
232
+ c = Stripe::Customer.new("c_test_customer")
233
+ c.mnemonic = "another_mn"
234
+ c.save
235
+ assert_equal false, c.livemode
236
+ end
237
+
238
+ should "deleting should send no props and result in an object that has no props other deleted" do
239
+ @mock.expects(:get).never
240
+ @mock.expects(:post).never
241
+ @mock.expects(:delete).with("https://api.stripe.com/v1/customers/c_test_customer", nil, nil).once.returns(test_response({ "id" => "test_customer", "deleted" => true }))
242
+
243
+ c = Stripe::Customer.construct_from(test_customer)
244
+ c.delete
245
+ assert_equal true, c.deleted
246
+
247
+ assert_raises NoMethodError do
248
+ c.livemode
249
+ end
250
+ end
251
+
252
+ should "loading an object with properties that have specific types should instantiate those classes" do
253
+ @mock.expects(:get).once.returns(test_response(test_charge))
254
+ c = Stripe::Charge.retrieve("test_charge")
255
+ assert c.card.kind_of?(Stripe::StripeObject) && c.card.object == 'card'
256
+ end
257
+
258
+ should "loading all of an APIResource should return an array of recursively instantiated objects" do
259
+ @mock.expects(:get).once.returns(test_response(test_charge_array))
260
+ c = Stripe::Charge.all.data
261
+ assert c.kind_of? Array
262
+ assert c[0].kind_of? Stripe::Charge
263
+ assert c[0].card.kind_of?(Stripe::StripeObject) && c[0].card.object == 'card'
264
+ end
265
+
266
+ context "account tests" do
267
+ should "account should be retrievable" do
268
+ resp = {:email => "test+bindings@stripe.com", :charge_enabled => false, :details_submitted => false}
269
+ @mock.expects(:get).once.returns(test_response(resp))
270
+ a = Stripe::Account.retrieve
271
+ assert_equal "test+bindings@stripe.com", a.email
272
+ assert !a.charge_enabled
273
+ assert !a.details_submitted
274
+ end
275
+ end
276
+
277
+ context "charge tests" do
278
+
279
+ should "charges should be listable" do
280
+ @mock.expects(:get).once.returns(test_response(test_charge_array))
281
+ c = Stripe::Charge.all.data
282
+ assert c.kind_of? Array
283
+ end
284
+
285
+ should "charges should be refundable" do
286
+ @mock.expects(:get).never
287
+ @mock.expects(:post).once.returns(test_response({:id => "ch_test_charge", :refunded => true}))
288
+ c = Stripe::Charge.new("test_charge")
289
+ c.refund
290
+ assert c.refunded
291
+ end
292
+
293
+ should "charges should not be deletable" do
294
+ assert_raises NoMethodError do
295
+ @mock.expects(:get).once.returns(test_response(test_charge))
296
+ c = Stripe::Charge.retrieve("test_charge")
297
+ c.delete
298
+ end
299
+ end
300
+
301
+ should "charges should be updateable" do
302
+ @mock.expects(:get).once.returns(test_response(test_charge))
303
+ @mock.expects(:post).once.returns(test_response(test_charge))
304
+ c = Stripe::Charge.new("test_charge")
305
+ c.refresh
306
+ c.mnemonic = "New charge description"
307
+ c.save
308
+ end
309
+
310
+ should "charges should have Card objects associated with their Card property" do
311
+ @mock.expects(:get).once.returns(test_response(test_charge))
312
+ c = Stripe::Charge.retrieve("test_charge")
313
+ assert c.card.kind_of?(Stripe::StripeObject) && c.card.object == 'card'
314
+ end
315
+
316
+ should "execute should return a new, fully executed charge when passed correct parameters" do
317
+ @mock.expects(:post).with('https://api.stripe.com/v1/charges', nil, {
318
+ :currency => 'usd', :amount => 100,
319
+ :card => {:exp_year => 2012, :number => '4242424242424242', :exp_month => 11}
320
+ }).once.returns(test_response(test_charge))
321
+
322
+ c = Stripe::Charge.create({
323
+ :amount => 100,
324
+ :card => {
325
+ :number => "4242424242424242",
326
+ :exp_month => 11,
327
+ :exp_year => 2012,
328
+ },
329
+ :currency => "usd"
330
+ })
331
+ assert c.paid
332
+ end
333
+
334
+ end
335
+
336
+ context "customer tests" do
337
+
338
+ should "customers should be listable" do
339
+ @mock.expects(:get).once.returns(test_response(test_customer_array))
340
+ c = Stripe::Customer.all.data
341
+ assert c.kind_of? Array
342
+ assert c[0].kind_of? Stripe::Customer
343
+ end
344
+
345
+ should "customers should be deletable" do
346
+ @mock.expects(:delete).once.returns(test_response(test_customer({:deleted => true})))
347
+ c = Stripe::Customer.new("test_customer")
348
+ c.delete
349
+ assert c.deleted
350
+ end
351
+
352
+ should "customers should be updateable" do
353
+ @mock.expects(:get).once.returns(test_response(test_customer({:mnemonic => "foo"})))
354
+ @mock.expects(:post).once.returns(test_response(test_customer({:mnemonic => "bar"})))
355
+ c = Stripe::Customer.new("test_customer").refresh
356
+ assert_equal c.mnemonic, "foo"
357
+ c.mnemonic = "bar"
358
+ c.save
359
+ assert_equal c.mnemonic, "bar"
360
+ end
361
+
362
+ should "customers should have Card objects associated with their active_ard property" do
363
+ @mock.expects(:get).once.returns(test_response(test_customer))
364
+ c = Stripe::Customer.retrieve("test_customer")
365
+ assert c.active_card.kind_of?(Stripe::StripeObject) && c.active_card.object == 'card'
366
+ end
367
+
368
+ should "create should return a new customer" do
369
+ @mock.expects(:post).once.returns(test_response(test_customer))
370
+ c = Stripe::Customer.create
371
+ assert_equal "c_test_customer", c.id
372
+ end
373
+
374
+ should "be able to update a customer's subscription" do
375
+ @mock.expects(:get).once.returns(test_response(test_customer))
376
+ c = Stripe::Customer.retrieve("test_customer")
377
+
378
+ @mock.expects(:post).once.with("https://api.stripe.com/v1/customers/c_test_customer/subscription", nil, {:plan => 'silver'}).returns(test_response(test_subscription('silver')))
379
+ s = c.update_subscription({:plan => 'silver'})
380
+
381
+ assert_equal 'subscription', s.object
382
+ assert_equal 'silver', s.plan.identifier
383
+ end
384
+
385
+ should "be able to cancel a customer's subscription" do
386
+ @mock.expects(:get).once.returns(test_response(test_customer))
387
+ c = Stripe::Customer.retrieve("test_customer")
388
+
389
+ # Not an accurate response, but whatever
390
+
391
+ @mock.expects(:delete).once.with("https://api.stripe.com/v1/customers/c_test_customer/subscription?at_period_end=true", nil, nil).returns(test_response(test_subscription('silver')))
392
+ s = c.cancel_subscription({:at_period_end => 'true'})
393
+
394
+ @mock.expects(:delete).once.with("https://api.stripe.com/v1/customers/c_test_customer/subscription?", nil, nil).returns(test_response(test_subscription('silver')))
395
+ s = c.cancel_subscription
396
+ end
397
+
398
+ should "be able to delete a customer's discount" do
399
+ @mock.expects(:get).once.returns(test_response(test_customer))
400
+ c = Stripe::Customer.retrieve("test_customer")
401
+
402
+ @mock.expects(:delete).once.with("https://api.stripe.com/v1/customers/c_test_customer/discount", nil, nil).returns(test_response(test_delete_discount_response))
403
+ s = c.delete_discount
404
+ assert_equal nil, c.discount
405
+ end
406
+ end
407
+
408
+ context "card tests" do
409
+ end
410
+
411
+ context "coupon tests" do
412
+ should "create should return a new coupon" do
413
+ @mock.expects(:post).once.returns(test_response(test_coupon))
414
+ c = Stripe::Coupon.create
415
+ assert_equal "co_test_coupon", c.id
416
+ end
417
+ end
418
+ context "error checking" do
419
+
420
+ should "404s should raise an InvalidRequestError" do
421
+ response = test_response(test_missing_id_error, 404)
422
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 404))
423
+
424
+ begin
425
+ Stripe::Customer.new("test_customer").refresh
426
+ assert false #shouldn't get here either
427
+ rescue Stripe::InvalidRequestError => e # we don't use assert_raises because we want to examine e
428
+ assert e.kind_of? Stripe::InvalidRequestError
429
+ assert_equal "id", e.param
430
+ assert_equal "Missing id", e.message
431
+ return
432
+ end
433
+
434
+ assert false #shouldn't get here
435
+ end
436
+
437
+ should "5XXs should raise an APIError" do
438
+ response = test_response(test_api_error, 500)
439
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 500))
440
+
441
+ begin
442
+ Stripe::Customer.new("test_customer").refresh
443
+ assert false #shouldn't get here either
444
+ rescue Stripe::APIError => e # we don't use assert_raises because we want to examine e
445
+ assert e.kind_of? Stripe::APIError
446
+ return
447
+ end
448
+
449
+ assert false #shouldn't get here
450
+ end
451
+
452
+ should "402s should raise a CardError" do
453
+ response = test_response(test_invalid_exp_year_error, 402)
454
+ @mock.expects(:get).once.raises(RestClient::ExceptionWithResponse.new(response, 402))
455
+
456
+ begin
457
+ Stripe::Customer.new("test_customer").refresh
458
+ assert false #shouldn't get here either
459
+ rescue Stripe::CardError => e # we don't use assert_raises because we want to examine e
460
+ assert e.kind_of? Stripe::CardError
461
+ assert_equal "invalid_expiry_year", e.code
462
+ assert_equal "exp_year", e.param
463
+ assert_equal "Your card's expiration year is invalid", e.message
464
+ return
465
+ end
466
+
467
+ assert false #shouldn't get here
468
+ end
469
+ end
470
+ end
471
+ end
472
+ end