1<?php
2
3namespace dokuwiki\plugin\struct\test\types;
4
5use dokuwiki\plugin\struct\meta\ValidationException;
6use dokuwiki\plugin\struct\meta\Value;
7use dokuwiki\plugin\struct\test\mock\Search;
8use dokuwiki\plugin\struct\test\StructTest;
9use dokuwiki\plugin\struct\types\Decimal;
10
11/**
12 * Testing the Decimal Type
13 *
14 * @group plugin_struct
15 * @group plugins
16 */
17class DecimalTest extends StructTest
18{
19
20    /**
21     * Provides failing min/max validation data
22     *
23     * @return array
24     */
25    public function validateFailProvider()
26    {
27        return [
28            // same as integer:
29            ['foo', '', ''],
30            ['foo222', '', ''],
31            ['-5', '0', ''],
32            ['5', '', '0'],
33            ['500', '100', '200'],
34            ['50', '100', '200'],
35            // decimal specifics
36            ['5.5', '5.6', ''],
37            ['5,5', '5.6', ''],
38            ['-5.5', '-5.4', ''],
39            ['-5,5', '-5.4', ''],
40        ];
41    }
42
43    /**
44     * Provides successful min/max validation data
45     *
46     * @return array
47     */
48    public function validateSuccessProvider()
49    {
50        return [
51            // same as integer
52            ['0', '', ''],
53            ['-5', '', ''],
54            ['5', '', ''],
55            ['5', '0', ''],
56            ['-5', '', '0'],
57            ['150', '100', '200'],
58            // decimal specifics
59            ['5.5', '', ''],
60            ['5,5', '', ''],
61            ['-5.5', '', ''],
62            ['-5,5', '', ''],
63            ['5.5', '4.5', ''],
64            ['5,5', '4.5', ''],
65            ['-5.5', '', '4.5'],
66            ['-5,5', '', '4.5'],
67            ['5.5645000', '', ''],
68            // boundaries
69            ['0', '0', ''],
70            ['0', '', '0'],
71            ['5', '5', ''],
72            ['5', '', '5'],
73            ['0', '0.0', ''],
74            ['0', '', '0.0'],
75            ['5.0', '5.0', ''],
76            ['5.0', '', '5.0'],
77        ];
78    }
79
80
81    /**
82     * @dataProvider validateFailProvider
83     */
84    public function test_validate_fail($value, $min, $max)
85    {
86        $this->expectException(ValidationException::class);
87        $decimal = new Decimal(array('min' => $min, 'max' => $max));
88        $decimal->validate($value);
89    }
90
91    /**
92     * @dataProvider validateSuccessProvider
93     */
94    public function test_validate_success($value, $min, $max, $decpoint = '.')
95    {
96        $decimal = new Decimal(array('min' => $min, 'max' => $max));
97        $decimal->validate($value);
98        $this->assertTrue(true); // we simply check that no exceptions are thrown
99    }
100
101
102    public function valueProvider()
103    {
104        return [
105            // $value, $expect, $roundto, $decpoint, $thousands, $trimzeros, $prefix='', $postfix='', $engineering = false
106            ['5000', '5 000,00', '2', ',', ' ', false],
107            ['5000', '5 000', '2', ',', ' ', true],
108            ['5000', '5 000', '0', ',', ' ', false],
109            ['5000', '5 000', '0', ',', ' ', true],
110            ['5000', '5 000', '', ',', ' ', false],
111            ['5000', '5 000', '', ',', ' ', true],
112            ['5000', '5 000', '-1', ',', ' ', false],
113            ['5000', '5 000', '-1', ',', ' ', true],
114
115            ['777.707', '778', '0', ',', ' ', true],
116            ['777.707', '778', '', ',', ' ', true],
117            ['777.707', '777,71', '2', ',', ' ', true],
118            ['777.707', '777,71', '2', ',', ' ', false],
119
120            ['-0.55600', '-0,56', '2', ',', ' ', false],
121            ['-0.55600', '-0,55600', '-1', ',', ' ', false],
122            ['-0.55600', '-0,556', '-1', ',', ' ', true],
123            ['-0.55600', '-0,5560', '4', ',', ' ', false],
124            ['-0.55600', '-0,556', '4', ',', ' ', true],
125
126            ['-0.55600', '$ -0,556', '4', ',', ' ', true, '$ '],
127            ['-0.55600', '-0,556 EUR', '4', ',', ' ', true, '', ' EUR'],
128
129            //engineering notation
130            ['1e-18', '1' . "\xE2\x80\xAF" . 'a', '-1', ',', ' ', true, '', '', true],
131            ['1e-15', '1' . "\xE2\x80\xAF" . 'f', '-1', ',', ' ', true, '', '', true],
132            ['1e-12', '1' . "\xE2\x80\xAF" . 'p', '-1', ',', ' ', true, '', '', true],
133            ['1e-9', '1' . "\xE2\x80\xAF" . 'n', '-1', ',', ' ', true, '', '', true],
134            ['1e-6', '1' . "\xE2\x80\xAF" . 'µ', '-1', ',', ' ', true, '', '', true],
135            ['1e-3', '1' . "\xE2\x80\xAF" . 'm', '-1', ',', ' ', true, '', '', true],
136
137            ['1e3', '1' . "\xE2\x80\xAF" . 'k', '-1', ',', ' ', true, '', '', true],
138            ['1e6', '1' . "\xE2\x80\xAF" . 'M', '-1', ',', ' ', true, '', '', true],
139            ['1e9', '1' . "\xE2\x80\xAF" . 'G', '-1', ',', ' ', true, '', '', true],
140            ['1e12', '1' . "\xE2\x80\xAF" . 'T', '-1', ',', ' ', true, '', '', true],
141
142            ['1e4', '10' . "\xE2\x80\xAF" . 'k', '-1', ',', ' ', true, '', '', true],
143            ['1e5', '100' . "\xE2\x80\xAF" . 'k', '-1', ',', ' ', true, '', '', true],
144
145            ['1e-4', '100' . "\xE2\x80\xAF" . 'µ', '-1', ',', ' ', true, '', '', true],
146            ['1e-5', '10' . "\xE2\x80\xAF" . 'µ', '-1', ',', ' ', true, '', '', true],
147
148            //test behaviour if number exceeds prefix array
149            ['1e15', '1000' . "\xE2\x80\xAF" . 'T', '-1', ',', ' ', true, '', '', true],
150            ['1e-21', '0.001' . "\xE2\x80\xAF" . 'a', '-1', ',', ' ', true, '', '', true],
151
152        ];
153    }
154
155    /**
156     * @dataProvider valueProvider
157     */
158    public function test_renderValue(
159        $value, $expect, $roundto, $decpoint,
160        $thousands, $trimzeros,
161        $prefix = '', $postfix = '', $engineering = false
162    )
163    {
164        $decimal = new Decimal([
165            'roundto' => $roundto,
166            'decpoint' => $decpoint,
167            'thousands' => $thousands,
168            'trimzeros' => $trimzeros,
169            'prefix' => $prefix,
170            'postfix' => $postfix,
171            'engineering' => $engineering
172        ]);
173        $R = new \Doku_Renderer_xhtml();
174        $R->doc = '';
175        $decimal->renderValue($value, $R, 'xhtml');
176        $this->assertEquals($expect, $R->doc);
177    }
178
179    public function test_sort()
180    {
181        $this->loadSchemaJSON('decimal');
182        $this->waitForTick();
183        $this->saveData('page1', 'decimal', ['field' => '5000']);
184        $this->saveData('page2', 'decimal', ['field' => '5000.001']);
185        $this->saveData('page3', 'decimal', ['field' => '900.5']);
186        $this->saveData('page4', 'decimal', ['field' => '1.5']);
187
188        $search = new Search();
189        $search->addSchema('decimal');
190        $search->addColumn('%pageid%');
191        $search->addColumn('field');
192        $search->addSort('field', true);
193        /** @var Value[][] $result */
194        $result = $search->getRows();
195
196        $this->assertEquals(4, count($result));
197        $this->assertEquals('page4', $result[0][0]->getValue());
198        $this->assertEquals('page3', $result[1][0]->getValue());
199        $this->assertEquals('page1', $result[2][0]->getValue());
200        $this->assertEquals('page2', $result[3][0]->getValue());
201    }
202
203    public function test_filter()
204    {
205        $this->loadSchemaJSON('decimal');
206        $this->waitForTick();
207        $this->saveData('page1', 'decimal', ['field' => '5000']);
208        $this->saveData('page2', 'decimal', ['field' => '5000.001']);
209        $this->saveData('page3', 'decimal', ['field' => '900.5']);
210        $this->saveData('page4', 'decimal', ['field' => '1.5']);
211
212        $search = new Search();
213        $search->addSchema('decimal');
214        $search->addColumn('%pageid%');
215        $search->addColumn('field');
216        $search->addFilter('field', '800', '>', 'AND');
217        $search->addSort('field', true);
218        /** @var Value[][] $result */
219        $result = $search->getRows();
220
221        $this->assertEquals(3, count($result));
222        $this->assertEquals('page3', $result[0][0]->getValue());
223        $this->assertEquals('page1', $result[1][0]->getValue());
224        $this->assertEquals('page2', $result[2][0]->getValue());
225    }
226
227}
228