itunes-receipt-mock 0.0.5 → 0.1.0

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.
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