1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace ValueFormatters\Test; |
4
|
|
|
|
5
|
|
|
use DataValues\QuantityValue; |
6
|
|
|
use DataValues\UnboundedQuantityValue; |
7
|
|
|
use PHPUnit\Framework\TestCase; |
8
|
|
|
use ValueFormatters\DecimalFormatter; |
9
|
|
|
use ValueFormatters\FormatterOptions; |
10
|
|
|
use ValueFormatters\QuantityFormatter; |
11
|
|
|
use ValueFormatters\ValueFormatter; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* @covers \ValueFormatters\QuantityFormatter |
15
|
|
|
* |
16
|
|
|
* @group ValueFormatters |
17
|
|
|
* @group DataValueExtensions |
18
|
|
|
* |
19
|
|
|
* @license GPL-2.0-or-later |
20
|
|
|
* @author Daniel Kinzler |
21
|
|
|
*/ |
22
|
|
|
class QuantityFormatterTest extends TestCase { |
23
|
|
|
|
24
|
|
|
public function setUp() : void { |
25
|
|
|
if ( !\extension_loaded( 'bcmath' ) ) { |
26
|
|
|
$this->markTestSkipped( 'bcmath extension not loaded' ); |
27
|
|
|
} |
28
|
|
|
} |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @see ValueFormatterTestBase::getInstance |
32
|
|
|
* |
33
|
|
|
* @param FormatterOptions|null $options |
34
|
|
|
* |
35
|
|
|
* @return QuantityFormatter |
36
|
|
|
*/ |
37
|
|
|
protected function getInstance( FormatterOptions $options = null ) { |
38
|
|
|
return $this->getQuantityFormatter( $options ); |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @param FormatterOptions|null $options |
43
|
|
|
* @param string|null $quantityWithUnitFormat |
44
|
|
|
* |
45
|
|
|
* @return QuantityFormatter |
46
|
|
|
*/ |
47
|
|
|
private function getQuantityFormatter( |
48
|
|
|
FormatterOptions $options = null, |
49
|
|
|
$quantityWithUnitFormat = null |
50
|
|
|
) { |
51
|
|
|
$vocabularyUriFormatter = $this->createMock( ValueFormatter::class ); |
52
|
|
|
$vocabularyUriFormatter->expects( $this->any() ) |
53
|
|
|
->method( 'format' ) |
54
|
|
|
->will( $this->returnCallback( function ( $unit ) { |
55
|
|
|
return $unit === '1' ? null : $unit; |
56
|
|
|
} ) ); |
57
|
|
|
|
58
|
|
|
return new QuantityFormatter( |
59
|
|
|
$options, |
60
|
|
|
new DecimalFormatter( $options ), |
61
|
|
|
$vocabularyUriFormatter, |
|
|
|
|
62
|
|
|
$quantityWithUnitFormat |
63
|
|
|
); |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
/** |
67
|
|
|
* @see ValueFormatterTestBase::validProvider |
68
|
|
|
*/ |
69
|
|
|
public function validProvider() { |
70
|
|
|
$noMargin = new FormatterOptions( [ |
71
|
|
|
QuantityFormatter::OPT_SHOW_UNCERTAINTY_MARGIN => false |
72
|
|
|
] ); |
73
|
|
|
|
74
|
|
|
$withMargin = new FormatterOptions( [ |
75
|
|
|
QuantityFormatter::OPT_SHOW_UNCERTAINTY_MARGIN => true |
76
|
|
|
] ); |
77
|
|
|
|
78
|
|
|
$noRounding = new FormatterOptions( [ |
79
|
|
|
QuantityFormatter::OPT_SHOW_UNCERTAINTY_MARGIN => true, |
80
|
|
|
QuantityFormatter::OPT_APPLY_ROUNDING => false |
81
|
|
|
] ); |
82
|
|
|
|
83
|
|
|
$exactRounding = new FormatterOptions( [ |
84
|
|
|
QuantityFormatter::OPT_SHOW_UNCERTAINTY_MARGIN => false, |
85
|
|
|
QuantityFormatter::OPT_APPLY_ROUNDING => -2 |
86
|
|
|
] ); |
87
|
|
|
|
88
|
|
|
$forceSign = new FormatterOptions( [ |
89
|
|
|
QuantityFormatter::OPT_SHOW_UNCERTAINTY_MARGIN => false, |
90
|
|
|
DecimalFormatter::OPT_FORCE_SIGN => true, |
91
|
|
|
] ); |
92
|
|
|
|
93
|
|
|
$noUnit = new FormatterOptions( [ |
94
|
|
|
QuantityFormatter::OPT_APPLY_UNIT => false, |
95
|
|
|
] ); |
96
|
|
|
|
97
|
|
|
return [ |
98
|
|
|
'+0/nm' => [ QuantityValue::newFromNumber( '+0', '1', '+0', '+0' ), '0', $noMargin ], |
99
|
|
|
'+0/wm' => [ QuantityValue::newFromNumber( '+0', '1', '+0', '+0' ), '0±0', $withMargin ], |
100
|
|
|
|
101
|
|
|
'+0.0/nm' => [ QuantityValue::newFromNumber( '+0.0', '°', '+0.1', '-0.1' ), '0.0 °', $noMargin ], |
102
|
|
|
'+0.0/wm' => [ QuantityValue::newFromNumber( '+0.0', '°', '+0.1', '-0.1' ), '0±0.1 °', $withMargin ], |
103
|
|
|
'+0.0/xr' => [ QuantityValue::newFromNumber( '+0.0', '°', '+0.1', '-0.1' ), '0.0 °', $exactRounding ], |
104
|
|
|
|
105
|
|
|
'-1205/nm' => [ QuantityValue::newFromNumber( '-1205', 'm', '-1105', '-1305' ), '-1200 m', $noMargin ], |
106
|
|
|
'-1205/wm' => [ |
107
|
|
|
QuantityValue::newFromNumber( '-1205', 'm', '-1105', '-1305' ), |
108
|
|
|
'-1205±100 m', |
109
|
|
|
$withMargin |
110
|
|
|
], |
111
|
|
|
'-1205/nr' => [ |
112
|
|
|
QuantityValue::newFromNumber( '-1205', 'm', '-1105', '-1305' ), |
113
|
|
|
'-1205±100 m', |
114
|
|
|
$noRounding |
115
|
|
|
], |
116
|
|
|
'-1205/xr' => [ |
117
|
|
|
QuantityValue::newFromNumber( '-1205', 'm', '-1105', '-1305' ), |
118
|
|
|
'-1205 m', |
119
|
|
|
$exactRounding |
120
|
|
|
], |
121
|
|
|
'-1205/nu' => [ QuantityValue::newFromNumber( '-1205', 'm', '-1105', '-1305' ), '-1205±100', $noUnit ], |
122
|
|
|
|
123
|
|
|
'+3.025/nm' => [ QuantityValue::newFromNumber( '+3.025', '1', '+3.02744', '+3.0211' ), '3.025', $noMargin ], |
124
|
|
|
'+3.025/wm' => [ |
125
|
|
|
QuantityValue::newFromNumber( '+3.025', '1', '+3.02744', '+3.0211' ), |
126
|
|
|
'3.025±0.0039', |
127
|
|
|
$withMargin |
128
|
|
|
], |
129
|
|
|
'+3.025/xr' => [ |
130
|
|
|
QuantityValue::newFromNumber( '+3.025', '1', '+3.02744', '+3.0211' ), |
131
|
|
|
'3.03', |
132
|
|
|
$exactRounding |
133
|
|
|
], |
134
|
|
|
'+3.125/nr' => [ |
135
|
|
|
QuantityValue::newFromNumber( '+3.125', '1', '+3.2', '+3.0' ), |
136
|
|
|
'3.125±0.125', |
137
|
|
|
$noRounding |
138
|
|
|
], |
139
|
|
|
'+3.125/xr' => [ QuantityValue::newFromNumber( '+3.125', '1', '+3.2', '+3.0' ), '3.13', $exactRounding ], |
140
|
|
|
|
141
|
|
|
'+3.125/fs' => [ QuantityValue::newFromNumber( '+3.125', '1', '+3.2', '+3.0' ), '+3.13', $forceSign ], |
142
|
|
|
|
143
|
|
|
// Unbounded quantities with different options |
144
|
|
|
'UB: +0.0/nm' => [ UnboundedQuantityValue::newFromNumber( '+0.0', '°' ), '0.0 °', $noMargin ], |
145
|
|
|
'UB: +0.0/wm' => [ UnboundedQuantityValue::newFromNumber( '+0.0', '°' ), '0.0 °', $withMargin ], |
146
|
|
|
'UB: +0.0/xr' => [ UnboundedQuantityValue::newFromNumber( '+0.0', '°' ), '0.0 °', $exactRounding ], |
147
|
|
|
'UB: +5.021/nm' => [ UnboundedQuantityValue::newFromNumber( '+5.021', '°' ), '5.021 °', $noMargin ], |
148
|
|
|
'UB: +5.021/wm' => [ UnboundedQuantityValue::newFromNumber( '+5.021', '°' ), '5.021 °', $withMargin ], |
149
|
|
|
'UB: +5.021/xr' => [ UnboundedQuantityValue::newFromNumber( '+5.021', '°' ), '5.02 °', $exactRounding ], |
150
|
|
|
'UB: +3.125/fs' => [ UnboundedQuantityValue::newFromNumber( '+3.125', '1' ), '+3.125', $forceSign ], |
151
|
|
|
|
152
|
|
|
// Unbounded quantities with enforced, exact rounding |
153
|
|
|
[ UnboundedQuantityValue::newFromNumber( '+0.00155', '1' ), '0.00', $exactRounding ], |
154
|
|
|
[ UnboundedQuantityValue::newFromNumber( '+0.0155', '1' ), '0.02', $exactRounding ], |
155
|
|
|
[ UnboundedQuantityValue::newFromNumber( '+0.155', '1' ), '0.16', $exactRounding ], |
156
|
|
|
[ UnboundedQuantityValue::newFromNumber( '+1.55', '1' ), '1.55', $exactRounding ], |
157
|
|
|
[ UnboundedQuantityValue::newFromNumber( '+15.5', '1' ), '15.5', $exactRounding ], |
158
|
|
|
[ UnboundedQuantityValue::newFromNumber( '+155', '1' ), '155', $exactRounding ], |
159
|
|
|
|
160
|
|
|
// Default options with different margins |
161
|
|
|
'24+-000.01' => [ QuantityValue::newFromNumber( '+24', '1', '+24.01', '+23.99' ), '24±0.01' ], |
162
|
|
|
'24+-000.10' => [ QuantityValue::newFromNumber( '+24', '1', '+24.1', '+23.9' ), '24±0.1' ], |
163
|
|
|
'24+-001.00' => [ QuantityValue::newFromNumber( '+24', '1', '+25', '+23' ), '24±1' ], |
164
|
|
|
'24+-010.00' => [ QuantityValue::newFromNumber( '+24', '1', '+34', '+14' ), '24±10' ], |
165
|
|
|
'24+-100.00' => [ QuantityValue::newFromNumber( '+24', '1', '+124', '-76' ), '24±100' ], |
166
|
|
|
|
167
|
|
|
// Rounding with a fixed +/-1 margin |
168
|
|
|
[ QuantityValue::newFromNumber( '+1.44', '1', '+2.44', '+0.44' ), '1', $noMargin ], |
169
|
|
|
[ QuantityValue::newFromNumber( '+1.45', '1', '+2.45', '+0.45' ), '1', $noMargin ], |
170
|
|
|
[ QuantityValue::newFromNumber( '+1.49', '1', '+2.49', '+0.49' ), '1', $noMargin ], |
171
|
|
|
[ QuantityValue::newFromNumber( '+1.50', '1', '+2.50', '+0.50' ), '2', $noMargin ], |
172
|
|
|
[ QuantityValue::newFromNumber( '+2.50', '1', '+3.50', '+1.50' ), '3', $noMargin ], |
173
|
|
|
|
174
|
|
|
// Rounding with different margins |
175
|
|
|
'1.55+/-0.09' => [ QuantityValue::newFromNumber( '+1.55', '1', '+1.64', '+1.46' ), '1.55', $noMargin ], |
176
|
|
|
'1.55+/-0.1' => [ QuantityValue::newFromNumber( '+1.55', '1', '+1.65', '+1.45' ), '1.6', $noMargin ], |
177
|
|
|
'1.55+/-0.49' => [ QuantityValue::newFromNumber( '+1.55', '1', '+2.04', '+1.06' ), '1.6', $noMargin ], |
178
|
|
|
'1.55+/-0.5' => [ QuantityValue::newFromNumber( '+1.55', '1', '+2.05', '+1.05' ), '1.6', $noMargin ], |
179
|
|
|
'1.55+/-0.99' => [ QuantityValue::newFromNumber( '+1.55', '1', '+2.54', '+0.56' ), '1.6', $noMargin ], |
180
|
|
|
'1.55+/-1' => [ QuantityValue::newFromNumber( '+1.55', '1', '+2.55', '+0.55' ), '2', $noMargin ], |
181
|
|
|
// FIXME: We should probably never round to zero as it is confusing. |
182
|
|
|
'1.55+/-10' => [ QuantityValue::newFromNumber( '+1.55', '1', '+11.55', '-8.45' ), '0', $noMargin ], |
183
|
|
|
|
184
|
|
|
// Do not mess with the value when the margin is rendered |
185
|
|
|
[ QuantityValue::newFromNumber( '+1500', '1', '+2500', '+500' ), '1500±1000' ], |
186
|
|
|
[ QuantityValue::newFromNumber( '+2', '1', '+2.005', '+1.995' ), '2±0.005' ], |
187
|
|
|
[ QuantityValue::newFromNumber( '+1.5', '1', '+2.5', '+0.5' ), '1.5±1' ], |
188
|
|
|
[ QuantityValue::newFromNumber( '+1.0005', '1', '+1.0015', '+0.9995' ), '1.0005±0.001' ], |
189
|
|
|
[ QuantityValue::newFromNumber( '+0.0015', '1', '+0.0025', '+0.0005' ), '0.0015±0.001' ], |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* Never mess with the margin |
193
|
|
|
* @see https://phabricator.wikimedia.org/T58892 |
194
|
|
|
*/ |
195
|
|
|
[ QuantityValue::newFromNumber( '+2', '1', '+3.5', '+0.5' ), '2±1.5' ], |
196
|
|
|
[ QuantityValue::newFromNumber( '+2', '1', '+2.016', '+1.984' ), '2±0.016' ], |
197
|
|
|
[ QuantityValue::newFromNumber( '+2', '1', '+2.0015', '+1.9985' ), '2±0.0015' ], |
198
|
|
|
[ QuantityValue::newFromNumber( '+0.0015', '1', '+0.003', '+0' ), '0.0015±0.0015' ], |
199
|
|
|
[ QuantityValue::newFromNumber( '+2.0011', '1', '+2.0022', '+2' ), '2.0011±0.0011' ], |
200
|
|
|
[ QuantityValue::newFromNumber( '+2.0099', '1', '+2.0198', '+2' ), '2.0099±0.0099' ], |
201
|
|
|
|
202
|
|
|
// IEEE edge cases |
203
|
|
|
[ |
204
|
|
|
QuantityValue::newFromNumber( |
205
|
|
|
'+1.00000000000000015', |
206
|
|
|
'1', |
207
|
|
|
'+1.00000000000000025', |
208
|
|
|
'+1.00000000000000005' |
209
|
|
|
), |
210
|
|
|
'1.00000000000000015±0.0000000000000001' |
211
|
|
|
], |
212
|
|
|
'0.2 / 3 * 3' => [ |
213
|
|
|
QuantityValue::newFromNumber( |
214
|
|
|
'+0.2000000000000000111', |
215
|
|
|
'1', |
216
|
|
|
'+0.2000000000000000111', |
217
|
|
|
'+0.2000000000000000111' |
218
|
|
|
), |
219
|
|
|
'0.2000000000000000111±0' |
220
|
|
|
], |
221
|
|
|
'8 - 6.4' => [ |
222
|
|
|
QuantityValue::newFromNumber( |
223
|
|
|
'+1.59999999999999964473', |
224
|
|
|
'1', |
225
|
|
|
'+1.59999999999999964473', |
226
|
|
|
'+1.59999999999999964473' |
227
|
|
|
), |
228
|
|
|
'1.59999999999999964473±0' |
229
|
|
|
], |
230
|
|
|
]; |
231
|
|
|
} |
232
|
|
|
|
233
|
|
|
public function testFormatWithFormatString() { |
234
|
|
|
$formatter = $this->getQuantityFormatter( null, '<$2>$1' ); |
235
|
|
|
$value = UnboundedQuantityValue::newFromNumber( '+5', 'USD' ); |
236
|
|
|
$formatted = $formatter->format( $value ); |
237
|
|
|
$this->assertSame( '<USD>5', $formatted ); |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
} |
241
|
|
|
|
It seems like the type of the argument is not accepted by the function/method which you are calling.
In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.
We suggest to add an explicit type cast like in the following example: