money-joshm1 5.1.2

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.
@@ -0,0 +1,183 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Money::Currency do
6
+
7
+ FOO = '{ "priority": 1, "iso_code": "FOO", "iso_numeric": "840", "name": "United States Dollar", "symbol": "$", "subunit": "Cent", "subunit_to_unit": 450, "symbol_first": true, "html_entity": "$", "decimal_mark": ".", "thousands_separator": "," }'
8
+
9
+ describe ".find" do
10
+ it "returns currency matching given id" do
11
+ Money::Currency.register(JSON.parse(FOO, :symbolize_names => true))
12
+
13
+ expected = Money::Currency.new(:foo)
14
+ Money::Currency.find(:foo).should == expected
15
+ Money::Currency.find(:FOO).should == expected
16
+ Money::Currency.find("foo").should == expected
17
+ Money::Currency.find("FOO").should == expected
18
+ end
19
+
20
+ it "returns nil unless currency matching given id" do
21
+ Money::Currency.find("ZZZ").should be_nil
22
+ end
23
+ end
24
+
25
+ describe ".find_by_iso_numeric" do
26
+ it "returns currency matching given numeric code" do
27
+ Money::Currency.find_by_iso_numeric(978).should == Money::Currency.new(:eur)
28
+ Money::Currency.find_by_iso_numeric(208).should_not == Money::Currency.new(:eur)
29
+ Money::Currency.find_by_iso_numeric('840').should == Money::Currency.new(:usd)
30
+
31
+ class Mock
32
+ def to_s
33
+ '208'
34
+ end
35
+ end
36
+ Money::Currency.find_by_iso_numeric(Mock.new).should == Money::Currency.new(:dkk)
37
+ Money::Currency.find_by_iso_numeric(Mock.new).should_not == Money::Currency.new(:usd)
38
+ end
39
+
40
+ it "returns nil if no currency has the given numeric code" do
41
+ Money::Currency.find_by_iso_numeric('non iso 4217 numeric code').should == nil
42
+ Money::Currency.find_by_iso_numeric(0).should == nil
43
+ end
44
+ end
45
+
46
+ describe ".wrap" do
47
+ it "returns nil if object is nil" do
48
+ Money::Currency.wrap(nil).should == nil
49
+ Money::Currency.wrap(Money::Currency.new(:usd)).should == Money::Currency.new(:usd)
50
+ Money::Currency.wrap(:usd).should == Money::Currency.new(:usd)
51
+ end
52
+ end
53
+
54
+ describe ".all" do
55
+ it "returns an array of currencies" do
56
+ Money::Currency.all.should include Money::Currency.new(:usd)
57
+ end
58
+ it "includes registered currencies" do
59
+ Money::Currency.register(JSON.parse(FOO, :symbolize_names => true))
60
+ Money::Currency.all.should include Money::Currency.new(:foo)
61
+ end
62
+ it 'is sorted by priority' do
63
+ Money::Currency.all.first.priority.should == 1
64
+ end
65
+ end
66
+
67
+ describe "#initialize" do
68
+ it "lookups data from loaded config" do
69
+ currency = Money::Currency.new("USD")
70
+ currency.id.should == :usd
71
+ currency.priority.should == 1
72
+ currency.iso_code.should == "USD"
73
+ currency.iso_numeric.should == "840"
74
+ currency.name.should == "United States Dollar"
75
+ currency.decimal_mark.should == "."
76
+ currency.separator.should == "."
77
+ currency.thousands_separator.should == ","
78
+ currency.delimiter.should == ","
79
+ end
80
+
81
+ it "raises UnknownMoney::Currency with unknown currency" do
82
+ expect { Money::Currency.new("xxx") }.to raise_error(Money::Currency::UnknownCurrency, /xxx/)
83
+ end
84
+ end
85
+
86
+ describe "#<=>" do
87
+ it "compares objects by priority" do
88
+ Money::Currency.new(:cad).should > Money::Currency.new(:usd)
89
+ Money::Currency.new(:usd).should < Money::Currency.new(:eur)
90
+ end
91
+ end
92
+
93
+ describe "#==" do
94
+ it "returns true if self === other" do
95
+ currency = Money::Currency.new(:eur)
96
+ currency.should == currency
97
+ end
98
+
99
+ it "returns true if the id is equal ignorning case" do
100
+ Money::Currency.new(:eur).should == Money::Currency.new(:eur)
101
+ Money::Currency.new(:eur).should == Money::Currency.new(:EUR)
102
+ Money::Currency.new(:eur).should_not == Money::Currency.new(:usd)
103
+ end
104
+
105
+ it "allows direct comparison of currencies and symbols/strings" do
106
+ Money::Currency.new(:eur).should == 'eur'
107
+ Money::Currency.new(:eur).should == :EUR
108
+ Money::Currency.new(:eur).should_not == 'usd'
109
+ end
110
+ end
111
+
112
+ describe "#eql?" do
113
+ it "returns true if #== returns true" do
114
+ Money::Currency.new(:eur).eql?(Money::Currency.new(:eur)).should be true
115
+ Money::Currency.new(:eur).eql?(Money::Currency.new(:usd)).should be false
116
+ end
117
+ end
118
+
119
+ describe "#hash" do
120
+ it "returns the same value for equal objects" do
121
+ Money::Currency.new(:eur).hash.should == Money::Currency.new(:eur).hash
122
+ Money::Currency.new(:eur).hash.should_not == Money::Currency.new(:usd).hash
123
+ end
124
+
125
+ it "can be used to return the intersection of Currency object arrays" do
126
+ intersection = [Money::Currency.new(:eur), Money::Currency.new(:usd)] & [Money::Currency.new(:eur)]
127
+ intersection.should == [Money::Currency.new(:eur)]
128
+ end
129
+ end
130
+
131
+ describe "#inspect" do
132
+ it "works as documented" do
133
+ Money::Currency.new(:usd).inspect.should ==
134
+ %Q{#<Money::Currency id: usd, priority: 1, symbol_first: true, thousands_separator: ,, html_entity: $, decimal_mark: ., name: United States Dollar, symbol: $, subunit_to_unit: 100, exponent: 2.0, iso_code: USD, iso_numeric: 840, subunit: Cent>}
135
+ end
136
+ end
137
+
138
+ describe "#to_s" do
139
+ it "works as documented" do
140
+ Money::Currency.new(:usd).to_s.should == "USD"
141
+ Money::Currency.new(:eur).to_s.should == "EUR"
142
+ end
143
+ end
144
+
145
+ describe "#to_currency" do
146
+ it "works as documented" do
147
+ usd = Money::Currency.new(:usd)
148
+ usd.to_currency.should == usd
149
+ end
150
+
151
+ it "doesn't create new symbols indefinitely" do
152
+ expect { Money::Currency.new("bogus") }.to raise_exception(Money::Currency::UnknownCurrency)
153
+ Symbol.all_symbols.map{|s| s.to_s}.should_not include("bogus")
154
+ end
155
+ end
156
+
157
+ describe "#code" do
158
+ it "works as documented" do
159
+ Money::Currency.new(:usd).code.should == "$"
160
+ Money::Currency.new(:azn).code.should == "AZN"
161
+ end
162
+ end
163
+
164
+ describe "#exponent" do
165
+ it "conforms to iso 4217" do
166
+ Money::Currency.new(:jpy).exponent == 0
167
+ Money::Currency.new(:usd).exponent == 2
168
+ Money::Currency.new(:iqd).exponent == 3
169
+ end
170
+ end
171
+
172
+ describe "#decimal_places" do
173
+ it "proper places for known currency" do
174
+ Money::Currency.new(:mro).decimal_places == 1
175
+ Money::Currency.new(:usd).decimal_places == 2
176
+ end
177
+
178
+ it "proper places for custom currency" do
179
+ Money::Currency.register(JSON.parse(FOO, :symbolize_names => true))
180
+ Money::Currency.new(:foo).decimal_places == 3
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,598 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Money do
6
+ describe "-@" do
7
+ it "changes the sign of a number" do
8
+ (- Money.new(0)).should == Money.new(0)
9
+ (- Money.new(1)).should == Money.new(-1)
10
+ (- Money.new(-1)).should == Money.new(1)
11
+ end
12
+ end
13
+
14
+ describe "#==" do
15
+ it "returns true if and only if their amount and currency are equal" do
16
+ Money.new(1_00, "USD").should == Money.new(1_00, "USD")
17
+ Money.new(1_00, "USD").should_not == Money.new(1_00, "EUR")
18
+ Money.new(1_00, "USD").should_not == Money.new(2_00, "USD")
19
+ Money.new(1_00, "USD").should_not == Money.new(99_00, "EUR")
20
+ end
21
+
22
+ it "returns false if used to compare with an object that doesn't respond to #to_money" do
23
+ Money.new(1_00, "USD").should_not == Object.new
24
+ Money.new(1_00, "USD").should_not == Class
25
+ Money.new(1_00, "USD").should_not == Kernel
26
+ Money.new(1_00, "USD").should_not == /foo/
27
+ Money.new(1_00, "USD").should_not == nil
28
+ end
29
+
30
+ it "can be used to compare with a String money value" do
31
+ Money.new(1_00, "USD").should == "1.00"
32
+ Money.new(1_00, "USD").should_not == "2.00"
33
+ Money.new(1_00, "GBP").should_not == "1.00"
34
+ end
35
+
36
+ it "can be used to compare with a Numeric money value" do
37
+ Money.new(1_00, "USD").should == 1
38
+ Money.new(1_57, "USD").should == 1.57
39
+ Money.new(1_00, "USD").should_not == 2
40
+ Money.new(1_00, "GBP").should_not == 1
41
+ end
42
+
43
+ it "can be used to compare with an object that responds to #to_money" do
44
+ klass = Class.new do
45
+ def initialize(money)
46
+ @money = money
47
+ end
48
+
49
+ def to_money
50
+ @money
51
+ end
52
+ end
53
+
54
+ Money.new(1_00, "USD").should == klass.new(Money.new(1_00, "USD"))
55
+ Money.new(2_50, "USD").should == klass.new(Money.new(2_50, "USD"))
56
+ Money.new(2_50, "USD").should_not == klass.new(Money.new(3_00, "USD"))
57
+ Money.new(1_00, "GBP").should_not == klass.new(Money.new(1_00, "USD"))
58
+ end
59
+ end
60
+
61
+ describe "#eql?" do
62
+ it "returns true if and only if their amount and currency are equal" do
63
+ Money.new(1_00, "USD").eql?(Money.new(1_00, "USD")).should be true
64
+ Money.new(1_00, "USD").eql?(Money.new(1_00, "EUR")).should be false
65
+ Money.new(1_00, "USD").eql?(Money.new(2_00, "USD")).should be false
66
+ Money.new(1_00, "USD").eql?(Money.new(99_00, "EUR")).should be false
67
+ end
68
+
69
+ it "returns false if used to compare with an object that doesn't respond to #to_money" do
70
+ Money.new(1_00, "USD").eql?(Object.new).should be false
71
+ Money.new(1_00, "USD").eql?(Class).should be false
72
+ Money.new(1_00, "USD").eql?(Kernel).should be false
73
+ Money.new(1_00, "USD").eql?(/foo/).should be false
74
+ Money.new(1_00, "USD").eql?(nil).should be false
75
+ end
76
+
77
+ it "can be used to compare with a String money value" do
78
+ Money.new(1_00, "USD").eql?("1.00").should be true
79
+ Money.new(1_00, "USD").eql?("2.00").should be false
80
+ Money.new(1_00, "GBP").eql?("1.00").should be false
81
+ end
82
+
83
+ it "can be used to compare with a Numeric money value" do
84
+ Money.new(1_00, "USD").eql?(1).should be true
85
+ Money.new(1_57, "USD").eql?(1.57).should be true
86
+ Money.new(1_00, "USD").eql?(2).should be false
87
+ Money.new(1_00, "GBP").eql?(1).should be false
88
+ end
89
+
90
+ it "can be used to compare with an object that responds to #to_money" do
91
+ klass = Class.new do
92
+ def initialize(money)
93
+ @money = money
94
+ end
95
+
96
+ def to_money
97
+ @money
98
+ end
99
+ end
100
+
101
+ Money.new(1_00, "USD").eql?(klass.new(Money.new(1_00, "USD"))).should be true
102
+ Money.new(2_50, "USD").eql?(klass.new(Money.new(2_50, "USD"))).should be true
103
+ Money.new(2_50, "USD").eql?(klass.new(Money.new(3_00, "USD"))).should be false
104
+ Money.new(1_00, "GBP").eql?(klass.new(Money.new(1_00, "USD"))).should be false
105
+ end
106
+ end
107
+
108
+ describe "#<=>" do
109
+ it "compares the two object amounts (same currency)" do
110
+ (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
111
+ (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
112
+ (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
113
+ end
114
+
115
+ it "converts other object amount to current currency, then compares the two object amounts (different currency)" do
116
+ target = Money.new(200_00, "EUR")
117
+ target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(300_00, "USD"))
118
+ (Money.new(100_00, "USD") <=> target).should < 0
119
+
120
+ target = Money.new(200_00, "EUR")
121
+ target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(100_00, "USD"))
122
+ (Money.new(100_00, "USD") <=> target).should == 0
123
+
124
+ target = Money.new(200_00, "EUR")
125
+ target.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(99_00, "USD"))
126
+ (Money.new(100_00, "USD") <=> target).should > 0
127
+ end
128
+
129
+ it "cannot compare objects with different currencies when no rate exists, unless one of the amounts is zero" do
130
+ expect { Money.new(100_00, "EUR") <=> Money.new(100_00, "USD") }.to raise_error(Money::Bank::UnknownRate)
131
+
132
+ (Money.new(100_00, "EUR") <=> Money.new(0, "USD")).should > 0
133
+ (Money.new(0, "EUR") <=> Money.new(100_00, "USD")).should < 0
134
+ (Money.new(0, "EUR") <=> Money.new(0, "USD")).should == 0
135
+ end
136
+
137
+ it "can be used to compare with a String money value when Money object is in default currency" do
138
+ (Money.new(1_00) <=> "1.00").should == 0
139
+ (Money.new(1_00) <=> ".99").should > 0
140
+ (Money.new(1_00) <=> "2.00").should < 0
141
+ end
142
+
143
+ it "can be used to compare with a String money value when Money object is not in default currency if String evaluates to zero" do
144
+ expect { Money.new(1_00, "EUR") <=> "1.00" }.to raise_error(Money::Bank::UnknownRate)
145
+
146
+ (Money.new(1_00, "EUR") <=> "0.00").should > 0
147
+ (Money.new(0_00, "EUR") <=> "0.00").should == 0
148
+ (Money.new(-1_00, "EUR") <=> "0.00").should < 0
149
+ end
150
+
151
+ it "can be used to compare with a Numeric money value when Money object is in default currency" do
152
+ (Money.new(1_00) <=> 1).should == 0
153
+ (Money.new(1_00) <=> 0.99).should > 0
154
+ (Money.new(1_00) <=> 2.00).should < 0
155
+ end
156
+
157
+ it "can be used to compare with a Numeric money value when Money object is not in default currency if String evaluates to zero" do
158
+ expect { Money.new(1_00, "EUR") <=> 1 }.to raise_error(Money::Bank::UnknownRate)
159
+
160
+ (Money.new(1_00, "EUR") <=> 0).should > 0
161
+ (Money.new(0_00, "EUR") <=> 0).should == 0
162
+ (Money.new(-1_00, "EUR") <=> 0).should < 0
163
+ end
164
+
165
+ it "can be used to compare with an object that responds to #to_money" do
166
+ klass = Class.new do
167
+ def initialize(money)
168
+ @money = money
169
+ end
170
+
171
+ def to_money
172
+ @money
173
+ end
174
+ end
175
+
176
+ (Money.new(1_00) <=> klass.new(Money.new(1_00))).should == 0
177
+ (Money.new(1_00) <=> klass.new(Money.new(99))).should > 0
178
+ (Money.new(1_00) <=> klass.new(Money.new(2_00))).should < 0
179
+ end
180
+
181
+ it "raises ArgumentError when used to compare with an object that doesn't respond to #to_money" do
182
+ expected_message = /Comparison .+ failed/
183
+ expect{ Money.new(1_00) <=> Object.new }.to raise_error(ArgumentError, expected_message)
184
+ expect{ Money.new(1_00) <=> Class }.to raise_error(ArgumentError, expected_message)
185
+ expect{ Money.new(1_00) <=> Kernel }.to raise_error(ArgumentError, expected_message)
186
+ expect{ Money.new(1_00) <=> /foo/ }.to raise_error(ArgumentError, expected_message)
187
+ end
188
+ end
189
+
190
+ describe "#positive?" do
191
+ it "returns true if the amount is greater than 0" do
192
+ Money.new(1).should be_positive
193
+ end
194
+
195
+ it "returns false if the amount is 0" do
196
+ Money.new(0).should_not be_positive
197
+ end
198
+
199
+ it "returns false if the amount is negative" do
200
+ Money.new(-1).should_not be_positive
201
+ end
202
+ end
203
+
204
+ describe "#negative?" do
205
+ it "returns true if the amount is less than 0" do
206
+ Money.new(-1).should be_negative
207
+ end
208
+
209
+ it "returns false if the amount is 0" do
210
+ Money.new(0).should_not be_negative
211
+ end
212
+
213
+ it "returns false if the amount is greater than 0" do
214
+ Money.new(1).should_not be_negative
215
+ end
216
+ end
217
+
218
+ describe "#+" do
219
+ it "adds other amount to current amount (same currency)" do
220
+ (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
221
+ end
222
+
223
+ it "converts other object amount to current currency and adds other amount to current amount (different currency)" do
224
+ other = Money.new(90, "EUR")
225
+ other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
226
+ (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
227
+ end
228
+ end
229
+
230
+ describe "#-" do
231
+ it "subtracts other amount from current amount (same currency)" do
232
+ (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
233
+ end
234
+
235
+ it "converts other object amount to current currency and subtracts other amount from current amount (different currency)" do
236
+ other = Money.new(90, "EUR")
237
+ other.should_receive(:exchange_to).with(Money::Currency.new("USD")).and_return(Money.new(9_00, "USD"))
238
+ (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
239
+ end
240
+ end
241
+
242
+ describe "#*" do
243
+ it "multiplies Money by Fixnum and returns Money" do
244
+ ts = [
245
+ {:a => Money.new( 10, :USD), :b => 4, :c => Money.new( 40, :USD)},
246
+ {:a => Money.new( 10, :USD), :b => -4, :c => Money.new(-40, :USD)},
247
+ {:a => Money.new(-10, :USD), :b => 4, :c => Money.new(-40, :USD)},
248
+ {:a => Money.new(-10, :USD), :b => -4, :c => Money.new( 40, :USD)},
249
+ ]
250
+ ts.each do |t|
251
+ (t[:a] * t[:b]).should == t[:c]
252
+ end
253
+ end
254
+
255
+ it "does not multiply Money by Money (same currency)" do
256
+ expect { Money.new( 10, :USD) * Money.new( 4, :USD) }.to raise_error(ArgumentError)
257
+ end
258
+
259
+ it "does not multiply Money by Money (different currency)" do
260
+ expect { Money.new( 10, :USD) * Money.new( 4, :EUR) }.to raise_error(ArgumentError)
261
+ end
262
+ end
263
+
264
+ describe "#/" do
265
+ it "divides Money by Fixnum and returns Money" do
266
+ ts = [
267
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
268
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
269
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
270
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
271
+ ]
272
+ ts.each do |t|
273
+ (t[:a] / t[:b]).should == t[:c]
274
+ end
275
+ end
276
+
277
+ it "divides Money by Money (same currency) and returns Float" do
278
+ ts = [
279
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
280
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
281
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
282
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
283
+ ]
284
+ ts.each do |t|
285
+ (t[:a] / t[:b]).should == t[:c]
286
+ end
287
+ end
288
+
289
+ it "divides Money by Money (different currency) and returns Float" do
290
+ ts = [
291
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
292
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
293
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
294
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
295
+ ]
296
+ ts.each do |t|
297
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
298
+ (t[:a] / t[:b]).should == t[:c]
299
+ end
300
+ end
301
+
302
+ context "infinite_precision = true" do
303
+ before do
304
+ Money.infinite_precision = true
305
+ end
306
+
307
+ after do
308
+ Money.infinite_precision = false
309
+ end
310
+
311
+ it "uses BigDecimal division" do
312
+ ts = [
313
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3.25, :USD)},
314
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3.25, :USD)},
315
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-3.25, :USD)},
316
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3.25, :USD)},
317
+ ]
318
+ ts.each do |t|
319
+ (t[:a] / t[:b]).should == t[:c]
320
+ end
321
+ end
322
+ end
323
+ end
324
+
325
+ describe "#div" do
326
+ it "divides Money by Fixnum and returns Money" do
327
+ ts = [
328
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3, :USD)},
329
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-4, :USD)},
330
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-4, :USD)},
331
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3, :USD)},
332
+ ]
333
+ ts.each do |t|
334
+ t[:a].div(t[:b]).should == t[:c]
335
+ end
336
+ end
337
+
338
+ it "divides Money by Money (same currency) and returns Float" do
339
+ ts = [
340
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => 3.25},
341
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => -3.25},
342
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => -3.25},
343
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => 3.25},
344
+ ]
345
+ ts.each do |t|
346
+ t[:a].div(t[:b]).should == t[:c]
347
+ end
348
+ end
349
+
350
+ it "divides Money by Money (different currency) and returns Float" do
351
+ ts = [
352
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => 1.625},
353
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => -1.625},
354
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => -1.625},
355
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => 1.625},
356
+ ]
357
+ ts.each do |t|
358
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
359
+ t[:a].div(t[:b]).should == t[:c]
360
+ end
361
+ end
362
+
363
+ context "infinite_precision = true" do
364
+ before do
365
+ Money.infinite_precision = true
366
+ end
367
+
368
+ after do
369
+ Money.infinite_precision = false
370
+ end
371
+
372
+ it "uses BigDecimal division" do
373
+ ts = [
374
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 3.25, :USD)},
375
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3.25, :USD)},
376
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-3.25, :USD)},
377
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new( 3.25, :USD)},
378
+ ]
379
+ ts.each do |t|
380
+ t[:a].div(t[:b]).should == t[:c]
381
+ end
382
+ end
383
+ end
384
+ end
385
+
386
+ describe "#divmod" do
387
+ it "calculates division and modulo with Fixnum" do
388
+ ts = [
389
+ {:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
390
+ {:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-4, :USD), Money.new(-3, :USD)]},
391
+ {:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-4, :USD), Money.new( 3, :USD)]},
392
+ {:a => Money.new(-13, :USD), :b => -4, :c => [Money.new( 3, :USD), Money.new(-1, :USD)]},
393
+ ]
394
+ ts.each do |t|
395
+ t[:a].divmod(t[:b]).should == t[:c]
396
+ end
397
+ end
398
+
399
+ it "calculates division and modulo with Money (same currency)" do
400
+ ts = [
401
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => [ 3, Money.new( 1, :USD)]},
402
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => [-4, Money.new(-3, :USD)]},
403
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => [-4, Money.new( 3, :USD)]},
404
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => [ 3, Money.new(-1, :USD)]},
405
+ ]
406
+ ts.each do |t|
407
+ t[:a].divmod(t[:b]).should == t[:c]
408
+ end
409
+ end
410
+
411
+ it "calculates division and modulo with Money (different currency)" do
412
+ ts = [
413
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => [ 1, Money.new( 5, :USD)]},
414
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => [-2, Money.new(-3, :USD)]},
415
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => [-2, Money.new( 3, :USD)]},
416
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => [ 1, Money.new(-5, :USD)]},
417
+ ]
418
+ ts.each do |t|
419
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
420
+ t[:a].divmod(t[:b]).should == t[:c]
421
+ end
422
+ end
423
+
424
+ context "infinite_precision = true" do
425
+ before do
426
+ Money.infinite_precision = true
427
+ end
428
+
429
+ after do
430
+ Money.infinite_precision = false
431
+ end
432
+
433
+ it "uses BigDecimal division" do
434
+ ts = [
435
+ {:a => Money.new( 13, :USD), :b => 4, :c => [Money.new( 3, :USD), Money.new( 1, :USD)]},
436
+ {:a => Money.new( 13, :USD), :b => -4, :c => [Money.new(-4, :USD), Money.new(-3, :USD)]},
437
+ {:a => Money.new(-13, :USD), :b => 4, :c => [Money.new(-4, :USD), Money.new( 3, :USD)]},
438
+ {:a => Money.new(-13, :USD), :b => -4, :c => [Money.new( 3, :USD), Money.new(-1, :USD)]},
439
+ ]
440
+ ts.each do |t|
441
+ t[:a].divmod(t[:b]).should == t[:c]
442
+ end
443
+ end
444
+ end
445
+ end
446
+
447
+ describe "#modulo" do
448
+ it "calculates modulo with Fixnum" do
449
+ ts = [
450
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
451
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
452
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
453
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
454
+ ]
455
+ ts.each do |t|
456
+ t[:a].modulo(t[:b]).should == t[:c]
457
+ end
458
+ end
459
+
460
+ it "calculates modulo with Money (same currency)" do
461
+ ts = [
462
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
463
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
464
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
465
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
466
+ ]
467
+ ts.each do |t|
468
+ t[:a].modulo(t[:b]).should == t[:c]
469
+ end
470
+ end
471
+
472
+ it "calculates modulo with Money (different currency)" do
473
+ ts = [
474
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
475
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
476
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
477
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
478
+ ]
479
+ ts.each do |t|
480
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
481
+ t[:a].modulo(t[:b]).should == t[:c]
482
+ end
483
+ end
484
+ end
485
+
486
+ describe "#%" do
487
+ it "calculates modulo with Fixnum" do
488
+ ts = [
489
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
490
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new(-3, :USD)},
491
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new( 3, :USD)},
492
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
493
+ ]
494
+ ts.each do |t|
495
+ (t[:a] % t[:b]).should == t[:c]
496
+ end
497
+ end
498
+
499
+ it "calculates modulo with Money (same currency)" do
500
+ ts = [
501
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
502
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-3, :USD)},
503
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 3, :USD)},
504
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
505
+ ]
506
+ ts.each do |t|
507
+ (t[:a] % t[:b]).should == t[:c]
508
+ end
509
+ end
510
+
511
+ it "calculates modulo with Money (different currency)" do
512
+ ts = [
513
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
514
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-3, :USD)},
515
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 3, :USD)},
516
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
517
+ ]
518
+ ts.each do |t|
519
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
520
+ (t[:a] % t[:b]).should == t[:c]
521
+ end
522
+ end
523
+ end
524
+
525
+ describe "#remainder" do
526
+ it "calculates remainder with Fixnum" do
527
+ ts = [
528
+ {:a => Money.new( 13, :USD), :b => 4, :c => Money.new( 1, :USD)},
529
+ {:a => Money.new( 13, :USD), :b => -4, :c => Money.new( 1, :USD)},
530
+ {:a => Money.new(-13, :USD), :b => 4, :c => Money.new(-1, :USD)},
531
+ {:a => Money.new(-13, :USD), :b => -4, :c => Money.new(-1, :USD)},
532
+ ]
533
+ ts.each do |t|
534
+ t[:a].remainder(t[:b]).should == t[:c]
535
+ end
536
+ end
537
+
538
+ it "calculates remainder with Money (same currency)" do
539
+ ts = [
540
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :USD), :c => Money.new( 1, :USD)},
541
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :USD), :c => Money.new( 1, :USD)},
542
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :USD), :c => Money.new(-1, :USD)},
543
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :USD), :c => Money.new(-1, :USD)},
544
+ ]
545
+ ts.each do |t|
546
+ t[:a].remainder(t[:b]).should == t[:c]
547
+ end
548
+ end
549
+
550
+ it "calculates remainder with Money (different currency)" do
551
+ ts = [
552
+ {:a => Money.new( 13, :USD), :b => Money.new( 4, :EUR), :c => Money.new( 5, :USD)},
553
+ {:a => Money.new( 13, :USD), :b => Money.new(-4, :EUR), :c => Money.new( 5, :USD)},
554
+ {:a => Money.new(-13, :USD), :b => Money.new( 4, :EUR), :c => Money.new(-5, :USD)},
555
+ {:a => Money.new(-13, :USD), :b => Money.new(-4, :EUR), :c => Money.new(-5, :USD)},
556
+ ]
557
+ ts.each do |t|
558
+ t[:b].should_receive(:exchange_to).once.with(t[:a].currency).and_return(Money.new(t[:b].cents * 2, :USD))
559
+ t[:a].remainder(t[:b]).should == t[:c]
560
+ end
561
+ end
562
+ end
563
+
564
+ describe "#abs" do
565
+ it "returns the absolute value as a new Money object" do
566
+ n = Money.new(-1, :USD)
567
+ n.abs.should == Money.new( 1, :USD)
568
+ n.should == Money.new(-1, :USD)
569
+ end
570
+ end
571
+
572
+ describe "#zero?" do
573
+ it "returns whether the amount is 0" do
574
+ Money.new(0, "USD").should be_zero
575
+ Money.new(0, "EUR").should be_zero
576
+ Money.new(1, "USD").should_not be_zero
577
+ Money.new(10, "YEN").should_not be_zero
578
+ Money.new(-1, "EUR").should_not be_zero
579
+ end
580
+ end
581
+
582
+ describe "#nonzero?" do
583
+ it "returns whether the amount is not 0" do
584
+ Money.new(0, "USD").should_not be_nonzero
585
+ Money.new(0, "EUR").should_not be_nonzero
586
+ Money.new(1, "USD").should be_nonzero
587
+ Money.new(10, "YEN").should be_nonzero
588
+ Money.new(-1, "EUR").should be_nonzero
589
+ end
590
+
591
+ it "has the same return-value semantics as Numeric#nonzero?" do
592
+ Money.new(0, "USD").nonzero?.should be_nil
593
+
594
+ money = Money.new(1, "USD")
595
+ money.nonzero?.should be_equal(money)
596
+ end
597
+ end
598
+ end