Passed
Push — testing ( 57c125...199f7f )
by Hennik
03:23
created

MysqlTest::testInsertPolygon()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 5
c 1
b 0
f 0
dl 0
loc 8
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
use LaravelSpatial\SpatialServiceProvider;
4
use GeoJson\Geometry\GeometryCollection;
5
use GeoJson\Geometry\LineString;
6
use GeoJson\Geometry\MultiPoint;
7
use GeoJson\Geometry\MultiPolygon;
8
use GeoJson\Geometry\Point;
9
use GeoJson\Geometry\Polygon;
10
use Illuminate\Filesystem\Filesystem;
11
use Illuminate\Support\Facades\DB;
12
use Laravel\BrowserKitTesting\TestCase as BaseTestCase;
13
14
class MysqlTest extends BaseTestCase
15
{
16
    protected $is_postgres = false;
17
18
    protected $after_fix = false;
19
20
    /**
21
     * Boots the application.
22
     *
23
     * @return \Illuminate\Foundation\Application
24
     */
25
    public function createApplication()
26
    {
27
        $app = require __DIR__ . '/../../vendor/laravel/laravel/bootstrap/app.php';
28
        $app->register(SpatialServiceProvider::class);
29
30
        $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();
31
32
        $app['config']->set('database.default', 'mysql');
33
        $app['config']->set('database.connections.mysql.host', env('DB_HOST', '127.0.0.1'));
34
        $app['config']->set('database.connections.mysql.database', 'spatial_test');
35
        $app['config']->set('database.connections.mysql.username', 'root');
36
        $app['config']->set('database.connections.mysql.password', '');
37
        $app['config']->set('database.connections.mysql.modes', [
38
            'ONLY_FULL_GROUP_BY',
39
            'STRICT_TRANS_TABLES',
40
            'NO_ZERO_IN_DATE',
41
            'NO_ZERO_DATE',
42
            'ERROR_FOR_DIVISION_BY_ZERO',
43
            'NO_ENGINE_SUBSTITUTION',
44
        ]);
45
46
        return $app;
47
    }
48
49
    /**
50
     * Setup DB before each test.
51
     *
52
     * @return void
53
     */
54
    public function setUp()
55
    {
56
        parent::setUp();
57
58
        $this->after_fix = $this->isMySQL8AfterFix();
59
60
        $this->onMigrations(function($migrationClass) {
61
            (new $migrationClass())->up();
62
        });
63
64
        //\DB::listen(function($sql) {
65
        //    var_dump($sql);
66
        //});
67
    }
68
69
    public function tearDown()
70
    {
71
        $this->onMigrations(function($migrationClass) {
72
            (new $migrationClass())->down();
73
        }, true);
74
75
        parent::tearDown();
76
    }
77
78
    // MySQL 8.0.4 fixed bug #26941370 and bug #88031
79
    protected function isMySQL8AfterFix()
80
    {
81
        $results = DB::select(DB::raw('select version()'));
82
        $mysql_version = $results[0]->{'version()'};
83
84
        return version_compare($mysql_version, '8.0.4', '>=');
85
    }
86
87
    protected function assertDatabaseHas($table, array $data, $connection = null)
88
    {
89
        if (method_exists($this, 'seeInDatabase')) {
90
            $this->seeInDatabase($table, $data, $connection);
91
        } else {
92
            parent::assertDatabaseHas($table, $data, $connection);
93
        }
94
    }
95
96
    protected function assertException($exceptionName)
97
    {
98
        if (method_exists(parent::class, 'expectException')) {
99
            parent::expectException($exceptionName);
100
        } else {
101
            /** @scrutinizer ignore-deprecated */
102
            $this->setExpectedException($exceptionName);
103
        }
104
    }
105
106
    private function onMigrations(\Closure $closure, $reverse_sort = false)
107
    {
108
        $fileSystem = new Filesystem();
109
        $classFinder = new Tools\ClassFinder();
110
111
        $migrations = $fileSystem->files(__DIR__ . '/Migrations');
112
        $reverse_sort ? rsort($migrations, SORT_STRING) : sort($migrations, SORT_STRING);
113
114
        foreach ($migrations as $file) {
115
            $fileSystem->requireOnce($file);
116
            $migrationClass = $classFinder->findClass($file);
117
118
            $closure($migrationClass);
119
        }
120
    }
121
122
    public function testSpatialFieldsNotDefinedException()
123
    {
124
        $this->assertException(\LaravelSpatial\Exceptions\SpatialFieldsNotDefinedException::class);
125
126
        $geo = new NoSpatialFieldsModel();
127
        $geo->geometry = new Point([1, 2]);
128
        $geo->save();
129
130
        NoSpatialFieldsModel::all();
131
    }
132
133
    public function testInsertPoint()
134
    {
135
        $geo = new GeometryModel();
136
        $geo->location = new Point([1, 2]);
137
        $geo->save();
138
        $this->assertDatabaseHas($geo->getTable(), ['id' => $geo->id]);
139
    }
140
141
    public function testInsertLineString()
142
    {
143
        $geo = new GeometryModel();
144
145
        $geo->location = new Point([1, 2]);
146
        $geo->line = new LineString([new Point([1, 1]), new Point([2, 2])]);
147
        $geo->save();
148
        $this->assertDatabaseHas($geo->getTable(), ['id' => $geo->id]);
149
    }
150
151
    public function testInsertPolygon()
152
    {
153
        $geo = new GeometryModel();
154
155
        $geo->location = new Point([1, 2]);
156
        $geo->shape = new Polygon([[[0, 10], [10, 10], [10, 0], [0, 0], [0, 10]]]);
157
        $geo->save();
158
        $this->assertDatabaseHas($geo->getTable(), ['id' => $geo->id]);
159
    }
160
161
    public function testInsertMultiPoint()
162
    {
163
        $geo = new GeometryModel();
164
165
        $geo->location = new Point([1, 2]);
166
        $geo->multi_locations = new MultiPoint([new Point([1, 1]), new Point([2, 2])]);
167
        $geo->save();
168
        $this->assertDatabaseHas($geo->getTable(), ['id' => $geo->id]);
169
    }
170
171
    public function testInsertMultiPolygon()
172
    {
173
        $geo = new GeometryModel();
174
175
        $geo->location = new Point([1, 2]);
176
177
        $geo->multi_shapes = new MultiPolygon([
178
            new Polygon([[[0, 10], [10, 10], [10, 0], [0, 0], [0, 10]]]),
179
            new Polygon([[[0, 0], [0, 5], [5, 5], [5, 0], [0, 0]]]),
180
        ]);
181
        $geo->save();
182
        $this->assertDatabaseHas($geo->getTable(), ['id' => $geo->id]);
183
    }
184
185
    public function testInsertGeometryCollection()
186
    {
187
        $geo = new GeometryModel();
188
189
        $geo->location = new Point([1, 2]);
190
191
        $geo->multi_geometries = new GeometryCollection([
192
            new Polygon([[[0, 10], [10, 10], [10, 0], [0, 0], [0, 10]]]),
193
            new Polygon([[[0, 0], [0, 5], [5, 5], [5, 0], [0, 0]]]),
194
            new Point([0, 0]),
195
        ]);
196
        $geo->save();
197
        $this->assertDatabaseHas($geo->getTable(), ['id' => $geo->id]);
198
    }
199
200
    public function testUpdate()
201
    {
202
        $geo = new GeometryModel();
203
        $geo->location = new Point([1, 2]);
204
        $geo->save();
205
206
        $to_update = GeometryModel::all()->first();
207
        $to_update->location = new Point([2, 3]);
208
        $to_update->save();
209
210
        $this->assertDatabaseHas($geo->getTable(), ['id' => $to_update->id]);
211
212
        $all = GeometryModel::all();
213
        $this->assertCount(1, $all);
214
215
        $updated = $all->first();
216
        $this->assertInstanceOf(Point::class, $updated->location);
217
        $this->assertEquals(2, $updated->location->getCoordinates()[0]);
218
        $this->assertEquals(3, $updated->location->getCoordinates()[1]);
219
    }
220
221
    public function testDistance()
222
    {
223
        $loc1 = new GeometryModel();
224
        $loc1->location = new Point([1, 1]);
225
        $loc1->save();
226
227
        $loc2 = new GeometryModel();
228
        $loc2->location = new Point([2, 2]); // Distance from loc1: 1.4142135623731
229
        $loc2->save();
230
231
        $loc3 = new GeometryModel();
232
        $loc3->location = new Point([3, 3]); // Distance from loc1: 2.8284271247462
233
        $loc3->save();
234
235
        $a = GeometryModel::distance('location', $loc1->location, 2)->get();
236
        $this->assertCount(2, $a);
237
        $this->assertTrue($a->contains('location', $loc1->location));
238
        $this->assertTrue($a->contains('location', $loc2->location));
239
        $this->assertFalse($a->contains('location', $loc3->location));
240
241
        // Excluding self
242
        $b = GeometryModel::distanceExcludingSelf('location', $loc1->location, 2)->get();
243
        $this->assertCount(1, $b);
244
        $this->assertFalse($b->contains('location', $loc1->location));
245
        $this->assertTrue($b->contains('location', $loc2->location));
246
        $this->assertFalse($b->contains('location', $loc3->location));
247
248
        $c = GeometryModel::distance('location', $loc1->location, 1)->get();
249
        $this->assertCount(1, $c);
250
        $this->assertTrue($c->contains('location', $loc1->location));
251
        $this->assertFalse($c->contains('location', $loc2->location));
252
        $this->assertFalse($c->contains('location', $loc3->location));
253
    }
254
255
    public function testDistanceSphere()
256
    {
257
        try {
258
            $loc1 = new GeometryModel();
259
            $loc1->location = new Point([-73.971732, 40.767864]);
260
            $loc1->save();
261
262
            $loc2 = new GeometryModel();
263
            $loc2->location = new Point([-73.971271, 40.767664]); // Distance from loc1: 44.741406484588
264
            $loc2->save();
265
266
            $loc3 = new GeometryModel();
267
            $loc3->location = new Point([-73.977619, 40.761434]); // Distance from loc1: 870.06424066202
268
            $loc3->save();
269
270
            $a = GeometryModel::distanceSphere('location', $loc1->location, 200)->get();
271
            $this->assertCount(2, $a);
272
            $this->assertTrue($a->contains('location', $loc1->location));
273
            $this->assertTrue($a->contains('location', $loc2->location));
274
            $this->assertFalse($a->contains('location', $loc3->location));
275
276
            // Excluding self
277
            $b = GeometryModel::distanceSphereExcludingSelf('location', $loc1->location, 200)->get();
278
            $this->assertCount(1, $b);
279
            $this->assertFalse($b->contains('location', $loc1->location));
280
            $this->assertTrue($b->contains('location', $loc2->location));
281
            $this->assertFalse($b->contains('location', $loc3->location));
282
283
            if ($this->is_postgres || $this->after_fix) {
284
                $c = GeometryModel::distanceSphere('location', $loc1->location, 44.741406484236)->get();
285
            } else {
286
                $c = GeometryModel::distanceSphere('location', $loc1->location, 44.741406484587)->get();
287
            }
288
            $this->assertCount(1, $c);
289
            $this->assertTrue($c->contains('location', $loc1->location));
290
            $this->assertFalse($c->contains('location', $loc2->location));
291
            $this->assertFalse($c->contains('location', $loc3->location));
292
        } catch (\Illuminate\Database\QueryException $e) {
293
            if (strpos($e->getMessage(), 'FUNCTION spatial_test.ST_Distance_Sphere does not exist') > -1) {
294
                $this->markTestSkipped('Spherical distance tests [distanceSphere*()] not supported on the current DBMS');
295
            }
296
            throw $e;
297
        }
298
    }
299
300
    public function testDistanceValue()
301
    {
302
        $loc1 = new GeometryModel();
303
        $loc1->location = new Point([1, 1]);
304
        $loc1->save();
305
306
        $loc2 = new GeometryModel();
307
        $loc2->location = new Point([2, 2]); // Distance from loc1: 1.4142135623731
308
        $loc2->save();
309
310
        $a = GeometryModel::distanceValue('location', $loc1->location)->get();
311
        $this->assertCount(2, $a);
312
        $this->assertEquals(0, $a[0]->distance);
313
        $this->assertEquals(1.4142135623, $a[1]->distance); // PHP floats' 11th+ digits don't matter
314
    }
315
316
    public function testDistanceSphereValue()
317
    {
318
        try {
319
            $loc1 = new GeometryModel();
320
            $loc1->location = new Point([-73.971732, 40.767864]);
321
            $loc1->save();
322
323
            $loc2 = new GeometryModel();
324
            $loc2->location = new Point([-73.971271, 40.767664]); // Distance from loc1: 44.741406484236
325
            $loc2->save();
326
327
            $a = GeometryModel::distanceSphereValue('location', $loc1->location)->get();
328
            $this->assertCount(2, $a);
329
            $this->assertEquals(0, $a[0]->distance);
330
331
            if ($this->is_postgres) {
332
                $this->assertEquals("44.7415664", number_format($a[1]->distance, 7)); // Postgres calculates this differently?
333
            } elseif ($this->after_fix) {
334
                $this->assertEquals(44.7414064842, $a[1]->distance); // PHP floats' 11th+ digits don't matter
335
            } else {
336
                $this->assertEquals(44.7414064845, $a[1]->distance); // PHP floats' 11th+ digits don't matter
337
            }
338
        } catch (\Illuminate\Database\QueryException $e) {
339
            if (strpos($e->getMessage(), 'FUNCTION spatial_test.ST_Distance_Sphere does not exist') > -1) {
340
                $this->markTestSkipped('Spherical distance tests [distanceSphere*()] not supported on the current DBMS');
341
            }
342
            throw $e;
343
        }
344
    }
345
346
    //public function testBounding() {
347
    //    $point = new Point([0, 0]);
348
    //
349
    //    $linestring1 = \GeoJson\Geometry\LineString::fromWkt("LINESTRING(1 1, 2 2)");
350
    //    $linestring2 = \GeoJson\Geometry\LineString::fromWkt("LINESTRING(20 20, 24 24)");
351
    //    $linestring3 = \GeoJson\Geometry\LineString::fromWkt("LINESTRING(0 10, 10 10)");
352
    //
353
    //    $geo1 = new GeometryModel();
354
    //    $geo1->location = $point;
355
    //    $geo1->line = $linestring1;
356
    //    $geo1->save();
357
    //
358
    //    $geo2 = new GeometryModel();
359
    //    $geo2->location = $point;
360
    //    $geo2->line = $linestring2;
361
    //    $geo2->save();
362
    //
363
    //    $geo3 = new GeometryModel();
364
    //    $geo3->location = $point;
365
    //    $geo3->line = $linestring3;
366
    //    $geo3->save();
367
    //
368
    //    $polygon = new Polygon([[[0, 10],[10, 10],[10, 0],[0, 0],[0, 10]]]);
369
    //
370
    //    $result = GeometryModel::Bounding($polygon, 'line')->get();
371
    //    $this->assertCount(2, $result);
372
    //    $this->assertTrue($result->contains($geo1));
373
    //    $this->assertFalse($result->contains($geo2));
374
    //    $this->assertTrue($result->contains($geo3));
375
    //
376
    //}
377
}
378