shopify-money 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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