itunes-receipt-mock 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e89959f9b704e3139a602239387361f6aa7a8b98
4
- data.tar.gz: e237a12123a3c5193b951359c79df514a0e89812
3
+ metadata.gz: efc7aa090d82b68d8a3ac83e0ddd6723aaef8259
4
+ data.tar.gz: 5397e14dd57d12944d392cdcfe8b49df155bdb49
5
5
  SHA512:
6
- metadata.gz: f21216a625c2226f9cc7f7f011e797f7fc03294f5c698361edc83993e90dcb23840bacb9115640bda5b54a9823a0d9d7430c0e4f64ad2da3f0de36af6e3d4278
7
- data.tar.gz: 506df8e5fb160fbacbf0172090cabb76d32310461cede025613380ebbae220053f58ce5020582af325fc0f6803b718d3e6732230d510464e2fc96453ea298816
6
+ metadata.gz: ed57db647afc32fc3dbab1154f61beb1d98ade455a80231d39b47efec02486454f2a22c88c3f775dfee0db6644f0e83cea917e53f3e4dcbf90ce2dce1acdefcf
7
+ data.tar.gz: 9b6fc7473831a9650378b176d1442fd43d2c314e0ac942d9984aeb2e4d67c1247f2e93b5fd0731f0fdb2afba1317a71faf57b58ae83a0271b9bb66abbc3cc430
@@ -1,6 +1,6 @@
1
1
  require 'base64'
2
2
  require 'itunes_receipt_mock/mixins'
3
- require 'itunes_receipt_mock/validation'
3
+ require 'itunes_receipt_mock/transaction_proxy'
4
4
  require 'itunes_receipt_mock/receipt'
5
5
  require 'itunes_receipt_mock/purchase'
6
6
  require 'itunes_receipt_mock/subscription'
@@ -10,24 +10,7 @@ require 'itunes_receipt_mock/subscription'
10
10
  module ItunesReceiptMock
11
11
  class MissingArgumentError < StandardError; end
12
12
 
13
- @transaction_id = 1_000_000_000
14
- @web_order_line_item_id = 1_000_000_000
15
- ##
16
- # Creates a new iTunes receipt
17
- #
18
- # Returns: rdoc-ref:ItunesReceiptMock::Validation
19
- #
20
- # Params:
21
- # +options+:: rdoc-ref:ItunesReceiptMock
22
13
  def self.new(options = {})
23
- Validation.new(options)
24
- end
25
-
26
- def self.next_transaction_id
27
- @transaction_id += 1
28
- end
29
-
30
- def self.next_web_order_line_item_id
31
- @web_order_line_item_id += 1
14
+ Receipt.new(options)
32
15
  end
33
16
  end
@@ -15,7 +15,7 @@ module ItunesReceiptMock
15
15
  def date_attrs(prefix, date)
16
16
  {
17
17
  "#{prefix}_date" => date.utc.strftime('%F %T') + ' Etc/GMT',
18
- "#{prefix}_date_ms" => date.utc.strftime('%s%L').to_i,
18
+ "#{prefix}_date_ms" => date.utc.strftime('%s%L'),
19
19
  "#{prefix}_date_pst" => date.getlocal('-08:00').strftime('%F %T') +
20
20
  ' America/Los_Angeles'
21
21
  }
@@ -7,30 +7,37 @@ module ItunesReceiptMock
7
7
  include ItunesReceiptMock::Mixins
8
8
 
9
9
  PURCHASE_DEFAULTS = {
10
+ receipt: nil,
10
11
  product_id: nil,
11
12
  quantity: 1,
12
- transaction_id: proc { ItunesReceiptMock.next_transaction_id },
13
+ transaction_id: proc { receipt.transactions.next_transaction_id },
13
14
  original_transaction_id: proc { transaction_id },
14
15
  purchase_date: proc { Time.now },
15
- original_purchase_date: proc { purchase_date }
16
+ original_purchase_date: proc { purchase_date },
17
+ is_trial_period: false,
18
+ in_app: true
16
19
  }
17
20
 
18
21
  attr_accessor :quantity, :product_id, :transaction_id,
19
22
  :original_transaction_id, :purchase_date,
20
- :original_purchase_date
23
+ :original_purchase_date, :is_trial_period,
24
+ :receipt, :in_app
25
+
26
+ alias_method :in_app?, :in_app
21
27
 
22
28
  def initialize(options = {})
23
29
  send_defaults(PURCHASE_DEFAULTS, options)
24
- fail ItunesReceiptMock::MissingArgumentError,
25
- 'product_id is required' unless @product_id
30
+ fail MissingArgumentError, 'product_id is required' unless @product_id
31
+ fail MissingArgumentError, 'receipt is required' unless @receipt
26
32
  end
27
33
 
28
- def result(_options = {})
34
+ def as_json
29
35
  {
30
- 'quantity' => quantity,
36
+ 'quantity' => quantity.to_s,
31
37
  'product_id' => product_id,
32
- 'transaction_id' => transaction_id,
33
- 'original_transaction_id' => original_transaction_id
38
+ 'transaction_id' => transaction_id.to_s,
39
+ 'original_transaction_id' => original_transaction_id.to_s,
40
+ 'is_trial_period' => is_trial_period.to_s
34
41
  }
35
42
  .merge(date_attrs('purchase', purchase_date))
36
43
  .merge(date_attrs('original_purchase', original_purchase_date))
@@ -6,9 +6,12 @@ module ItunesReceiptMock
6
6
  class Receipt
