money 3.6.1 → 3.6.2

Sign up to get free protection for your applications and to get access to all the features.
data/spec/money_spec.rb CHANGED
@@ -1,1268 +1,271 @@
1
- # encoding: utf-8
2
-
3
- require "spec_helper"
4
-
5
- describe Money do
6
-
7
- describe "#new" do
8
- it "rounds the given cents to an integer" do
9
- Money.new(1.00, "USD").cents.should == 1
10
- Money.new(1.01, "USD").cents.should == 1
11
- Money.new(1.50, "USD").cents.should == 2
12
- end
13
-
14
- it "is associated to the singleton instance of Bank::VariableExchange by default" do
15
- Money.new(0).bank.should be_equal(Money::Bank::VariableExchange.instance)
16
- end
17
-
18
- end
19
-
20
- describe "#cents" do
21
- it "returns the amount of cents passed to the constructor" do
22
- Money.new(200_00, "USD").cents.should == 200_00
23
- end
24
-
25
- it "stores cents as an integer regardless of what is passed into the constructor" do
26
- [ Money.new(100), 1.to_money, 1.00.to_money, BigDecimal('1.00').to_money ].each do |m|
27
- m.cents.should == 100
28
- m.cents.should be_an_instance_of(Fixnum)
29
- end
30
- end
31
- end
32
-
33
- describe "#dollars" do
34
- it "gets cents as dollars" do
35
- Money.new_with_dollars(1).should == Money.new(100)
36
- Money.new_with_dollars(1, "USD").should == Money.new(100, "USD")
37
- Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR")
38
- end
39
-
40
- it "should respect :subunit_to_unit currency property" do
41
- Money.new(1_00, "USD").dollars.should == 1
42
- Money.new(1_000, "TND").dollars.should == 1
43
- Money.new(1, "CLP").dollars.should == 1
44
- end
45
-
46
- it "should not loose precision" do
47
- Money.new(100_37).dollars.should == 100.37
48
- Money.new_with_dollars(100.37).dollars.should == 100.37
49
- end
50
- end
51
-
52
- specify "#currency returns the currency passed to the constructor" do
53
- Money.new(200_00, "USD").currency.should == Money::Currency.new("USD")
54
- end
55
-
56
- specify "#currency_string returns the iso_code of the currency object" do
57
- Money.new(200_00, "USD").currency_as_string.should == Money::Currency.new("USD").to_s
58
- Money.new(200_00, "USD").currency_as_string.should == "USD"
59
- Money.new(200_00, "EUR").currency_as_string.should == "EUR"
60
- Money.new(200_00, "YEN").currency_as_string.should == "YEN"
61
- end
62
-
63
- specify "#currency_string= set the currency object using the provided string" do
64
- obj = Money.new(200_00, "USD")
65
- obj.currency_as_string = "EUR"
66
- obj.currency.should == Money::Currency.new("EUR")
67
- obj.currency_as_string = "YEN"
68
- obj.currency.should == Money::Currency.new("YEN")
69
- obj.currency_as_string = "USD"
70
- obj.currency.should == Money::Currency.new("USD")
71
- end
72
-
73
- specify "#zero? returns whether the amount is 0" do
74
- Money.new(0, "USD").should be_zero
75
- Money.new(0, "EUR").should be_zero
76
- Money.new(1, "USD").should_not be_zero
77
- Money.new(10, "YEN").should_not be_zero
78
- Money.new(-1, "EUR").should_not be_zero
79
- end
80
-
81
- specify "#nonzero? returns whether the amount is not 0" do
82
- Money.new(0, "USD").should_not be_nonzero
83
- Money.new(0, "EUR").should_not be_nonzero
84
- Money.new(1, "USD").should be_nonzero
85
- Money.new(10, "YEN").should be_nonzero
86
- Money.new(-1, "EUR").should be_nonzero
87
- end
88
-
89
- specify "#nonzero? has the same return-value semantics as Numeric#nonzero?" do
90
- Money.new(0, "USD").nonzero?.should be_nil
91
-
92
- money = Money.new(1, "USD")
93
- money.nonzero?.should be_equal(money)
94
- end
95
-
96
- specify "#exchange_to exchanges the amount via its exchange bank" do
97
- money = Money.new(100_00, "USD")
98
- money.bank.should_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')))
99
- money.exchange_to("EUR")
100
- end
101
-
102
- specify "#exchange_to exchanges the amount properly" do
103
- money = Money.new(100_00, "USD")
104
- money.bank.should_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')))
105
- money.exchange_to("EUR").should == Money.new(200_00, "EUR")
106
- end
107
-
108
- specify "#== returns true if and only if their amount and currency are equal" do
109
- Money.new(1_00, "USD").should == Money.new(1_00, "USD")
110
- Money.new(1_00, "USD").should_not == Money.new(1_00, "EUR")
111
- Money.new(1_00, "USD").should_not == Money.new(2_00, "USD")
112
- Money.new(1_00, "USD").should_not == Money.new(99_00, "EUR")
113
- end
114
-
115
- specify "#== can be used to compare with a String money value" do
116
- Money.new(1_00, "USD").should == "1.00"
117
- Money.new(1_00, "USD").should_not == "2.00"
118
- Money.new(1_00, "GBP").should_not == "1.00"
119
- end
120
-
121
- specify "#== can be used to compare with a Numeric money value" do
122
- Money.new(1_00, "USD").should == 1
123
- Money.new(1_57, "USD").should == 1.57
124
- Money.new(1_00, "USD").should_not == 2
125
- Money.new(1_00, "GBP").should_not == 1
126
- end
127
-
128
- specify "#== can be used to compare with an object that responds to #to_money" do
129
- klass = Class.new do
130
- def initialize(money)
131
- @money = money
132
- end
133
-
134
- def to_money
135
- @money
136
- end
137
- end
138
-
139
- Money.new(1_00, "USD").should == klass.new(Money.new(1_00, "USD"))
140
- Money.new(2_50, "USD").should == klass.new(Money.new(2_50, "USD"))
141
- Money.new(2_50, "USD").should_not == klass.new(Money.new(3_00, "USD"))
142
- Money.new(1_00, "GBP").should_not == klass.new(Money.new(1_00, "USD"))
143
- end
144
-
145
- specify "#== returns false if used to compare with an object that doesn't respond to #to_money" do
146
- Money.new(1_00, "USD").should_not == Object.new
147
- Money.new(1_00, "USD").should_not == Class
148
- Money.new(1_00, "USD").should_not == Kernel
149
- Money.new(1_00, "USD").should_not == /foo/
150
- Money.new(1_00, "USD").should_not == nil
151
- end
152
-
153
- specify "#eql? returns true if and only if their amount and currency are equal" do
154
- Money.new(1_00, "USD").eql?(Money.new(1_00, "USD")).should be true
155
- Money.new(1_00, "USD").eql?(Money.new(1_00, "EUR")).should be false
156
- Money.new(1_00, "USD").eql?(Money.new(2_00, "USD")).should be false
157
- Money.new(1_00, "USD").eql?(Money.new(99_00, "EUR")).should be false
158
- end
159
-
160
- specify "#eql? can be used to compare with a String money value" do
161
- Money.new(1_00, "USD").eql?("1.00").should be true
162
- Money.new(1_00, "USD").eql?("2.00").should be false
163
- Money.new(1_00, "GBP").eql?("1.00").should be false
164
- end
165
-
166
- specify "#eql? can be used to compare with a Numeric money value" do
167
- Money.new(1_00, "USD").eql?(1).should be true
168
- Money.new(1_57, "USD").eql?(1.57).should be true
169
- Money.new(1_00, "USD").eql?(2).should be false
170
- Money.new(1_00, "GBP").eql?(1).should be false
171
- end
172
-
173
- specify "#eql? can be used to compare with an object that responds to #to_money" do
174
- klass = Class.new do
175
- def initialize(money)
176
- @money = money
177
- end
178
-
179
- def to_money
180
- @money
181
- end
182
- end
183
-
184
- Money.new(1_00, "USD").eql?(klass.new(Money.new(1_00, "USD"))).should be true
185
- Money.new(2_50, "USD").eql?(klass.new(Money.new(2_50, "USD"))).should be true
186
- Money.new(2_50, "USD").eql?(klass.new(Money.new(3_00, "USD"))).should be false
187
- Money.new(1_00, "GBP").eql?(klass.new(Money.new(1_00, "USD"))).should be false
188
- end
189
-
190
- specify "#eql? returns false if used to compare with an object that doesn't respond to #to_money" do
191
- Money.new(1_00, "USD").eql?(Object.new).should be false
192
- Money.new(1_00, "USD").eql?(Class).should be false
193
- Money.new(1_00, "USD").eql?(Kernel).should be false
194
- Money.new(1_00, "USD").eql?(/foo/).should be false
195
- Money.new(1_00, "USD").eql?(nil).should be false
196
- end
197
-
198
- specify "#hash should return the same value for equal objects" do
199
- Money.new(1_00, :eur).hash.should == Money.new(1_00, :eur).hash
200
- Money.new(2_00, :usd).hash.should == Money.new(2_00, :usd).hash
201
- Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :eur).hash
202
- Money.new(1_00, :eur).hash.should_not == Money.new(1_00, :usd).hash
203
- Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :usd).hash
204
- end
205
-
206
- specify "#hash can be used to return the intersection of Money object arrays" do
207
- intersection = [Money.new(1_00, :eur), Money.new(1_00, :usd)] & [Money.new(1_00, :eur)]
208
- intersection.should == [Money.new(1_00, :eur)]
209
- end
210
-
211
- specify "#<=> can be used to compare with a String money value" do
212
- (Money.new(1_00) <=> "1.00").should == 0
213
- (Money.new(1_00) <=> ".99").should > 0
214
- (Money.new(1_00) <=> "2.00").should < 0
215
- end
216
-
217
- specify "#<=> can be used to compare with a Numeric money value" do
218
- (Money.new(1_00) <=> 1).should == 0
219
- (Money.new(1_00) <=> 0.99).should > 0
220
- (Money.new(1_00) <=> 2.00).should < 0
221
- end
222
-
223
- specify "#<=> can be used to compare with an object that responds to #to_money" do
224
- klass = Class.new do
225
- def initialize(money)
226
- @money = money
227
- end
228
-
229
- def to_money
230
- @money
231
- end
232
- end
233
-
234
- (Money.new(1_00) <=> klass.new(Money.new(1_00))).should == 0
235
- (Money.new(1_00) <=> klass.new(Money.new(99))).should > 0
236
- (Money.new(1_00) <=> klass.new(Money.new(2_00))).should < 0
237
- end
238
-
239
- specify "#<=> raises ArgumentError when used to compare with an object that doesn't respond to #to_money" do
240
- expected_message = /Comparison .+ failed/
241
- lambda{ Money.new(1_00) <=> Object.new }.should raise_error(ArgumentError, expected_message)
242
- lambda{ Money.new(1_00) <=> Class }.should raise_error(ArgumentError, expected_message)
243
- lambda{ Money.new(1_00) <=> Kernel }.should raise_error(ArgumentError, expected_message)
244
- lambda{ Money.new(1_00) <=> /foo/ }.should raise_error(ArgumentError, expected_message)
245
- end
246
-
247
- describe "#*" do
248
- it "should multiply current money amount by the multiplier while retaining the currency" do
249
- (Money.new(1_00, "USD") * 10).should == Money.new(10_00, "USD")
250
- end
251
-
252
- it "should multiply Money by Fixnum and returns Money" do
253
- ts = [
254
- {:a => Money.new( 10, :USD), :b => 4, :c => Money.new( 40, :USD)},
255
- {:a => Money.new( 10, :USD), :b => -4, :c => Money.new(-40, :USD)},
256
- {:a => Money.new(-10, :USD), :b => 4, :c => Money.new(-40, :USD)},
257
- {:a => Money.new(-10, :USD), :b => -4, :c => Money.new( 40, :USD)},
258
- ]
259
- ts.each do |t|
260
- (t[:a] * t[:b]).should == t[:c]
261
- end
262
- end
263
-
264
- it "should not multiply Money by Money (same currency)" do
265
- lambda { Money.new( 10, :USD) * Money.new( 4, :USD) }.should raise_error(ArgumentError)
266
- end
267
-
268
- it "should not multiply Money by Money (different currency)" do
269
- lambda { Money.new( 10, :USD) * Money.new( 4, :EUR) }.should raise_error(ArgumentError)
270
- end
271
- end
272
-
273
- describe "#/" do
274
- it "divides current money amount by the divisor while retaining the currency" do
275
- (Money.new(10_00, "USD") / 10).should == Money.new(1_00, "USD")
276
- end
277
-
278
- it "divides Money by Fixnum and returns Money" do
279
- ts = [
280
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
281
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
282
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
283
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
284
- ]
285
- ts.each do |t|
286
- (t[:a] / t[:b]).should == t[:c]
287
- end
288
- end
289
-
290
- it "divides Money by Money (same currency) and returns Float" do
291
- ts = [
292
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
293
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
294
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
295
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
296
- ]
297
- ts.each do |t|
298
- (t[:a] / t[:b]).should == t[:c]
299
- end
300
- end
301
-
302
- it "divides Money by Money (different currency) and returns Float" do
303
- ts = [
304
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
305
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
306
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
307
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
308
- ]
309
- ts.each do |t|
310
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
311
- (t[:a] / t[:b]).should == t[:c]
312
- end
313
- end
314
- end
315
-
316
- specify "#div -> money / fixnum" do
317
- ts = [
318
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
319
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
320
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
321
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
322
- ]
323
- ts.each do |t|
324
- t[:a].div(t[:b]).should == t[:c]
325
- end
326
- end
327
-
328
- specify "#div -> money / money (same currency)" do
329
- ts = [
330
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
331
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
332
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
333
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
334
- ]
335
- ts.each do |t|
336
- t[:a].div(t[:b]).should == t[:c]
337
- end
338
- end
339
-
340
- specify "#div -> money / money (different currency)" do
341
- ts = [
342
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
343
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
344
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
345
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
346
- ]
347
- ts.each do |t|
348
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
349
- t[:a].div(t[:b]).should == t[:c]
350
- end
351
- end
352
-
353
- specify "#divmod -> money `divmod` fixnum" do
354
- ts = [
355
- {:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
356
- {:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-4, :USD), Money.new(-3, :USD)]},
357
- {:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-4, :USD), Money.new( 3, :USD)]},
358
- {:a => Money.new(-13, :USD), :b => -4, :c => [Money.new( 3, :USD), Money.new(-1, :USD)]},
359
- ]
360
- ts.each do |t|
361
- t[:a].divmod(t[:b]).should == t[:c]
362
- end
363
- end
364
-
365
- specify "#divmod -> money `divmod` money (same currency)" do
366
- ts = [
367
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => [ 3, Money.new( 1, :USD)]},
368
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => [-4, Money.new(-3, :USD)]},
369
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => [-4, Money.new( 3, :USD)]},
370
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => [ 3, Money.new(-1, :USD)]},
371
- ]
372
- ts.each do |t|
373
- t[:a].divmod(t[:b]).should == t[:c]
374
- end
375
- end
376
-
377
- specify "#divmod -> money `divmod` money (different currency)" do
378
- ts = [
379
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => [ 1, Money.new( 5, :USD)]},
380
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => [-2, Money.new(-3, :USD)]},
381
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => [-2, Money.new( 3, :USD)]},
382
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => [ 1, Money.new(-5, :USD)]},
383
- ]
384
- ts.each do |t|
385
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
386
- t[:a].divmod(t[:b]).should == t[:c]
387
- end
388
- end
389
-
390
- specify "#modulo -> money `modulo` fixnum" do
391
- ts = [
392
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
393
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
394
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
395
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
396
- ]
397
- ts.each do |t|
398
- t[:a].modulo(t[:b]).should == t[:c]
399
- end
400
- end
401
-
402
- specify "#modulo -> money `modulo` money (same currency)" do
403
- ts = [
404
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
405
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
406
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
407
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
408
- ]
409
- ts.each do |t|
410
- t[:a].modulo(t[:b]).should == t[:c]
411
- end
412
- end
413
-
414
- specify "#modulo -> money `modulo` money (different currency)" do
415
- ts = [
416
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
417
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
418
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
419
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
420
- ]
421
- ts.each do |t|
422
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
423
- t[:a].modulo(t[:b]).should == t[:c]
424
- end
425
- end
426
-
427
- specify "#% -> money % fixnum" do
428
- ts = [
429
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
430
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
431
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
432
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
433
- ]
434
- ts.each do |t|
435
- (t[:a] % t[:b]).should == t[:c]
436
- end
437
- end
438
-
439
- specify "#% -> money % money (same currency)" do
440
- ts = [
441
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
442
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
443
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
444
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
445
- ]
446
- ts.each do |t|
447
- (t[:a] % t[:b]).should == t[:c]
448
- end
449
- end
450
-
451
- specify "#% -> money % money (different currency)" do
452
- ts = [
453
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
454
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
455
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
456
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
457
- ]
458
- ts.each do |t|
459
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
460
- (t[:a] % t[:b]).should == t[:c]
461
- end
462
- end
463
-
464
- specify "#remainder -> money `remainder` fixnum" do
465
- ts = [
466
- {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
467
- {:a => Money.new( 13, :USD), :b => -4, :c => Money.new( 1, :USD)},
468
- {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-1, :USD)},
469
- {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
470
- ]
471
- ts.each do |t|
472
- t[:a].remainder(t[:b]).should == t[:c]
473
- end
474
- end
475
-
476
- specify "#remainder -> money `remainder` money (same currency)" do
477
- ts = [
478
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
479
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new( 1, :USD)},
480
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new(-1, :USD)},
481
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
482
- ]
483
- ts.each do |t|
484
- t[:a].remainder(t[:b]).should == t[:c]
485
- end
486
- end
487
-
488
- specify "#remainder -> money `remainder` money (different currency)" do
489
- ts = [
490
- {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
491
- {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new( 5, :USD)},
492
- {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new(-5, :USD)},
493
- {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
494
- ]
495
- ts.each do |t|
496
- t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
497
- t[:a].remainder(t[:b]).should == t[:c]
498
- end
499
- end
500
-
501
- specify "#abs correctly returns the absolute value as a new Money object" do
502
- n = Money.new(-1, :USD)
503
- n.abs.should == Money.new( 1, :USD)
504
- n.should == Money.new(-1, :USD)
505
- end
506
-
507
- specify "Money.format brute force :subunit_to_unit = 1" do
508
- ("0".."9").each do |amt|
509
- amt.to_money("VUV").format(:symbol => false).should == amt
510
- end
511
- ("-1".."-9").each do |amt|
512
- amt.to_money("VUV").format(:symbol => false).should == amt
513
- end
514
- "1000".to_money("VUV").format(:symbol => false).should == "1,000"
515
- "-1000".to_money("VUV").format(:symbol => false).should == "-1,000"
516
- end
517
-
518
- specify "Money.format brute force :subunit_to_unit = 5" do
519
- ("0.0".."9.4").each do |amt|
520
- next if amt[-1].to_i > 4
521
- amt.to_money("MGA").format(:symbol => false).should == amt
522
- end
523
- ("-0.1".."-9.4").each do |amt|
524
- next if amt[-1].to_i > 4
525
- amt.to_money("MGA").format(:symbol => false).should == amt
526
- end
527
- "1000.0".to_money("MGA").format(:symbol => false).should == "1,000.0"
528
- "-1000.0".to_money("MGA").format(:symbol => false).should == "-1,000.0"
529
- end
530
-
531
- specify "Money.format brute force :subunit_to_unit = 10" do
532
- ("0.0".."9.9").each do |amt|
533
- amt.to_money("VND").format(:symbol => false).should == amt.to_s.gsub(/\./, ",")
534
- end
535
- ("-0.1".."-9.9").each do |amt|
536
- amt.to_money("VND").format(:symbol => false).should == amt.to_s.gsub(/\./, ",")
537
- end
538
- "1000.0".to_money("VND").format(:symbol => false).should == "1.000,0"
539
- "-1000.0".to_money("VND").format(:symbol => false).should == "-1.000,0"
540
- end
541
-
542
- specify "Money.format brute force :subunit_to_unit = 100" do
543
- ("0.00".."9.99").each do |amt|
544
- amt.to_money("USD").format(:symbol => false).should == amt
545
- end
546
- ("-0.01".."-9.99").each do |amt|
547
- amt.to_money("USD").format(:symbol => false).should == amt
548
- end
549
- "1000.00".to_money("USD").format(:symbol => false).should == "1,000.00"
550
- "-1000.00".to_money("USD").format(:symbol => false).should == "-1,000.00"
551
- end
552
-
553
- specify "Money.format brute force :subunit_to_unit = 1000" do
554
- ("0.000".."9.999").each do |amt|
555
- amt.to_money("IQD").format(:symbol => false).should == amt
556
- end
557
- ("-0.001".."-9.999").each do |amt|
558
- amt.to_money("IQD").format(:symbol => false).should == amt
559
- end
560
- "1000.000".to_money("IQD").format(:symbol => false).should == "1,000.000"
561
- "-1000.000".to_money("IQD").format(:symbol => false).should == "-1,000.000"
562
- end
563
-
564
- specify "Money.to_s works" do
565
- Money.new(10_00).to_s.should == "10.00"
566
- Money.new(400_08).to_s.should == "400.08"
567
- Money.new(-237_43).to_s.should == "-237.43"
568
- end
569
-
570
- specify "Money.to_s should respect :subunit_to_unit currency property" do
571
- Money.new(10_00, "BHD").to_s.should == "1.000"
572
- Money.new(10_00, "CNY").to_s.should == "10.00"
573
- end
574
-
575
- specify "Money.to_s shouldn't have decimal when :subunit_to_unit is 1" do
576
- Money.new(10_00, "CLP").to_s.should == "1000"
577
- end
578
-
579
- specify "Money.to_s should work with :subunit_to_unit == 5" do
580
- Money.new(10_00, "MGA").to_s.should == "200.0"
581
- end
582
-
583
- specify "Money.to_s should respect :decimal_mark" do
584
- Money.new(10_00, "BRL").to_s.should == "10,00"
585
- end
586
-
587
- specify "Money.to_f works" do
588
- Money.new(10_00).to_f.should == 10.0
589
- end
590
-
591
- specify "Money.to_f should respect :subunit_to_unit currency property" do
592
- Money.new(10_00, "BHD").to_f.should == 1.0
593
- end
594
-
595
- specify "#symbol works as documented" do
596
- currency = Money::Currency.new("EUR")
597
- currency.should_receive(:symbol).and_return("€")
598
- Money.empty(currency).symbol.should == "€"
599
-
600
- currency = Money::Currency.new("EUR")
601
- currency.should_receive(:symbol).and_return(nil)
602
- Money.empty(currency).symbol.should == "¤"
603
- end
604
-
605
- {
606
- :thousands_separator => { :default => ",", :other => "." },
607
- :decimal_mark => { :default => ".", :other => "," }
608
- }.each do |method, options|
609
- describe "##{method}" do
610
- context "without I18n" do
611
- it "works as documented" do
612
- Money.empty("USD").send(method).should == options[:default]
613
- Money.empty("EUR").send(method).should == options[:other]
614
- Money.empty("BRL").send(method).should == options[:other]
615
- end
616
- end
617
-
618
- if Object.const_defined?("I18n")
619
- context "with I18n" do
620
- before :all do
621
- reset_i18n
622
- store_number_formats(:en, method => options[:default])
623
- store_number_formats(:de, method => options[:other])
624
- end
625
-
626
- it "looks up #{method} for current locale" do
627
- I18n.locale = :en
628
- Money.empty("USD").send(method).should == options[:default]
629
- I18n.locale = :de
630
- Money.empty("USD").send(method).should == options[:other]
631
- end
632
-
633
- it "fallbacks to default behaviour for missing translations" do
634
- I18n.locale = :de
635
- Money.empty("USD").send(method).should == options[:other]
636
- I18n.locale = :fr
637
- Money.empty("USD").send(method).should == options[:default]
638
- end
639
-
640
- after :all do
641
- reset_i18n
642
- end
643
- end
644
- else
645
- puts "can't test ##{method} with I18n because it isn't loaded"
646
- end
647
- end
648
- end
649
-
650
- describe "#format" do
651
- it "returns the monetary value as a string" do
652
- Money.ca_dollar(100).format.should == "$1.00"
653
- Money.new(40008).format.should == "$400.08"
654
- end
655
-
656
- it "should respect :subunit_to_unit currency property" do
657
- Money.new(10_00, "BHD").format.should == "ب.د1.000"
658
- end
659
-
660
- it "doesn't display a decimal when :subunit_to_unit is 1" do
661
- Money.new(10_00, "CLP").format.should == "$1.000"
662
- end
663
-
664
- it "respects the thousands_separator and decimal_mark defaults" do
665
- one_thousand = Proc.new do |currency|
666
- Money.new(1000_00, currency).format
667
- end
668
-
669
- # Pounds
670
- one_thousand["GBP"].should == "£1,000.00"
671
-
672
- # Dollars
673
- one_thousand["USD"].should == "$1,000.00"
674
- one_thousand["CAD"].should == "$1,000.00"
675
- one_thousand["AUD"].should == "$1,000.00"
676
- one_thousand["NZD"].should == "$1,000.00"
677
- one_thousand["ZWD"].should == "$1,000.00"
678
-
679
- # Yen
680
- one_thousand["JPY"].should == "¥1,000.00"
681
- one_thousand["CNY"].should == "¥1,000.00"
682
-
683
- # Euro
684
- one_thousand["EUR"].should == "1.000,00 €"
685
-
686
- # Rupees
687
- one_thousand["INR"].should == "₨1,000.00"
688
- one_thousand["NPR"].should == "₨1,000.00"
689
- one_thousand["SCR"].should == "1,000.00 ₨"
690
- one_thousand["LKR"].should == "1,000.00 ₨"
691
-
692
- # Brazilian Real
693
- one_thousand["BRL"].should == "R$ 1.000,00"
694
-
695
- # Other
696
- one_thousand["SEK"].should == "kr1,000.00"
697
- one_thousand["GHC"].should == "₵1,000.00"
698
- end
699
-
700
- describe "if the monetary value is 0" do
701
- before :each do
702
- @money = Money.us_dollar(0)
703
- end
704
-
705
- it "returns 'free' when :display_free is true" do
706
- @money.format(:display_free => true).should == 'free'
707
- end
708
-
709
- it "returns '$0.00' when :display_free is false or not given" do
710
- @money.format.should == '$0.00'
711
- @money.format(:display_free => false).should == '$0.00'
712
- @money.format(:display_free => nil).should == '$0.00'
713
- end
714
-
715
- it "returns the value specified by :display_free if it's a string-like object" do
716
- @money.format(:display_free => 'gratis').should == 'gratis'
717
- end
718
- end
719
-
720
- specify "#format(:with_currency => true) works as documented" do
721
- Money.ca_dollar(100).format(:with_currency => true).should == "$1.00 CAD"
722
- Money.us_dollar(85).format(:with_currency => true).should == "$0.85 USD"
723
- end
724
-
725
- specify "#format(:no_cents => true) works as documented" do
726
- Money.ca_dollar(100).format(:no_cents => true).should == "$1"
727
- Money.ca_dollar(599).format(:no_cents => true).should == "$5"
728
- Money.ca_dollar(570).format(:no_cents => true, :with_currency => true).should == "$5 CAD"
729
- Money.ca_dollar(39000).format(:no_cents => true).should == "$390"
730
- end
731
-
732
- specify "#format(:no_cents => true) should respect :subunit_to_unit currency property" do
733
- Money.new(10_00, "BHD").format(:no_cents => true).should == "ب.د1"
734
- end
735
-
736
- specify "#format(:symbol => a symbol string) uses the given value as the money symbol" do
737
- Money.new(100, "GBP").format(:symbol => "£").should == "£1.00"
738
- end
739
-
740
- specify "#format(:symbol => true) returns symbol based on the given currency code" do
741
- one = Proc.new do |currency|
742
- Money.new(100, currency).format(:symbol => true)
743
- end
744
-
745
- # Pounds
746
- one["GBP"].should == "£1.00"
747
-
748
- # Dollars
749
- one["USD"].should == "$1.00"
750
- one["CAD"].should == "$1.00"
751
- one["AUD"].should == "$1.00"
752
- one["NZD"].should == "$1.00"
753
- one["ZWD"].should == "$1.00"
754
-
755
- # Yen
756
- one["JPY"].should == "¥1.00"
757
- one["CNY"].should == "¥1.00"
758
-
759
- # Euro
760
- one["EUR"].should == "1,00 €"
761
-
762
- # Rupees
763
- one["INR"].should == "₨1.00"
764
- one["NPR"].should == "₨1.00"
765
- one["SCR"].should == "1.00 ₨"
766
- one["LKR"].should == "1.00 ₨"
767
-
768
- # Brazilian Real
769
- one["BRL"].should == "R$ 1,00"
770
-
771
- # Other
772
- one["SEK"].should == "kr1.00"
773
- one["GHC"].should == "₵1.00"
774
- end
775
-
776
- specify "#format(:symbol => true) returns $ when currency code is not recognized" do
777
- currency = Money::Currency.new("EUR")
778
- currency.should_receive(:symbol).and_return(nil)
779
- Money.new(100, currency).format(:symbol => true).should == "1,00 ¤"
780
- end
781
-
782
- specify "#format(:symbol => some non-Boolean value that evaluates to true) returns symbol based on the given currency code" do
783
- Money.new(100, "GBP").format(:symbol => true).should == "£1.00"
784
- Money.new(100, "EUR").format(:symbol => true).should == "1,00 €"
785
- Money.new(100, "SEK").format(:symbol => true).should == "kr1.00"
786
- end
787
-
788
- specify "#format with :symbol == "", nil or false returns the amount without a symbol" do
789
- money = Money.new(100, "GBP")
790
- money.format(:symbol => "").should == "1.00"
791
- money.format(:symbol => nil).should == "1.00"
792
- money.format(:symbol => false).should == "1.00"
793
- end
794
-
795
- specify "#format without :symbol assumes that :symbol is set to true" do
796
- money = Money.new(100)
797
- money.format.should == "$1.00"
798
-
799
- money = Money.new(100, "GBP")
800
- money.format.should == "£1.00"
801
-
802
- money = Money.new(100, "EUR")
803
- money.format.should == "1,00 €"
804
- end
805
-
806
- specify "#format(:decimal_mark => a decimal_mark string) works as documented" do
807
- Money.us_dollar(100).format(:decimal_mark => ",").should == "$1,00"
808
- end
809
-
810
- specify "#format will default decimal_mark to '.' if currency isn't recognized" do
811
- Money.new(100, "ZWD").format.should == "$1.00"
812
- end
813
-
814
- specify "#format(:separator => a separator string) works as documented" do
815
- Money.us_dollar(100).format(:separator => ",").should == "$1,00"
816
- end
817
-
818
- specify "#format(:thousands_separator => a thousands_separator string) works as documented" do
819
- Money.us_dollar(100000).format(:thousands_separator => ".").should == "$1.000.00"
820
- Money.us_dollar(200000).format(:thousands_separator => "").should == "$2000.00"
821
- end
822
-
823
- specify "#format(:thousands_separator => false or nil) works as documented" do
824
- Money.us_dollar(100000).format(:thousands_separator => false).should == "$1000.00"
825
- Money.us_dollar(200000).format(:thousands_separator => nil).should == "$2000.00"
826
- end
827
-
828
- specify "#format(:delimiter => a delimiter string) works as documented" do
829
- Money.us_dollar(100000).format(:delimiter => ".").should == "$1.000.00"
830
- Money.us_dollar(200000).format(:delimiter => "").should == "$2000.00"
831
- end
832
-
833
- specify "#format(:delimiter => false or nil) works as documented" do
834
- Money.us_dollar(100000).format(:delimiter => false).should == "$1000.00"
835
- Money.us_dollar(200000).format(:delimiter => nil).should == "$2000.00"
836
- end
837
-
838
- specify "#format will default thousands_separator to ',' if currency isn't recognized" do
839
- Money.new(100000, "ZWD").format.should == "$1,000.00"
840
- end
841
-
842
- specify "#format(:html => true) works as documented" do
843
- string = Money.ca_dollar(570).format(:html => true, :with_currency => true)
844
- string.should == "$5.70 <span class=\"currency\">CAD</span>"
845
- end
846
-
847
- it "should insert commas into the result if the amount is sufficiently large" do
848
- Money.us_dollar(1_000_000_000_12).format.should == "$1,000,000,000.12"
849
- Money.us_dollar(1_000_000_000_12).format(:no_cents => true).should == "$1,000,000,000"
850
- end
851
-
852
- it "inserts thousands separator into the result if the amount is sufficiently large and the currency symbol is at the end" do
853
- Money.euro(1_234_567_12).format.should == "1.234.567,12 €"
854
- Money.euro(1_234_567_12).format(:no_cents => true).should == "1.234.567 €"
855
- end
856
-
857
- it "inserts currency symbol before the amount when :symbol_position is set to :before" do
858
- Money.euro(1_234_567_12).format(:symbol_position => :before).should == "€1.234.567,12"
859
- end
860
-
861
- it "inserts currency symbol after the amount when :symbol_position is set to :after" do
862
- Money.us_dollar(1_000_000_000_12).format(:symbol_position => :after).should == "1,000,000,000.12 $"
863
- end
864
- end
865
-
866
-
867
- describe "Money.empty" do
868
- it "Money.empty creates a new Money object of 0 cents" do
869
- Money.empty.should == Money.new(0)
870
- end
871
- end
872
-
873
- describe "Money.ca_dollar" do
874
- it "creates a new Money object of the given value in CAD" do
875
- Money.ca_dollar(50).should == Money.new(50, "CAD")
876
- end
877
- end
878
-
879
- describe "Money.us_dollar" do
880
- it "creates a new Money object of the given value in USD" do
881
- Money.us_dollar(50).should == Money.new(50, "USD")
882
- end
883
- end
884
-
885
- describe "Money.euro" do
886
- it "creates a new Money object of the given value in EUR" do
887
- Money.euro(50).should == Money.new(50, "EUR")
888
- end
889
- end
890
-
891
-
892
- describe "Money.new_with_dollars" do
893
- it "converts given amount to cents" do
894
- Money.new_with_dollars(1).should == Money.new(100)
895
- Money.new_with_dollars(1, "USD").should == Money.new(100, "USD")
896
- Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR")
897
- end
898
-
899
- it "should respect :subunit_to_unit currency property" do
900
- Money.new_with_dollars(1, "USD").should == Money.new(1_00, "USD")
901
- Money.new_with_dollars(1, "TND").should == Money.new(1_000, "TND")
902
- Money.new_with_dollars(1, "CLP").should == Money.new(1, "CLP")
903
- end
904
-
905
- it "should not loose precision" do
906
- Money.new_with_dollars(1234).cents.should == 1234_00
907
- Money.new_with_dollars(100.37).cents.should == 100_37
908
- Money.new_with_dollars(BigDecimal.new('1234')).cents.should == 1234_00
909
- end
910
-
911
- it "accepts a currency options" do
912
- m = Money.new_with_dollars(1)
913
- m.currency.should == Money.default_currency
914
-
915
- m = Money.new_with_dollars(1, Money::Currency.wrap("EUR"))
916
- m.currency.should == Money::Currency.wrap("EUR")
917
-
918
- m = Money.new_with_dollars(1, "EUR")
919
- m.currency.should == Money::Currency.wrap("EUR")
920
- end
921
-
922
- it "accepts a bank options" do
923
- m = Money.new_with_dollars(1)
924
- m.bank.should == Money.default_bank
925
-
926
- m = Money.new_with_dollars(1, "EUR", bank = Object.new)
927
- m.bank.should == bank
928
- end
929
-
930
- it "is associated to the singleton instance of Bank::VariableExchange by default" do
931
- Money.new_with_dollars(0).bank.should be_equal(Money::Bank::VariableExchange.instance)
932
- end
933
- end
934
-
935
- describe "Money.from_string" do
936
- it "converts given amount to cents" do
937
- Money.from_string("1").should == Money.new(1_00)
938
- Money.from_string("1").should == Money.new(1_00, "USD")
939
- Money.from_string("1", "EUR").should == Money.new(1_00, "EUR")
940
- end
941
-
942
- it "should respect :subunit_to_unit currency property" do
943
- Money.from_string("1", "USD").should == Money.new(1_00, "USD")
944
- Money.from_string("1", "TND").should == Money.new(1_000, "TND")
945
- Money.from_string("1", "CLP").should == Money.new(1, "CLP")
946
- end
947
-
948
- it "accepts a currency options" do
949
- m = Money.from_string("1")
950
- m.currency.should == Money.default_currency
951
-
952
- m = Money.from_string("1", Money::Currency.wrap("EUR"))
953
- m.currency.should == Money::Currency.wrap("EUR")
954
-
955
- m = Money.from_string("1", "EUR")
956
- m.currency.should == Money::Currency.wrap("EUR")
957
- end
958
- end
959
-
960
- describe "Money.from_fixnum" do
961
- it "converts given amount to cents" do
962
- Money.from_fixnum(1).should == Money.new(1_00)
963
- Money.from_fixnum(1).should == Money.new(1_00, "USD")
964
- Money.from_fixnum(1, "EUR").should == Money.new(1_00, "EUR")
965
- end
966
-
967
- it "should respect :subunit_to_unit currency property" do
968
- Money.from_fixnum(1, "USD").should == Money.new(1_00, "USD")
969
- Money.from_fixnum(1, "TND").should == Money.new(1_000, "TND")
970
- Money.from_fixnum(1, "CLP").should == Money.new(1, "CLP")
971
- end
972
-
973
- it "accepts a currency options" do
974
- m = Money.from_fixnum(1)
975
- m.currency.should == Money.default_currency
976
-
977
- m = Money.from_fixnum(1, Money::Currency.wrap("EUR"))
978
- m.currency.should == Money::Currency.wrap("EUR")
979
-
980
- m = Money.from_fixnum(1, "EUR")
981
- m.currency.should == Money::Currency.wrap("EUR")
982
- end
983
- end
984
-
985
- describe "Money.from_float" do
986
- it "converts given amount to cents" do
987
- Money.from_float(1.2).should == Money.new(1_20)
988
- Money.from_float(1.2).should == Money.new(1_20, "USD")
989
- Money.from_float(1.2, "EUR").should == Money.new(1_20, "EUR")
990
- end
991
-
992
- it "should respect :subunit_to_unit currency property" do
993
- Money.from_float(1.2, "USD").should == Money.new(1_20, "USD")
994
- Money.from_float(1.2, "TND").should == Money.new(1_200, "TND")
995
- Money.from_float(1.2, "CLP").should == Money.new(1, "CLP")
996
- end
997
-
998
- it "accepts a currency options" do
999
- m = Money.from_float(1.2)
1000
- m.currency.should == Money.default_currency
1001
-
1002
- m = Money.from_float(1.2, Money::Currency.wrap("EUR"))
1003
- m.currency.should == Money::Currency.wrap("EUR")
1004
-
1005
- m = Money.from_float(1.2, "EUR")
1006
- m.currency.should == Money::Currency.wrap("EUR")
1007
- end
1008
- end
1009
-
1010
- describe "Money.from_bigdecimal" do
1011
- it "converts given amount to cents" do
1012
- Money.from_bigdecimal(BigDecimal.new("1")).should == Money.new(1_00)
1013
- Money.from_bigdecimal(BigDecimal.new("1")).should == Money.new(1_00, "USD")
1014
- Money.from_bigdecimal(BigDecimal.new("1"), "EUR").should == Money.new(1_00, "EUR")
1015
- end
1016
-
1017
- it "should respect :subunit_to_unit currency property" do
1018
- Money.from_bigdecimal(BigDecimal.new("1"), "USD").should == Money.new(1_00, "USD")
1019
- Money.from_bigdecimal(BigDecimal.new("1"), "TND").should == Money.new(1_000, "TND")
1020
- Money.from_bigdecimal(BigDecimal.new("1"), "CLP").should == Money.new(1, "CLP")
1021
- end
1022
-
1023
- it "accepts a currency options" do
1024
- m = Money.from_bigdecimal(BigDecimal.new("1"))
1025
- m.currency.should == Money.default_currency
1026
-
1027
- m = Money.from_bigdecimal(BigDecimal.new("1"), Money::Currency.wrap("EUR"))
1028
- m.currency.should == Money::Currency.wrap("EUR")
1029
-
1030
- m = Money.from_bigdecimal(BigDecimal.new("1"), "EUR")
1031
- m.currency.should == Money::Currency.wrap("EUR")
1032
- end
1033
- end
1034
-
1035
- describe "Money.from_numeric" do
1036
- it "converts given amount to cents" do
1037
- Money.from_numeric(1).should == Money.new(1_00)
1038
- Money.from_numeric(1.0).should == Money.new(1_00)
1039
- Money.from_numeric(BigDecimal.new("1")).should == Money.new(1_00)
1040
- end
1041
-
1042
- it "should raise ArgumentError with unsupported argument" do
1043
- lambda { Money.from_numeric("100") }.should raise_error(ArgumentError)
1044
- end
1045
-
1046
- it "should optimize workload" do
1047
- Money.should_receive(:from_fixnum).with(1, "USD").and_return(Money.new(1_00, "USD"))
1048
- Money.from_numeric(1, "USD").should == Money.new(1_00, "USD")
1049
- Money.should_receive(:from_bigdecimal).with(BigDecimal.new("1.0"), "USD").and_return(Money.new(1_00, "USD"))
1050
- Money.from_numeric(1.0, "USD").should == Money.new(1_00, "USD")
1051
- end
1052
-
1053
- it "should respect :subunit_to_unit currency property" do
1054
- Money.from_numeric(1, "USD").should == Money.new(1_00, "USD")
1055
- Money.from_numeric(1, "TND").should == Money.new(1_000, "TND")
1056
- Money.from_numeric(1, "CLP").should == Money.new(1, "CLP")
1057
- end
1058
-
1059
- it "accepts a bank option" do
1060
- Money.from_numeric(1).should == Money.new(1_00)
1061
- Money.from_numeric(1).should == Money.new(1_00, "USD")
1062
- Money.from_numeric(1, "EUR").should == Money.new(1_00, "EUR")
1063
- end
1064
-
1065
- it "accepts a currency options" do
1066
- m = Money.from_numeric(1)
1067
- m.currency.should == Money.default_currency
1068
-
1069
- m = Money.from_numeric(1, Money::Currency.wrap("EUR"))
1070
- m.currency.should == Money::Currency.wrap("EUR")
1071
-
1072
- m = Money.from_numeric(1, "EUR")
1073
- m.currency.should == Money::Currency.wrap("EUR")
1074
- end
1075
- end
1076
-
1077
- describe "split" do
1078
- specify "#split needs at least one party" do
1079
- lambda {Money.us_dollar(1).split(0)}.should raise_error(ArgumentError)
1080
- lambda {Money.us_dollar(1).split(-1)}.should raise_error(ArgumentError)
1081
- end
1082
-
1083
-
1084
- specify "#gives 1 cent to both people if we start with 2" do
1085
- Money.us_dollar(2).split(2).should == [Money.us_dollar(1), Money.us_dollar(1)]
1086
- end
1087
-
1088
- specify "#split may distribute no money to some parties if there isnt enough to go around" do
1089
- Money.us_dollar(2).split(3).should == [Money.us_dollar(1), Money.us_dollar(1), Money.us_dollar(0)]
1090
- end
1091
-
1092
- specify "#split does not lose pennies" do
1093
- Money.us_dollar(5).split(2).should == [Money.us_dollar(3), Money.us_dollar(2)]
1094
- end
1095
-
1096
- specify "#split a dollar" do
1097
- moneys = Money.us_dollar(100).split(3)
1098
- moneys[0].cents.should == 34
1099
- moneys[1].cents.should == 33
1100
- moneys[2].cents.should == 33
1101
- end
1102
- end
1103
-
1104
- describe "allocation" do
1105
- specify "#allocate takes no action when one gets all" do
1106
- Money.us_dollar(005).allocate([1.0]).should == [Money.us_dollar(5)]
1107
- end
1108
-
1109
- specify "#allocate keeps currencies intact" do
1110
- Money.ca_dollar(005).allocate([1]).should == [Money.ca_dollar(5)]
1111
- end
1112
-
1113
- specify "#allocate does not loose pennies" do
1114
- moneys = Money.us_dollar(5).allocate([0.3,0.7])
1115
- moneys[0].should == Money.us_dollar(2)
1116
- moneys[1].should == Money.us_dollar(3)
1117
- end
1118
-
1119
- specify "#allocate does not loose pennies" do
1120
- moneys = Money.us_dollar(100).allocate([0.333,0.333, 0.333])
1121
- moneys[0].cents.should == 34
1122
- moneys[1].cents.should == 33
1123
- moneys[2].cents.should == 33
1124
- end
1125
-
1126
- specify "#allocate requires total to be less then 1" do
1127
- lambda { Money.us_dollar(0.05).allocate([0.5,0.6]) }.should raise_error(ArgumentError)
1128
- end
1129
- end
1130
-
1131
- describe "Money.add_rate" do
1132
- it "saves rate into current bank" do
1133
- Money.add_rate("EUR", "USD", 10)
1134
- Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
1135
- end
1136
- end
1137
-
1138
-
1139
- # Sets $VERBOSE to nil for the duration of the block and back to its original value afterwards.
1140
- #
1141
- # silence_warnings do
1142
- # value = noisy_call # no warning voiced
1143
- # end
1144
- #
1145
- # noisy_call # warning voiced
1146
- def silence_warnings
1147
- old_verbose, $VERBOSE = $VERBOSE, nil
1148
- yield
1149
- ensure
1150
- $VERBOSE = old_verbose
1151
- end
1152
-
1153
- end
1154
-
1155
- describe "Actions involving two Money objects" do
1156
- describe "if the other Money object has the same currency" do
1157
- specify "#<=> compares the two object amounts" do
1158
- (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
1159
- (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
1160
- (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
1161
- end
1162
-
1163
- specify "#+ adds other amount to current amount and returns a Money while retaining the currency" do
1164
- (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
1165
- end
1166
-
1167
- specify "#- subtracts other amount from current amount and returns a Money while retaining the currency" do
1168
- (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
1169
- end
1170
-
1171
- specify "#* should raise ArgumentError" do
1172
- lambda { Money.new(10_00, "USD") * Money.new(2, "USD") }.should raise_error(ArgumentError)
1173
- end
1174
-
1175
- specify "#/ divides current amount by other amount and returns a Float" do
1176
- (Money.new(10_00, "USD") / Money.new(100_00, "USD")).should == 0.1
1177
- end
1178
- end
1179
-
1180
- describe "if the other Money object has a different currency" do
1181
- specify "#<=> converts other object amount to current currency, then compares the two object amounts" do
1182
- target = Money.new(200_00, "EUR")
1183
- target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(300_00, "USD"))
1184
- (Money.new(100_00, "USD") <=> target).should < 0
1185
-
1186
- target = Money.new(200_00, "EUR")
1187
- target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
1188
- (Money.new(100_00, "USD") <=> target).should == 0
1189
-
1190
- target = Money.new(200_00, "EUR")
1191
- target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(99_00, "USD"))
1192
- (Money.new(100_00, "USD") <=> target).should > 0
1193
- end
1194
-
1195
- specify "#+ converts other object amount to current currency, then adds other amount to current amount and returns a Money" do
1196
- other = Money.new(90, "EUR")
1197
- other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
1198
- (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
1199
- end
1200
-
1201
- specify "#- converts other object amount to current currency, then subtracts other amount from current amount and returns a Money" do
1202
- other = Money.new(90, "EUR")
1203
- other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
1204
- (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
1205
- end
1206
-
1207
- specify "#* should raise ArgumentError" do
1208
- lambda { Money.new(10_00, "USD") * Money.new(10, "EUR") }.should raise_error(ArgumentError)
1209
- end
1210
-
1211
- specify "#/ converts other object amount to current currency, then divides current amount by other amount and returns a Float" do
1212
- other = Money.new(1000, "EUR")
1213
- other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
1214
- (Money.new(10_00, "USD") / other).should == 0.1
1215
- end
1216
- end
1217
- end
1218
-
1219
-
1220
- describe "Money.parse" do
1221
-
1222
- it "should be able to parse european-formatted inputs under 10EUR" do
1223
- five_ninety_five = Money.new(595, 'EUR')
1224
-
1225
- Money.parse('EUR 5,95').should == five_ninety_five
1226
- #TODO: try and handle these
1227
- #Money.parse('€5,95').should == five_ninety_five
1228
- #Money.parse('&#036;5.95').should == five_ninety_five
1229
- end
1230
-
1231
- it "should be able to parse european-formatted inputs with multiple thousands-seperators" do
1232
- Money.parse('EUR 1.234.567,89').should == Money.new(123456789, 'EUR')
1233
- Money.parse('EUR 1.111.234.567,89').should == Money.new(111123456789, 'EUR')
1234
- end
1235
-
1236
- it "should be able to parse USD-formatted inputs under $10" do
1237
- five_ninety_five = Money.new(595, 'USD')
1238
-
1239
- Money.parse(5.95).should == five_ninety_five
1240
- Money.parse('5.95').should == five_ninety_five
1241
- Money.parse('$5.95').should == five_ninety_five
1242
- Money.parse("\n $5.95 \n").should == five_ninety_five
1243
- Money.parse('$ 5.95').should == five_ninety_five
1244
- Money.parse('$5.95 ea.').should == five_ninety_five
1245
- Money.parse('$5.95, each').should == five_ninety_five
1246
- end
1247
-
1248
- it "should be able to parse USD-formatted inputs with multiple thousands-seperators" do
1249
- Money.parse('1,234,567.89').should == Money.new(123456789, 'USD')
1250
- Money.parse('1,111,234,567.89').should == Money.new(111123456789, 'USD')
1251
- end
1252
-
1253
- it "should not return a price if there is a price range" do
1254
- lambda {Money.parse('$5.95-10.95')}.should raise_error ArgumentError
1255
- lambda {Money.parse('$5.95 - 10.95')}.should raise_error ArgumentError
1256
- lambda {Money.parse('$5.95 - $10.95')}.should raise_error ArgumentError
1257
- end
1258
-
1259
- it "should not return a price for completely invalid input" do
1260
- # TODO: shouldn't these throw an error instead of being considered
1261
- # equal to $0.0?
1262
- empty_price = Money.new(0, 'USD')
1263
-
1264
- Money.parse(nil).should == empty_price
1265
- Money.parse('hellothere').should == empty_price
1266
- Money.parse('').should == empty_price
1267
- end
1268
- end
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Money do
6
+
7
+ describe "#new" do
8
+ it "rounds the given cents to an integer" do
9
+ Money.new(1.00, "USD").cents.should == 1
10
+ Money.new(1.01, "USD").cents.should == 1
11
+ Money.new(1.50, "USD").cents.should == 2
12
+ end
13
+
14
+ it "is associated to the singleton instance of Bank::VariableExchange by default" do
15
+ Money.new(0).bank.should be_equal(Money::Bank::VariableExchange.instance)
16
+ end
17
+
18
+ end
19
+
20
+ describe "#cents" do
21
+ it "returns the amount of cents passed to the constructor" do
22
+ Money.new(200_00, "USD").cents.should == 200_00
23
+ end
24
+
25
+ it "stores cents as an integer regardless of what is passed into the constructor" do
26
+ [ Money.new(100), 1.to_money, 1.00.to_money, BigDecimal('1.00').to_money ].each do |m|
27
+ m.cents.should == 100
28
+ m.cents.should be_an_instance_of(Fixnum)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe "#dollars" do
34
+ it "gets cents as dollars" do
35
+ Money.new_with_dollars(1).should == Money.new(100)
36
+ Money.new_with_dollars(1, "USD").should == Money.new(100, "USD")
37
+ Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR")
38
+ end
39
+
40
+ it "should respect :subunit_to_unit currency property" do
41
+ Money.new(1_00, "USD").dollars.should == 1
42
+ Money.new(1_000, "TND").dollars.should == 1
43
+ Money.new(1, "CLP").dollars.should == 1
44
+ end
45
+
46
+ it "should not loose precision" do
47
+ Money.new(100_37).dollars.should == 100.37
48
+ Money.new_with_dollars(100.37).dollars.should == 100.37
49
+ end
50
+ end
51
+
52
+ specify "#currency returns the currency passed to the constructor" do
53
+ Money.new(200_00, "USD").currency.should == Money::Currency.new("USD")
54
+ end
55
+
56
+ specify "#currency_string returns the iso_code of the currency object" do
57
+ Money.new(200_00, "USD").currency_as_string.should == Money::Currency.new("USD").to_s
58
+ Money.new(200_00, "USD").currency_as_string.should == "USD"
59
+ Money.new(200_00, "EUR").currency_as_string.should == "EUR"
60
+ Money.new(200_00, "YEN").currency_as_string.should == "YEN"
61
+ end
62
+
63
+ specify "#currency_string= set the currency object using the provided string" do
64
+ obj = Money.new(200_00, "USD")
65
+ obj.currency_as_string = "EUR"
66
+ obj.currency.should == Money::Currency.new("EUR")
67
+ obj.currency_as_string = "YEN"
68
+ obj.currency.should == Money::Currency.new("YEN")
69
+ obj.currency_as_string = "USD"
70
+ obj.currency.should == Money::Currency.new("USD")
71
+ end
72
+
73
+
74
+ specify "#exchange_to exchanges the amount via its exchange bank" do
75
+ money = Money.new(100_00, "USD")
76
+ money.bank.should_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')))
77
+ money.exchange_to("EUR")
78
+ end
79
+
80
+ specify "#exchange_to exchanges the amount properly" do
81
+ money = Money.new(100_00, "USD")
82
+ money.bank.should_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')))
83
+ money.exchange_to("EUR").should == Money.new(200_00, "EUR")
84
+ end
85
+
86
+ specify "#hash should return the same value for equal objects" do
87
+ Money.new(1_00, :eur).hash.should == Money.new(1_00, :eur).hash
88
+ Money.new(2_00, :usd).hash.should == Money.new(2_00, :usd).hash
89
+ Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :eur).hash
90
+ Money.new(1_00, :eur).hash.should_not == Money.new(1_00, :usd).hash
91
+ Money.new(1_00, :eur).hash.should_not == Money.new(2_00, :usd).hash
92
+ end
93
+
94
+ specify "#hash can be used to return the intersection of Money object arrays" do
95
+ intersection = [Money.new(1_00, :eur), Money.new(1_00, :usd)] & [Money.new(1_00, :eur)]
96
+ intersection.should == [Money.new(1_00, :eur)]
97
+ end
98
+
99
+
100
+ specify "Money.to_s works" do
101
+ Money.new(10_00).to_s.should == "10.00"
102
+ Money.new(400_08).to_s.should == "400.08"
103
+ Money.new(-237_43).to_s.should == "-237.43"
104
+ end
105
+
106
+ specify "Money.to_s should respect :subunit_to_unit currency property" do
107
+ Money.new(10_00, "BHD").to_s.should == "1.000"
108
+ Money.new(10_00, "CNY").to_s.should == "10.00"
109
+ end
110
+
111
+ specify "Money.to_s shouldn't have decimal when :subunit_to_unit is 1" do
112
+ Money.new(10_00, "CLP").to_s.should == "1000"
113
+ end
114
+
115
+ specify "Money.to_s should work with :subunit_to_unit == 5" do
116
+ Money.new(10_00, "MGA").to_s.should == "200.0"
117
+ end
118
+
119
+ specify "Money.to_s should respect :decimal_mark" do
120
+ Money.new(10_00, "BRL").to_s.should == "10,00"
121
+ end
122
+
123
+ specify "Money.to_f works" do
124
+ Money.new(10_00).to_f.should == 10.0
125
+ end
126
+
127
+ specify "Money.to_f should respect :subunit_to_unit currency property" do
128
+ Money.new(10_00, "BHD").to_f.should == 1.0
129
+ end
130
+
131
+ specify "#symbol works as documented" do
132
+ currency = Money::Currency.new("EUR")
133
+ currency.should_receive(:symbol).and_return("€")
134
+ Money.empty(currency).symbol.should == "€"
135
+
136
+ currency = Money::Currency.new("EUR")
137
+ currency.should_receive(:symbol).and_return(nil)
138
+ Money.empty(currency).symbol.should == "¤"
139
+ end
140
+
141
+ describe "Money.empty" do
142
+ it "Money.empty creates a new Money object of 0 cents" do
143
+ Money.empty.should == Money.new(0)
144
+ end
145
+ end
146
+
147
+ describe "Money.ca_dollar" do
148
+ it "creates a new Money object of the given value in CAD" do
149
+ Money.ca_dollar(50).should == Money.new(50, "CAD")
150
+ end
151
+ end
152
+
153
+ describe "Money.us_dollar" do
154
+ it "creates a new Money object of the given value in USD" do
155
+ Money.us_dollar(50).should == Money.new(50, "USD")
156
+ end
157
+ end
158
+
159
+ describe "Money.euro" do
160
+ it "creates a new Money object of the given value in EUR" do
161
+ Money.euro(50).should == Money.new(50, "EUR")
162
+ end
163
+ end
164
+
165
+
166
+ describe "Money.new_with_dollars" do
167
+ it "converts given amount to cents" do
168
+ Money.new_with_dollars(1).should == Money.new(100)
169
+ Money.new_with_dollars(1, "USD").should == Money.new(100, "USD")
170
+ Money.new_with_dollars(1, "EUR").should == Money.new(100, "EUR")
171
+ end
172
+
173
+ it "should respect :subunit_to_unit currency property" do
174
+ Money.new_with_dollars(1, "USD").should == Money.new(1_00, "USD")
175
+ Money.new_with_dollars(1, "TND").should == Money.new(1_000, "TND")
176
+ Money.new_with_dollars(1, "CLP").should == Money.new(1, "CLP")
177
+ end
178
+
179
+ it "should not loose precision" do
180
+ Money.new_with_dollars(1234).cents.should == 1234_00
181
+ Money.new_with_dollars(100.37).cents.should == 100_37
182
+ Money.new_with_dollars(BigDecimal.new('1234')).cents.should == 1234_00
183
+ end
184
+
185
+ it "accepts a currency options" do
186
+ m = Money.new_with_dollars(1)
187
+ m.currency.should == Money.default_currency
188
+
189
+ m = Money.new_with_dollars(1, Money::Currency.wrap("EUR"))
190
+ m.currency.should == Money::Currency.wrap("EUR")
191
+
192
+ m = Money.new_with_dollars(1, "EUR")
193
+ m.currency.should == Money::Currency.wrap("EUR")
194
+ end
195
+
196
+ it "accepts a bank options" do
197
+ m = Money.new_with_dollars(1)
198
+ m.bank.should == Money.default_bank
199
+
200
+ m = Money.new_with_dollars(1, "EUR", bank = Object.new)
201
+ m.bank.should == bank
202
+ end
203
+
204
+ it "is associated to the singleton instance of Bank::VariableExchange by default" do
205
+ Money.new_with_dollars(0).bank.should be_equal(Money::Bank::VariableExchange.instance)
206
+ end
207
+ end
208
+
209
+ describe "split" do
210
+ specify "#split needs at least one party" do
211
+ lambda {Money.us_dollar(1).split(0)}.should raise_error(ArgumentError)
212
+ lambda {Money.us_dollar(1).split(-1)}.should raise_error(ArgumentError)
213
+ end
214
+
215
+
216
+ specify "#gives 1 cent to both people if we start with 2" do
217
+ Money.us_dollar(2).split(2).should == [Money.us_dollar(1), Money.us_dollar(1)]
218
+ end
219
+
220
+ specify "#split may distribute no money to some parties if there isnt enough to go around" do
221
+ Money.us_dollar(2).split(3).should == [Money.us_dollar(1), Money.us_dollar(1), Money.us_dollar(0)]
222
+ end
223
+
224
+ specify "#split does not lose pennies" do
225
+ Money.us_dollar(5).split(2).should == [Money.us_dollar(3), Money.us_dollar(2)]
226
+ end
227
+
228
+ specify "#split a dollar" do
229
+ moneys = Money.us_dollar(100).split(3)
230
+ moneys[0].cents.should == 34
231
+ moneys[1].cents.should == 33
232
+ moneys[2].cents.should == 33
233
+ end
234
+ end
235
+
236
+ describe "allocation" do
237
+ specify "#allocate takes no action when one gets all" do
238
+ Money.us_dollar(005).allocate([1.0]).should == [Money.us_dollar(5)]
239
+ end
240
+
241
+ specify "#allocate keeps currencies intact" do
242
+ Money.ca_dollar(005).allocate([1]).should == [Money.ca_dollar(5)]
243
+ end
244
+
245
+ specify "#allocate does not loose pennies" do
246
+ moneys = Money.us_dollar(5).allocate([0.3,0.7])
247
+ moneys[0].should == Money.us_dollar(2)
248
+ moneys[1].should == Money.us_dollar(3)
249
+ end
250
+
251
+ specify "#allocate does not loose pennies" do
252
+ moneys = Money.us_dollar(100).allocate([0.333,0.333, 0.333])
253
+ moneys[0].cents.should == 34
254
+ moneys[1].cents.should == 33
255
+ moneys[2].cents.should == 33
256
+ end
257
+
258
+ specify "#allocate requires total to be less then 1" do
259
+ lambda { Money.us_dollar(0.05).allocate([0.5,0.6]) }.should raise_error(ArgumentError)
260
+ end
261
+ end
262
+
263
+ describe "Money.add_rate" do
264
+ it "saves rate into current bank" do
265
+ Money.add_rate("EUR", "USD", 10)
266
+ Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
267
+ end
268
+ end
269
+
270
+ end
271
+