money 6.13.2 → 6.13.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,14 +0,0 @@
1
- # encoding: utf-8
2
-
3
- describe Money::LocaleBackend do
4
- describe '.find' do
5
- it 'returns an initialized backend' do
6
- expect(described_class.find(:legacy)).to be_a(Money::LocaleBackend::Legacy)
7
- expect(described_class.find(:i18n)).to be_a(Money::LocaleBackend::I18n)
8
- end
9
-
10
- it 'raises an error if a backend is unknown' do
11
- expect { described_class.find(:foo) }.to raise_error(Money::LocaleBackend::Unknown)
12
- end
13
- end
14
- end
@@ -1,894 +0,0 @@
1
- # encoding: utf-8
2
-
3
- describe Money do
4
- describe '.locale_backend' do
5
- after { Money.locale_backend = :legacy }
6
-
7
- it 'sets the locale_backend' do
8
- Money.locale_backend = :i18n
9
-
10
- expect(Money.locale_backend).to be_a(Money::LocaleBackend::I18n)
11
- end
12
-
13
- it 'sets the locale_backend to nil' do
14
- Money.locale_backend = nil
15
-
16
- expect(Money.locale_backend).to eq(nil)
17
- end
18
- end
19
-
20
- describe ".new" do
21
- let(:initializing_value) { 1 }
22
- subject(:money) { Money.new(initializing_value) }
23
-
24
- it "should be an instance of `Money::Bank::VariableExchange`" do
25
- expect(money.bank).to be Money::Bank::VariableExchange.instance
26
- end
27
-
28
- context 'given the initializing value is an integer' do
29
- let(:initializing_value) { Integer(1) }
30
- it 'stores the integer as the number of cents' do
31
- expect(money.cents).to eq initializing_value
32
- end
33
- end
34
-
35
- context 'given the initializing value is a float' do
36
- context 'and the value is 1.00' do
37
- let(:initializing_value) { 1.00 }
38
- it { is_expected.to eq Money.new(1) }
39
- end
40
-
41
- context 'and the value is 1.01' do
42
- let(:initializing_value) { 1.01 }
43
- it { is_expected.to eq Money.new(1) }
44
- end
45
-
46
- context 'and the value is 1.50' do
47
- let(:initializing_value) { 1.50 }
48
- it { is_expected.to eq Money.new(2) }
49
- end
50
- end
51
-
52
- context 'given the initializing value is a rational' do
53
- let(:initializing_value) { Rational(1) }
54
- it { is_expected.to eq Money.new(1) }
55
- end
56
-
57
- context 'given the initializing value is money' do
58
- let(:initializing_value) { Money.new(1_00, Money::Currency.new('NZD')) }
59
- it { is_expected.to eq initializing_value }
60
- end
61
-
62
- context "given the initializing value doesn't respond to .to_d" do
63
- let(:initializing_value) { :"1" }
64
- it { is_expected.to eq Money.new(1) }
65
- end
66
-
67
- context 'given a currency is not provided' do
68
- subject(:money) { Money.new(initializing_value) }
69
-
70
- it "should have the default currency" do
71
- expect(money.currency).to eq Money.default_currency
72
- end
73
- end
74
-
75
- context 'given a currency is provided' do
76
- subject(:money) { Money.new(initializing_value, currency) }
77
-
78
- context 'and the currency is NZD' do
79
- let(:currency) { Money::Currency.new('NZD') }
80
-
81
- it "should have NZD currency" do
82
- expect(money.currency).to eq Money::Currency.new('NZD')
83
- end
84
- end
85
-
86
- context 'and the currency is nil' do
87
- let(:currency) { nil }
88
-
89
- it "should have the default currency" do
90
- expect(money.currency).to eq Money.default_currency
91
- end
92
- end
93
- end
94
-
95
- context 'non-finite value is given' do
96
- let(:error) { 'must be initialized with a finite value' }
97
-
98
- it 'raises an error when trying to initialize with Infinity' do
99
- expect { Money.new('Infinity') }.to raise_error(ArgumentError, error)
100
- expect { Money.new(BigDecimal('Infinity')) }.to raise_error(ArgumentError, error)
101
- end
102
-
103
- it 'raises an error when trying to initialize with NaN' do
104
- expect { Money.new('NaN') }.to raise_error(ArgumentError, error)
105
- expect { Money.new(BigDecimal('NaN')) }.to raise_error(ArgumentError, error)
106
- end
107
- end
108
-
109
- context "with infinite_precision", :infinite_precision do
110
- context 'given the initializing value is 1.50' do
111
- let(:initializing_value) { 1.50 }
112
-
113
- it "should have the correct cents" do
114
- expect(money.cents).to eq BigDecimal('1.50')
115
- end
116
- end
117
- end
118
- end
119
-
120
- describe ".add_rate" do
121
- before do
122
- @default_bank = Money.default_bank
123
- Money.default_bank = Money::Bank::VariableExchange.new
124
- end
125
-
126
- after do
127
- Money.default_bank = @default_bank
128
- end
129
-
130
- it "saves rate into current bank" do
131
- Money.add_rate("EUR", "USD", 10)
132
- expect(Money.new(10_00, "EUR").exchange_to("USD")).to eq Money.new(100_00, "USD")
133
- end
134
- end
135
-
136
- describe ".disallow_currency_conversions!" do
137
- before do
138
- @default_bank = Money.default_bank
139
- end
140
-
141
- after do
142
- Money.default_bank = @default_bank
143
- end
144
-
145
- it "disallows conversions when doing money arithmetic" do
146
- Money.disallow_currency_conversion!
147
- expect { Money.new(100, "USD") + Money.new(100, "EUR") }.to raise_exception(Money::Bank::DifferentCurrencyError)
148
- end
149
- end
150
-
151
- describe ".from_amount" do
152
- it "accepts numeric values" do
153
- expect(Money.from_amount(1, "USD")).to eq Money.new(1_00, "USD")
154
- expect(Money.from_amount(1.0, "USD")).to eq Money.new(1_00, "USD")
155
- expect(Money.from_amount("1".to_d, "USD")).to eq Money.new(1_00, "USD")
156
- end
157
-
158
- it "raises ArgumentError with unsupported argument" do
159
- expect { Money.from_amount("1") }.to raise_error(ArgumentError)
160
- expect { Money.from_amount(Object.new) }.to raise_error(ArgumentError)
161
- end
162
-
163
- it "converts given amount to subunits according to currency" do
164
- expect(Money.from_amount(1, "USD")).to eq Money.new(1_00, "USD")
165
- expect(Money.from_amount(1, "TND")).to eq Money.new(1_000, "TND")
166
- expect(Money.from_amount(1, "JPY")).to eq Money.new(1, "JPY")
167
- end
168
-
169
- it "rounds the given amount to subunits" do
170
- expect(Money.from_amount(4.444, "USD").amount).to eq "4.44".to_d
171
- expect(Money.from_amount(5.555, "USD").amount).to eq "5.56".to_d
172
- expect(Money.from_amount(444.4, "JPY").amount).to eq "444".to_d
173
- expect(Money.from_amount(555.5, "JPY").amount).to eq "556".to_d
174
- end
175
-
176
- it "does not round the given amount when infinite_precision is set", :infinite_precision do
177
- expect(Money.from_amount(4.444, "USD").amount).to eq "4.444".to_d
178
- expect(Money.from_amount(5.555, "USD").amount).to eq "5.555".to_d
179
- expect(Money.from_amount(444.4, "JPY").amount).to eq "444.4".to_d
180
- expect(Money.from_amount(555.5, "JPY").amount).to eq "555.5".to_d
181
- end
182
-
183
- it "accepts an optional currency" do
184
- expect(Money.from_amount(1).currency).to eq Money.default_currency
185
- jpy = Money::Currency.wrap("JPY")
186
- expect(Money.from_amount(1, jpy).currency).to eq jpy
187
- expect(Money.from_amount(1, "JPY").currency).to eq jpy
188
- end
189
-
190
- it "accepts an optional bank" do
191
- expect(Money.from_amount(1).bank).to eq Money.default_bank
192
- bank = double "bank"
193
- expect(Money.from_amount(1, "USD", bank).bank).to eq bank
194
- end
195
-
196
- it 'rounds using rounding_mode' do
197
- expect(Money.from_amount(1.999).to_d).to eq 2
198
- expect(Money.rounding_mode(BigDecimal::ROUND_DOWN) do
199
- Money.from_amount(1.999).to_d
200
- end).to eq 1.99
201
- end
202
-
203
- context 'given a currency is provided' do
204
- context 'and the currency is nil' do
205
- let(:currency) { nil }
206
-
207
- it "should have the default currency" do
208
- expect(Money.from_amount(1, currency).currency).to eq Money.default_currency
209
- end
210
- end
211
- end
212
- end
213
-
214
- %w[cents pence].each do |units|
215
- describe "##{units}" do
216
- it "is a synonym of #fractional" do
217
- expectation = Money.new(0)
218
- def expectation.fractional
219
- "expectation"
220
- end
221
- expect(expectation.cents).to eq "expectation"
222
- end
223
- end
224
- end
225
-
226
- describe "#fractional" do
227
- it "returns the amount in fractional unit" do
228
- expect(Money.new(1_00).fractional).to eq 1_00
229
- end
230
-
231
- it "stores fractional as an integer regardless of what is passed into the constructor" do
232
- m = Money.new(100)
233
- expect(m.fractional).to eq 100
234
- expect(m.fractional).to be_a(Integer)
235
- end
236
-
237
- context "loading a serialized Money via YAML" do
238
-
239
- let(:serialized) { <<YAML
240
- !ruby/object:Money
241
- fractional: 249.5
242
- currency: !ruby/object:Money::Currency
243
- id: :eur
244
- priority: 2
245
- iso_code: EUR
246
- name: Euro
247
- symbol: €
248
- alternate_symbols: []
249
- subunit: Cent
250
- subunit_to_unit: 100
251
- symbol_first: true
252
- html_entity: ! '&#x20AC;'
253
- decimal_mark: ! ','
254
- thousands_separator: .
255
- iso_numeric: '978'
256
- mutex: !ruby/object:Mutex {}
257
- last_updated: 2012-11-23 20:41:47.454438399 +02:00
258
- YAML
259
- }
260
-
261
- it "uses BigDecimal when rounding" do
262
- m = YAML::load serialized
263
- expect(m).to be_a(Money)
264
- expect(m.class.infinite_precision).to be false
265
- expect(m.fractional).to eq 250 # 249.5 rounded up
266
- expect(m.fractional).to be_a(Integer)
267
- end
268
-
269
- it "is a BigDecimal when using infinite_precision", :infinite_precision do
270
- money = YAML::load serialized
271
- expect(money.fractional).to be_a BigDecimal
272
- end
273
- end
274
-
275
- context "user changes rounding_mode" do
276
- after do
277
- Money.rounding_mode = BigDecimal::ROUND_HALF_EVEN
278
- end
279
-
280
- context "with the setter" do
281
- it "respects the rounding_mode" do
282
- Money.rounding_mode = BigDecimal::ROUND_DOWN
283
- expect(Money.new(1.9).fractional).to eq 1
284
-
285
- Money.rounding_mode = BigDecimal::ROUND_UP
286
- expect(Money.new(1.1).fractional).to eq 2
287
- end
288
- end
289
-
290
- context "with a block" do
291
- it "respects the rounding_mode" do
292
- expect(Money.rounding_mode(BigDecimal::ROUND_DOWN) do
293
- Money.new(1.9).fractional
294
- end).to eq 1
295
-
296
- expect(Money.rounding_mode(BigDecimal::ROUND_UP) do
297
- Money.new(1.1).fractional
298
- end).to eq 2
299
-
300
- expect(Money.rounding_mode).to eq BigDecimal::ROUND_HALF_EVEN
301
- end
302
-
303
- it "works for multiplication within a block" do
304
- Money.rounding_mode(BigDecimal::ROUND_DOWN) do
305
- expect((Money.new(1_00) * "0.019".to_d).fractional).to eq 1
306
- end
307
-
308
- Money.rounding_mode(BigDecimal::ROUND_UP) do
309
- expect((Money.new(1_00) * "0.011".to_d).fractional).to eq 2
310
- end
311
-
312
- expect(Money.rounding_mode).to eq BigDecimal::ROUND_HALF_EVEN
313
- end
314
- end
315
- end
316
-
317
- context "with infinite_precision", :infinite_precision do
318
- it "returns the amount in fractional unit" do
319
- expect(Money.new(1_00).fractional).to eq BigDecimal("100")
320
- end
321
-
322
- it "stores in fractional unit as an integer regardless of what is passed into the constructor" do
323
- m = Money.new(100)
324
- expect(m.fractional).to eq BigDecimal("100")
325
- expect(m.fractional).to be_a(BigDecimal)
326
- end
327
- end
328
- end
329
-
330
- describe "#round_to_nearest_cash_value" do
331
- it "rounds to the nearest possible cash value" do
332
- money = Money.new(2350, "AED")
333
- expect(money.round_to_nearest_cash_value).to eq 2350
334
-
335
- money = Money.new(-2350, "AED")
336
- expect(money.round_to_nearest_cash_value).to eq(-2350)
337
-
338
- money = Money.new(2213, "AED")
339
- expect(money.round_to_nearest_cash_value).to eq 2225
340
-
341
- money = Money.new(-2213, "AED")
342
- expect(money.round_to_nearest_cash_value).to eq(-2225)
343
-
344
- money = Money.new(2212, "AED")
345
- expect(money.round_to_nearest_cash_value).to eq 2200
346
-
347
- money = Money.new(-2212, "AED")
348
- expect(money.round_to_nearest_cash_value).to eq(-2200)
349
-
350
- money = Money.new(178, "CHF")
351
- expect(money.round_to_nearest_cash_value).to eq 180
352
-
353
- money = Money.new(-178, "CHF")
354
- expect(money.round_to_nearest_cash_value).to eq(-180)
355
-
356
- money = Money.new(177, "CHF")
357
- expect(money.round_to_nearest_cash_value).to eq 175
358
-
359
- money = Money.new(-177, "CHF")
360
- expect(money.round_to_nearest_cash_value).to eq(-175)
361
-
362
- money = Money.new(175, "CHF")
363
- expect(money.round_to_nearest_cash_value).to eq 175
364
-
365
- money = Money.new(-175, "CHF")
366
- expect(money.round_to_nearest_cash_value).to eq(-175)
367
-
368
- money = Money.new(299, "USD")
369
- expect(money.round_to_nearest_cash_value).to eq 299
370
-
371
- money = Money.new(-299, "USD")
372
- expect(money.round_to_nearest_cash_value).to eq(-299)
373
-
374
- money = Money.new(300, "USD")
375
- expect(money.round_to_nearest_cash_value).to eq 300
376
-
377
- money = Money.new(-300, "USD")
378
- expect(money.round_to_nearest_cash_value).to eq(-300)
379
-
380
- money = Money.new(301, "USD")
381
- expect(money.round_to_nearest_cash_value).to eq 301
382
-
383
- money = Money.new(-301, "USD")
384
- expect(money.round_to_nearest_cash_value).to eq(-301)
385
- end
386
-
387
- it "raises an exception if smallest denomination is not defined" do
388
- money = Money.new(100, "XAG")
389
- expect {money.round_to_nearest_cash_value}.to raise_error(Money::UndefinedSmallestDenomination)
390
- end
391
-
392
- it "returns a Integer when infinite_precision is not set" do
393
- money = Money.new(100, "USD")
394
- expect(money.round_to_nearest_cash_value).to be_a Integer
395
- end
396
-
397
- it "returns a BigDecimal when infinite_precision is set", :infinite_precision do
398
- money = Money.new(100, "EUR")
399
- expect(money.round_to_nearest_cash_value).to be_a BigDecimal
400
- end
401
- end
402
-
403
- describe "#amount" do
404
- it "returns the amount of cents as dollars" do
405
- expect(Money.new(1_00).amount).to eq 1
406
- end
407
-
408
- it "respects :subunit_to_unit currency property" do
409
- expect(Money.new(1_00, "USD").amount).to eq 1
410
- expect(Money.new(1_000, "TND").amount).to eq 1
411
- expect(Money.new(1, "VUV").amount).to eq 1
412
- expect(Money.new(1, "CLP").amount).to eq 1
413
- end
414
-
415
- it "does not lose precision" do
416
- expect(Money.new(100_37).amount).to eq 100.37
417
- end
418
-
419
- it 'produces a BigDecimal' do
420
- expect(Money.new(1_00).amount).to be_a BigDecimal
421
- end
422
- end
423
-
424
- describe "#dollars" do
425
- it "is synonym of #amount" do
426
- m = Money.new(0)
427
-
428
- # Make a small expectation
429
- def m.amount
430
- 5
431
- end
432
-
433
- expect(m.dollars).to eq 5
434
- end
435
- end
436
-
437
- describe "#currency" do
438
- it "returns the currency object" do
439
- expect(Money.new(1_00, "USD").currency).to eq Money::Currency.new("USD")
440
- end
441
- end
442
-
443
- describe "#currency_as_string" do
444
- it "returns the iso_code of the currency object" do
445
- expect(Money.new(1_00, "USD").currency_as_string).to eq "USD"
446
- expect(Money.new(1_00, "EUR").currency_as_string).to eq "EUR"
447
- end
448
- end
449
-
450
- describe "#currency_as_string=" do
451
- it "sets the currency object using the provided string leaving cents intact" do
452
- money = Money.new(100_00, "USD")
453
-
454
- money.currency_as_string = "EUR"
455
- expect(money.currency).to eq Money::Currency.new("EUR")
456
- expect(money.cents).to eq 100_00
457
-
458
- money.currency_as_string = "YEN"
459
- expect(money.currency).to eq Money::Currency.new("YEN")
460
- expect(money.cents).to eq 100_00
461
- end
462
- end
463
-
464
- describe "#hash=" do
465
- it "returns the same value for equal objects" do
466
- expect(Money.new(1_00, "EUR").hash).to eq Money.new(1_00, "EUR").hash
467
- expect(Money.new(2_00, "USD").hash).to eq Money.new(2_00, "USD").hash
468
- expect(Money.new(1_00, "EUR").hash).not_to eq Money.new(2_00, "EUR").hash
469
- expect(Money.new(1_00, "EUR").hash).not_to eq Money.new(1_00, "USD").hash
470
- expect(Money.new(1_00, "EUR").hash).not_to eq Money.new(2_00, "USD").hash
471
- end
472
-
473
- it "can be used to return the intersection of Money object arrays" do
474
- intersection = [Money.new(1_00, "EUR"), Money.new(1_00, "USD")] & [Money.new(1_00, "EUR")]
475
- expect(intersection).to eq [Money.new(1_00, "EUR")]
476
- end
477
- end
478
-
479
- describe "#symbol" do
480
- it "works as documented" do
481
- currency = Money::Currency.new("EUR")
482
- expect(currency).to receive(:symbol).and_return("€")
483
- expect(Money.new(0, currency).symbol).to eq "€"
484
-
485
- currency = Money::Currency.new("EUR")
486
- expect(currency).to receive(:symbol).and_return(nil)
487
- expect(Money.new(0, currency).symbol).to eq "¤"
488
- end
489
- end
490
-
491
- describe "#to_s" do
492
- it "works as documented" do
493
- expect(Money.new(10_00).to_s).to eq "10.00"
494
- expect(Money.new(400_08).to_s).to eq "400.08"
495
- expect(Money.new(-237_43).to_s).to eq "-237.43"
496
- end
497
-
498
- it "respects :subunit_to_unit currency property" do
499
- expect(Money.new(10_00, "BHD").to_s).to eq "1.000"
500
- expect(Money.new(10_00, "CNY").to_s).to eq "10.00"
501
- end
502
-
503
- it "does not have decimal when :subunit_to_unit == 1" do
504
- expect(Money.new(10_00, "VUV").to_s).to eq "1000"
505
- end
506
-
507
- it "does not work when :subunit_to_unit == 5" do
508
- expect(Money.new(10_00, "MGA").to_s).to eq "200.0"
509
- end
510
-
511
- it "respects :decimal_mark" do
512
- expect(Money.new(10_00, "BRL").to_s).to eq "10,00"
513
- end
514
-
515
- context "using i18n" do
516
- before { I18n.backend.store_translations(:en, number: { format: { separator: "." } }) }
517
- after { reset_i18n }
518
-
519
- it "respects decimal mark" do
520
- expect(Money.new(10_00, "BRL").to_s).to eq "10.00"
521
- end
522
- end
523
-
524
- context "with defaults set" do
525
- before { Money.default_formatting_rules = { with_currency: true } }
526
- after { Money.default_formatting_rules = nil }
527
-
528
- it "ignores defaults" do
529
- expect(Money.new(10_00, 'USD').to_s).to eq '10.00'
530
- end
531
- end
532
-
533
- context "with infinite_precision", :infinite_precision do
534
- it "shows fractional cents" do
535
- expect(Money.new(1.05, "USD").to_s).to eq "0.0105"
536
- end
537
-
538
- it "suppresses fractional cents when there is none" do
539
- expect(Money.new(1.0, "USD").to_s).to eq "0.01"
540
- end
541
-
542
- it "shows fractional if needed when :subunut_to_unit == 1" do
543
- expect(Money.new(10_00.1, "VUV").to_s).to eq "1000.1"
544
- end
545
- end
546
- end
547
-
548
- describe "#to_d" do
549
- it "works as documented" do
550
- decimal = Money.new(10_00).to_d
551
- expect(decimal).to be_a(BigDecimal)
552
- expect(decimal).to eq 10.0
553
- end
554
-
555
- it "respects :subunit_to_unit currency property" do
556
- decimal = Money.new(10_00, "BHD").to_d
557
- expect(decimal).to be_a(BigDecimal)
558
- expect(decimal).to eq 1.0
559
- end
560
-
561
- it "works with float :subunit_to_unit currency property" do
562
- money = Money.new(10_00, "BHD")
563
- allow(money.currency).to receive(:subunit_to_unit).and_return(1000.0)
564
-
565
- decimal = money.to_d
566
- expect(decimal).to be_a(BigDecimal)
567
- expect(decimal).to eq 1.0
568
- end
569
- end
570
-
571
- describe "#to_f" do
572
- it "works as documented" do
573
- expect(Money.new(10_00).to_f).to eq 10.0
574
- end
575
-
576
- it "respects :subunit_to_unit currency property" do
577
- expect(Money.new(10_00, "BHD").to_f).to eq 1.0
578
- end
579
- end
580
-
581
- describe "#to_i" do
582
- it "works as documented" do
583
- expect(Money.new(10_00).to_i).to eq 10
584
- end
585
-
586
- it "respects :subunit_to_unit currency property" do
587
- expect(Money.new(10_00, "BHD").to_i).to eq 1
588
- end
589
- end
590
-
591
- describe "#to_money" do
592
- it "works as documented" do
593
- money = Money.new(10_00, "DKK")
594
- expect(money).to eq money.to_money
595
- expect(money).to eq money.to_money("DKK")
596
- expect(money.bank).to receive(:exchange_with).with(Money.new(10_00, Money::Currency.new("DKK")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR')))
597
- expect(money.to_money("EUR")).to eq Money.new(200_00, "EUR")
598
- end
599
- end
600
-
601
- describe "#with_currency" do
602
- it 'returns self if currency is the same' do
603
- money = Money.new(10_00, 'USD')
604
-
605
- expect(money.with_currency('USD')).to eq(money)
606
- expect(money.with_currency('USD').object_id).to eq(money.object_id)
607
- end
608
-
609
- it 'returns a new instance in a given currency' do
610
- money = Money.new(10_00, 'USD')
611
- new_money = money.with_currency('EUR')
612
-
613
- expect(new_money).to eq(Money.new(10_00, 'EUR'))
614
- expect(money.fractional).to eq(new_money.fractional)
615
- expect(money.bank).to eq(new_money.bank)
616
- expect(money.object_id).not_to eq(new_money.object_id)
617
- end
618
- end
619
-
620
- describe "#exchange_to" do
621
- it "exchanges the amount via its exchange bank" do
622
- money = Money.new(100_00, "USD")
623
- expect(money.bank).to receive(:exchange_with).with(Money.new(100_00, Money::Currency.new("USD")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR')))
624
- money.exchange_to("EUR")
625
- end
626
-
627
- it "exchanges the amount properly" do
628
- money = Money.new(100_00, "USD")
629
- expect(money.bank).to receive(:exchange_with).with(Money.new(100_00, Money::Currency.new("USD")), Money::Currency.new("EUR")).and_return(Money.new(200_00, Money::Currency.new('EUR')))
630
- expect(money.exchange_to("EUR")).to eq Money.new(200_00, "EUR")
631
- end
632
-
633
- it 'uses the block given as rounding method' do
634
- money = Money.new(100_00, 'USD')
635
- expect(money.bank).to receive(:exchange_with).and_yield(300_00)
636
- expect { |block| money.exchange_to(Money::Currency.new('EUR'), &block) }.to yield_successive_args(300_00)
637
- end
638
-
639
- it "does no exchange when the currencies are the same" do
640
- money = Money.new(100_00, "USD")
641
- expect(money.bank).to_not receive(:exchange_with)
642
- expect(money.exchange_to("USD")).to eq money
643
- end
644
- end
645
-
646
- describe "#allocate" do
647
- it "takes no action when one gets all" do
648
- expect(Money.us_dollar(005).allocate([1.0])).to eq [Money.us_dollar(5)]
649
- end
650
-
651
- it "keeps currencies intact" do
652
- expect(Money.ca_dollar(005).allocate([1])).to eq [Money.ca_dollar(5)]
653
- end
654
-
655
- it "does not lose pennies" do
656
- moneys = Money.us_dollar(5).allocate([0.3, 0.7])
657
- expect(moneys[0]).to eq Money.us_dollar(2)
658
- expect(moneys[1]).to eq Money.us_dollar(3)
659
- end
660
-
661
- it "handles small splits" do
662
- moneys = Money.us_dollar(5).allocate([0.03, 0.07])
663
- expect(moneys[0]).to eq Money.us_dollar(2)
664
- expect(moneys[1]).to eq Money.us_dollar(3)
665
- end
666
-
667
- it "handles large splits" do
668
- moneys = Money.us_dollar(5).allocate([3, 7])
669
- expect(moneys[0]).to eq Money.us_dollar(2)
670
- expect(moneys[1]).to eq Money.us_dollar(3)
671
- end
672
-
673
- it "does not lose pennies" do
674
- moneys = Money.us_dollar(100).allocate([0.333, 0.333, 0.333])
675
- expect(moneys[0].cents).to eq 34
676
- expect(moneys[1].cents).to eq 33
677
- expect(moneys[2].cents).to eq 33
678
- end
679
-
680
- it "does not round rationals" do
681
- splits = 7.times.map { Rational(950, 6650) }
682
- moneys = Money.us_dollar(6650).allocate(splits)
683
- moneys.each do |money|
684
- expect(money.cents).to eq 950
685
- end
686
- end
687
-
688
- it "handles mixed split types" do
689
- splits = [Rational(1, 4), 0.25, 0.25, BigDecimal('0.25')]
690
- moneys = Money.us_dollar(100).allocate(splits)
691
- moneys.each do |money|
692
- expect(money.cents).to eq 25
693
- end
694
- end
695
-
696
- context "negative amount" do
697
- it "does not lose pennies" do
698
- moneys = Money.us_dollar(-100).allocate([0.333, 0.333, 0.333])
699
-
700
- expect(moneys[0].cents).to eq(-34)
701
- expect(moneys[1].cents).to eq(-33)
702
- expect(moneys[2].cents).to eq(-33)
703
- end
704
-
705
- it "allocates the same way as positive amounts" do
706
- ratios = [0.6667, 0.3333]
707
-
708
- expect(Money.us_dollar(10_00).allocate(ratios).map(&:fractional)).to eq([6_67, 3_33])
709
- expect(Money.us_dollar(-10_00).allocate(ratios).map(&:fractional)).to eq([-6_67, -3_33])
710
- end
711
- end
712
-
713
- it "keeps subclasses intact" do
714
- special_money_class = Class.new(Money)
715
- expect(special_money_class.new(005).allocate([1]).first).to be_a special_money_class
716
- end
717
-
718
- context "with infinite_precision", :infinite_precision do
719
- it "allows for fractional cents allocation" do
720
- moneys = Money.new(100).allocate([1, 1, 1])
721
- expect(moneys.inject(0, :+)).to eq(Money.new(100))
722
- end
723
- end
724
- end
725
-
726
- describe "#split" do
727
- it "needs at least one party" do
728
- expect { Money.us_dollar(1).split(0) }.to raise_error(ArgumentError)
729
- expect { Money.us_dollar(1).split(-1) }.to raise_error(ArgumentError)
730
- end
731
-
732
- it "gives 1 cent to both people if we start with 2" do
733
- expect(Money.us_dollar(2).split(2)).to eq [Money.us_dollar(1), Money.us_dollar(1)]
734
- end
735
-
736
- it "may distribute no money to some parties if there isnt enough to go around" do
737
- expect(Money.us_dollar(2).split(3)).to eq [Money.us_dollar(1), Money.us_dollar(1), Money.us_dollar(0)]
738
- end
739
-
740
- it "does not lose pennies" do
741
- expect(Money.us_dollar(5).split(2)).to eq [Money.us_dollar(3), Money.us_dollar(2)]
742
- end
743
-
744
- it "splits a dollar" do
745
- moneys = Money.us_dollar(100).split(3)
746
- expect(moneys[0].cents).to eq 34
747
- expect(moneys[1].cents).to eq 33
748
- expect(moneys[2].cents).to eq 33
749
- end
750
-
751
- it "preserves the class in the result when using a subclass of Money" do
752
- special_money_class = Class.new(Money)
753
- expect(special_money_class.new(10_00).split(1).first).to be_a special_money_class
754
- end
755
-
756
- context "with infinite_precision", :infinite_precision do
757
- it "allows for splitting by fractional cents" do
758
- moneys = Money.new(100).split(3)
759
- expect(moneys.inject(0, :+)).to eq(Money.new(100))
760
- end
761
- end
762
- end
763
-
764
- describe "#round" do
765
- let(:money) { Money.new(15.75, 'NZD') }
766
- subject(:rounded) { money.round }
767
-
768
- context "without infinite_precision" do
769
- it "returns a different money" do
770
- expect(rounded).not_to be money
771
- end
772
-
773
- it "rounds the cents" do
774
- expect(rounded.cents).to eq 16
775
- end
776
-
777
- it "maintains the currency" do
778
- expect(rounded.currency).to eq Money::Currency.new('NZD')
779
- end
780
-
781
- it "uses a provided rounding strategy" do
782
- rounded = money.round(BigDecimal::ROUND_DOWN)
783
- expect(rounded.cents).to eq 15
784
- end
785
-
786
- it "does not accumulate rounding error" do
787
- money_1 = Money.new(10.9).round(BigDecimal::ROUND_DOWN)
788
- money_2 = Money.new(10.9).round(BigDecimal::ROUND_DOWN)
789
-
790
- expect(money_1 + money_2).to eq(Money.new(20))
791
- end
792
- end
793
-
794
- context "with infinite_precision", :infinite_precision do
795
- it "returns a different money" do
796
- expect(rounded).not_to be money
797
- end
798
-
799
- it "rounds the cents" do
800
- expect(rounded.cents).to eq 16
801
- end
802
-
803
- it "maintains the currency" do
804
- expect(rounded.currency).to eq Money::Currency.new('NZD')
805
- end
806
-
807
- it "uses a provided rounding strategy" do
808
- rounded = money.round(BigDecimal::ROUND_DOWN)
809
- expect(rounded.cents).to eq 15
810
- end
811
-
812
- context "when using a specific rounding precision" do
813
- let(:money) { Money.new(15.7526, 'NZD') }
814
-
815
- it "uses the provided rounding precision" do
816
- rounded = money.round(BigDecimal::ROUND_DOWN, 3)
817
- expect(rounded.fractional).to eq 15.752
818
- end
819
- end
820
- end
821
-
822
- it 'preserves assigned bank' do
823
- bank = Money::Bank::VariableExchange.new
824
- rounded = Money.new(1_00, 'USD', bank).round
825
-
826
- expect(rounded.bank).to eq(bank)
827
- end
828
-
829
- context "when using a subclass of Money" do
830
- let(:special_money_class) { Class.new(Money) }
831
- let(:money) { special_money_class.new(15.75, 'NZD') }
832
-
833
- it "preserves the class in the result" do
834
- expect(rounded).to be_a special_money_class
835
- end
836
- end
837
- end
838
-
839
- describe "#inspect" do
840
- it "reports the class name properly when using inheritance" do
841
- expect(Money.new(1).inspect).to start_with '#<Money'
842
- Subclass = Class.new(Money)
843
- expect(Subclass.new(1).inspect).to start_with '#<Subclass'
844
- end
845
- end
846
-
847
- describe "#as_*" do
848
- before do
849
- Money.default_bank = Money::Bank::VariableExchange.new
850
- Money.add_rate("EUR", "USD", 1)
851
- Money.add_rate("EUR", "CAD", 1)
852
- Money.add_rate("USD", "EUR", 1)
853
- end
854
-
855
- after do
856
- Money.default_bank = Money::Bank::VariableExchange.instance
857
- end
858
-
859
- specify "as_us_dollar converts Money object to USD" do
860
- obj = Money.new(1, "EUR")
861
- expect(obj.as_us_dollar).to eq Money.new(1, "USD")
862
- end
863
-
864
- specify "as_ca_dollar converts Money object to CAD" do
865
- obj = Money.new(1, "EUR")
866
- expect(obj.as_ca_dollar).to eq Money.new(1, "CAD")
867
- end
868
-
869
- specify "as_euro converts Money object to EUR" do
870
- obj = Money.new(1, "USD")
871
- expect(obj.as_euro).to eq Money.new(1, "EUR")
872
- end
873
- end
874
-
875
- describe ".default_currency" do
876
- before do
877
- @default_currency = Money.default_currency
878
- end
879
-
880
- after do
881
- Money.default_currency = @default_currency
882
- end
883
-
884
- it "accepts a lambda" do
885
- Money.default_currency = lambda { :eur }
886
- expect(Money.default_currency).to eq Money::Currency.new(:eur)
887
- end
888
-
889
- it "accepts a symbol" do
890
- Money.default_currency = :eur
891
- expect(Money.default_currency).to eq Money::Currency.new(:eur)
892
- end
893
- end
894
- end