1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Money |
4
|
|
|
* |
5
|
|
|
* @author Pronamic <[email protected]> |
6
|
|
|
* @copyright 2005-2021 Pronamic |
7
|
|
|
* @license GPL-3.0-or-later |
8
|
|
|
* @package Pronamic\WordPress\Money |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace Pronamic\WordPress\Money; |
12
|
|
|
|
13
|
|
|
use WP_Locale; |
14
|
|
|
use WP_UnitTestCase; |
15
|
|
|
|
16
|
|
|
/** |
17
|
|
|
* Money |
18
|
|
|
* |
19
|
|
|
* @author Remco Tolsma |
20
|
|
|
* @version 1.2.2 |
21
|
|
|
* @since 1.0.0 |
22
|
|
|
*/ |
23
|
|
|
class MoneyTest extends WP_UnitTestCase { |
24
|
|
|
/** |
25
|
|
|
* Setup. |
26
|
|
|
*/ |
27
|
|
|
public function setUp() { |
28
|
|
|
parent::setUp(); |
29
|
|
|
|
30
|
|
|
if ( version_compare( PHP_VERSION, '5.4', '<' ) ) { |
31
|
|
|
add_filter( 'number_format_i18n', array( $this, 'maybe_fix_multibyte_number_format' ), 10, 3 ); |
32
|
|
|
} |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Maybe fix multibyte number format. |
37
|
|
|
* |
38
|
|
|
* @link https://github.com/WordPress/WordPress/blob/4.9.6/wp-includes/functions.php#L206-L237 |
39
|
|
|
* |
40
|
|
|
* @param string $formatted Formatted number. |
41
|
|
|
* @param float $number The number to convert based on locale. |
42
|
|
|
* @param int $decimals Optional. Precision of the number of decimal places. Default 0. |
43
|
|
|
* |
44
|
|
|
* @return string Converted number in string format. |
45
|
|
|
* @global WP_Locale $wp_locale |
46
|
|
|
*/ |
47
|
|
|
public function maybe_fix_multibyte_number_format( $formatted, $number, $decimals ) { |
48
|
|
|
global $wp_locale; |
49
|
|
|
|
50
|
|
|
if ( empty( $wp_locale ) ) { |
51
|
|
|
return $formatted; |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
$dec_point = $wp_locale->number_format['decimal_point']; |
55
|
|
|
$thousands_sep = $wp_locale->number_format['thousands_sep']; |
56
|
|
|
|
57
|
|
|
if ( 1 === strlen( $dec_point ) && 1 === strlen( $thousands_sep ) ) { |
58
|
|
|
return $formatted; |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
$formatted = number_format( $number, $decimals, 'd', 't' ); |
62
|
|
|
|
63
|
|
|
$formatted = strtr( |
64
|
|
|
$formatted, |
65
|
|
|
array( |
66
|
|
|
'd' => $dec_point, |
67
|
|
|
't' => $thousands_sep, |
68
|
|
|
) |
69
|
|
|
); |
70
|
|
|
|
71
|
|
|
return $formatted; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* Test default format. |
76
|
|
|
* |
77
|
|
|
* @link https://github.com/WordPress/WordPress/blob/4.9.5/wp-includes/l10n.php |
78
|
|
|
* |
79
|
|
|
* @dataProvider default_format_provider |
80
|
|
|
* |
81
|
|
|
* @param string $locale Locale to test. |
82
|
|
|
* @param string $expected Expected default format. |
83
|
|
|
*/ |
84
|
|
|
public function test_default_format( $locale, $expected ) { |
85
|
|
|
switch_to_locale( $locale ); |
86
|
|
|
|
87
|
|
|
$value = Money::get_default_format(); |
88
|
|
|
|
89
|
|
|
$this->assertEquals( $locale, get_locale() ); |
90
|
|
|
$this->assertEquals( $expected, $value ); |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Default format provider. |
95
|
|
|
* |
96
|
|
|
* @return array |
97
|
|
|
*/ |
98
|
|
|
public function default_format_provider() { |
99
|
|
|
return array( |
100
|
|
|
array( 'en_US', '%1$s%2$s %3$s' ), |
101
|
|
|
array( 'fr_FR', '%1$s%2$s %3$s' ), |
102
|
|
|
array( 'nl_NL', '%1$s %2$s' ), |
103
|
|
|
); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Test format i18n. |
108
|
|
|
* |
109
|
|
|
* @link https://github.com/WordPress/WordPress/blob/4.9.5/wp-includes/l10n.php |
110
|
|
|
* |
111
|
|
|
* @param string $locale Locale. |
112
|
|
|
* @param string $currency Money currency. |
113
|
|
|
* @param float $value Money value. |
114
|
|
|
* @param string $expected Expected format. |
115
|
|
|
* |
116
|
|
|
* @dataProvider format_i18n_provider |
117
|
|
|
*/ |
118
|
|
|
public function test_format_i18n( $locale, $currency, $value, $expected ) { |
119
|
|
|
switch_to_locale( $locale ); |
120
|
|
|
|
121
|
|
|
$money = new Money( $value, $currency ); |
122
|
|
|
|
123
|
|
|
$string = $money->format_i18n(); |
124
|
|
|
|
125
|
|
|
$this->assertEquals( $locale, get_locale() ); |
126
|
|
|
/* translators: 1: currency symbol, 2: amount value, 3: currency code, note: use non-breaking space! */ |
127
|
|
|
$this->assertEquals( $expected, $string, 'Locale: ' . get_locale() . ' Money format: ' . Money::get_default_format() . ' Test: ' . _x( '%1$s%2$s %3$s', 'money format', 'pronamic-money' ) ); |
128
|
|
|
} |
129
|
|
|
|
130
|
|
|
/** |
131
|
|
|
* Format i18n provider. |
132
|
|
|
* |
133
|
|
|
* @return array |
134
|
|
|
*/ |
135
|
|
|
public function format_i18n_provider() { |
136
|
|
|
return array( |
137
|
|
|
// Dutch. |
138
|
|
|
array( 'nl_NL', 'EUR', 49.7512, '€ 49,75' ), |
139
|
|
|
array( 'nl_NL', 'NLG', 49.7512, 'G 49,7512' ), |
140
|
|
|
array( 'nl_NL', 'USD', 49.7512, '$ 49,75' ), |
141
|
|
|
array( 'nl_NL', 'USD', 1234567890.1234, '$ 1.234.567.890,12' ), |
142
|
|
|
|
143
|
|
|
// English. |
144
|
|
|
array( 'en_US', 'EUR', 49.7512, '€49.75 EUR' ), |
145
|
|
|
array( 'en_US', 'USD', 1234567890.1234, '$1,234,567,890.12 USD' ), |
146
|
|
|
|
147
|
|
|
// French. |
148
|
|
|
array( 'fr_FR', 'USD', 1234567890.1234, '$1 234 567 890,12 USD' ), |
149
|
|
|
); |
150
|
|
|
} |
151
|
|
|
|
152
|
|
|
/** |
153
|
|
|
* Test format i18n without trailing zeros. |
154
|
|
|
* |
155
|
|
|
* @link https://github.com/WordPress/WordPress/blob/4.9.5/wp-includes/l10n.php |
156
|
|
|
* |
157
|
|
|
* @param string $locale Locale. |
158
|
|
|
* @param string $currency Money currency. |
159
|
|
|
* @param float $value Money value. |
160
|
|
|
* @param string $expected Expected format. |
161
|
|
|
* |
162
|
|
|
* @dataProvider format_i18n_non_trailing_zeros_provider |
163
|
|
|
*/ |
164
|
|
|
public function test_format_i18n_non_trailing_zeros( $locale, $currency, $value, $expected ) { |
165
|
|
|
switch_to_locale( $locale ); |
166
|
|
|
|
167
|
|
|
$money = new Money( $value, $currency ); |
168
|
|
|
|
169
|
|
|
$string = $money->format_i18n_non_trailing_zeros(); |
170
|
|
|
|
171
|
|
|
$this->assertEquals( $locale, get_locale() ); |
172
|
|
|
|
173
|
|
|
/* translators: 1: currency symbol, 2: amount value, 3: currency code, note: use non-breaking space! */ |
174
|
|
|
$this->assertEquals( $expected, $string, 'Locale: ' . get_locale() . ' Money format: ' . Money::get_default_format() . ' Test: ' . _x( '%1$s%2$s %3$s', 'money format', 'pronamic-money' ) ); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* Format i18n without trailing zeros provider. |
179
|
|
|
* |
180
|
|
|
* @return array |
181
|
|
|
*/ |
182
|
|
|
public function format_i18n_non_trailing_zeros_provider() { |
183
|
|
|
return array( |
184
|
|
|
// Dutch. |
185
|
|
|
array( 'nl_NL', 'EUR', 49.7512, '€ 49,75' ), |
186
|
|
|
array( 'nl_NL', 'NLG', 49, 'G 49' ), |
187
|
|
|
array( 'nl_NL', 'USD', 49.00, '$ 49' ), |
188
|
|
|
array( 'nl_NL', 'USD', 1234567890.00, '$ 1.234.567.890' ), |
189
|
|
|
|
190
|
|
|
// English. |
191
|
|
|
array( 'en_US', 'EUR', 49.7512, '€49.75 EUR' ), |
192
|
|
|
array( 'en_US', 'USD', 1234567890.00, '$1,234,567,890 USD' ), |
193
|
|
|
|
194
|
|
|
// French. |
195
|
|
|
array( 'fr_FR', 'USD', 1234567890, '$1 234 567 890 USD' ), |
196
|
|
|
); |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Test minor units. |
201
|
|
|
* |
202
|
|
|
* @since 1.2.1 |
203
|
|
|
* |
204
|
|
|
* @dataProvider minor_units_provider |
205
|
|
|
* |
206
|
|
|
* @param string $currency Currency. |
207
|
|
|
* @param int|float $value Money value to test. |
208
|
|
|
* @param int $expected Expected value. |
209
|
|
|
*/ |
210
|
|
|
public function test_minor_units( $currency, $value, $expected ) { |
211
|
|
|
$money = new Money( $value, $currency ); |
212
|
|
|
|
213
|
|
|
$this->assertSame( $expected, $money->get_minor_units()->to_int() ); |
214
|
|
|
} |
215
|
|
|
|
216
|
|
|
/** |
217
|
|
|
* Minor units provider. |
218
|
|
|
* |
219
|
|
|
* @since 1.2.1 |
220
|
|
|
* |
221
|
|
|
* @return array |
222
|
|
|
*/ |
223
|
|
|
public function minor_units_provider() { |
224
|
|
|
return array( |
225
|
|
|
// Value 10. |
226
|
|
|
array( 'JPY', 10, 10 ), |
227
|
|
|
array( 'EUR', 10, 1000 ), |
228
|
|
|
array( 'BHD', 10, 10000 ), |
229
|
|
|
array( 'NLG', 10, 100000 ), |
230
|
|
|
|
231
|
|
|
// Value 100.65. |
232
|
|
|
array( 'JPY', 100.65, 100 ), |
233
|
|
|
array( 'EUR', 100.65, 10065 ), |
234
|
|
|
array( 'BHD', 100.65, 100650 ), |
235
|
|
|
array( 'NLG', 100.65, 1006500 ), |
236
|
|
|
|
237
|
|
|
// Value 100.655. |
238
|
|
|
array( 'JPY', 100.655, 100 ), |
239
|
|
|
array( 'EUR', 100.655, 10065 ), |
240
|
|
|
array( 'BHD', 100.655, 100655 ), |
241
|
|
|
array( 'NLG', 100.655, 1006550 ), |
242
|
|
|
|
243
|
|
|
// Value 0.00010. |
244
|
|
|
array( 'JPY', 0.00010, 0 ), |
245
|
|
|
array( 'EUR', 0.00010, 0 ), |
246
|
|
|
array( 'BHD', 0.00010, 0 ), |
247
|
|
|
array( 'NLG', 0.00010, 1 ), |
248
|
|
|
); |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
/** |
252
|
|
|
* Test add. |
253
|
|
|
* |
254
|
|
|
* @since 1.3.0 |
255
|
|
|
*/ |
256
|
|
|
public function test_add() { |
257
|
|
|
$money_1 = new Money( 99.75, 'EUR' ); |
258
|
|
|
|
259
|
|
|
$money_2 = new Money( 0.25, 'EUR' ); |
260
|
|
|
|
261
|
|
|
$money_3 = $money_1->add( $money_2 ); |
262
|
|
|
|
263
|
|
|
$this->assertEquals( 100, $money_3->get_value() ); |
264
|
|
|
} |
265
|
|
|
|
266
|
|
|
/** |
267
|
|
|
* Test JSON. |
268
|
|
|
*/ |
269
|
|
|
public function test_json() { |
270
|
|
|
$money = new Money( 99.75, 'EUR' ); |
271
|
|
|
|
272
|
|
|
$this->assertJsonStringEqualsJsonString( |
273
|
|
|
' |
274
|
|
|
{ |
275
|
|
|
"value": "99.75", |
276
|
|
|
"currency": "EUR" |
277
|
|
|
} |
278
|
|
|
', |
279
|
|
|
\wp_json_encode( $money ) |
|
|
|
|
280
|
|
|
); |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Test number format. |
285
|
|
|
*/ |
286
|
|
|
public function test_number_format() { |
287
|
|
|
$money = new Money( 12345678.90, 'EUR' ); |
288
|
|
|
|
289
|
|
|
$this->assertSame( '12345678.90', $money->number_format( null, '.', '' ) ); |
290
|
|
|
$this->assertSame( '12,345,678.90', $money->number_format( null, '.', ',' ) ); |
291
|
|
|
$this->assertSame( '12345678.9', $money->number_format( 1, '.', '' ) ); |
292
|
|
|
} |
293
|
|
|
|
294
|
|
|
/** |
295
|
|
|
* Test number format i18n. |
296
|
|
|
*/ |
297
|
|
|
public function test_number_format_i18n() { |
298
|
|
|
\switch_to_locale( 'en_US' ); |
299
|
|
|
|
300
|
|
|
$money = new Money( 12345678.90, 'EUR' ); |
301
|
|
|
|
302
|
|
|
$this->assertSame( '12,345,678.90', $money->number_format_i18n( null ) ); |
303
|
|
|
$this->assertSame( '12,345,678.9', $money->number_format_i18n( 1 ) ); |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* Test multiply. |
308
|
|
|
*/ |
309
|
|
|
public function test_multiply() { |
310
|
|
|
$money = new Money( '123', 'EUR' ); |
311
|
|
|
|
312
|
|
|
$money_2 = $money->multiply( 2 ); |
313
|
|
|
|
314
|
|
|
$this->assertSame( '246.00', $money_2->number_format( null, '.', '' ) ); |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
/** |
318
|
|
|
* Test divide. |
319
|
|
|
*/ |
320
|
|
|
public function test_divide() { |
321
|
|
|
$money = new Money( '246', 'EUR' ); |
322
|
|
|
|
323
|
|
|
$money_2 = $money->divide( 2 ); |
324
|
|
|
|
325
|
|
|
$this->assertSame( '123.00', $money_2->number_format( null, '.', '' ) ); |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
/** |
329
|
|
|
* Test absolute. |
330
|
|
|
*/ |
331
|
|
|
public function test_absolute() { |
332
|
|
|
$money = new Money( '-123', 'EUR' ); |
333
|
|
|
|
334
|
|
|
$this->assertSame( '-123.00', $money->number_format( null, '.', '' ) ); |
335
|
|
|
|
336
|
|
|
$money_2 = $money->absolute(); |
337
|
|
|
|
338
|
|
|
$this->assertSame( '123.00', $money_2->number_format( null, '.', '' ) ); |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* Test to string. |
343
|
|
|
*/ |
344
|
|
|
public function test_to_string() { |
345
|
|
|
$money = new Money( '-123', 'EUR' ); |
346
|
|
|
|
347
|
|
|
$string = (string) $money; |
348
|
|
|
|
349
|
|
|
$this->assertSame( 'EUR -123.00', $string ); |
350
|
|
|
|
351
|
|
|
} |
352
|
|
|
} |
353
|
|
|
|