shopify-money 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,355 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe MoneyParser do
4
+ before(:each) do
5
+ @parser = MoneyParser
6
+ end
7
+
8
+ describe "parsing of amounts with period decimal separator" do
9
+ it "parses an empty string to $0" do
10
+ expect(@parser.parse("")).to eq(Money.zero)
11
+ end
12
+
13
+ it "parses an invalid string when not strict" do
14
+ expect(Money).to receive(:deprecate).twice
15
+ expect(@parser.parse("no money")).to eq(Money.zero)
16
+ expect(@parser.parse("1..")).to eq(Money.new(1))
17
+ end
18
+
19
+ it "parses raise with an invalid string and strict option" do
20
+ expect { @parser.parse("no money", strict: true) }.to raise_error(MoneyParser::MoneyFormatError)
21
+ expect { @parser.parse("1..1", strict: true) }.to raise_error(MoneyParser::MoneyFormatError)
22
+ end
23
+
24
+ it "parses a single digit integer string" do
25
+ expect(@parser.parse("1")).to eq(Money.new(1.00))
26
+ end
27
+
28
+ it "parses a double digit integer string" do
29
+ expect(@parser.parse("10")).to eq(Money.new(10.00))
30
+ end
31
+
32
+ it "parses an integer string amount with a leading $" do
33
+ expect(@parser.parse("$1")).to eq(Money.new(1.00))
34
+ end
35
+
36
+ it "parses a float string amount" do
37
+ expect(@parser.parse("1.37")).to eq(Money.new(1.37))
38
+ end
39
+
40
+ it "parses a float string amount with a leading $" do
41
+ expect(@parser.parse("$1.37")).to eq(Money.new(1.37))
42
+ end
43
+
44
+ it "parses a float string with a single digit after the decimal" do
45
+ expect(@parser.parse("10.0")).to eq(Money.new(10.00))
46
+ end
47
+
48
+ it "parses a float string with two digits after the decimal" do
49
+ expect(@parser.parse("10.00")).to eq(Money.new(10.00))
50
+ end
51
+
52
+ it "parses the amount from an amount surrounded by whitespace and garbage" do
53
+ expect(@parser.parse("Rubbish $1.00 Rubbish")).to eq(Money.new(1.00))
54
+ end
55
+
56
+ it "parses the amount from an amount surrounded by garbage" do
57
+ expect(@parser.parse("Rubbish$1.00Rubbish")).to eq(Money.new(1.00))
58
+ end
59
+
60
+ it "parses a negative integer amount in the hundreds" do
61
+ expect(@parser.parse("-100")).to eq(Money.new(-100.00))
62
+ end
63
+
64
+ it "parses an integer amount in the hundreds" do
65
+ expect(@parser.parse("410")).to eq(Money.new(410.00))
66
+ end
67
+
68
+ it "parses an amount ending with a ." do
69
+ expect(@parser.parse("1.")).to eq(Money.new(1))
70
+ expect(@parser.parse("100,000.")).to eq(Money.new(100_000))
71
+ end
72
+
73
+ it "parses an amount starting with a ." do
74
+ expect(@parser.parse(".12")).to eq(Money.new(0.12))
75
+ end
76
+
77
+ it "parses a positive amount with a thousands separator" do
78
+ expect(@parser.parse("100,000.00")).to eq(Money.new(100_000.00))
79
+ end
80
+
81
+ it "parses a negative amount with a thousands separator" do
82
+ expect(@parser.parse("-100,000.00")).to eq(Money.new(-100_000.00))
83
+ end
84
+
85
+ it "parses a positive amount with a thousands separator with no decimal" do
86
+ expect(@parser.parse("1,000")).to eq(Money.new(1_000))
87
+ end
88
+
89
+ it "parses a positive amount with a thousands separator with no decimal with a currency" do
90
+ expect(@parser.parse("1,000", 'JOD')).to eq(Money.new(1_000, 'JOD'))
91
+ end
92
+
93
+ it "parses a positive amount with a thousands separator with no decimal" do
94
+ expect(@parser.parse("12,34,567.89", 'INR')).to eq(Money.new(1_234_567.89, 'INR'))
95
+ end
96
+
97
+ it "parses negative $1.00" do
98
+ expect(@parser.parse("-1.00")).to eq(Money.new(-1.00))
99
+ end
100
+
101
+ it "parses a negative cents amount" do
102
+ expect(@parser.parse("-0.90")).to eq(Money.new(-0.90))
103
+ end
104
+
105
+ it "parses amount with 3 decimals and 0 dollar amount" do
106
+ expect(@parser.parse("0.123")).to eq(Money.new(0.12))
107
+ end
108
+
109
+ it "parses negative amount with 3 decimals and 0 dollar amount" do
110
+ expect(@parser.parse("-0.123")).to eq(Money.new(-0.12))
111
+ end
112
+
113
+ it "parses negative amount with multiple leading - signs" do
114
+ expect(@parser.parse("--0.123")).to eq(Money.new(-0.12))
115
+ end
116
+
117
+ it "parses negative amount with multiple - signs" do
118
+ expect(@parser.parse("--0.123--")).to eq(Money.new(-0.12))
119
+ end
120
+
121
+ it "parses a positive amount with a thousands dot separator currency and no decimal" do
122
+ expect(@parser.parse("1.000", 'EUR')).to eq(Money.new(1_000, 'EUR'))
123
+ end
124
+
125
+ it "parses a three digit currency" do
126
+ expect(@parser.parse("1.000", 'JOD')).to eq(Money.new(1, 'JOD'))
127
+ end
128
+
129
+ it "parses uses currency when passed as block to with_currency" do
130
+ expect(Money.with_currency('JOD') { @parser.parse("1.000") }).to eq(Money.new(1, 'JOD'))
131
+ end
132
+
133
+ it "parses no currency amount" do
134
+ expect(@parser.parse("1.000", Money::NULL_CURRENCY)).to eq(Money.new(1000, Money::NULL_CURRENCY))
135
+ end
136
+
137
+ it "parses amount with more than 3 decimals correctly" do
138
+ expect(@parser.parse("1.11111111")).to eq(Money.new(1.11))
139
+ end
140
+
141
+ it "parses amount with multiple consistent thousands delimiters" do
142
+ expect(@parser.parse("1.111.111")).to eq(Money.new(1_111_111))
143
+ end
144
+
145
+ it "parses amount with multiple inconsistent thousands delimiters" do
146
+ expect(Money).to receive(:deprecate).once
147
+ expect(@parser.parse("1.1.11.111")).to eq(Money.new(1_111_111))
148
+ end
149
+
150
+ it "parses raises with multiple inconsistent thousands delimiters and strict option" do
151
+ expect { @parser.parse("1.1.11.111", strict: true) }.to raise_error(MoneyParser::MoneyFormatError)
152
+ end
153
+ end
154
+
155
+ describe "parsing of amounts with comma decimal separator" do
156
+ it "parses dollar amount $1,00 with leading $" do
157
+ expect(@parser.parse("$1,00")).to eq(Money.new(1.00))
158
+ end
159
+
160
+ it "parses dollar amount $1,37 with leading $, and non-zero cents" do
161
+ expect(@parser.parse("$1,37")).to eq(Money.new(1.37))
162
+ end
163
+
164
+ it "parses the amount from an amount surrounded by whitespace and garbage" do
165
+ expect(@parser.parse("Rubbish $1,00 Rubbish")).to eq(Money.new(1.00))
166
+ end
167
+
168
+ it "parses the amount from an amount surrounded by garbage" do
169
+ expect(@parser.parse("Rubbish$1,00Rubbish")).to eq(Money.new(1.00))
170
+ end
171
+
172
+ it "parses negative hundreds amount" do
173
+ expect(@parser.parse("-100,00")).to eq(Money.new(-100.00))
174
+ end
175
+
176
+ it "parses positive hundreds amount" do
177
+ expect(@parser.parse("410,00")).to eq(Money.new(410.00))
178
+ end
179
+
180
+ it "parses a positive amount with a thousands separator" do
181
+ expect(@parser.parse("100.000,00")).to eq(Money.new(100_000.00))
182
+ end
183
+
184
+ it "parses a negative amount with a thousands separator" do
185
+ expect(@parser.parse("-100.000,00")).to eq(Money.new(-100_000.00))
186
+ end
187
+
188
+ it "parses amount ending with a comma" do
189
+ expect(@parser.parse("1,")).to eq(Money.new(1))
190
+ expect(@parser.parse("100.000,")).to eq(Money.new(100_000))
191
+ end
192
+
193
+ it "parses amount with 3 decimals and 0 dollar amount" do
194
+ expect(@parser.parse("0,123")).to eq(Money.new(0.12))
195
+ end
196
+
197
+ it "parses negative amount with 3 decimals and 0 dollar amount" do
198
+ expect(@parser.parse("-0,123")).to eq(Money.new(-0.12))
199
+ end
200
+
201
+ it "parses amount 2 decimals correctly" do
202
+ expect(@parser.parse("1,11", Money::NULL_CURRENCY)).to eq(Money.new(1.11, Money::NULL_CURRENCY))
203
+ end
204
+
205
+ it "parses amount with more than 3 decimals correctly" do
206
+ expect(@parser.parse("1,11111111", Money::NULL_CURRENCY)).to eq(Money.new(111_111_111, Money::NULL_CURRENCY))
207
+ end
208
+
209
+ it "parses amount with more than 3 decimals correctly and a currency" do
210
+ expect(@parser.parse("1,11111111", 'CAD')).to eq(Money.new(111_111_111))
211
+ end
212
+
213
+ it "parses amount with multiple consistent thousands delimiters" do
214
+ expect(@parser.parse("1,111,111")).to eq(Money.new(1_111_111))
215
+ end
216
+
217
+ it "parses amount with multiple inconsistent thousands delimiters" do
218
+ expect(Money).to receive(:deprecate).once
219
+ expect(@parser.parse("1,1,11,111")).to eq(Money.new(1_111_111))
220
+ end
221
+
222
+ it "parses raises with multiple inconsistent thousands delimiters and strict option" do
223
+ expect { @parser.parse("1,1,11,111", strict: true) }.to raise_error(MoneyParser::MoneyFormatError)
224
+ end
225
+ end
226
+
227
+ describe "3 digit decimal currency" do
228
+ it "parses thousands correctly" do
229
+ expect(@parser.parse("1,111", "JOD")).to eq(Money.new(1_111, 'JOD'))
230
+ expect(@parser.parse("1.111.111", "JOD")).to eq(Money.new(1_111_111, 'JOD'))
231
+ expect(@parser.parse("1 111", "JOD")).to eq(Money.new(1_111, 'JOD'))
232
+ expect(@parser.parse("1111,111", "JOD")).to eq(Money.new(1_111_111, 'JOD'))
233
+ end
234
+
235
+ it "parses decimals correctly" do
236
+ expect(@parser.parse("1.111", "JOD")).to eq(Money.new(1.111, 'JOD'))
237
+ expect(@parser.parse("1,11", "JOD")).to eq(Money.new(1.110, 'JOD'))
238
+ expect(@parser.parse("1111.111", "JOD")).to eq(Money.new(1_111.111, 'JOD'))
239
+ end
240
+ end
241
+
242
+ describe "no decimal currency" do
243
+ it "parses thousands correctly" do
244
+ expect(@parser.parse("1,111", "JPY")).to eq(Money.new(1_111, 'JPY'))
245
+ expect(@parser.parse("1.111", "JPY")).to eq(Money.new(1_111, 'JPY'))
246
+ expect(@parser.parse("1 111", "JPY")).to eq(Money.new(1_111, 'JPY'))
247
+ expect(@parser.parse("1111,111", "JPY")).to eq(Money.new(1_111_111, 'JPY'))
248
+ end
249
+
250
+ it "parses decimals correctly" do
251
+ expect(@parser.parse("1,11", "JPY")).to eq(Money.new(1, 'JPY'))
252
+ expect(@parser.parse("1.11", "JPY")).to eq(Money.new(1, 'JPY'))
253
+ expect(@parser.parse("1111.111", "JPY")).to eq(Money.new(1111, 'JPY'))
254
+ end
255
+ end
256
+
257
+ describe "two decimal currency" do
258
+ it "parses thousands correctly" do
259
+ expect(@parser.parse("1,111", "USD")).to eq(Money.new(1_111, 'USD'))
260
+ expect(@parser.parse("1.111", "USD")).to eq(Money.new(1_111, 'USD'))
261
+ expect(@parser.parse("1 111", "USD")).to eq(Money.new(1_111, 'USD'))
262
+ expect(@parser.parse("1111,111", "USD")).to eq(Money.new(1_111_111, 'USD'))
263
+ end
264
+
265
+ it "parses decimals correctly" do
266
+ expect(@parser.parse("1,11", "USD")).to eq(Money.new(1.11, 'USD'))
267
+ expect(@parser.parse("1.11", "USD")).to eq(Money.new(1.11, 'USD'))
268
+ expect(@parser.parse("1111.111", "USD")).to eq(Money.new(1111.11, 'USD'))
269
+ end
270
+ end
271
+
272
+ describe "parsing of decimal cents amounts from 0 to 10" do
273
+ it "parses 50.0" do
274
+ expect(@parser.parse("50.0")).to eq(Money.new(50.00))
275
+ end
276
+
277
+ it "parses 50.1" do
278
+ expect(@parser.parse("50.1")).to eq(Money.new(50.10))
279
+ end
280
+
281
+ it "parses 50.2" do
282
+ expect(@parser.parse("50.2")).to eq(Money.new(50.20))
283
+ end
284
+
285
+ it "parses 50.3" do
286
+ expect(@parser.parse("50.3")).to eq(Money.new(50.30))
287
+ end
288
+
289
+ it "parses 50.4" do
290
+ expect(@parser.parse("50.4")).to eq(Money.new(50.40))
291
+ end
292
+
293
+ it "parses 50.5" do
294
+ expect(@parser.parse("50.5")).to eq(Money.new(50.50))
295
+ end
296
+
297
+ it "parses 50.6" do
298
+ expect(@parser.parse("50.6")).to eq(Money.new(50.60))
299
+ end
300
+
301
+ it "parses 50.7" do
302
+ expect(@parser.parse("50.7")).to eq(Money.new(50.70))
303
+ end
304
+
305
+ it "parses 50.8" do
306
+ expect(@parser.parse("50.8")).to eq(Money.new(50.80))
307
+ end
308
+
309
+ it "parses 50.9" do
310
+ expect(@parser.parse("50.9")).to eq(Money.new(50.90))
311
+ end
312
+
313
+ it "parses 50.10" do
314
+ expect(@parser.parse("50.10")).to eq(Money.new(50.10))
315
+ end
316
+ end
317
+
318
+ describe "parsing of fixnum" do
319
+ it "parses 1" do
320
+ expect(@parser.parse(1)).to eq(Money.new(1))
321
+ end
322
+
323
+ it "parses 50" do
324
+ expect(@parser.parse(50)).to eq(Money.new(50))
325
+ end
326
+ end
327
+
328
+ describe "parsing of float" do
329
+ it "parses 1.00" do
330
+ expect(@parser.parse(1.00)).to eq(Money.new(1.00))
331
+ end
332
+
333
+ it "parses 1.32" do
334
+ expect(@parser.parse(1.32)).to eq(Money.new(1.32))
335
+ end
336
+ end
337
+
338
+ describe "parsing with thousands separators" do
339
+ [
340
+ '1,234,567.89',
341
+ '1 234 567.89',
342
+ '1 234 567,89',
343
+ '1.234.567,89',
344
+ '1˙234˙567,89',
345
+ '12,34,567.89',
346
+ "1'234'567.89",
347
+ "1'234'567,89",
348
+ '123,4567.89',
349
+ ].each do |number|
350
+ it "parses #{number}" do
351
+ expect(@parser.parse(number)).to eq(Money.new(1_234_567.89))
352
+ end
353
+ end
354
+ end
355
+ end
@@ -0,0 +1,853 @@
1
+ require 'spec_helper'
2
+ require 'yaml'
3
+
4
+ RSpec.describe "Money" do
5
+
6
+ let (:money) {Money.new(1)}
7
+ let (:amount_money) { Money.new(1.23, 'USD') }
8
+ let (:non_fractional_money) { Money.new(1, 'JPY') }
9
+ let (:zero_money) { Money.new(0) }
10
+
11
+ it "is contructable with empty class method" do
12
+ expect(Money.empty).to eq(Money.new)
13
+ end
14
+
15
+ context "default currency not set" do
16
+ before(:each) do
17
+ @default_currency = Money.default_currency
18
+ Money.default_currency = nil
19
+ end
20
+ after(:each) do
21
+ Money.default_currency = @default_currency
22
+ end
23
+
24
+ it "raises an error" do
25
+ expect { money }.to raise_error(ArgumentError)
26
+ end
27
+ end
28
+
29
+ it ".zero has no currency" do
30
+ expect(Money.zero.currency).to be_a(Money::NullCurrency)
31
+ end
32
+
33
+ it ".zero is a 0$ value" do
34
+ expect(Money.zero).to eq(Money.new(0))
35
+ end
36
+
37
+ it "returns itself with to_money" do
38
+ expect(money.to_money).to eq(money)
39
+ end
40
+
41
+ it "defaults to 0 when constructed with no arguments" do
42
+ expect(Money.new).to eq(Money.new(0))
43
+ end
44
+
45
+ it "defaults to 0 when constructed with an empty string" do
46
+ expect(Money.new('')).to eq(Money.new(0))
47
+ end
48
+
49
+ it "defaults to 0 when constructed with an invalid string" do
50
+ expect(Money).to receive(:deprecate).once
51
+ expect(Money.new('invalid')).to eq(Money.new(0.00))
52
+ end
53
+
54
+ it "to_s correctly displays the right number of decimal places" do
55
+ expect(money.to_s).to eq("1.00")
56
+ expect(non_fractional_money.to_s).to eq("1")
57
+ end
58
+
59
+ it "to_s with a legacy_dollars style" do
60
+ expect(amount_money.to_s(:legacy_dollars)).to eq("1.23")
61
+ expect(non_fractional_money.to_s(:legacy_dollars)).to eq("1.00")
62
+ end
63
+
64
+ it "to_s with a amount style" do
65
+ expect(amount_money.to_s(:amount)).to eq("1.23")
66
+ expect(non_fractional_money.to_s(:amount)).to eq("1")
67
+ end
68
+
69
+ it "as_json as a float with 2 decimal places" do
70
+ expect(money.as_json).to eq("1.00")
71
+ end
72
+
73
+ it "is constructable with a BigDecimal" do
74
+ expect(Money.new(BigDecimal.new("1.23"))).to eq(Money.new(1.23))
75
+ end
76
+
77
+ it "is constructable with a Fixnum" do
78
+ expect(Money.new(3)).to eq(Money.new(3.00))
79
+ end
80
+
81
+ it "is construcatable with a Float" do
82
+ expect(Money.new(3.00)).to eq(Money.new(BigDecimal.new('3.00')))
83
+ end
84
+
85
+ it "is construcatable with a String" do
86
+ expect(Money.new('3.00')).to eq(Money.new(3.00))
87
+ end
88
+
89
+ it "is aware of the currency" do
90
+ expect(Money.new(1.00, 'CAD').currency.iso_code).to eq('CAD')
91
+ end
92
+
93
+ it "is addable" do
94
+ expect((Money.new(1.51) + Money.new(3.49))).to eq(Money.new(5.00))
95
+ end
96
+
97
+ it "keeps currency across calculations" do
98
+ expect(Money.new(1, 'USD') - Money.new(1, 'USD') + Money.new(1.23, Money::NULL_CURRENCY)).to eq(Money.new(1.23, 'USD'))
99
+ end
100
+
101
+ it "raises error if added other is not compatible" do
102
+ expect{ Money.new(5.00) + nil }.to raise_error(TypeError)
103
+ end
104
+
105
+ it "is able to add $0 + $0" do
106
+ expect((Money.new + Money.new)).to eq(Money.new)
107
+ end
108
+
109
+ it "adds inconsistent currencies" do
110
+ expect(Money).to receive(:deprecate).once
111
+ expect(Money.new(5, 'USD') + Money.new(1, 'CAD')).to eq(Money.new(6, 'USD'))
112
+ end
113
+
114
+ it "is subtractable" do
115
+ expect((Money.new(5.00) - Money.new(3.49))).to eq(Money.new(1.51))
116
+ end
117
+
118
+ it "raises error if subtracted other is not compatible" do
119
+ expect{ Money.new(5.00) - nil }.to raise_error(TypeError)
120
+ end
121
+
122
+ it "is subtractable to $0" do
123
+ expect((Money.new(5.00) - Money.new(5.00))).to eq(Money.new)
124
+ end
125
+
126
+ it "logs a deprecation warning when adding across currencies" do
127
+ expect(Money).to receive(:deprecate)
128
+ expect(Money.new(10, 'USD') - Money.new(1, 'JPY')).to eq(Money.new(9, 'USD'))
129
+ end
130
+
131
+ it "keeps currency when doing a computation with a null currency" do
132
+ currency = Money.new(10, 'JPY')
133
+ no_currency = Money.new(1, Money::NULL_CURRENCY)
134
+ expect((no_currency + currency).currency).to eq(Money::Currency.find!('JPY'))
135
+ expect((currency - no_currency).currency).to eq(Money::Currency.find!('JPY'))
136
+ end
137
+
138
+ it "does not log a deprecation warning when adding with a null currency value" do
139
+ currency = Money.new(10, 'USD')
140
+ no_currency = Money.new(1, Money::NULL_CURRENCY)
141
+ expect(Money).not_to receive(:deprecate)
142
+ expect(no_currency + currency).to eq(Money.new(11, 'USD'))
143
+ expect(currency - no_currency).to eq(Money.new(9, 'USD'))
144
+ end
145
+
146
+ it "is substractable to a negative amount" do
147
+ expect((Money.new(0.00) - Money.new(1.00))).to eq(Money.new("-1.00"))
148
+ end
149
+
150
+ it "is never negative zero" do
151
+ expect(Money.new(-0.00).to_s).to eq("0.00")
152
+ expect((Money.new(0) * -1).to_s).to eq("0.00")
153
+ end
154
+
155
+ it "#inspects to a presentable string" do
156
+ expect(money.inspect).to eq("#<Money value:1.00 currency:CAD>")
157
+ expect(Money.new(1, 'JPY').inspect).to eq("#<Money value:1 currency:JPY>")
158
+ expect(Money.new(1, 'JOD').inspect).to eq("#<Money value:1.000 currency:JOD>")
159
+ end
160
+
161
+ it "is inspectable within an array" do
162
+ expect([money].inspect).to eq("[#<Money value:1.00 currency:CAD>]")
163
+ end
164
+
165
+ it "correctly support eql? as a value object" do
166
+ expect(money).to eq(Money.new(1))
167
+ expect(money).to eq(Money.new(1, 'CAD'))
168
+ end
169
+
170
+ it "does not eql? with a non money object" do
171
+ expect(money).to_not eq(1)
172
+ expect(money).to_not eq(OpenStruct.new(value: 1))
173
+ end
174
+
175
+ it "does not eql? when currency missmatch" do
176
+ expect(money).to_not eq(Money.new(1, 'JPY'))
177
+ end
178
+
179
+ it "is addable with integer" do
180
+ expect((Money.new(1.33) + 1)).to eq(Money.new(2.33))
181
+ expect((1 + Money.new(1.33))).to eq(Money.new(2.33))
182
+ end
183
+
184
+ it "is addable with float" do
185
+ expect((Money.new(1.33) + 1.50)).to eq(Money.new(2.83))
186
+ expect((1.50 + Money.new(1.33))).to eq(Money.new(2.83))
187
+ end
188
+
189
+ it "is subtractable with integer" do
190
+ expect((Money.new(1.66) - 1)).to eq(Money.new(0.66))
191
+ expect((2 - Money.new(1.66))).to eq(Money.new(0.34))
192
+ end
193
+
194
+ it "is subtractable with float" do
195
+ expect((Money.new(1.66) - 1.50)).to eq(Money.new(0.16))
196
+ expect((1.50 - Money.new(1.33))).to eq(Money.new(0.17))
197
+ end
198
+
199
+ it "is multipliable with an integer" do
200
+ expect((Money.new(1.00) * 55)).to eq(Money.new(55.00))
201
+ expect((55 * Money.new(1.00))).to eq(Money.new(55.00))
202
+ end
203
+
204
+ it "is multiplable with a float" do
205
+ expect((Money.new(1.00) * 1.50)).to eq(Money.new(1.50))
206
+ expect((1.50 * Money.new(1.00))).to eq(Money.new(1.50))
207
+ end
208
+
209
+ it "is multipliable by a cents amount" do
210
+ expect((Money.new(1.00) * 0.50)).to eq(Money.new(0.50))
211
+ expect((0.50 * Money.new(1.00))).to eq(Money.new(0.50))
212
+ end
213
+
214
+ it "is multipliable by a rational" do
215
+ expect((Money.new(3.3) * Rational(1, 12))).to eq(Money.new(0.28))
216
+ expect((Rational(1, 12) * Money.new(3.3))).to eq(Money.new(0.28))
217
+ end
218
+
219
+ it "is multipliable by a repeatable floating point number" do
220
+ expect((Money.new(24.00) * (1 / 30.0))).to eq(Money.new(0.80))
221
+ expect(((1 / 30.0) * Money.new(24.00))).to eq(Money.new(0.80))
222
+ end
223
+
224
+ it "is multipliable by a repeatable floating point number where the floating point error rounds down" do
225
+ expect((Money.new(3.3) * (1.0 / 12))).to eq(Money.new(0.28))
226
+ expect(((1.0 / 12) * Money.new(3.3))).to eq(Money.new(0.28))
227
+ end
228
+
229
+ it "is multipliable by a money object" do
230
+ expect(Money).to receive(:deprecate).once
231
+ expect((Money.new(3.3) * Money.new(1))).to eq(Money.new(3.3))
232
+ end
233
+
234
+ it "rounds multiplication result with fractional penny of 5 or higher up" do
235
+ expect((Money.new(0.03) * 0.5)).to eq(Money.new(0.02))
236
+ expect((0.5 * Money.new(0.03))).to eq(Money.new(0.02))
237
+ end
238
+
239
+ it "rounds multiplication result with fractional penny of 4 or lower down" do
240
+ expect((Money.new(0.10) * 0.33)).to eq(Money.new(0.03))
241
+ expect((0.33 * Money.new(0.10))).to eq(Money.new(0.03))
242
+ end
243
+
244
+ it "is less than a bigger integer" do
245
+ expect(Money.new(1)).to be < 2
246
+ expect(2).to be > Money.new(1)
247
+ end
248
+
249
+ it "is less than or equal to a bigger integer" do
250
+ expect(Money.new(1)).to be <= 2
251
+ expect(2).to be >= Money.new(1)
252
+ end
253
+
254
+ it "is greater than a lesser integer" do
255
+ expect(Money.new(2)).to be > 1
256
+ expect(1).to be < Money.new(2)
257
+ end
258
+
259
+ it "is greater than or equal to a lesser integer" do
260
+ expect(Money.new(2)).to be >= 1
261
+ expect(1).to be <= Money.new(2)
262
+ end
263
+
264
+ it "raises if divided" do
265
+ expect { Money.new(55.00) / 55 }.to raise_error(RuntimeError)
266
+ end
267
+
268
+ it "returns cents in to_liquid" do
269
+ expect(Money.new(1.00).to_liquid).to eq(100)
270
+ end
271
+
272
+ it "returns cents in to_json" do
273
+ expect(Money.new(1.00).to_json).to eq("1.00")
274
+ end
275
+
276
+ it "supports absolute value" do
277
+ expect(Money.new(-1.00).abs).to eq(Money.new(1.00))
278
+ end
279
+
280
+ it "supports to_i" do
281
+ expect(Money.new(1.50).to_i).to eq(1)
282
+ end
283
+
284
+ it "supports to_d" do
285
+ expect(Money.new(1.29).to_d).to eq(BigDecimal.new('1.29'))
286
+ end
287
+
288
+ it "supports to_f" do
289
+ expect(Money.new(1.50).to_f.to_s).to eq("1.5")
290
+ end
291
+
292
+ it "is creatable from an integer value in cents" do
293
+ expect(Money.from_cents(1950)).to eq(Money.new(19.50))
294
+ end
295
+
296
+ it "is creatable from an integer value of 0 in cents" do
297
+ expect(Money.from_cents(0)).to eq(Money.new)
298
+ end
299
+
300
+ it "is creatable from a float cents amount" do
301
+ expect(Money.from_cents(1950.5)).to eq(Money.new(19.51))
302
+ end
303
+
304
+ it "is creatable from an integer value in cents and currency" do
305
+ expect(Money.from_subunits(1950, 'CAD')).to eq(Money.new(19.50))
306
+ end
307
+
308
+ it "is creatable from an integer value in dollars and currency with no cents" do
309
+ expect(Money.from_subunits(1950, 'JPY')).to eq(Money.new(1950, 'JPY'))
310
+ end
311
+
312
+ it "raises when constructed with a NaN value" do
313
+ expect { Money.new( 0.0 / 0) }.to raise_error(ArgumentError)
314
+ end
315
+
316
+ it "is comparable with non-money objects" do
317
+ expect(money).not_to eq(nil)
318
+ end
319
+
320
+ it "supports floor" do
321
+ expect(Money.new(15.52).floor).to eq(Money.new(15.00))
322
+ expect(Money.new(18.99).floor).to eq(Money.new(18.00))
323
+ expect(Money.new(21).floor).to eq(Money.new(21))
324
+ end
325
+
326
+ it "generates a true rational" do
327
+ expect(Money.rational(Money.new(10.0), Money.new(15.0))).to eq(Rational(2,3))
328
+ expect(Money).to receive(:deprecate).once
329
+ expect(Money.rational(Money.new(10.0, 'USD'), Money.new(15.0, 'JPY'))).to eq(Rational(2,3))
330
+ end
331
+
332
+ describe "frozen with amount of $1" do
333
+ let (:money) { Money.new(1.00) }
334
+
335
+ it "is equals to $1" do
336
+ expect(money).to eq(Money.new(1.00))
337
+ end
338
+
339
+ it "is not equals to $2" do
340
+ expect(money).not_to eq(Money.new(2.00))
341
+ end
342
+
343
+ it "<=> $1 is 0" do
344
+ expect((money <=> Money.new(1.00))).to eq(0)
345
+ end
346
+
347
+ it "<=> $2 is -1" do
348
+ expect((money <=> Money.new(2.00))).to eq(-1)
349
+ end
350
+
351
+ it "<=> $0.50 equals 1" do
352
+ expect((money <=> Money.new(0.50))).to eq(1)
353
+ end
354
+
355
+ it "<=> works with non-money objects" do
356
+ expect((money <=> 1)).to eq(0)
357
+ expect((money <=> 2)).to eq(-1)
358
+ expect((money <=> 0.5)).to eq(1)
359
+ expect((1 <=> money)).to eq(0)
360
+ expect((2 <=> money)).to eq(1)
361
+ expect((0.5 <=> money)).to eq(-1)
362
+ end
363
+
364
+ it "raises error if compared other is not compatible" do
365
+ expect{ Money.new(5.00) <=> nil }.to raise_error(TypeError)
366
+ end
367
+
368
+ it "have the same hash value as $1" do
369
+ expect(money.hash).to eq(Money.new(1.00).hash)
370
+ end
371
+
372
+ it "does not have the same hash value as $2" do
373
+ expect(money.hash).to eq(Money.new(1.00).hash)
374
+ end
375
+
376
+ it "<=> can compare with and without currency" do
377
+ expect(Money.new(1000, Money::NULL_CURRENCY) <=> Money.new(2000, 'JPY')).to eq(-1)
378
+ expect(Money.new(2000, 'JPY') <=> Money.new(1000, Money::NULL_CURRENCY)).to eq(1)
379
+ end
380
+
381
+ it "<=> issues deprecation warning when comparing incompatible currency" do
382
+ expect(Money).to receive(:deprecate).twice
383
+ expect(Money.new(1000, 'USD') <=> Money.new(2000, 'JPY')).to eq(-1)
384
+ expect(Money.new(2000, 'JPY') <=> Money.new(1000, 'USD')).to eq(1)
385
+ end
386
+ end
387
+
388
+ describe "#subunits" do
389
+ it 'multiplies by the number of decimal places for the currency' do
390
+ expect(Money.new(1, 'USD').subunits).to eq(100)
391
+ expect(Money.new(1, 'JPY').subunits).to eq(1)
392
+ expect(Money.new(1, 'IQD').subunits).to eq(1000)
393
+ expect(Money.new(1).subunits).to eq(100)
394
+ end
395
+ end
396
+
397
+ describe "value" do
398
+ it "rounds to the number of minor units provided by the currency" do
399
+ expect(Money.new(1.1111, 'USD').value).to eq(1.11)
400
+ expect(Money.new(1.1111, 'JPY').value).to eq(1)
401
+ expect(Money.new(1.1111, 'IQD').value).to eq(1.111)
402
+ end
403
+ end
404
+
405
+ describe "with amount of $0" do
406
+ let (:money) { Money.new(0) }
407
+
408
+ it "is zero" do
409
+ expect(money).to be_zero
410
+ end
411
+
412
+ it "is greater than -$1" do
413
+ expect(money).to be > Money.new("-1.00")
414
+ end
415
+
416
+ it "is greater than or equal to $0" do
417
+ expect(money).to be >= Money.new
418
+ end
419
+
420
+ it "is less than or equal to $0" do
421
+ expect(money).to be <= Money.new
422
+ end
423
+
424
+ it "is less than $1" do
425
+ expect(money).to be < Money.new(1.00)
426
+ end
427
+ end
428
+
429
+ describe "with amount of $1" do
430
+ let (:money) { Money.new(1.00) }
431
+
432
+ it "is not zero" do
433
+ expect(money).not_to be_zero
434
+ end
435
+
436
+ it "returns cents as a decimal value = 1.00" do
437
+ expect(money.value).to eq(BigDecimal.new("1.00"))
438
+ end
439
+
440
+ it "returns cents as 100 cents" do
441
+ expect(money.cents).to eq(100)
442
+ end
443
+
444
+ it "returns cents as 100 cents" do
445
+ expect(money.subunits).to eq(100)
446
+ end
447
+
448
+ it "returns cents as a Fixnum" do
449
+ expect(money.subunits).to be_an_instance_of(Fixnum)
450
+ end
451
+
452
+ it "is greater than $0" do
453
+ expect(money).to be > Money.new(0.00)
454
+ end
455
+
456
+ it "is less than $2" do
457
+ expect(money).to be < Money.new(2.00)
458
+ end
459
+
460
+ it "is equal to $1" do
461
+ expect(money).to eq(Money.new(1.00))
462
+ end
463
+ end
464
+
465
+ describe "allocation"do
466
+ specify "#allocate takes no action when one gets all" do
467
+ expect(Money.new(5).allocate([1])).to eq([Money.new(5)])
468
+ end
469
+
470
+ specify "#allocate does not lose pennies" do
471
+ moneys = Money.new(0.05).allocate([0.3,0.7])
472
+ expect(moneys[0]).to eq(Money.new(0.02))
473
+ expect(moneys[1]).to eq(Money.new(0.03))
474
+ end
475
+
476
+ specify "#allocate does not lose dollars with non-decimal currency" do
477
+ moneys = Money.new(5, 'JPY').allocate([0.3,0.7])
478
+ expect(moneys[0]).to eq(Money.new(2, 'JPY'))
479
+ expect(moneys[1]).to eq(Money.new(3, 'JPY'))
480
+ end
481
+
482
+ specify "#allocate does not lose dollars with three decimal currency" do
483
+ moneys = Money.new(0.005, 'JOD').allocate([0.3,0.7])
484
+ expect(moneys[0]).to eq(Money.new(0.002, 'JOD'))
485
+ expect(moneys[1]).to eq(Money.new(0.003, 'JOD'))
486
+ end
487
+
488
+ specify "#allocate does not lose pennies even when given a lossy split" do
489
+ moneys = Money.new(1).allocate([0.333,0.333, 0.333])
490
+ expect(moneys[0].subunits).to eq(34)
491
+ expect(moneys[1].subunits).to eq(33)
492
+ expect(moneys[2].subunits).to eq(33)
493
+ end
494
+
495
+ specify "#allocate requires total to be less than 1" do
496
+ expect { Money.new(0.05).allocate([0.5,0.6]) }.to raise_error(ArgumentError)
497
+ end
498
+
499
+ specify "#allocate will use rationals if provided" do
500
+ splits = [128400,20439,14589,14589,25936].map{ |num| Rational(num, 203953) } # sums to > 1 if converted to float
501
+ expect(Money.new(2.25).allocate(splits)).to eq([Money.new(1.42), Money.new(0.23), Money.new(0.16), Money.new(0.16), Money.new(0.28)])
502
+ end
503
+
504
+ specify "#allocate will convert rationals with high precision" do
505
+ ratios = [Rational(1, 1), Rational(0)]
506
+ expect(Money.new("858993456.12").allocate(ratios)).to eq([Money.new("858993456.12"), Money.empty])
507
+ ratios = [Rational(1, 6), Rational(5, 6)]
508
+ expect(Money.new("3.00").allocate(ratios)).to eq([Money.new("0.50"), Money.new("2.50")])
509
+ end
510
+
511
+ specify "#allocate doesn't raise with weird negative rational ratios" do
512
+ rate = Rational(-5, 1201)
513
+ expect { Money.new(1).allocate([rate, 1 - rate]) }.not_to raise_error
514
+ end
515
+
516
+ specify "#allocate_max_amounts returns the weighted allocation without exceeding the maxima when there is room for the remainder" do
517
+ expect(
518
+ Money.new(30.75).allocate_max_amounts([Money.new(26), Money.new(4.75)]),
519
+ ).to eq([Money.new(26), Money.new(4.75)])
520
+ end
521
+
522
+ specify "#allocate_max_amounts returns the weighted allocation without exceeding the maxima when there is room for the remainder with currency" do
523
+ expect(
524
+ Money.new(3075, 'JPY').allocate_max_amounts([Money.new(2600, 'JPY'), Money.new(475, 'JPY')]),
525
+ ).to eq([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
526
+ end
527
+
528
+ specify "#allocate_max_amounts legal computation with no currency objects" do
529
+ expect(
530
+ Money.new(3075, 'JPY').allocate_max_amounts([2600, 475]),
531
+ ).to eq([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
532
+
533
+ expect(
534
+ Money.new(3075, Money::NULL_CURRENCY).allocate_max_amounts([Money.new(2600, 'JPY'), Money.new(475, 'JPY')]),
535
+ ).to eq([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
536
+ end
537
+
538
+ specify "#allocate_max_amounts illegal computation across currencies" do
539
+ expect {
540
+ Money.new(3075, 'USD').allocate_max_amounts([Money.new(2600, 'JPY'), Money.new(475, 'JPY')])
541
+ }.to raise_error(ArgumentError)
542
+ end
543
+
544
+ specify "#allocate_max_amounts drops the remainder when returning the weighted allocation without exceeding the maxima when there is no room for the remainder" do
545
+ expect(
546
+ Money.new(30.75).allocate_max_amounts([Money.new(26), Money.new(4.74)]),
547
+ ).to eq([Money.new(26), Money.new(4.74)])
548
+ end
549
+
550
+ specify "#allocate_max_amounts returns the weighted allocation when there is no remainder" do
551
+ expect(
552
+ Money.new(30).allocate_max_amounts([Money.new(15), Money.new(15)]),
553
+ ).to eq([Money.new(15), Money.new(15)])
554
+ end
555
+
556
+ specify "#allocate_max_amounts allocates the remainder round-robin when the maxima are not reached" do
557
+ expect(
558
+ Money.new(1).allocate_max_amounts([Money.new(33), Money.new(33), Money.new(33)]),
559
+ ).to eq([Money.new(0.34), Money.new(0.33), Money.new(0.33)])
560
+ end
561
+
562
+ specify "#allocate_max_amounts allocates up to the maxima specified" do
563
+ expect(
564
+ Money.new(100).allocate_max_amounts([Money.new(5), Money.new(2)]),
565
+ ).to eq([Money.new(5), Money.new(2)])
566
+ end
567
+
568
+ specify "#allocate_max_amounts supports all-zero maxima" do
569
+ expect(
570
+ Money.new(3).allocate_max_amounts([Money.empty, Money.empty, Money.empty]),
571
+ ).to eq([Money.empty, Money.empty, Money.empty])
572
+ end
573
+ end
574
+
575
+ describe "split" do
576
+ specify "#split needs at least one party" do
577
+ expect {Money.new(1).split(0)}.to raise_error(ArgumentError)
578
+ expect {Money.new(1).split(-1)}.to raise_error(ArgumentError)
579
+ end
580
+
581
+ specify "#gives 1 cent to both people if we start with 2" do
582
+ expect(Money.new(0.02).split(2)).to eq([Money.new(0.01), Money.new(0.01)])
583
+ end
584
+
585
+ specify "#split may distribute no money to some parties if there isnt enough to go around" do
586
+ expect(Money.new(0.02).split(3)).to eq([Money.new(0.01), Money.new(0.01), Money.new(0)])
587
+ end
588
+
589
+ specify "#split does not lose pennies" do
590
+ expect(Money.new(0.05).split(2)).to eq([Money.new(0.03), Money.new(0.02)])
591
+ end
592
+
593
+ specify "#split does not lose dollars with non-decimal currencies" do
594
+ expect(Money.new(5, 'JPY').split(2)).to eq([Money.new(3, 'JPY'), Money.new(2, 'JPY')])
595
+ end
596
+
597
+ specify "#split a dollar" do
598
+ moneys = Money.new(1).split(3)
599
+ expect(moneys[0].subunits).to eq(34)
600
+ expect(moneys[1].subunits).to eq(33)
601
+ expect(moneys[2].subunits).to eq(33)
602
+ end
603
+
604
+ specify "#split a 100 yen" do
605
+ moneys = Money.new(100, 'JPY').split(3)
606
+ expect(moneys[0].value).to eq(34)
607
+ expect(moneys[1].value).to eq(33)
608
+ expect(moneys[2].value).to eq(33)
609
+ end
610
+ end
611
+
612
+ describe "fraction" do
613
+ specify "#fraction needs a positive rate" do
614
+ expect {Money.new(1).fraction(-0.5)}.to raise_error(ArgumentError)
615
+ end
616
+
617
+ specify "#fraction returns the amount minus a fraction" do
618
+ expect(Money.new(1.15).fraction(0.15)).to eq(Money.new(1.00))
619
+ expect(Money.new(2.50).fraction(0.15)).to eq(Money.new(2.17))
620
+ expect(Money.new(35.50).fraction(0)).to eq(Money.new(35.50))
621
+ end
622
+ end
623
+
624
+ describe "with amount of $1 with created with 3 decimal places" do
625
+ let (:money) { Money.new(1.125) }
626
+
627
+ it "rounds 3rd decimal place" do
628
+ expect(money.value).to eq(BigDecimal.new("1.13"))
629
+ end
630
+ end
631
+
632
+ describe "parser dependency injection" do
633
+ before(:each) { Money.parser = AccountingMoneyParser }
634
+ after(:each) { Money.parser = MoneyParser }
635
+
636
+ it "keeps AccountingMoneyParser class on new money objects" do
637
+ expect(Money.new.class.parser).to eq(AccountingMoneyParser)
638
+ end
639
+
640
+ it "supports parenthesis from AccountingMoneyParser" do
641
+ expect(Money.parse("($5.00)")).to eq(Money.new(-5))
642
+ end
643
+
644
+ it "supports parenthesis from AccountingMoneyParser for .to_money" do
645
+ expect("($5.00)".to_money).to eq(Money.new(-5))
646
+ end
647
+ end
648
+
649
+ describe "round" do
650
+
651
+ it "rounds to 0 decimal places by default" do
652
+ expect(Money.new(54.1).round).to eq(Money.new(54))
653
+ expect(Money.new(54.5).round).to eq(Money.new(55))
654
+ end
655
+
656
+ # Overview of standard vs. banker's rounding for next 4 specs:
657
+ # http://www.xbeat.net/vbspeed/i_BankersRounding.htm
658
+ it "implements standard rounding for 2 digits" do
659
+ expect(Money.new(54.1754).round(2)).to eq(Money.new(54.18))
660
+ expect(Money.new(343.2050).round(2)).to eq(Money.new(343.21))
661
+ expect(Money.new(106.2038).round(2)).to eq(Money.new(106.20))
662
+ end
663
+
664
+ it "implements standard rounding for 1 digit" do
665
+ expect(Money.new(27.25).round(1)).to eq(Money.new(27.3))
666
+ expect(Money.new(27.45).round(1)).to eq(Money.new(27.5))
667
+ expect(Money.new(27.55).round(1)).to eq(Money.new(27.6))
668
+ end
669
+
670
+ end
671
+
672
+ describe "from_amount quacks like RubyMoney" do
673
+ it "accepts numeric values" do
674
+ expect(Money.from_amount(1)).to eq Money.from_cents(1_00)
675
+ expect(Money.from_amount(1.0)).to eq Money.from_cents(1_00)
676
+ expect(Money.from_amount(BigDecimal.new("1"))).to eq Money.from_cents(1_00)
677
+ end
678
+
679
+ it "accepts string values" do
680
+ expect(Money.from_amount("1")).to eq Money.from_cents(1_00)
681
+ end
682
+
683
+ it "accepts nil values" do
684
+ expect(Money.from_amount(nil)).to eq Money.from_cents(0)
685
+ end
686
+
687
+ it "accepts an optional currency parameter" do
688
+ expect { Money.from_amount(1, "CAD") }.to_not raise_error
689
+ end
690
+
691
+ it "accepts Rationla number" do
692
+ expect(Money.from_amount(Rational("999999999999999999.999")).value).to eql(BigDecimal.new("1000000000000000000", Money::Helpers::MAX_DECIMAL))
693
+ expect(Money.from_amount(Rational("999999999999999999.99")).value).to eql(BigDecimal.new("999999999999999999.99", Money::Helpers::MAX_DECIMAL))
694
+ end
695
+
696
+ it "raises ArgumentError with unsupported argument" do
697
+ expect { Money.from_amount(Object.new) }.to raise_error(ArgumentError)
698
+ end
699
+ end
700
+
701
+ describe "YAML serialization" do
702
+ it "accepts values with currencies" do
703
+ money = YAML.dump(Money.new(750, 'usd'))
704
+ expect(money).to eq("--- !ruby/object:Money\nvalue: '750.0'\ncurrency: USD\n")
705
+ end
706
+ end
707
+
708
+ describe "YAML deserialization" do
709
+
710
+ it "accepts values with currencies" do
711
+ money = YAML.load("--- !ruby/object:Money\nvalue: '750.0'\ncurrency: USD\n")
712
+ expect(money).to eq(Money.new(750, 'usd'))
713
+ end
714
+
715
+ it "accepts values with null currencies" do
716
+ money = YAML.load("--- !ruby/object:Money\nvalue: '750.0'\ncurrency: XXX\n")
717
+ expect(money).to eq(Money.new(750))
718
+ end
719
+
720
+ it "accepts serialized NullCurrency objects" do
721
+ money = YAML.load(<<~EOS)
722
+ ---
723
+ !ruby/object:Money
724
+ currency: !ruby/object:Money::NullCurrency
725
+ symbol: >-
726
+ $
727
+ disambiguate_symbol:
728
+ iso_code: >-
729
+ XXX
730
+ iso_numeric: >-
731
+ 999
732
+ name: >-
733
+ No Currency
734
+ smallest_denomination: 1
735
+ subunit_to_unit: 100
736
+ minor_units: 2
737
+ value: !ruby/object:BigDecimal 27:0.6935E2
738
+ cents: 6935
739
+ EOS
740
+ expect(money).to eq(Money.new(69.35, Money::NULL_CURRENCY))
741
+ end
742
+
743
+ it "accepts BigDecimal values" do
744
+ money = YAML.load(<<~EOS)
745
+ ---
746
+ !ruby/object:Money
747
+ value: !ruby/object:BigDecimal 18:0.75E3
748
+ cents: 75000
749
+ EOS
750
+ expect(money).to be == Money.new(750)
751
+ expect(money.value).to be_a BigDecimal
752
+ end
753
+
754
+ it "accepts old float values..." do
755
+ money = YAML.load(<<~EOS)
756
+ ---
757
+ !ruby/object:Money
758
+ value: 750.00
759
+ cents: 75000
760
+ EOS
761
+ expect(money).to be == Money.new(750)
762
+ expect(money.value).to be_a BigDecimal
763
+ end
764
+ end
765
+
766
+ describe('.deprecate') do
767
+ it "uses ruby warn if active support is not defined" do
768
+ stub_const("ACTIVE_SUPPORT_DEFINED", false)
769
+ expect(Kernel).to receive(:warn).once
770
+ Money.deprecate('ok')
771
+ end
772
+
773
+ it "uses active support warn if active support is defined" do
774
+ expect(Kernel).to receive(:warn).never
775
+ expect_any_instance_of(ActiveSupport::Deprecation).to receive(:warn).once
776
+ Money.deprecate('ok')
777
+ end
778
+
779
+ it "only sends a callstack of events outside of the money gem" do
780
+ expect_any_instance_of(ActiveSupport::Deprecation).to receive(:warn).with(
781
+ -> (message) { message == "[Shopify/Money] message\n" },
782
+ -> (callstack) { !callstack.first.to_s.include?('gems/money') && callstack.size > 0 }
783
+ )
784
+ Money.deprecate('message')
785
+ end
786
+ end
787
+
788
+ describe '#use_currency' do
789
+ it "allows setting the implicit default currency for a block scope" do
790
+ money = nil
791
+ Money.with_currency('CAD') do
792
+ money = Money.new(1.00)
793
+ end
794
+
795
+ expect(money.currency.iso_code).to eq('CAD')
796
+ end
797
+
798
+ it "does not use the currency for a block scope when explicitly set" do
799
+ money = nil
800
+ Money.with_currency('CAD') do
801
+ money = Money.new(1.00, 'USD')
802
+ end
803
+
804
+ expect(money.currency.iso_code).to eq('USD')
805
+ end
806
+
807
+ context "with .default_currency set" do
808
+ before(:each) { Money.default_currency = Money::Currency.new('EUR') }
809
+ after(:each) { Money.default_currency = Money::NULL_CURRENCY }
810
+
811
+ it "can be nested and falls back to default_currency outside of the blocks" do
812
+ money2, money3 = nil
813
+
814
+ money1 = Money.new(1.00)
815
+ Money.with_currency('CAD') do
816
+ Money.with_currency('USD') do
817
+ money2 = Money.new(1.00)
818
+ end
819
+ money3 = Money.new(1.00)
820
+ end
821
+ money4 = Money.new(1.00)
822
+
823
+ expect(money1.currency.iso_code).to eq('EUR')
824
+ expect(money2.currency.iso_code).to eq('USD')
825
+ expect(money3.currency.iso_code).to eq('CAD')
826
+ expect(money4.currency.iso_code).to eq('EUR')
827
+ end
828
+ end
829
+ end
830
+
831
+ describe '.clamp' do
832
+ let(:max) { 9000 }
833
+ let(:min) { -max }
834
+
835
+ it 'returns the same value if the value is within the min..max range' do
836
+ money = Money.new(5000, 'EUR').clamp(min, max)
837
+ expect(money.value).to eq(5000)
838
+ expect(money.currency.iso_code).to eq('EUR')
839
+ end
840
+
841
+ it 'returns the max value if the original value is larger' do
842
+ money = Money.new(9001, 'EUR').clamp(min, max)
843
+ expect(money.clamp(min, max).value).to eq(9000)
844
+ expect(money.clamp(min, max).currency.iso_code).to eq('EUR')
845
+ end
846
+
847
+ it 'returns the min value if the original value is smaller' do
848
+ money = Money.new(-9001, 'EUR').clamp(min, max)
849
+ expect(money.value).to eq(-9000)
850
+ expect(money.currency.iso_code).to eq('EUR')
851
+ end
852
+ end
853
+ end