Passed
Pull Request — master (#28)
by Maurício
12:24
created

ShapeFileTest::shapesProvider()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 39
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 30
nc 1
nop 0
dl 0
loc 39
rs 9.44
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * phpMyAdmin ShapeFile library
7
 * <https://github.com/phpmyadmin/shapefile/>.
8
 *
9
 * Copyright 2006-2007 Ovidio <ovidio AT users.sourceforge.net>
10
 * Copyright 2016 - 2017 Michal Čihař <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or
13
 * modify it under the terms of the GNU General Public License
14
 * as published by the Free Software Foundation.
15
 *
16
 * This program is distributed in the hope that it will be useful,
17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
 * GNU General Public License for more details.
20
 *
21
 * You should have received a copy of the GNU General Public License
22
 * along with this program; if not, you can download one from
23
 * https://www.gnu.org/copyleft/gpl.html.
24
 */
25
26
namespace PhpMyAdminTest\ShapeFile;
27
28
use PhpMyAdmin\ShapeFile\ShapeFile;
29
use PhpMyAdmin\ShapeFile\ShapeRecord;
30
use PHPUnit\Framework\TestCase;
31
32
use function count;
33
34
class ShapeFileTest extends TestCase
35
{
36
    /**
37
     * Tests loading of a file.
38
     *
39
     * @param string   $filename Name of file
40
     * @param int      $records  Expected number of records
41
     * @param int|null $parts    Expected number of parts in first record
42
     *
43
     * @dataProvider provideFiles
44
     */
45
    public function testLoad(string $filename, int $records, int|null $parts): void
46
    {
47
        $shp = new ShapeFile(1);
48
        $shp->loadFromFile($filename);
49
        $this->assertEquals('', $shp->lastError);
50
        $this->assertEquals($records, count($shp->records));
51
        if ($parts === null) {
52
            return;
53
        }
54
55
        $this->assertEquals($parts, count($shp->records[0]->shpData['parts']));
56
    }
57
58
    /**
59
     * Data provider for file loading tests.
60
     *
61
     * @psalm-return list<array{string, int, int|null}>
62
     */
63
    public static function provideFiles(): array
64
    {
65
        return [
66
            [
67
                'data/capitals.*',
68
                652,
69
                null,
70
            ],
71
            [
72
                'data/mexico.*',
73
                32,
74
                3,
75
            ],
76
            [
77
                'data/Czech_Republic_AL2.*',
78
                1,
79
                1,
80
            ],
81
            [
82
                'data/w001n05f.*',
83
                16,
84
                1,
85
            ],
86
            [
87
                'data/bc_hospitals.*',
88
                44,
89
                null,
90
            ],
91
            [
92
                'data/multipoint.*',
93
                312,
94
                null,
95
            ],
96
        ];
97
    }
98
99
    /**
100
     * Test error handling in loader.
101
     *
102
     * @param string $filename name to load
103
     *
104
     * @dataProvider provideErrorFiles
105
     */
106
    public function testLoadError(string $filename): void
107
    {
108
        $shp = new ShapeFile(1);
109
        $shp->loadFromFile($filename);
110
        $this->assertNotEquals('', $shp->lastError);
111
    }
112
113
    /**
114
     * Test load an empty file name
115
     */
116
    public function testLoadEmptyFilename(): void
117
    {
118
        $shp = new ShapeFile(1);
119
        $shp->loadFromFile('');
120
        if (ShapeFile::supportsDbase()) {
121
            $this->assertEquals('It wasn\'t possible to find the DBase file ""', $shp->lastError);
122
123
            return;
124
        }
125
126
        $this->assertEquals('Not a SHP file (file code mismatch)', $shp->lastError);
127
    }
128
129
    /**
130
     * Test to call getDBFHeader on a non loaded file
131
     */
132
    public function testGetDBFHeader(): void
133
    {
134
        $shp = new ShapeFile(1);
135
        $this->assertNull($shp->getDBFHeader());
136
    }
137
138
    /**
139
     * Data provider for file loading error tests.
140
     *
141
     * @psalm-return list<array{string}>
142
     */
143
    public static function provideErrorFiles(): array
144
    {
145
        $result = [
146
            ['data/no-shp.*'],
147
            ['data/missing.*'],
148
            ['data/invalid-shp.*'],
149
        ];
150
151
        if (ShapeFile::supportsDbase()) {
152
            $result[] = ['data/no-dbf.*'];
153
            $result[] = ['data/invalid-dbf.*'];
154
        }
155
156
        return $result;
157
    }
158
159
    /**
160
     * Creates test data.
161
     */
162
    private function createTestData(): void
163
    {
164
        $shp = new ShapeFile(1);
165
166
        $record0 = new ShapeRecord(1);
167
        $record0->addPoint(['x' => 482131.764567, 'y' => 2143634.39608]);
168
169
        $record1 = new ShapeRecord(11);
170
        $record1->addPoint(['x' => 472131.764567, 'y' => 2143634.39608, 'z' => 220, 'm' => 120]);
171
172
        $record2 = new ShapeRecord(21);
173
        $record2->addPoint(['x' => 492131.764567, 'y' => 2143634.39608, 'z' => 150, 'm' => 80]);
174
175
        $record3 = new ShapeRecord(3);
176
        $record3->addPoint(['x' => 482131.764567, 'y' => 2143634.39608], 0);
177
        $record3->addPoint(['x' => 482132.764567, 'y' => 2143635.39608], 0);
178
        $record3->addPoint(['x' => 482131.764567, 'y' => 2143635.39608], 1);
179
        $record3->addPoint(['x' => 482132.764567, 'y' => 2143636.39608], 1);
180
181
        $shp->addRecord($record0);
182
        $shp->addRecord($record1);
183
        $shp->addRecord($record2);
184
        $shp->addRecord($record3);
185
186
        $shp->setDBFHeader(
187
            [
188
                [
189
                    'ID',
190
                    'N',
191
                    8,
192
                    0,
193
                ],
194
                [
195
                    'DESC',
196
                    'C',
197
                    50,
198
                    0,
199
                ],
200
            ],
201
        );
202
203
        $shp->records[0]->dbfData['ID'] = '1';
204
        $shp->records[0]->dbfData['DESC'] = 'AAAAAAAAA';
205
206
        $shp->records[1]->dbfData['ID'] = '2';
207
        $shp->records[1]->dbfData['DESC'] = 'BBBBBBBBBB';
208
209
        $shp->records[2]->dbfData['ID'] = '3';
210
        $shp->records[2]->dbfData['DESC'] = 'CCCCCCCCCCC';
211
212
        $shp->records[3]->dbfData['ID'] = '4';
213
        $shp->records[3]->dbfData['DESC'] = 'CCCCCCCCCCC';
214
215
        $shp->saveToFile('./data/test_shape.*');
216
    }
217
218
    /**
219
     * Tests creating file.
220
     */
221
    public function testCreate(): void
222
    {
223
        if (! ShapeFile::supportsDbase()) {
224
            $this->markTestSkipped('dbase extension missing');
225
        }
226
227
        $this->createTestData();
228
229
        $shp = new ShapeFile(1);
230
        $shp->loadFromFile('./data/test_shape.*');
231
        $this->assertEquals(4, count($shp->records));
232
    }
233
234
    /**
235
     * Tests removing record from a file.
236
     */
237
    public function testDelete(): void
238
    {
239
        if (! ShapeFile::supportsDbase()) {
240
            $this->markTestSkipped('dbase extension missing');
241
        }
242
243
        $this->createTestData();
244
245
        $shp = new ShapeFile(1);
246
        $shp->loadFromFile('./data/test_shape.*');
247
        $shp->deleteRecord(1);
248
        $shp->saveToFile();
249
        $this->assertEquals(3, count($shp->records));
250
251
        $shp = new ShapeFile(1);
252
        $shp->loadFromFile('./data/test_shape.*');
253
        $this->assertEquals(3, count($shp->records));
254
    }
255
256
    /**
257
     * Test adding record to a file.
258
     */
259
    public function testAdd(): void
260
    {
261
        if (! ShapeFile::supportsDbase()) {
262
            $this->markTestSkipped('dbase extension missing');
263
        }
264
265
        $this->createTestData();
266
267
        $shp = new ShapeFile(1);
268
        $shp->loadFromFile('./data/test_shape.*');
269
270
        $record0 = new ShapeRecord(1);
271
        $record0->addPoint(['x' => 482131.764567, 'y' => 2143634.39608]);
272
273
        $shp->addRecord($record0);
274
        $shp->records[4]->dbfData['ID'] = '4';
275
        $shp->records[4]->dbfData['DESC'] = 'CCCCCCCCCCC';
276
277
        $shp->saveToFile();
278
        $this->assertEquals(5, count($shp->records));
279
280
        $shp = new ShapeFile(1);
281
        $shp->loadFromFile('./data/test_shape.*');
282
        $this->assertEquals(5, count($shp->records));
283
    }
284
285
    /**
286
     * Tests saving without DBF.
287
     */
288
    public function testSaveNoDBF(): void
289
    {
290
        $shp = new ShapeFile(1);
291
        $shp->saveToFile('./data/test_nodbf.*');
292
293
        $this->assertFileDoesNotExist('./data/test_nodbf.dbf');
294
    }
295
296
    /**
297
     * Test shape naming.
298
     */
299
    public function testShapeName(): void
300
    {
301
        $obj = new ShapeRecord(1);
302
        $this->assertEquals('Point', $obj->getShapeName());
303
        $obj = new ShapeFile(1);
304
        $this->assertEquals('Point', $obj->getShapeName());
305
        $obj = new ShapeRecord(-1);
306
        $this->assertEquals('Shape -1', $obj->getShapeName());
307
    }
308
309
    /**
310
     * Test shapes save/load round-robin.
311
     *
312
     * @psalm-param list<array{mixed[], int}> $points
313
     *
314
     * @dataProvider shapesProvider
315
     */
316
    public function testShapeSaveLoad(int $shapeType, array $points): void
317
    {
318
        $filename = './data/test_shape-' . $shapeType . '.*';
319
        $shp = new ShapeFile($shapeType);
320
        $shp->setDBFHeader([['ID', 'N', 19, 0], ['DESC', 'C', 14, 0]]);
321
322
        $record0 = new ShapeRecord($shapeType);
323
324
        foreach ($points as $point) {
325
            $record0->addPoint($point[0], $point[1]);
326
        }
327
328
        $shp->addRecord($record0);
329
330
        $shp->saveToFile($filename);
331
332
        $shp2 = new ShapeFile($shapeType);
333
        $shp2->loadFromFile($filename);
334
335
        $this->assertEquals(count($shp->records), count($shp2->records));
336
337
        $record = $shp->records[0];
338
        $record2 = $shp2->records[0];
339
340
        $items = ['numparts', 'numpoints'];
341
        foreach ($items as $item) {
342
            if (! isset($record->shpData[$item])) {
343
                continue;
344
            }
345
346
            $this->assertEquals($record->shpData[$item], $record2->shpData[$item]);
347
        }
348
349
        /* Test deletion works */
350
        $record->deletePoint();
351
    }
352
353
    /**
354
     * Data provider for save/load testing.
355
     *
356
     * @psalm-return list<array{int, list<array{mixed[], int}>}>
357
     */
358
    public static function shapesProvider(): array
359
    {
360
        $pointsForPointType = [[['x' => 10, 'y' => 20], 0]];
361
362
        $pointsForPolyLineType = [
363
            [['x' => 10, 'y' => 20], 0],
364
            [['x' => 20, 'y' => 20], 0],
365
            [['x' => 20, 'y' => 20], 1],
366
            [['x' => 20, 'y' => 10], 1],
367
        ];
368
369
        $pointsForPolygonType = [
370
            [['x' => 10, 'y' => 20], 0],
371
            [['x' => 20, 'y' => 20], 0],
372
            [['x' => 20, 'y' => 20], 1],
373
            [['x' => 20, 'y' => 10], 1],
374
            [['x' => 20, 'y' => 10], 2],
375
            [['x' => 10, 'y' => 20], 2],
376
        ];
377
378
        $pointsForMultiPointType = [
379
            [['x' => 10, 'y' => 20], 0],
380
            [['x' => 20, 'y' => 20], 0],
381
            [['x' => 20, 'y' => 10], 0],
382
        ];
383
384
        return [
385
            [1, $pointsForPointType],
386
            [3, $pointsForPolyLineType],
387
            [5, $pointsForPolygonType],
388
            [8, $pointsForMultiPointType],
389
            [11, $pointsForPointType],
390
            [13, $pointsForPolyLineType],
391
            [15, $pointsForPolygonType],
392
            [18, $pointsForMultiPointType],
393
            [21, $pointsForPointType],
394
            [23, $pointsForPolyLineType],
395
            [25, $pointsForPolygonType],
396
            [28, $pointsForMultiPointType],
397
        ];
398
    }
399
400
    public function testSearch(): void
401
    {
402
        $shp = new ShapeFile(0);
403
        $shp->loadFromFile('data/capitals.*');
404
        /* Nonexisting entry or no dbase support */
405
        $this->assertEquals(
406
            -1,
407
            $shp->getIndexFromDBFData('CNTRY_NAME', 'nonexisting'),
408
        );
409
        if (! ShapeFile::supportsDbase()) {
410
            return;
411
        }
412
413
        $this->assertEquals(
414
            218,
415
            $shp->getIndexFromDBFData('CNTRY_NAME', 'Czech Republic'),
416
        );
417
    }
418
}
419