7
7
  include ItunesReceiptMock::Mixins
8
8
 
9
- RECEIPT_DEFAULTS = {
10
- bundle_id: nil,
9
+ STATUS_CODES = [0, 21_000] + (21_002..21_008).to_a
10
+ DEFAULTS = {
11
+ status: 0,
12
+ request_date: proc { Time.now },
11
13
  environment: 'Production',
14
+ bundle_id: nil,
12
15
  adam_id: 1,
13
16
  app_item_id: 1,
14
17
  application_version: 1,
@@ -18,20 +21,37 @@ module ItunesReceiptMock
18
21
  original_application_version: 1
19
22
  }
20
23
 
21
- attr_reader :in_app
22
- attr_accessor :environment, :adam_id, :app_item_id, :bundle_id,
23
- :application_version, :download_id,
24
+ attr_reader :transactions
25
+ attr_accessor :status, :environment, :request_date, :adam_id, :app_item_id,
26
+ :bundle_id, :application_version, :download_id,
24
27
  :version_external_identifier, :original_purchase_date,
25
28
  :original_application_version
26
29
 
27
30
  def initialize(options = {})
28
- @in_app = {}
29
- send_defaults(RECEIPT_DEFAULTS, options)
31
+ send_defaults(DEFAULTS, options)
32
+ @transactions = TransactionProxy.new(self)
30
33
  fail MissingArgumentError, 'bundle_id is required' unless @bundle_id
31
34
  end
32
35
 
33
- def result(options = {})
34
- request_date = options.fetch :request_date, Time.now
36
+ def as_json
37
+ result = { 'status' => status }
38
+ if status == 0
39
+ result.merge!(
40
+ 'status' => status,
41
+ 'environment' => environment,
42
+ 'receipt' => inner_json,
43
+ 'latest_receipt_info' => transactions.latest_receipt_info
44
+ )
45
+ result.merge!(
46
+ 'latest_receipt' => Base64.strict_encode64(result.to_json)
47
+ )
48
+ end
49
+ result
50
+ end
51
+
52
+ private
53
+
54
+ def inner_json
35
55
  {
36
56
  'receipt_type' => environment,
37
57
  'adam_id' => adam_id.to_i,
@@ -42,28 +62,10 @@ module ItunesReceiptMock
42
62
  'version_external_identifier' => version_external_identifier.to_i,
43
63
  'original_application_version' =>
44
64
  format('%.1f', original_application_version),
45
- 'in_app' => in_app_result(options)
65
+ 'in_app' => transactions.in_app
46
66
  }
47
67
  .merge(date_attrs('request', request_date))
48
68
  .merge(date_attrs('original_purchase', original_purchase_date))
49
69
  end
50
-
51
- def add_purchase(options = {})
52
- purchase = Purchase.new(options)
53
- @in_app[purchase.transaction_id] = purchase
54
- purchase
55
- end
56
-
57
- def add_subscription(options = {})
58
- purchase = Subscription.new(options)
59
- @in_app[purchase.transaction_id] = purchase
60
- purchase
61
- end
62
-
63
- private
64
-
65
- def in_app_result(options)
66
- in_app.map { |_, v| v.result(options) }
67
- end
68
70
  end
69
71
  end
@@ -7,23 +7,34 @@ module ItunesReceiptMock
7
7
  SUBSCRIPTION_DEFAULTS = {
8
8
  expires_date: nil,
9
9
  web_order_line_item_id: proc do
10
- ItunesReceiptMock.next_web_order_line_item_id
11
- end,
12
- is_trial_period: false
10
+ receipt.transactions.next_web_order_line_item_id
11
+ end
13
12
  }
14
13
 
15
- attr_accessor :expires_date, :web_order_line_item_id, :is_trial_period
14
+ attr_accessor :expires_date, :web_order_line_item_id
16
15
 
17
- def initialize(options = {})
16
+ def initialize(options)
18
17
  super
19
18
  send_defaults(SUBSCRIPTION_DEFAULTS, options)
20
19
  fail MissingArgumentError, 'expires_date is required' unless @expires_date
21
20
  end
22
21
 
23
- def result(_options = {})
22
+ def renew(options)
23
+ attrs = {
24
+ receipt: receipt,
25
+ in_app: false,
26
+ quantity: quantity,
27
+ product_id: product_id,
28
+ original_transaction_id: transaction_id,
29
+ original_purchase_date: purchase_date,
30
+ is_trial_period: is_trial_period
31
+ }.merge(options)
32
+ receipt.transactions.create attrs
33
+ end
34
+
35
+ def as_json
24
36
  super.merge(
25
- 'web_order_line_item_id' => web_order_line_item_id.to_s,
26
- 'is_trial_period' => is_trial_period
37
+ 'web_order_line_item_id' => web_order_line_item_id.to_s
27
38
  ).merge(date_attrs('expires', expires_date))
28
39
  end
29
40
  end
@@ -0,0 +1,38 @@
1
+ ##
2
+ # ItunesReceiptMock
3
+ module ItunesReceiptMock
4
+ ##
5
+ # ItunesReceiptMock::TransactionProxy
6
+ class TransactionProxy < Array
7
+ attr_accessor :receipt, :transaction_id, :web_order_line_item_id
8
+
9
+ def initialize(receipt)
10
+ @receipt = receipt
11
+ @transaction_id = 1_000_000_000
12
+ @web_order_line_item_id = 1_000_000_000
13
+ end
14
+
15
+ def create(options)
16
+ klass = options[:expires_date].nil? ? Purchase : Subscription
17
+ transaction = klass.new options.merge(receipt: @receipt)
18
+ self << transaction
19
+ transaction
20
+ end
21
+
22
+ def in_app
23
+ select(&:in_app?).map(&:as_json)
24
+ end
25
+
26
+ def latest_receipt_info
27
+ map(&:as_json)
28
+ end
29
+
30
+ def next_transaction_id
31
+ @transaction_id += 1
32
+ end
33
+
34
+ def next_web_order_line_item_id
35
+ @web_order_line_item_id += 1
36
+ end
37
+ end
38
+ end
@@ -1,5 +1,5 @@
1
1
  ##
2
2
  # ItunesReceiptMock::VERSION
3
3
  module ItunesReceiptMock
4
- VERSION = '0.0.5'
4
+ VERSION = '0.1.0'
5
5
  end
@@ -0,0 +1,409 @@
1
+ require 'spec_helper'
2
+
3
+ describe ItunesReceiptMock do
4
+ before do
5
+ Timecop.freeze
6
+ end
7
+
8
+ after do
9
+ Timecop.return
10
+ end
11
+
12
+ describe '.new' do
13
+ subject { described_class.new(options) }
14
+
15
+ let(:options) { { bundle_id: 'com.example' } }
16
+
17
+ it 'initializes a Receipt' do
18
+ expect(subject).to be_a(described_class::Receipt)
19
+ end
20
+
21
+ it 'sets the attributes' do
22
+ expect(subject.status).to eq(0)
23
+ expect(subject.request_date).to eq(Time.now)
24
+ expect(subject.environment).to eq('Production')
25
+ expect(subject.bundle_id).to eq('com.example')
26
+ expect(subject.adam_id).to eq(1)
27
+ expect(subject.app_item_id).to eq(1)
28
+ expect(subject.application_version).to eq(1)
29
+ expect(subject.download_id).to eq(1)
30
+ expect(subject.version_external_identifier).to eq(1)
31
+ expect(subject.original_purchase_date).to eq(Time.now)
32
+ expect(subject.original_application_version).to eq(1)
33
+ end
34
+
35
+ it 'initializes the transactions' do
36
+ expect(subject.transactions).to be_a(described_class::TransactionProxy)
37
+ end
38
+
39
+ context 'when options are populated' do
40
+ let(:options) do
41
+ {
42
+ status: 21_000,
43
+ request_date: 1.day.ago,
44
+ environment: 'Sandbox',
45
+ bundle_id: 'com.example2',
46
+ adam_id: 2,
47
+ app_item_id: 2,
48
+ application_version: 2,
49
+ download_id: 2,
50
+ version_external_identifier: 2,
51
+ original_purchase_date: 1.day.ago,
52
+ original_application_version: 2
53
+ }
54
+ end
55
+
56
+ it 'sets the attributes' do
57
+ expect(subject.status).to eq(21_000)
58
+ expect(subject.request_date).to eq(1.day.ago)
59
+ expect(subject.environment).to eq('Sandbox')
60
+ expect(subject.bundle_id).to eq('com.example2')
61
+ expect(subject.adam_id).to eq(2)
62
+ expect(subject.app_item_id).to eq(2)
63
+ expect(subject.application_version).to eq(2)
64
+ expect(subject.download_id).to eq(2)
65
+ expect(subject.version_external_identifier).to eq(2)
66
+ expect(subject.original_purchase_date).to eq(1.day.ago)
67
+ expect(subject.original_application_version).to eq(2)
68
+ end
69
+ end
70
+
71
+ context 'when bundle_id is not present' do
72
+ let(:options) { {} }
73
+
74
+ it 'raises an MissingArgumentError' do
75
+ expect { subject }.to raise_error(
76
+ described_class::MissingArgumentError,
77
+ 'bundle_id is required'
78
+ )
79
+ end
80
+ end
81
+ end
82
+
83
+ describe '#receipt.transactions.create' do
84
+ subject { receipt.transactions.create(options) }
85
+
86
+ let(:receipt) { described_class.new(bundle_id: 'com.example') }
87
+
88
+ shared_examples 'a Purchase' do
89
+ it 'adds it to the transactions' do
90
+ expect(receipt.transactions).to include(subject)
91
+ end
92
+
93
+ it 'increments the transaction_id' do
94
+ expect(receipt.transactions.transaction_id).to eq(1_000_000_000)
95
+ subject
96
+ expect(receipt.transactions.transaction_id).to eq(1_000_000_001)
97
+ end
98
+
99
+ it 'sets the attributes' do
100
+ expect(subject.product_id).to eq('foobar')
101
+ expect(subject.quantity).to eq(1)
102
+ expect(subject.transaction_id).to eq(1_000_000_001)
103
+ expect(subject.original_transaction_id).to eq(subject.transaction_id)
104
+ expect(subject.purchase_date).to eq(Time.now)
105
+ expect(subject.original_purchase_date).to eq(subject.purchase_date)
106
+ expect(subject.is_trial_period).to eq(false)
107
+ expect(subject.in_app).to eq(true)
108
+ expect(subject.receipt).to eq(receipt)
109
+ end
110
+
111
+ context 'when options are populated' do
112
+ let(:options) do
113
+ {
114
+ product_id: 'whatever',
115
+ quantity: 2,
116
+ transaction_id: 999,
117
+ original_transaction_id: 998,
118
+ purchase_date: 1.day.ago,
119
+ original_purchase_date: 2.days.ago,
120
+ is_trial_period: true
121
+ }
122
+ end
123
+
124
+ it 'sets the attributes' do
125
+ expect(subject.product_id).to eq('whatever')
126
+ expect(subject.quantity).to eq(2)
127
+ expect(subject.transaction_id).to eq(999)
128
+ expect(subject.original_transaction_id).to eq(998)
129
+ expect(subject.purchase_date).to eq(1.day.ago)
130
+ expect(subject.original_purchase_date).to eq(2.days.ago)
131
+ expect(subject.is_trial_period).to eq(true)
132
+ end
133
+ end
134
+
135
+ context 'when product_id is missing' do
136
+ let(:options) { {} }
137
+
138
+ it 'raises an MissingArgumentError' do
139
+ expect { subject }.to raise_error(
140
+ described_class::MissingArgumentError,
141
+ 'product_id is required'
142
+ )
143
+ end
144
+ end
145
+ end
146
+
147
+ shared_examples 'a Subscription' do
148
+ it_behaves_like 'a Purchase'
149
+
150
+ it 'increments the web_order_line_item_id' do
151
+ expect(receipt.transactions.web_order_line_item_id).to eq(1_000_000_000)
152
+ subject
153
+ expect(receipt.transactions.web_order_line_item_id).to eq(1_000_000_001)
154
+ end
155
+
156
+ it 'sets the attributes' do
157
+ expect(subject.expires_date).to eq(1.month.from_now)
158
+ expect(subject.web_order_line_item_id).to eq(1_000_000_001)
159
+ end
160
+
161
+ context 'when options are populated' do
162
+ let(:options) do
163
+ {
164
+ product_id: 'whatever',
165
+ expires_date: 7.days.from_now,
166
+ web_order_line_item_id: 999
167
+ }
168
+ end
169
+
170
+ it 'sets the attributes' do
171
+ expect(subject.web_order_line_item_id).to eq(999)
172
+ end
173
+ end
174
+ end
175
+
176
+ context 'creating a purchase' do
177
+ let(:options) do
178
+ {
179
+ product_id: 'foobar'
180
+ }
181
+ end
182
+
183
+ it 'initializes a Purchase' do
184
+ expect(subject).to be_a(described_class::Purchase)
185
+ end
186
+
187
+ it_behaves_like 'a Purchase'
188
+ end
189
+
190
+ context 'creating a subscription' do
191
+ let(:options) do
192
+ {
193
+ product_id: 'foobar',
194
+ expires_date: 1.month.from_now
195
+ }
196
+ end
197
+
198
+ it 'initializes a Subscription' do
199
+ expect(subject).to be_a(described_class::Subscription)
200
+ end
201
+
202
+ it_behaves_like 'a Subscription'
203
+ end
204
+ end
205
+
206
+ describe 'subscription.renew' do
207
+ subject { subscription.renew(options) }
208
+
209
+ let(:receipt) { described_class.new(bundle_id: 'com.example') }
210
+ let!(:subscription) do
211
+ receipt.transactions.create(
212
+ product_id: 'premium',
213
+ purchase_date: 1.month.ago,
214
+ expires_date: Time.now
215
+ )
216
+ end
217
+ let(:options) do
218
+ {
219
+ expires_date: 1.month.from_now
220
+ }
221
+ end
222
+
223
+ it 'initializes a Subscription' do
224
+ expect(subject).to be_a(described_class::Subscription)
225
+ end
226
+
227
+ it 'adds the new subscription to transactions' do
228
+ expect(receipt.transactions).to include(subject)
229
+ expect(receipt.transactions).to include(subscription)
230
+ end
231
+
232
+ it 'assigns the attributes' do
233
+ expect(subject.expires_date).to eq(1.month.from_now)
234
+ expect(subject.in_app).to eq(false)
235
+ end
236
+
237
+ context 'when in_app is set to true' do
238
+ let(:options) do
239
+ {
240
+ expires_date: 1.month.from_now,
241
+ in_app: true
242
+ }
243
+ end
244
+
245
+ it 'sets in_app to true' do
246
+ expect(subject.in_app).to eq(true)
247
+ end
248
+ end
249
+ end
250
+
251
+ describe '#receipt.as_json' do
252
+ subject { receipt.as_json }
253
+
254
+ let(:receipt) { described_class.new(bundle_id: 'com.example') }
255
+ let!(:purchase) do
256
+ receipt.transactions.create(product_id: 'foobar')
257
+ end
258
+ let!(:subscription) do
259
+ receipt.transactions.create(
260
+ product_id: 'premium',
261
+ purchase_date: 1.month.ago,
262
+ expires_date: Time.now
263
+ )
264
+ end
265
+ let(:in_app_purchase_json) do
266
+ subject['receipt']['in_app'].detect do |t|
267
+ t['transaction_id'].to_i == purchase.transaction_id
268
+ end
269
+ end
270
+ let(:latest_receipt_info_purchase_json) do
271
+ subject['latest_receipt_info'].detect do |t|
272
+ t['transaction_id'].to_i == purchase.transaction_id
273
+ end
274
+ end
275
+ let(:in_app_subscription_json) do
276
+ subject['receipt']['in_app'].detect do |t|
277
+ t['transaction_id'].to_i == subscription.transaction_id
278
+ end
279
+ end
280
+ let(:latest_receipt_info_subscription_json) do
281
+ subject['latest_receipt_info'].detect do |t|
282
+ t['transaction_id'].to_i == subscription.transaction_id
283
+ end
284
+ end
285
+
286
+ shared_examples 'a date' do
287
+ it 'displays the date in GMT' do
288
+ expect(json[prefix + '_date'])
289
+ .to eq(date.utc.strftime('%F %T') + ' Etc/GMT')
290
+ end
291
+
292
+ it 'displays the date as a ms timestamp' do
293
+ expect(json[prefix + '_date_ms'])
294
+ .to eq(date.utc.strftime('%s%L'))
295
+ end
296
+
297
+ it 'displays the date in PST' do
298
+ expect(json[prefix + '_date_pst'])
299
+ .to eq(date.getlocal('-08:00').strftime('%F %T') +
300
+ ' America/Los_Angeles')
301
+ end
302
+ end
303
+
304
+ shared_examples 'a purchase json object' do
305
+ it 'contains all the details for a purchase' do
306
+ expect(json['product_id']).to eq(obj.product_id)
307
+ expect(json['quantity']).to eq(obj.quantity.to_s)
308
+ expect(json['original_transaction_id'])
309
+ .to eq(obj.original_transaction_id.to_s)
310
+ end
311
+
312
+ describe 'purchase date' do
313
+ let(:date) { obj.purchase_date }
314
+ let(:prefix) { 'purchase' }
315
+ it_behaves_like 'a date'
316
+ end
317
+
318
+ describe 'original purchase date' do
319
+ let(:date) { obj.original_purchase_date }
320
+ let(:prefix) { 'original_purchase' }
321
+ it_behaves_like 'a date'
322
+ end
323
+ end
324
+
325
+ shared_examples 'a subscription json object' do
326
+ it_behaves_like 'a purchase json object'
327
+
328
+ it 'contains all the details for a subscription' do
329
+ expect(json['web_order_line_item_id'])
330
+ .to eq(obj.web_order_line_item_id.to_s)
331
+ expect(json['is_trial_period']).to eq(obj.is_trial_period.to_s)
332
+ end
333
+
334
+ describe 'expires date' do
335
+ let(:date) { obj.expires_date }
336
+ let(:prefix) { 'expires' }
337
+ it_behaves_like 'a date'
338
+ end
339
+ end
340
+
341
+ it 'contains the lastest_receipt' do
342
+ expect(subject['latest_receipt']).to_not be_nil
343
+ end
344
+
345
+ it 'contains all the purchases in the receipt.in_app object' do
346
+ expect(subject['receipt']['in_app'].length).to eq(2)
347
+ end
348
+
349
+ it 'contains all the purchases in the latest_receipt_info object' do
350
+ expect(subject['latest_receipt_info'].length).to eq(2)
351
+ end
352
+
353
+ it_behaves_like 'a purchase json object' do
354
+ let(:obj) { purchase }
355
+ let(:json) { in_app_purchase_json }
356
+ end
357
+
358
+ it 'contains the same object for the purchase in latest_receipt_info' do
359
+ expect(in_app_purchase_json).to eq(latest_receipt_info_purchase_json)
360
+ end
361
+
362
+ it_behaves_like 'a subscription json object' do
363
+ let(:obj) { subscription }
364
+ let(:json) { in_app_subscription_json }
365
+ end
366
+
367
+ it 'contains the same object for the subscription in latest_receipt_info' do
368
+ expect(in_app_subscription_json)
369
+ .to eq(latest_receipt_info_subscription_json)
370
+ end
371
+
372
+ context 'renewing the subscription' do
373
+ let(:subscription_options) do
374
+ {
375
+ expires_date: 1.month.from_now
376
+ }
377
+ end
378
+
379
+ let!(:renewal) do
380
+ subscription.renew subscription_options
381
+ end
382
+
383
+ it 'contains two transactions in receipt.in_app' do
384
+ expect(subject['receipt']['in_app'].length).to eq(2)
385
+ end
386
+
387
+ it 'contains three transactions in latest_receipt_info' do
388
+ expect(subject['latest_receipt_info'].length).to eq(3)
389
+ end
390
+
391
+ context 'when in_app is true' do
392
+ let(:subscription_options) do
393
+ {
394
+ expires_date: 1.month.from_now,
395
+ in_app: true
396
+ }
397
+ end
398
+
399
+ it 'contains three transactions in receipt.in_app' do
400
+ expect(subject['receipt']['in_app'].length).to eq(3)
401
+ end
402
+
403
+ it 'contains three transactions in latest_receipt_info' do
404
+ expect(subject['latest_receipt_info'].length).to eq(3)
405
+ end
406
+ end
407
+ end
408
+ end
409
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: itunes-receipt-mock
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - mbaasy.com
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-12 00:00:00.000000000 Z
11
+ date: 2015-08-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -119,12 +119,10 @@ files:
119
119
  - lib/itunes_receipt_mock/purchase.rb
120
120
  - lib/itunes_receipt_mock/receipt.rb
121
121
  - lib/itunes_receipt_mock/subscription.rb
122
- - lib/itunes_receipt_mock/validation.rb
122
+ - lib/itunes_receipt_mock/transaction_proxy.rb
123
123
  - lib/itunes_receipt_mock/version.rb
124
- - spec/module_spec.rb
125
- - spec/receipt_spec.rb
124
+ - spec/itunes_receipt_mock_spec.rb
126
125
  - spec/spec_helper.rb
127
- - spec/validation_spec.rb
128
126
  homepage: https://github.com/mbaasy/itunes-receipt-mock-ruby
129
127
  licenses:
130
128
  - MIT
@@ -1,70 +0,0 @@
1
- ##
2
- # ItunesReceiptMock
3
- module ItunesReceiptMock
4
- ##
5
- # ItunesReceiptMock::Validation
6
- class Validation
7
- include ItunesReceiptMock::Mixins
8
-
9
- STATUS_CODES = [0, 21_000] + (21_002..21_008).to_a
10
-
11
- attr_reader :receipt, :latest_receipt_info
12
-
13
- def initialize(options = {})
14
- @latest_receipt_info = {}
15
- @receipt = Receipt.new(options)
16
- end
17
-
18
- def result(options = {})
19
- status = options.fetch(:status, 0)
20
- result = { 'status' => status }
21
- if status == 0
22
- result.merge!(
23
- 'status' => status,
24
- 'environment' => receipt.environment,
25
- 'receipt' => receipt.result(options),
26
- 'latest_receipt_info' => latest_receipt_info_result(options)
27
- )
28
- result.merge!(
29
- 'latest_receipt' => Base64.strict_encode64(result.to_json)
30
- )
31
- end
32
- result
33
- end
34
-
35
- def add_purchase(options = {})
36
- purchase = receipt.add_purchase(options)
37
- @latest_receipt_info[purchase.transaction_id] = purchase
38
- purchase
39
- end
40
-
41
- def add_subscription(options = {})
42
- purchase = receipt.add_subscription(options)
43
- @latest_receipt_info[purchase.transaction_id] = purchase
44
- purchase
45
- end
46
-
47
- def renew_subscription(purchase, options = {})
48
- expires_date = options.fetch(:expires_date, nil)
49
- fail MissingArgumentError, 'expires_date is required' unless expires_date
50
-
51
- attrs = {
52
- quantity: purchase.quantity,
53
- product_id: purchase.product_id,
54
- original_transaction_id: purchase.original_transaction_id,
55
- original_purchase_date: purchase.original_purchase_date,
56
- web_order_line_item_id: purchase.web_order_line_item_id,
57
- is_trial_period: purchase.is_trial_period
58
- }.merge(expires_date: expires_date).merge(options)
59
-
60
- receipt.in_app.delete(purchase.original_transaction_id)
61
- add_subscription(attrs)
62
- end
63
-
64
- private
65
-
66
- def latest_receipt_info_result(options)
67
- latest_receipt_info.map { |_, v| v.result(options) }
68
- end
69
- end
70
- end
@@ -1,151 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ItunesReceiptMock do
4
- describe '.new' do
5
- subject { described_class.new(options) }
6
-
7
- context 'with minimal options' do
8
- let(:options) { { bundle_id: 'foobar' } }
9
-
10
- it 'creates an instance of Validation' do
11
- expect(subject).to be_a(described_class::Validation)
12
- end
13
- end
14
-
15
- context 'when bundle_id is not present' do
16
- let(:options) { {} }
17
-
18
- it 'raises an MissingArgumentError' do
19
- expect { subject }.to raise_error(
20
- described_class::MissingArgumentError,
21
- 'bundle_id is required'
22
- )
23
- end
24
- end
25
- end
26
-
27
- describe 'full integration' do
28
- let(:validation) { described_class.new(bundle_id: 'com.example') }
29
- let!(:purchase) { validation.add_purchase(product_id: 'foobar') }
30
- let!(:subscription) do
31
- validation.add_subscription product_id: 'premium',
32
- purchase_date: 1.month.ago,
33
- expires_date: Time.now
34
- end
35
- let(:in_app_purchase_json) do
36
- subject['receipt']['in_app'].detect do |t|
37
- t['transaction_id'] == purchase.transaction_id
38
- end
39
- end
40
- let(:latest_receipt_info_purchase_json) do
41
- subject['latest_receipt_info'].detect do |t|
42
- t['transaction_id'] == purchase.transaction_id
43
- end
44
- end
45
- let(:in_app_subscription_json) do
46
- subject['receipt']['in_app'].detect do |t|
47
- t['transaction_id'] == subscription.transaction_id
48
- end
49
- end
50
- let(:latest_receipt_info_subscription_json) do
51
- subject['latest_receipt_info'].detect do |t|
52
- t['transaction_id'] == subscription.transaction_id
53
- end
54
- end
55
-
56
- subject { validation.result }
57
-
58
- shared_examples 'a date' do
59
- it 'displays the date in GMT' do
60
- expect(json[prefix + '_date'])
61
- .to eq(date.utc.strftime('%F %T') + ' Etc/GMT')
62
- end
63
-
64
- it 'displays the date as a ms timestamp' do
65
- expect(json[prefix + '_date_ms'])
66
- .to eq(date.utc.strftime('%s%L').to_i)
67
- end
68
-
69
- it 'displays the date in PST' do
70
- expect(json[prefix + '_date_pst'])
71
- .to eq(date.getlocal('-08:00').strftime('%F %T') +
72
- ' America/Los_Angeles')
73
- end
74
- end
75
-
76
- shared_examples 'a purchase json object' do
77
- it 'contains all the details for a purchase' do
78
- expect(json['product_id']).to eq(obj.product_id)
79
- expect(json['quantity']).to eq(obj.quantity)
80
- expect(json['original_transaction_id'])
81
- .to eq(obj.original_transaction_id)
82
- end
83
-
84
- describe 'purchase date' do
85
- let(:date) { obj.purchase_date }
86
- let(:prefix) { 'purchase' }
87
- it_behaves_like 'a date'
88
- end
89
-
90
- describe 'original purchase date' do
91
- let(:date) { obj.original_purchase_date }
92
- let(:prefix) { 'original_purchase' }
93
- it_behaves_like 'a date'
94
- end
95
- end
96
-
97
- shared_examples 'a subscription json object' do
98
- it_behaves_like 'a purchase json object'
99
-
100
- it 'contains all the details for a subscription' do
101
- expect(json['web_order_line_item_id'])
102
- .to eq(obj.web_order_line_item_id.to_s)
103
- expect(json['is_trial_period']).to eq(obj.is_trial_period)
104
- end
105
-
106
- describe 'expires date' do
107
- let(:date) { obj.expires_date }
108
- let(:prefix) { 'expires' }
109
- it_behaves_like 'a date'
110
- end
111
- end
112
-
113
- it 'contains all the purchases in the receipt.in_app object' do
114
- expect(subject['receipt']['in_app'].length).to eq(2)
115
- end
116
-
117
- it 'contains all the purchases in the latest_receipt_info object' do
118
- expect(subject['latest_receipt_info'].length).to eq(2)
119
- end
120
-
121
- it_behaves_like 'a purchase json object' do
122
- let(:obj) { purchase }
123
- let(:json) { in_app_purchase_json }
124
- end
125
-
126
- it 'contains the same object for the purchase in latest_receipt_info' do
127
- expect(in_app_purchase_json).to eq(latest_receipt_info_purchase_json)
128
- end
129
-
130
- it_behaves_like 'a subscription json object' do
131
- let(:obj) { subscription }
132
- let(:json) { in_app_subscription_json }
133
- end
134
-
135
- it 'contains the same object for the subscription in latest_receipt_info' do
136
- expect(in_app_subscription_json)
137
- .to eq(latest_receipt_info_subscription_json)
138
- end
139
-
140
- context 'renewing the subscription' do
141
- let!(:renewal) do
142
- validation.renew_subscription subscription,
143
- expires_date: 1.month.from_now
144
- end
145
-
146
- it 'contains two subscription transactions in latest_receipt_info' do
147
- expect(subject['latest_receipt_info'].length).to eq(3)
148
- end
149
- end
150
- end
151
- end
@@ -1,162 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ItunesReceiptMock::Receipt do
4
- before do
5
- Timecop.freeze
6
- end
7
-
8
- after do
9
- Timecop.return
10
- end
11
-
12
- describe '.new' do
13
- subject { described_class.new(options) }
14
-
15
- context 'with minimal options' do
16
- let(:options) { { bundle_id: 'foobar' } }
17
-
18
- it 'sets "bundle_id" to the option value' do
19
- expect(subject.bundle_id).to eq(options[:bundle_id])
20
- end
21
-
22
- it 'defaults everything else' do
23
- expect(subject.environment).to eq('Production')
24
- expect(subject.adam_id).to eq(1)
25
- expect(subject.app_item_id).to eq(1)
26
- expect(subject.application_version).to eq(1)
27
- expect(subject.download_id).to eq(1)
28
- expect(subject.version_external_identifier).to eq(1)
29
- expect(subject.original_purchase_date).to eq(Time.now)
30
- end
31
- end
32
-
33
- context 'when options are complete' do
34
- let(:options) do
35
- {
36
- bundle_id: 'foobar',
37
- environment: 'Sandbox',
38
- adam_id: rand(1..5),
39
- app_item_id: rand(1..5),
40
- application_version: rand(1..5).to_s,
41
- download_id: rand(1..5),
42
- version_external_identifier: rand(1..5),
43
- original_purchase_date: Time.new(2015, 06, 20, 8, 16, 32)
44
- }
45
- end
46
-
47
- it 'sets all the things' do
48
- expect(subject.environment).to eq(options[:environment])
49
- expect(subject.adam_id).to eq(options[:adam_id])
50
- expect(subject.app_item_id).to eq(options[:app_item_id])
51
- expect(subject.application_version).to eq(options[:application_version])
52
- expect(subject.download_id).to eq(options[:download_id])
53
- expect(subject.version_external_identifier).to eq(
54
- options[:version_external_identifier]
55
- )
56
- expect(subject.original_purchase_date).to eq(
57
- options[:original_purchase_date]
58
- )
59
- end
60
- end
61
- end
62
-
63
- describe '#add_purchase' do
64
- let(:receipt) { described_class.new(bundle_id: 'foobar') }
65
-
66
- subject { receipt.add_purchase(options) }
67
-
68
- context 'with minimal options' do
69
- let(:options) { { product_id: 'whatever' } }
70
-
71
- it 'creates an instance of Purchase' do
72
- expect(subject).to be_a(ItunesReceiptMock::Purchase)
73
- end
74
-
75
- it 'adds the purchase to the #in_app object' do
76
- expect(receipt.in_app[subject.transaction_id]).to eq(subject)
77
- end
78
- end
79
-
80
- context 'when product_id is not present' do
81
- let(:options) { {} }
82
-
83
- it 'raises an MissingArgumentError' do
84
- expect { subject }.to raise_error(
85
- ItunesReceiptMock::MissingArgumentError,
86
- 'product_id is required'
87
- )
88
- end
89
- end
90
- end
91
-
92
- describe '#add_subscription' do
93
- let(:receipt) { described_class.new(bundle_id: 'foobar') }
94
-
95
- subject { receipt.add_subscription(options) }
96
-
97
- context 'with minimal options' do
98
- let(:options) do
99
- {
100
- product_id: 'whatever',
101
- expires_date: 1.month.from_now
102
- }
103
- end
104
-
105
- it 'creates an instance of Subscription' do
106
- expect(subject).to be_a(ItunesReceiptMock::Subscription)
107
- end
108
-
109
- it 'adds the subscription to the #in_app object' do
110
- expect(receipt.in_app[subject.transaction_id]).to eq(subject)
111
- end
112
- end
113
-
114
- context 'when expires_date is not present' do
115
- let(:options) { { product_id: 'whatever' } }
116
-
117
- it 'raises an MissingArgumentError' do
118
- expect { subject }.to raise_error(
119
- ItunesReceiptMock::MissingArgumentError,
120
- 'expires_date is required'
121
- )
122
- end
123
- end
124
- end
125
-
126
- describe '#result' do
127
- let(:receipt) { described_class.new(bundle_id: 'foobar') }
128
- let(:options) { {} }
129
-
130
- subject { receipt.result(options) }
131
-
132
- it 'returns everything' do
133
- expect(subject['receipt_type']).to eq(receipt.environment)
134
- expect(subject['adam_id']).to eq(receipt.adam_id)
135
- expect(subject['app_item_id']).to eq(receipt.app_item_id)
136
- expect(subject['bundle_id']).to eq(receipt.bundle_id)
137
- expect(subject['application_version'])
138
- .to eq(receipt.application_version.to_s)
139
- expect(subject['download_id']).to eq(receipt.download_id)
140
- expect(subject['version_external_identifier'])
141
- .to eq(receipt.version_external_identifier)
142
- expect(subject['original_application_version'])
143
- .to eq(format('%.1f', receipt.original_application_version))
144
- expect(subject['in_app']).to be_a(Array)
145
- expect(subject['request_date'])
146
- .to eq(Time.now.utc.strftime('%F %T') + ' Etc/GMT')
147
- expect(subject['original_purchase_date'])
148
- .to eq(receipt.original_purchase_date.utc.strftime('%F %T') +
149
- ' Etc/GMT')
150
- end
151
-
152
- context 'when "request_date" is in options' do
153
- let(:options) { { request_date: rand(1..5).hours.ago } }
154
-
155
- it 'returns the request_date as specified' do
156
- expect(subject['request_date']).to eq(
157
- options[:request_date].utc.strftime('%F %T') + ' Etc/GMT'
158
- )
159
- end
160
- end
161
- end
162
- end
@@ -1,99 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe ItunesReceiptMock::Validation do
4
- describe '.new' do
5
- let(:options) { { bundle_id: 'foobar' } }
6
-
7
- subject { described_class.new(options) }
8
-
9
- it 'creates an instance of Receipt' do
10
- expect(subject.receipt).to be_a(ItunesReceiptMock::Receipt)
11
- end
12
- end
13
-
14
- describe '#result' do
15
- let(:validation) { described_class.new(bundle_id: 'foobar') }
16
-
17
- subject { validation.result(options) }
18
-
19
- context 'when status is 0' do
20
- let(:options) { { status: 0 } }
21
-
22
- it 'returns everything' do
23
- expect(subject['status']).to eq(0)
24
- expect(subject['environment']).to_not be_nil
25
- expect(subject['receipt']).to_not be_nil
26
- end
27
- end
28
-
29
- context 'when status is not 0' do
30
- let(:options) { { status: 1 } }
31
-
32
- it 'returns just the status' do
33
- expect(subject).to eq('status' => options[:status])
34
- end
35
- end
36
- end
37
-
38
- describe '#add_purchase' do
39
- let(:validation) { described_class.new(bundle_id: 'foobar') }
40
-
41
- subject { validation.add_purchase(product_id: 'foobar') }
42
-
43
- it 'adds the purchase to the #latest_receipt_info object' do
44
- expect(validation.latest_receipt_info[subject.transaction_id])
45
- .to eq(subject)
46
- end
47
- end
48
-
49
- describe '#add_subscription' do
50
- let(:validation) { described_class.new(bundle_id: 'foobar') }
51
-
52
- subject do
53
- validation.add_subscription product_id: 'foobar',
54
- expires_date: 1.month.from_now
55
- end
56
-
57
- it 'adds the subscription to the #latest_receipt_info object' do
58
- expect(validation.latest_receipt_info[subject.transaction_id])
59
- .to eq(subject)
60
- end
61
- end
62
-
63
- describe '#renew_subscription' do
64
- let(:validation) { described_class.new(bundle_id: 'foobar') }
65
- let(:subscription) do
66
- validation.add_subscription product_id: 'foobar',
67
- purchase_date: 1.month.ago,
68
- expires_date: Time.now
69
- end
70
-
71
- subject do
72
- validation.renew_subscription subscription,
73
- expires_date: 1.month.from_now
74
- end
75
-
76
- it 'removes the old transaction from #receipt#in_app' do
77
- expect(validation.receipt.in_app[subscription.transaction_id])
78
- .to eq(subscription)
79
- subject
80
- expect(validation.receipt.in_app[subscription.transaction_id])
81
- .to be_nil
82
- end
83
-
84
- it 'adds the new transaction to #receipt#in_app' do
85
- expect(validation.receipt.in_app[subject.transaction_id]).to eq(subject)
86
- end
87
-
88
- it 'adds the new tranaction to #latest_receipt_info' do
89
- expect(validation.latest_receipt_info[subject.transaction_id])
90
- .to eq(subject)
91
- end
92
-
93
- it 'preserves both transactions in #latest_receipt_info' do
94
- subject
95
- expect(validation.latest_receipt_info.values)
96
- .to match_array([subscription, subject])
97
- end
98
- end
99
- end