You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@baremaps.apache.org by bc...@apache.org on 2023/12/20 12:56:40 UTC

(incubator-baremaps) branch osm-test created (now bf66facb)

This is an automated email from the ASF dual-hosted git repository.

bchapuis pushed a change to branch osm-test
in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git


      at bf66facb Test the readers with osm-test data

This branch includes the following new commits:

     new bf66facb Test the readers with osm-test data

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(incubator-baremaps) 01/01: Test the readers with osm-test data

Posted by bc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

bchapuis pushed a commit to branch osm-test
in repository https://gitbox.apache.org/repos/asf/incubator-baremaps.git

commit bf66facbe9644fa8c8e2319f3b3ff2155fe824e8
Author: Bertil Chapuis <bc...@gmail.com>
AuthorDate: Wed Dec 20 13:56:22 2023 +0100

    Test the readers with osm-test data
---
 .../function/CleanDuplicatePoints.java             |   103 +
 .../function/EntityGeometryBuilder.java            |     4 +-
 .../function/NodeGeometryBuilder.java              |     5 +-
 .../function/RelationGeometryBuilder.java          |    22 +-
 .../openstreetmap/function/WayGeometryBuilder.java |    14 +-
 .../openstreetmap/xml/XmlEntityReader.java         |    70 +-
 .../baremaps/openstreetmap/OsmTestRunner.java      |   224 +
 .../baremaps/openstreetmap/store/MockDataMap.java  |     5 +
 .../osm-testdata/.github/workflows/ci.yml          |    19 +
 .../src/test/resources/osm-testdata/.gitignore     |     1 +
 .../src/test/resources/osm-testdata/README.md      |    34 +
 .../resources/osm-testdata/bin/compare-areas.rb    |   256 +
 .../test/resources/osm-testdata/bin/compare-wkt.sh |    86 +
 .../resources/osm-testdata/bin/concat-test-json.rb |    31 +
 .../test/resources/osm-testdata/grid/.gitignore    |     7 +
 .../src/test/resources/osm-testdata/grid/Makefile  |    53 +
 .../src/test/resources/osm-testdata/grid/README.md |   154 +
 .../resources/osm-testdata/grid/bin/concat.xsl     |    26 +
 .../resources/osm-testdata/grid/bin/create-grid.sh |    40 +
 .../grid/bin/create-sql-for-multipolygons.rb       |    26 +
 .../resources/osm-testdata/grid/bin/create-wkt.sh  |    28 +
 .../osm-testdata/grid/bin/osm2nodes_wkt.xsl        |    20 +
 .../osm-testdata/grid/bin/osm2ways_wkt.xsl         |    31 +
 .../resources/osm-testdata/grid/bin/show-tests.sh  |    20 +
 .../osm-testdata/grid/data/1/100/data.osm          |     4 +
 .../osm-testdata/grid/data/1/100/data.osm.pbf      |   Bin 0 -> 152 bytes
 .../osm-testdata/grid/data/1/100/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/1/100/result  |     1 +
 .../osm-testdata/grid/data/1/100/test.json         |     4 +
 .../osm-testdata/grid/data/1/101/data.osm          |     7 +
 .../osm-testdata/grid/data/1/101/data.osm.pbf      |   Bin 0 -> 180 bytes
 .../osm-testdata/grid/data/1/101/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/1/101/result  |     1 +
 .../osm-testdata/grid/data/1/101/test.json         |     4 +
 .../osm-testdata/grid/data/1/102/data.osm          |     5 +
 .../osm-testdata/grid/data/1/102/data.osm.pbf      |   Bin 0 -> 162 bytes
 .../osm-testdata/grid/data/1/102/nodes.wkt         |     2 +
 .../resources/osm-testdata/grid/data/1/102/result  |     1 +
 .../osm-testdata/grid/data/1/102/test.json         |     4 +
 .../osm-testdata/grid/data/1/110/data.osm          |    11 +
 .../osm-testdata/grid/data/1/110/data.osm.pbf      |   Bin 0 -> 276 bytes
 .../osm-testdata/grid/data/1/110/nodes.wkt         |     2 +
 .../resources/osm-testdata/grid/data/1/110/result  |     1 +
 .../osm-testdata/grid/data/1/110/test.json         |     4 +
 .../osm-testdata/grid/data/1/110/ways.wkt          |     1 +
 .../osm-testdata/grid/data/1/111/data.osm          |    15 +
 .../osm-testdata/grid/data/1/111/data.osm.pbf      |   Bin 0 -> 293 bytes
 .../osm-testdata/grid/data/1/111/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/1/111/result  |     1 +
 .../osm-testdata/grid/data/1/111/test.json         |     4 +
 .../osm-testdata/grid/data/1/111/ways.wkt          |     1 +
 .../osm-testdata/grid/data/1/112/data.osm          |    16 +
 .../osm-testdata/grid/data/1/112/data.osm.pbf      |   Bin 0 -> 289 bytes
 .../osm-testdata/grid/data/1/112/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/1/112/result  |     1 +
 .../osm-testdata/grid/data/1/112/test.json         |     4 +
 .../osm-testdata/grid/data/1/112/ways.wkt          |     1 +
 .../osm-testdata/grid/data/1/113/data.osm          |    19 +
 .../osm-testdata/grid/data/1/113/data.osm.pbf      |   Bin 0 -> 302 bytes
 .../osm-testdata/grid/data/1/113/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/1/113/result  |     1 +
 .../osm-testdata/grid/data/1/113/test.json         |     4 +
 .../osm-testdata/grid/data/1/113/ways.wkt          |     2 +
 .../osm-testdata/grid/data/1/114/data.osm          |    18 +
 .../osm-testdata/grid/data/1/114/data.osm.pbf      |   Bin 0 -> 296 bytes
 .../osm-testdata/grid/data/1/114/nodes.wkt         |     3 +
 .../resources/osm-testdata/grid/data/1/114/result  |     1 +
 .../osm-testdata/grid/data/1/114/test.json         |     4 +
 .../osm-testdata/grid/data/1/114/ways.wkt          |     2 +
 .../osm-testdata/grid/data/1/115/data.osm          |    18 +
 .../osm-testdata/grid/data/1/115/data.osm.pbf      |   Bin 0 -> 297 bytes
 .../osm-testdata/grid/data/1/115/nodes.wkt         |     3 +
 .../resources/osm-testdata/grid/data/1/115/result  |     1 +
 .../osm-testdata/grid/data/1/115/test.json         |     4 +
 .../osm-testdata/grid/data/1/115/ways.wkt          |     2 +
 .../osm-testdata/grid/data/1/116/data.osm          |    28 +
 .../osm-testdata/grid/data/1/116/data.osm.pbf      |   Bin 0 -> 317 bytes
 .../osm-testdata/grid/data/1/116/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/1/116/result  |     1 +
 .../osm-testdata/grid/data/1/116/test.json         |     4 +
 .../osm-testdata/grid/data/1/116/ways.wkt          |     3 +
 .../osm-testdata/grid/data/1/120/data.osm          |     7 +
 .../osm-testdata/grid/data/1/120/data.osm.pbf      |   Bin 0 -> 177 bytes
 .../resources/osm-testdata/grid/data/1/120/result  |     1 +
 .../osm-testdata/grid/data/1/120/test.json         |     4 +
 .../osm-testdata/grid/data/1/121/data.osm          |     9 +
 .../osm-testdata/grid/data/1/121/data.osm.pbf      |   Bin 0 -> 265 bytes
 .../osm-testdata/grid/data/1/121/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/1/121/result  |     1 +
 .../osm-testdata/grid/data/1/121/test.json         |     4 +
 .../osm-testdata/grid/data/1/121/ways.wkt          |     1 +
 .../osm-testdata/grid/data/1/122/data.osm          |    10 +
 .../osm-testdata/grid/data/1/122/data.osm.pbf      |   Bin 0 -> 262 bytes
 .../osm-testdata/grid/data/1/122/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/1/122/result  |     1 +
 .../osm-testdata/grid/data/1/122/test.json         |     4 +
 .../osm-testdata/grid/data/1/122/ways.wkt          |     1 +
 .../osm-testdata/grid/data/1/123/data.osm          |    11 +
 .../osm-testdata/grid/data/1/123/data.osm.pbf      |   Bin 0 -> 272 bytes
 .../osm-testdata/grid/data/1/123/nodes.wkt         |     2 +
 .../resources/osm-testdata/grid/data/1/123/result  |     1 +
 .../osm-testdata/grid/data/1/123/test.json         |     4 +
 .../osm-testdata/grid/data/1/123/ways.wkt          |     1 +
 .../osm-testdata/grid/data/1/124/data.osm          |    13 +
 .../osm-testdata/grid/data/1/124/data.osm.pbf      |   Bin 0 -> 282 bytes
 .../osm-testdata/grid/data/1/124/nodes.wkt         |     3 +
 .../resources/osm-testdata/grid/data/1/124/result  |     1 +
 .../osm-testdata/grid/data/1/124/test.json         |     4 +
 .../osm-testdata/grid/data/1/124/ways.wkt          |     1 +
 .../osm-testdata/grid/data/1/130/data.osm          |    19 +
 .../osm-testdata/grid/data/1/130/data.osm.pbf      |   Bin 0 -> 298 bytes
 .../osm-testdata/grid/data/1/130/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/1/130/result  |     1 +
 .../osm-testdata/grid/data/1/130/test.json         |     4 +
 .../osm-testdata/grid/data/1/130/ways.wkt          |     2 +
 .../osm-testdata/grid/data/1/131/data.osm          |    22 +
 .../osm-testdata/grid/data/1/131/data.osm.pbf      |   Bin 0 -> 306 bytes
 .../osm-testdata/grid/data/1/131/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/1/131/result  |     1 +
 .../osm-testdata/grid/data/1/131/test.json         |     4 +
 .../osm-testdata/grid/data/1/131/ways.wkt          |     2 +
 .../osm-testdata/grid/data/1/132/data.osm          |    23 +
 .../osm-testdata/grid/data/1/132/data.osm.pbf      |   Bin 0 -> 306 bytes
 .../osm-testdata/grid/data/1/132/nodes.wkt         |     6 +
 .../resources/osm-testdata/grid/data/1/132/result  |     1 +
 .../osm-testdata/grid/data/1/132/test.json         |     4 +
 .../osm-testdata/grid/data/1/132/ways.wkt          |     2 +
 .../osm-testdata/grid/data/1/133/data.osm          |    15 +
 .../osm-testdata/grid/data/1/133/data.osm.pbf      |   Bin 0 -> 286 bytes
 .../osm-testdata/grid/data/1/133/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/1/133/result  |     1 +
 .../osm-testdata/grid/data/1/133/test.json         |     4 +
 .../osm-testdata/grid/data/1/133/ways.wkt          |     1 +
 .../osm-testdata/grid/data/1/134/data.osm          |    18 +
 .../osm-testdata/grid/data/1/134/data.osm.pbf      |   Bin 0 -> 298 bytes
 .../osm-testdata/grid/data/1/134/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/1/134/result  |     1 +
 .../osm-testdata/grid/data/1/134/test.json         |     4 +
 .../osm-testdata/grid/data/1/134/ways.wkt          |     1 +
 .../osm-testdata/grid/data/1/description.txt       |     1 +
 .../osm-testdata/grid/data/3/300/data.osm          |     4 +
 .../osm-testdata/grid/data/3/300/data.osm.pbf      |   Bin 0 -> 156 bytes
 .../osm-testdata/grid/data/3/300/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/3/300/result  |     1 +
 .../osm-testdata/grid/data/3/300/test.json         |     4 +
 .../osm-testdata/grid/data/3/301/data.osm          |     4 +
 .../osm-testdata/grid/data/3/301/data.osm.pbf      |   Bin 0 -> 152 bytes
 .../osm-testdata/grid/data/3/301/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/3/301/result  |     1 +
 .../osm-testdata/grid/data/3/301/test.json         |     4 +
 .../osm-testdata/grid/data/3/302/data.osm          |     4 +
 .../osm-testdata/grid/data/3/302/data.osm.pbf      |   Bin 0 -> 152 bytes
 .../osm-testdata/grid/data/3/302/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/3/302/result  |     1 +
 .../osm-testdata/grid/data/3/302/test.json         |     4 +
 .../osm-testdata/grid/data/3/303/data.osm          |     4 +
 .../osm-testdata/grid/data/3/303/data.osm.pbf      |   Bin 0 -> 152 bytes
 .../osm-testdata/grid/data/3/303/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/3/303/result  |     1 +
 .../osm-testdata/grid/data/3/303/test.json         |     4 +
 .../osm-testdata/grid/data/3/304/data.osm          |     4 +
 .../osm-testdata/grid/data/3/304/data.osm.pbf      |   Bin 0 -> 152 bytes
 .../osm-testdata/grid/data/3/304/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/3/304/result  |     1 +
 .../osm-testdata/grid/data/3/304/test.json         |     4 +
 .../osm-testdata/grid/data/3/305/data.osm          |     4 +
 .../osm-testdata/grid/data/3/305/data.osm.pbf      |   Bin 0 -> 155 bytes
 .../osm-testdata/grid/data/3/305/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/3/305/result  |     1 +
 .../osm-testdata/grid/data/3/305/test.json         |     4 +
 .../osm-testdata/grid/data/3/306/data.osm          |     4 +
 .../osm-testdata/grid/data/3/306/data.osm.pbf      |   Bin 0 -> 167 bytes
 .../osm-testdata/grid/data/3/306/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/3/306/result  |     1 +
 .../osm-testdata/grid/data/3/306/test.json         |     4 +
 .../osm-testdata/grid/data/3/307/data.osm          |     4 +
 .../osm-testdata/grid/data/3/307/data.osm.pbf      |   Bin 0 -> 167 bytes
 .../osm-testdata/grid/data/3/307/nodes.wkt         |     1 +
 .../resources/osm-testdata/grid/data/3/307/result  |     1 +
 .../osm-testdata/grid/data/3/307/test.json         |     4 +
 .../osm-testdata/grid/data/3/description.txt       |     1 +
 .../osm-testdata/grid/data/7/700/data.osm          |    17 +
 .../osm-testdata/grid/data/7/700/data.osm.pbf      |   Bin 0 -> 300 bytes
 .../osm-testdata/grid/data/7/700/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/700/result  |     1 +
 .../osm-testdata/grid/data/7/700/test.json         |    18 +
 .../osm-testdata/grid/data/7/700/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/701/data.osm          |    29 +
 .../osm-testdata/grid/data/7/701/data.osm.pbf      |   Bin 0 -> 456 bytes
 .../osm-testdata/grid/data/7/701/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/701/result  |     1 +
 .../osm-testdata/grid/data/7/701/test.json         |    18 +
 .../osm-testdata/grid/data/7/701/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/702/data.osm          |    37 +
 .../osm-testdata/grid/data/7/702/data.osm.pbf      |   Bin 0 -> 474 bytes
 .../osm-testdata/grid/data/7/702/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/702/result  |     1 +
 .../osm-testdata/grid/data/7/702/test.json         |    18 +
 .../osm-testdata/grid/data/7/702/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/703/data.osm          |    37 +
 .../osm-testdata/grid/data/7/703/data.osm.pbf      |   Bin 0 -> 473 bytes
 .../osm-testdata/grid/data/7/703/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/703/result  |     1 +
 .../osm-testdata/grid/data/7/703/test.json         |    18 +
 .../osm-testdata/grid/data/7/703/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/704/data.osm          |    51 +
 .../osm-testdata/grid/data/7/704/data.osm.pbf      |   Bin 0 -> 479 bytes
 .../osm-testdata/grid/data/7/704/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/704/result  |     1 +
 .../osm-testdata/grid/data/7/704/test.json         |    18 +
 .../osm-testdata/grid/data/7/704/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/705/data.osm          |    53 +
 .../osm-testdata/grid/data/7/705/data.osm.pbf      |   Bin 0 -> 508 bytes
 .../osm-testdata/grid/data/7/705/nodes.wkt         |    13 +
 .../resources/osm-testdata/grid/data/7/705/result  |     1 +
 .../osm-testdata/grid/data/7/705/test.json         |    18 +
 .../osm-testdata/grid/data/7/705/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/706/data.osm          |    44 +
 .../osm-testdata/grid/data/7/706/data.osm.pbf      |   Bin 0 -> 493 bytes
 .../osm-testdata/grid/data/7/706/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/706/result  |     1 +
 .../osm-testdata/grid/data/7/706/test.json         |    18 +
 .../osm-testdata/grid/data/7/706/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/707/data.osm          |    43 +
 .../osm-testdata/grid/data/7/707/data.osm.pbf      |   Bin 0 -> 492 bytes
 .../osm-testdata/grid/data/7/707/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/707/result  |     1 +
 .../osm-testdata/grid/data/7/707/test.json         |    18 +
 .../osm-testdata/grid/data/7/707/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/708/data.osm          |    59 +
 .../osm-testdata/grid/data/7/708/data.osm.pbf      |   Bin 0 -> 508 bytes
 .../osm-testdata/grid/data/7/708/nodes.wkt         |    16 +
 .../resources/osm-testdata/grid/data/7/708/result  |     1 +
 .../osm-testdata/grid/data/7/708/test.json         |    18 +
 .../osm-testdata/grid/data/7/708/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/709/data.osm          |    54 +
 .../osm-testdata/grid/data/7/709/data.osm.pbf      |   Bin 0 -> 517 bytes
 .../osm-testdata/grid/data/7/709/nodes.wkt         |     9 +
 .../resources/osm-testdata/grid/data/7/709/result  |     1 +
 .../osm-testdata/grid/data/7/709/test.json         |    18 +
 .../osm-testdata/grid/data/7/709/ways.wkt          |     4 +
 .../osm-testdata/grid/data/7/710/data.osm          |    43 +
 .../osm-testdata/grid/data/7/710/data.osm.pbf      |   Bin 0 -> 494 bytes
 .../osm-testdata/grid/data/7/710/labels.wkt        |     1 +
 .../osm-testdata/grid/data/7/710/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/710/result  |     1 +
 .../osm-testdata/grid/data/7/710/test.json         |    13 +
 .../osm-testdata/grid/data/7/710/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/711/data.osm          |    30 +
 .../osm-testdata/grid/data/7/711/data.osm.pbf      |   Bin 0 -> 458 bytes
 .../osm-testdata/grid/data/7/711/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/711/result  |     1 +
 .../osm-testdata/grid/data/7/711/test.json         |    25 +
 .../osm-testdata/grid/data/7/711/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/714/data.osm          |    24 +
 .../osm-testdata/grid/data/7/714/data.osm.pbf      |   Bin 0 -> 446 bytes
 .../osm-testdata/grid/data/7/714/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/7/714/result  |     1 +
 .../osm-testdata/grid/data/7/714/test.json         |    25 +
 .../osm-testdata/grid/data/7/714/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/715/data.osm          |    31 +
 .../osm-testdata/grid/data/7/715/data.osm.pbf      |   Bin 0 -> 464 bytes
 .../osm-testdata/grid/data/7/715/nodes.wkt         |     6 +
 .../resources/osm-testdata/grid/data/7/715/result  |     1 +
 .../osm-testdata/grid/data/7/715/test.json         |    25 +
 .../osm-testdata/grid/data/7/715/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/720/data.osm          |    37 +
 .../osm-testdata/grid/data/7/720/data.osm.pbf      |   Bin 0 -> 479 bytes
 .../osm-testdata/grid/data/7/720/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/720/result  |     1 +
 .../osm-testdata/grid/data/7/720/test.json         |    18 +
 .../osm-testdata/grid/data/7/720/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/721/data.osm          |    36 +
 .../osm-testdata/grid/data/7/721/data.osm.pbf      |   Bin 0 -> 479 bytes
 .../osm-testdata/grid/data/7/721/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/721/result  |     1 +
 .../osm-testdata/grid/data/7/721/test.json         |    18 +
 .../osm-testdata/grid/data/7/721/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/722/data.osm          |    37 +
 .../osm-testdata/grid/data/7/722/data.osm.pbf      |   Bin 0 -> 485 bytes
 .../osm-testdata/grid/data/7/722/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/722/result  |     1 +
 .../osm-testdata/grid/data/7/722/test.json         |    18 +
 .../osm-testdata/grid/data/7/722/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/723/data.osm          |    37 +
 .../osm-testdata/grid/data/7/723/data.osm.pbf      |   Bin 0 -> 485 bytes
 .../osm-testdata/grid/data/7/723/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/723/result  |     1 +
 .../osm-testdata/grid/data/7/723/test.json         |    18 +
 .../osm-testdata/grid/data/7/723/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/724/data.osm          |    44 +
 .../osm-testdata/grid/data/7/724/data.osm.pbf      |   Bin 0 -> 512 bytes
 .../osm-testdata/grid/data/7/724/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/724/result  |     1 +
 .../osm-testdata/grid/data/7/724/test.json         |    18 +
 .../osm-testdata/grid/data/7/724/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/725/data.osm          |    33 +
 .../osm-testdata/grid/data/7/725/data.osm.pbf      |   Bin 0 -> 465 bytes
 .../osm-testdata/grid/data/7/725/nodes.wkt         |     6 +
 .../resources/osm-testdata/grid/data/7/725/result  |     1 +
 .../osm-testdata/grid/data/7/725/test.json         |    18 +
 .../osm-testdata/grid/data/7/725/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/726/data.osm          |    45 +
 .../osm-testdata/grid/data/7/726/data.osm.pbf      |   Bin 0 -> 493 bytes
 .../osm-testdata/grid/data/7/726/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/726/result  |     1 +
 .../osm-testdata/grid/data/7/726/test.json         |    18 +
 .../osm-testdata/grid/data/7/726/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/727/data.osm          |    45 +
 .../osm-testdata/grid/data/7/727/data.osm.pbf      |   Bin 0 -> 498 bytes
 .../osm-testdata/grid/data/7/727/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/727/result  |     1 +
 .../osm-testdata/grid/data/7/727/test.json         |    18 +
 .../osm-testdata/grid/data/7/727/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/728/data.osm          |    33 +
 .../osm-testdata/grid/data/7/728/data.osm.pbf      |   Bin 0 -> 472 bytes
 .../osm-testdata/grid/data/7/728/nodes.wkt         |     9 +
 .../resources/osm-testdata/grid/data/7/728/result  |     1 +
 .../osm-testdata/grid/data/7/728/test.json         |    18 +
 .../osm-testdata/grid/data/7/728/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/729/data.osm          |    51 +
 .../osm-testdata/grid/data/7/729/data.osm.pbf      |   Bin 0 -> 510 bytes
 .../osm-testdata/grid/data/7/729/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/729/result  |     1 +
 .../osm-testdata/grid/data/7/729/test.json         |    18 +
 .../osm-testdata/grid/data/7/729/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/730/data.osm          |    71 +
 .../osm-testdata/grid/data/7/730/data.osm.pbf      |   Bin 0 -> 535 bytes
 .../osm-testdata/grid/data/7/730/nodes.wkt         |    17 +
 .../resources/osm-testdata/grid/data/7/730/result  |     1 +
 .../osm-testdata/grid/data/7/730/test.json         |    18 +
 .../osm-testdata/grid/data/7/730/ways.wkt          |     4 +
 .../osm-testdata/grid/data/7/731/data.osm          |    96 +
 .../osm-testdata/grid/data/7/731/data.osm.pbf      |   Bin 0 -> 581 bytes
 .../osm-testdata/grid/data/7/731/nodes.wkt         |    22 +
 .../resources/osm-testdata/grid/data/7/731/result  |     1 +
 .../osm-testdata/grid/data/7/731/test.json         |    18 +
 .../osm-testdata/grid/data/7/731/ways.wkt          |     6 +
 .../osm-testdata/grid/data/7/732/data.osm          |    56 +
 .../osm-testdata/grid/data/7/732/data.osm.pbf      |   Bin 0 -> 512 bytes
 .../osm-testdata/grid/data/7/732/labels.wkt        |     1 +
 .../osm-testdata/grid/data/7/732/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/732/result  |     1 +
 .../osm-testdata/grid/data/7/732/test.json         |    18 +
 .../osm-testdata/grid/data/7/732/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/733/data.osm          |    37 +
 .../osm-testdata/grid/data/7/733/data.osm.pbf      |   Bin 0 -> 469 bytes
 .../osm-testdata/grid/data/7/733/nodes.wkt         |     6 +
 .../resources/osm-testdata/grid/data/7/733/result  |     1 +
 .../osm-testdata/grid/data/7/733/test.json         |    18 +
 .../osm-testdata/grid/data/7/733/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/734/data.osm          |    53 +
 .../osm-testdata/grid/data/7/734/data.osm.pbf      |   Bin 0 -> 493 bytes
 .../osm-testdata/grid/data/7/734/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/734/result  |     1 +
 .../osm-testdata/grid/data/7/734/test.json         |    18 +
 .../osm-testdata/grid/data/7/734/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/740/data.osm          |    29 +
 .../osm-testdata/grid/data/7/740/data.osm.pbf      |   Bin 0 -> 457 bytes
 .../osm-testdata/grid/data/7/740/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/740/result  |     1 +
 .../osm-testdata/grid/data/7/740/test.json         |    13 +
 .../osm-testdata/grid/data/7/740/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/741/data.osm          |    25 +
 .../osm-testdata/grid/data/7/741/data.osm.pbf      |   Bin 0 -> 442 bytes
 .../osm-testdata/grid/data/7/741/nodes.wkt         |     2 +
 .../resources/osm-testdata/grid/data/7/741/result  |     1 +
 .../osm-testdata/grid/data/7/741/test.json         |    13 +
 .../osm-testdata/grid/data/7/741/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/742/data.osm          |    32 +
 .../osm-testdata/grid/data/7/742/data.osm.pbf      |   Bin 0 -> 463 bytes
 .../osm-testdata/grid/data/7/742/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/7/742/result  |     1 +
 .../osm-testdata/grid/data/7/742/test.json         |    25 +
 .../osm-testdata/grid/data/7/742/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/743/data.osm          |    31 +
 .../osm-testdata/grid/data/7/743/data.osm.pbf      |   Bin 0 -> 462 bytes
 .../osm-testdata/grid/data/7/743/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/7/743/result  |     1 +
 .../osm-testdata/grid/data/7/743/test.json         |    25 +
 .../osm-testdata/grid/data/7/743/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/744/data.osm          |    28 +
 .../osm-testdata/grid/data/7/744/data.osm.pbf      |   Bin 0 -> 455 bytes
 .../osm-testdata/grid/data/7/744/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/744/result  |     1 +
 .../osm-testdata/grid/data/7/744/test.json         |    13 +
 .../osm-testdata/grid/data/7/744/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/745/data.osm          |    36 +
 .../osm-testdata/grid/data/7/745/data.osm.pbf      |   Bin 0 -> 469 bytes
 .../osm-testdata/grid/data/7/745/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/745/result  |     1 +
 .../osm-testdata/grid/data/7/745/test.json         |    13 +
 .../osm-testdata/grid/data/7/745/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/746/data.osm          |    42 +
 .../osm-testdata/grid/data/7/746/data.osm.pbf      |   Bin 0 -> 483 bytes
 .../osm-testdata/grid/data/7/746/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/746/result  |     1 +
 .../osm-testdata/grid/data/7/746/test.json         |    13 +
 .../osm-testdata/grid/data/7/746/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/747/data.osm          |    25 +
 .../osm-testdata/grid/data/7/747/data.osm.pbf      |   Bin 0 -> 444 bytes
 .../osm-testdata/grid/data/7/747/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/7/747/result  |     1 +
 .../osm-testdata/grid/data/7/747/test.json         |    25 +
 .../osm-testdata/grid/data/7/747/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/748/data.osm          |    19 +
 .../osm-testdata/grid/data/7/748/data.osm.pbf      |   Bin 0 -> 304 bytes
 .../osm-testdata/grid/data/7/748/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/7/748/result  |     1 +
 .../osm-testdata/grid/data/7/748/test.json         |    25 +
 .../osm-testdata/grid/data/7/748/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/749/data.osm          |    24 +
 .../osm-testdata/grid/data/7/749/data.osm.pbf      |   Bin 0 -> 330 bytes
 .../osm-testdata/grid/data/7/749/nodes.wkt         |     7 +
 .../resources/osm-testdata/grid/data/7/749/result  |     1 +
 .../osm-testdata/grid/data/7/749/test.json         |    18 +
 .../osm-testdata/grid/data/7/749/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/750/data.osm          |    57 +
 .../osm-testdata/grid/data/7/750/data.osm.pbf      |   Bin 0 -> 520 bytes
 .../osm-testdata/grid/data/7/750/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/750/result  |     1 +
 .../osm-testdata/grid/data/7/750/test.json         |    18 +
 .../osm-testdata/grid/data/7/750/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/751/data.osm          |    52 +
 .../osm-testdata/grid/data/7/751/data.osm.pbf      |   Bin 0 -> 512 bytes
 .../osm-testdata/grid/data/7/751/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/751/result  |     1 +
 .../osm-testdata/grid/data/7/751/test.json         |    18 +
 .../osm-testdata/grid/data/7/751/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/752/data.osm          |    54 +
 .../osm-testdata/grid/data/7/752/data.osm.pbf      |   Bin 0 -> 506 bytes
 .../osm-testdata/grid/data/7/752/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/752/result  |     1 +
 .../osm-testdata/grid/data/7/752/test.json         |    25 +
 .../osm-testdata/grid/data/7/752/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/753/data.osm          |    55 +
 .../osm-testdata/grid/data/7/753/data.osm.pbf      |   Bin 0 -> 512 bytes
 .../osm-testdata/grid/data/7/753/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/753/result  |     1 +
 .../osm-testdata/grid/data/7/753/test.json         |    25 +
 .../osm-testdata/grid/data/7/753/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/754/data.osm          |    39 +
 .../osm-testdata/grid/data/7/754/data.osm.pbf      |   Bin 0 -> 479 bytes
 .../osm-testdata/grid/data/7/754/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/754/result  |     1 +
 .../osm-testdata/grid/data/7/754/test.json         |    25 +
 .../osm-testdata/grid/data/7/754/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/755/data.osm          |    40 +
 .../osm-testdata/grid/data/7/755/data.osm.pbf      |   Bin 0 -> 485 bytes
 .../osm-testdata/grid/data/7/755/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/755/result  |     1 +
 .../osm-testdata/grid/data/7/755/test.json         |    18 +
 .../osm-testdata/grid/data/7/755/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/756/data.osm          |    39 +
 .../osm-testdata/grid/data/7/756/data.osm.pbf      |   Bin 0 -> 475 bytes
 .../osm-testdata/grid/data/7/756/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/756/result  |     1 +
 .../osm-testdata/grid/data/7/756/test.json         |    25 +
 .../osm-testdata/grid/data/7/756/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/757/data.osm          |    41 +
 .../osm-testdata/grid/data/7/757/data.osm.pbf      |   Bin 0 -> 481 bytes
 .../osm-testdata/grid/data/7/757/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/757/result  |     1 +
 .../osm-testdata/grid/data/7/757/test.json         |    25 +
 .../osm-testdata/grid/data/7/757/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/758/data.osm          |    40 +
 .../osm-testdata/grid/data/7/758/data.osm.pbf      |   Bin 0 -> 488 bytes
 .../osm-testdata/grid/data/7/758/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/758/result  |     1 +
 .../osm-testdata/grid/data/7/758/test.json         |    18 +
 .../osm-testdata/grid/data/7/758/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/759/data.osm          |    33 +
 .../osm-testdata/grid/data/7/759/data.osm.pbf      |   Bin 0 -> 469 bytes
 .../osm-testdata/grid/data/7/759/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/759/result  |     1 +
 .../osm-testdata/grid/data/7/759/test.json         |    18 +
 .../osm-testdata/grid/data/7/759/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/760/data.osm          |    37 +
 .../osm-testdata/grid/data/7/760/data.osm.pbf      |   Bin 0 -> 466 bytes
 .../osm-testdata/grid/data/7/760/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/760/result  |     1 +
 .../osm-testdata/grid/data/7/760/test.json         |    18 +
 .../osm-testdata/grid/data/7/760/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/761/data.osm          |    31 +
 .../osm-testdata/grid/data/7/761/data.osm.pbf      |   Bin 0 -> 322 bytes
 .../osm-testdata/grid/data/7/761/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/761/result  |     1 +
 .../osm-testdata/grid/data/7/761/test.json         |    18 +
 .../osm-testdata/grid/data/7/761/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/762/data.osm          |    49 +
 .../osm-testdata/grid/data/7/762/data.osm.pbf      |   Bin 0 -> 501 bytes
 .../osm-testdata/grid/data/7/762/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/762/result  |     1 +
 .../osm-testdata/grid/data/7/762/test.json         |    18 +
 .../osm-testdata/grid/data/7/762/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/763/data.osm          |    83 +
 .../osm-testdata/grid/data/7/763/data.osm.pbf      |   Bin 0 -> 507 bytes
 .../osm-testdata/grid/data/7/763/nodes.wkt         |    21 +
 .../resources/osm-testdata/grid/data/7/763/result  |     1 +
 .../osm-testdata/grid/data/7/763/test.json         |    18 +
 .../osm-testdata/grid/data/7/763/ways.wkt          |     4 +
 .../osm-testdata/grid/data/7/764/data.osm          |    98 +
 .../osm-testdata/grid/data/7/764/data.osm.pbf      |   Bin 0 -> 547 bytes
 .../osm-testdata/grid/data/7/764/nodes.wkt         |    25 +
 .../resources/osm-testdata/grid/data/7/764/result  |     1 +
 .../osm-testdata/grid/data/7/764/test.json         |    18 +
 .../osm-testdata/grid/data/7/764/ways.wkt          |     5 +
 .../osm-testdata/grid/data/7/765/data.osm          |    35 +
 .../osm-testdata/grid/data/7/765/data.osm.pbf      |   Bin 0 -> 468 bytes
 .../osm-testdata/grid/data/7/765/nodes.wkt         |     9 +
 .../resources/osm-testdata/grid/data/7/765/result  |     1 +
 .../osm-testdata/grid/data/7/765/test.json         |    18 +
 .../osm-testdata/grid/data/7/765/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/766/data.osm          |    52 +
 .../osm-testdata/grid/data/7/766/data.osm.pbf      |   Bin 0 -> 506 bytes
 .../osm-testdata/grid/data/7/766/nodes.wkt         |    13 +
 .../resources/osm-testdata/grid/data/7/766/result  |     1 +
 .../osm-testdata/grid/data/7/766/test.json         |    18 +
 .../osm-testdata/grid/data/7/766/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/767/data.osm          |    29 +
 .../osm-testdata/grid/data/7/767/data.osm.pbf      |   Bin 0 -> 323 bytes
 .../osm-testdata/grid/data/7/767/nodes.wkt         |     9 +
 .../resources/osm-testdata/grid/data/7/767/result  |     1 +
 .../osm-testdata/grid/data/7/767/test.json         |    18 +
 .../osm-testdata/grid/data/7/767/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/768/data.osm          |    39 +
 .../osm-testdata/grid/data/7/768/data.osm.pbf      |   Bin 0 -> 484 bytes
 .../osm-testdata/grid/data/7/768/nodes.wkt         |     7 +
 .../resources/osm-testdata/grid/data/7/768/result  |     1 +
 .../osm-testdata/grid/data/7/768/test.json         |    13 +
 .../osm-testdata/grid/data/7/768/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/770/data.osm          |    38 +
 .../osm-testdata/grid/data/7/770/data.osm.pbf      |   Bin 0 -> 472 bytes
 .../osm-testdata/grid/data/7/770/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/770/result  |     1 +
 .../osm-testdata/grid/data/7/770/test.json         |    18 +
 .../osm-testdata/grid/data/7/770/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/771/data.osm          |    37 +
 .../osm-testdata/grid/data/7/771/data.osm.pbf      |   Bin 0 -> 470 bytes
 .../osm-testdata/grid/data/7/771/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/771/result  |     1 +
 .../osm-testdata/grid/data/7/771/test.json         |    13 +
 .../osm-testdata/grid/data/7/771/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/772/data.osm          |    55 +
 .../osm-testdata/grid/data/7/772/data.osm.pbf      |   Bin 0 -> 512 bytes
 .../osm-testdata/grid/data/7/772/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/772/result  |     1 +
 .../osm-testdata/grid/data/7/772/test.json         |    18 +
 .../osm-testdata/grid/data/7/772/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/773/data.osm          |    54 +
 .../osm-testdata/grid/data/7/773/data.osm.pbf      |   Bin 0 -> 513 bytes
 .../osm-testdata/grid/data/7/773/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/7/773/result  |     1 +
 .../osm-testdata/grid/data/7/773/test.json         |    13 +
 .../osm-testdata/grid/data/7/773/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/774/data.osm          |    43 +
 .../osm-testdata/grid/data/7/774/data.osm.pbf      |   Bin 0 -> 481 bytes
 .../osm-testdata/grid/data/7/774/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/774/result  |     1 +
 .../osm-testdata/grid/data/7/774/test.json         |    18 +
 .../osm-testdata/grid/data/7/774/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/775/data.osm          |    43 +
 .../osm-testdata/grid/data/7/775/data.osm.pbf      |   Bin 0 -> 480 bytes
 .../osm-testdata/grid/data/7/775/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/775/result  |     1 +
 .../osm-testdata/grid/data/7/775/test.json         |    18 +
 .../osm-testdata/grid/data/7/775/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/776/data.osm          |    43 +
 .../osm-testdata/grid/data/7/776/data.osm.pbf      |   Bin 0 -> 479 bytes
 .../osm-testdata/grid/data/7/776/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/776/result  |     1 +
 .../osm-testdata/grid/data/7/776/test.json         |    18 +
 .../osm-testdata/grid/data/7/776/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/777/data.osm          |    57 +
 .../osm-testdata/grid/data/7/777/data.osm.pbf      |   Bin 0 -> 516 bytes
 .../osm-testdata/grid/data/7/777/nodes.wkt         |    14 +
 .../resources/osm-testdata/grid/data/7/777/result  |     1 +
 .../osm-testdata/grid/data/7/777/test.json         |    18 +
 .../osm-testdata/grid/data/7/777/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/778/data.osm          |    57 +
 .../osm-testdata/grid/data/7/778/data.osm.pbf      |   Bin 0 -> 517 bytes
 .../osm-testdata/grid/data/7/778/nodes.wkt         |    14 +
 .../resources/osm-testdata/grid/data/7/778/result  |     1 +
 .../osm-testdata/grid/data/7/778/test.json         |    18 +
 .../osm-testdata/grid/data/7/778/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/779/data.osm          |    57 +
 .../osm-testdata/grid/data/7/779/data.osm.pbf      |   Bin 0 -> 515 bytes
 .../osm-testdata/grid/data/7/779/nodes.wkt         |    14 +
 .../resources/osm-testdata/grid/data/7/779/result  |     1 +
 .../osm-testdata/grid/data/7/779/test.json         |    18 +
 .../osm-testdata/grid/data/7/779/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/780/data.osm          |    18 +
 .../osm-testdata/grid/data/7/780/data.osm.pbf      |   Bin 0 -> 299 bytes
 .../osm-testdata/grid/data/7/780/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/7/780/result  |     1 +
 .../osm-testdata/grid/data/7/780/test.json         |    25 +
 .../osm-testdata/grid/data/7/780/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/781/data.osm          |    24 +
 .../osm-testdata/grid/data/7/781/data.osm.pbf      |   Bin 0 -> 443 bytes
 .../osm-testdata/grid/data/7/781/nodes.wkt         |     5 +
 .../resources/osm-testdata/grid/data/7/781/result  |     1 +
 .../osm-testdata/grid/data/7/781/test.json         |    25 +
 .../osm-testdata/grid/data/7/781/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/782/data.osm          |    46 +
 .../osm-testdata/grid/data/7/782/data.osm.pbf      |   Bin 0 -> 498 bytes
 .../osm-testdata/grid/data/7/782/nodes.wkt         |     9 +
 .../resources/osm-testdata/grid/data/7/782/result  |     1 +
 .../osm-testdata/grid/data/7/782/test.json         |    25 +
 .../osm-testdata/grid/data/7/782/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/783/data.osm          |    68 +
 .../osm-testdata/grid/data/7/783/data.osm.pbf      |   Bin 0 -> 529 bytes
 .../osm-testdata/grid/data/7/783/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/7/783/result  |     1 +
 .../osm-testdata/grid/data/7/783/test.json         |    18 +
 .../osm-testdata/grid/data/7/783/ways.wkt          |     5 +
 .../osm-testdata/grid/data/7/784/data.osm          |    71 +
 .../osm-testdata/grid/data/7/784/data.osm.pbf      |   Bin 0 -> 534 bytes
 .../osm-testdata/grid/data/7/784/nodes.wkt         |    14 +
 .../resources/osm-testdata/grid/data/7/784/result  |     1 +
 .../osm-testdata/grid/data/7/784/test.json         |    18 +
 .../osm-testdata/grid/data/7/784/ways.wkt          |     4 +
 .../osm-testdata/grid/data/7/785/data.osm          |    61 +
 .../osm-testdata/grid/data/7/785/data.osm.pbf      |   Bin 0 -> 523 bytes
 .../osm-testdata/grid/data/7/785/nodes.wkt         |    14 +
 .../resources/osm-testdata/grid/data/7/785/result  |     1 +
 .../osm-testdata/grid/data/7/785/test.json         |    18 +
 .../osm-testdata/grid/data/7/785/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/790/data.osm          |    24 +
 .../osm-testdata/grid/data/7/790/data.osm.pbf      |   Bin 0 -> 447 bytes
 .../osm-testdata/grid/data/7/790/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/790/result  |     1 +
 .../osm-testdata/grid/data/7/790/test.json         |    25 +
 .../osm-testdata/grid/data/7/790/ways.wkt          |     1 +
 .../osm-testdata/grid/data/7/791/data.osm          |    33 +
 .../osm-testdata/grid/data/7/791/data.osm.pbf      |   Bin 0 -> 453 bytes
 .../osm-testdata/grid/data/7/791/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/791/result  |     1 +
 .../osm-testdata/grid/data/7/791/test.json         |    25 +
 .../osm-testdata/grid/data/7/791/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/792/data.osm          |    33 +
 .../osm-testdata/grid/data/7/792/data.osm.pbf      |   Bin 0 -> 457 bytes
 .../osm-testdata/grid/data/7/792/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/792/result  |     1 +
 .../osm-testdata/grid/data/7/792/test.json         |    25 +
 .../osm-testdata/grid/data/7/792/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/793/data.osm          |    32 +
 .../osm-testdata/grid/data/7/793/data.osm.pbf      |   Bin 0 -> 456 bytes
 .../osm-testdata/grid/data/7/793/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/793/result  |     1 +
 .../osm-testdata/grid/data/7/793/test.json         |    25 +
 .../osm-testdata/grid/data/7/793/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/794/data.osm          |    43 +
 .../osm-testdata/grid/data/7/794/data.osm.pbf      |   Bin 0 -> 460 bytes
 .../osm-testdata/grid/data/7/794/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/7/794/result  |     1 +
 .../osm-testdata/grid/data/7/794/test.json         |    25 +
 .../osm-testdata/grid/data/7/794/ways.wkt          |     3 +
 .../osm-testdata/grid/data/7/795/data.osm          |    38 +
 .../osm-testdata/grid/data/7/795/data.osm.pbf      |   Bin 0 -> 483 bytes
 .../osm-testdata/grid/data/7/795/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/7/795/result  |     1 +
 .../osm-testdata/grid/data/7/795/test.json         |    25 +
 .../osm-testdata/grid/data/7/795/ways.wkt          |     2 +
 .../osm-testdata/grid/data/7/description.txt       |     1 +
 .../osm-testdata/grid/data/9/900/data.osm          |    22 +
 .../osm-testdata/grid/data/9/900/data.osm.pbf      |   Bin 0 -> 426 bytes
 .../osm-testdata/grid/data/9/900/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/9/900/result  |     1 +
 .../osm-testdata/grid/data/9/900/test.json         |    17 +
 .../osm-testdata/grid/data/9/900/ways.wkt          |     1 +
 .../osm-testdata/grid/data/9/901/data.osm          |    29 +
 .../osm-testdata/grid/data/9/901/data.osm.pbf      |   Bin 0 -> 454 bytes
 .../osm-testdata/grid/data/9/901/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/9/901/result  |     1 +
 .../osm-testdata/grid/data/9/901/test.json         |    18 +
 .../osm-testdata/grid/data/9/901/ways.wkt          |     2 +
 .../osm-testdata/grid/data/9/902/data.osm          |    29 +
 .../osm-testdata/grid/data/9/902/data.osm.pbf      |   Bin 0 -> 461 bytes
 .../osm-testdata/grid/data/9/902/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/9/902/result  |     1 +
 .../osm-testdata/grid/data/9/902/test.json         |    18 +
 .../osm-testdata/grid/data/9/902/ways.wkt          |     2 +
 .../osm-testdata/grid/data/9/903/data.osm          |    23 +
 .../osm-testdata/grid/data/9/903/data.osm.pbf      |   Bin 0 -> 440 bytes
 .../osm-testdata/grid/data/9/903/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/9/903/result  |     1 +
 .../osm-testdata/grid/data/9/903/test.json         |    18 +
 .../osm-testdata/grid/data/9/903/ways.wkt          |     1 +
 .../osm-testdata/grid/data/9/904/data.osm          |    47 +
 .../osm-testdata/grid/data/9/904/data.osm.pbf      |   Bin 0 -> 487 bytes
 .../osm-testdata/grid/data/9/904/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/904/result  |     1 +
 .../osm-testdata/grid/data/9/904/test.json         |    18 +
 .../osm-testdata/grid/data/9/904/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/905/data.osm          |    52 +
 .../osm-testdata/grid/data/9/905/data.osm.pbf      |   Bin 0 -> 493 bytes
 .../osm-testdata/grid/data/9/905/nodes.wkt         |    10 +
 .../resources/osm-testdata/grid/data/9/905/result  |     1 +
 .../osm-testdata/grid/data/9/905/test.json         |    18 +
 .../osm-testdata/grid/data/9/905/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/910/data.osm          |    23 +
 .../osm-testdata/grid/data/9/910/data.osm.pbf      |   Bin 0 -> 405 bytes
 .../osm-testdata/grid/data/9/910/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/9/910/result  |     1 +
 .../osm-testdata/grid/data/9/910/test.json         |    18 +
 .../osm-testdata/grid/data/9/910/ways.wkt          |     1 +
 .../osm-testdata/grid/data/9/911/data.osm          |    25 +
 .../osm-testdata/grid/data/9/911/data.osm.pbf      |   Bin 0 -> 442 bytes
 .../osm-testdata/grid/data/9/911/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/9/911/result  |     1 +
 .../osm-testdata/grid/data/9/911/test.json         |    18 +
 .../osm-testdata/grid/data/9/911/ways.wkt          |     1 +
 .../osm-testdata/grid/data/9/912/data.osm          |    33 +
 .../osm-testdata/grid/data/9/912/data.osm.pbf      |   Bin 0 -> 457 bytes
 .../osm-testdata/grid/data/9/912/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/9/912/result  |     1 +
 .../osm-testdata/grid/data/9/912/test.json         |    18 +
 .../osm-testdata/grid/data/9/912/ways.wkt          |     2 +
 .../osm-testdata/grid/data/9/913/data.osm          |    31 +
 .../osm-testdata/grid/data/9/913/data.osm.pbf      |   Bin 0 -> 465 bytes
 .../osm-testdata/grid/data/9/913/nodes.wkt         |     4 +
 .../resources/osm-testdata/grid/data/9/913/result  |     1 +
 .../osm-testdata/grid/data/9/913/test.json         |    17 +
 .../osm-testdata/grid/data/9/913/ways.wkt          |     2 +
 .../osm-testdata/grid/data/9/920/data.osm          |    47 +
 .../osm-testdata/grid/data/9/920/data.osm.pbf      |   Bin 0 -> 495 bytes
 .../osm-testdata/grid/data/9/920/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/920/result  |     1 +
 .../osm-testdata/grid/data/9/920/test.json         |    18 +
 .../osm-testdata/grid/data/9/920/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/921/data.osm          |    47 +
 .../osm-testdata/grid/data/9/921/data.osm.pbf      |   Bin 0 -> 506 bytes
 .../osm-testdata/grid/data/9/921/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/921/result  |     1 +
 .../osm-testdata/grid/data/9/921/test.json         |    18 +
 .../osm-testdata/grid/data/9/921/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/922/data.osm          |    42 +
 .../osm-testdata/grid/data/9/922/data.osm.pbf      |   Bin 0 -> 509 bytes
 .../osm-testdata/grid/data/9/922/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/922/result  |     1 +
 .../osm-testdata/grid/data/9/922/test.json         |    28 +
 .../osm-testdata/grid/data/9/922/ways.wkt          |     2 +
 .../osm-testdata/grid/data/9/923/data.osm          |    42 +
 .../osm-testdata/grid/data/9/923/data.osm.pbf      |   Bin 0 -> 492 bytes
 .../osm-testdata/grid/data/9/923/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/923/result  |     1 +
 .../osm-testdata/grid/data/9/923/test.json         |    28 +
 .../osm-testdata/grid/data/9/923/ways.wkt          |     2 +
 .../osm-testdata/grid/data/9/924/data.osm          |    49 +
 .../osm-testdata/grid/data/9/924/data.osm.pbf      |   Bin 0 -> 523 bytes
 .../osm-testdata/grid/data/9/924/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/924/result  |     1 +
 .../osm-testdata/grid/data/9/924/test.json         |    18 +
 .../osm-testdata/grid/data/9/924/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/925/data.osm          |    49 +
 .../osm-testdata/grid/data/9/925/data.osm.pbf      |   Bin 0 -> 507 bytes
 .../osm-testdata/grid/data/9/925/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/925/result  |     1 +
 .../osm-testdata/grid/data/9/925/test.json         |    18 +
 .../osm-testdata/grid/data/9/925/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/926/data.osm          |    42 +
 .../osm-testdata/grid/data/9/926/data.osm.pbf      |   Bin 0 -> 508 bytes
 .../osm-testdata/grid/data/9/926/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/926/result  |     1 +
 .../osm-testdata/grid/data/9/926/test.json         |    18 +
 .../osm-testdata/grid/data/9/926/ways.wkt          |     2 +
 .../osm-testdata/grid/data/9/927/data.osm          |    42 +
 .../osm-testdata/grid/data/9/927/data.osm.pbf      |   Bin 0 -> 481 bytes
 .../osm-testdata/grid/data/9/927/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/927/result  |     1 +
 .../osm-testdata/grid/data/9/927/test.json         |    18 +
 .../osm-testdata/grid/data/9/927/ways.wkt          |     2 +
 .../osm-testdata/grid/data/9/930/data.osm          |    49 +
 .../osm-testdata/grid/data/9/930/data.osm.pbf      |   Bin 0 -> 522 bytes
 .../osm-testdata/grid/data/9/930/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/930/result  |     1 +
 .../osm-testdata/grid/data/9/930/test.json         |    18 +
 .../osm-testdata/grid/data/9/930/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/931/data.osm          |    49 +
 .../osm-testdata/grid/data/9/931/data.osm.pbf      |   Bin 0 -> 497 bytes
 .../osm-testdata/grid/data/9/931/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/931/result  |     1 +
 .../osm-testdata/grid/data/9/931/test.json         |    18 +
 .../osm-testdata/grid/data/9/931/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/940/data.osm          |    59 +
 .../osm-testdata/grid/data/9/940/data.osm.pbf      |   Bin 0 -> 571 bytes
 .../osm-testdata/grid/data/9/940/nodes.wkt         |    12 +
 .../resources/osm-testdata/grid/data/9/940/result  |     1 +
 .../osm-testdata/grid/data/9/940/test.json         |    38 +
 .../osm-testdata/grid/data/9/940/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/950/data.osm          |    48 +
 .../osm-testdata/grid/data/9/950/data.osm.pbf      |   Bin 0 -> 510 bytes
 .../osm-testdata/grid/data/9/950/nodes.wkt         |     8 +
 .../resources/osm-testdata/grid/data/9/950/result  |     1 +
 .../osm-testdata/grid/data/9/950/test.json         |    19 +
 .../osm-testdata/grid/data/9/950/ways.wkt          |     3 +
 .../osm-testdata/grid/data/9/description.txt       |     1 +
 .../test/resources/osm-testdata/grid/data/all.osm  |  4113 ++++++
 .../resources/osm-testdata/grid/data/tests.json    |  2091 +++
 .../src/test/resources/osm-testdata/grid/grid.db   |   Bin 0 -> 6225920 bytes
 .../osm-testdata/grid/multipolygon-tests.png       |   Bin 0 -> 308201 bytes
 .../src/test/resources/osm-testdata/grid/setup.sql |    41 +
 .../src/test/resources/osm-testdata/grid/tests.qgs |  1682 +++
 .../src/test/resources/osm-testdata/index.js       |     1 +
 .../test/resources/osm-testdata/misc/64bit_ids.osm |  4751 +++++++
 .../src/test/resources/osm-testdata/misc/README.md |     4 +
 .../osm-testdata/misc/multipolygon_testcases.osm   | 13383 +++++++++++++++++++
 .../resources/osm-testdata/misc/tag_lengths.osm    |    17 +
 .../src/test/resources/osm-testdata/package.json   |    20 +
 .../src/test/resources/osm-testdata/xml/Makefile   |     4 +
 .../src/test/resources/osm-testdata/xml/README.md  |     5 +
 .../resources/osm-testdata/xml/bin/show-tests.sh   |    27 +
 .../xml/data/100-correct_but_no_data/data.osm      |     3 +
 .../xml/data/100-correct_but_no_data/data.osm.pbf  |   Bin 0 -> 73 bytes
 .../data/100-correct_but_no_data/description.txt   |     1 +
 .../xml/data/100-correct_but_no_data/result        |     1 +
 .../xml/data/101-missing_version/data.osm          |     3 +
 .../xml/data/101-missing_version/description.txt   |     1 +
 .../xml/data/101-missing_version/result            |     1 +
 .../xml/data/102-wrong_version/data.osm            |     3 +
 .../xml/data/102-wrong_version/description.txt     |     1 +
 .../osm-testdata/xml/data/102-wrong_version/result |     1 +
 .../osm-testdata/xml/data/103-old_version/data.osm |     3 +
 .../xml/data/103-old_version/description.txt       |     1 +
 .../osm-testdata/xml/data/104-empty_file/data.osm  |     0
 .../xml/data/104-empty_file/description.txt        |     1 +
 .../osm-testdata/xml/data/104-empty_file/result    |     1 +
 .../xml/data/105-incomplete_xml_file/data.osm      |     2 +
 .../data/105-incomplete_xml_file/description.txt   |     1 +
 .../xml/data/105-incomplete_xml_file/result        |     1 +
 .../xml/data/106-invalid_xml_file/data.osm         |     6 +
 .../xml/data/106-invalid_xml_file/description.txt  |     1 +
 .../xml/data/106-invalid_xml_file/result           |     1 +
 .../xml/data/107-wrongly_nested_xml_file/data.osm  |     8 +
 .../data/107-wrongly_nested_xml_file/data.osm.pbf  |   Bin 0 -> 73 bytes
 .../107-wrongly_nested_xml_file/description.txt    |     1 +
 .../xml/data/107-wrongly_nested_xml_file/result    |     1 +
 .../xml/data/108-unknown_top_level/data.osm        |     3 +
 .../xml/data/108-unknown_top_level/description.txt |     1 +
 .../xml/data/108-unknown_top_level/result          |     1 +
 .../xml/data/109-unknown_data_level/data.osm       |     5 +
 .../xml/data/109-unknown_data_level/data.osm.pbf   |   Bin 0 -> 143 bytes
 .../data/109-unknown_data_level/description.txt    |     1 +
 .../xml/data/109-unknown_data_level/result         |     1 +
 .../xml/data/110-entity_declaration/data.osm       |     8 +
 .../data/110-entity_declaration/description.txt    |     1 +
 .../xml/data/110-entity_declaration/result         |     1 +
 .../120-correct_gzip_file_without_data/data.osm.gz |   Bin 0 -> 122 bytes
 .../description.txt                                |     1 +
 .../data/120-correct_gzip_file_without_data/result |     1 +
 .../xml/data/121-truncated_gzip_file/data.osm.gz   |   Bin 0 -> 110 bytes
 .../data/121-truncated_gzip_file/description.txt   |     1 +
 .../xml/data/121-truncated_gzip_file/result        |     1 +
 .../xml/data/122-no_osm_element/data.osm           |     2 +
 .../xml/data/122-no_osm_element/description.txt    |     1 +
 .../xml/data/122-no_osm_element/result             |     1 +
 .../xml/data/123-unknown_element_in_node/data.osm  |     6 +
 .../data/123-unknown_element_in_node/data.osm.pbf  |   Bin 0 -> 73 bytes
 .../123-unknown_element_in_node/description.txt    |     1 +
 .../xml/data/123-unknown_element_in_node/result    |     1 +
 .../xml/data/124-unknown_element_in_way/data.osm   |     9 +
 .../data/124-unknown_element_in_way/data.osm.pbf   |   Bin 0 -> 73 bytes
 .../124-unknown_element_in_way/description.txt     |     1 +
 .../xml/data/124-unknown_element_in_way/result     |     1 +
 .../data/125-unknown_element_in_relation/data.osm  |     7 +
 .../125-unknown_element_in_relation/data.osm.pbf   |   Bin 0 -> 73 bytes
 .../description.txt                                |     1 +
 .../data/125-unknown_element_in_relation/result    |     1 +
 .../xml/data/126-wrong_member_type/data.osm        |     7 +
 .../xml/data/126-wrong_member_type/data.osm.pbf    |   Bin 0 -> 73 bytes
 .../xml/data/126-wrong_member_type/description.txt |     1 +
 .../xml/data/126-wrong_member_type/result          |     1 +
 .../xml/data/127-missing_member_type/data.osm      |     7 +
 .../xml/data/127-missing_member_type/data.osm.pbf  |   Bin 0 -> 73 bytes
 .../data/127-missing_member_type/description.txt   |     1 +
 .../xml/data/127-missing_member_type/result        |     1 +
 .../xml/data/128-missing_member_ref/data.osm       |     7 +
 .../xml/data/128-missing_member_ref/data.osm.pbf   |   Bin 0 -> 73 bytes
 .../data/128-missing_member_ref/description.txt    |     1 +
 .../xml/data/128-missing_member_ref/result         |     1 +
 .../osm-testdata/xml/data/140-unicode/data.osm     |    38 +
 .../osm-testdata/xml/data/140-unicode/data.osm.pbf |   Bin 0 -> 444 bytes
 .../xml/data/140-unicode/description.txt           |     1 +
 .../osm-testdata/xml/data/140-unicode/result       |     1 +
 .../osm-testdata/xml/data/141-entities/data.osm    |    10 +
 .../xml/data/141-entities/data.osm.pbf             |   Bin 0 -> 229 bytes
 .../xml/data/141-entities/description.txt          |     1 +
 .../osm-testdata/xml/data/141-entities/result      |     1 +
 .../osm-testdata/xml/data/142-whitespace/data.osm  |    29 +
 .../xml/data/142-whitespace/data.osm.pbf           |   Bin 0 -> 474 bytes
 .../xml/data/142-whitespace/description.txt        |     1 +
 .../xml/data/142-whitespace/osmosis-out.osm        |    25 +
 .../osm-testdata/xml/data/142-whitespace/out.osm   |    25 +
 .../osm-testdata/xml/data/142-whitespace/result    |     1 +
 .../osm-testdata/xml/data/200-nodes/data.osm       |     6 +
 .../osm-testdata/xml/data/200-nodes/data.osm.pbf   |   Bin 0 -> 255 bytes
 .../xml/data/200-nodes/description.txt             |     1 +
 .../osm-testdata/xml/data/200-nodes/result         |     1 +
 .../osm-testdata/xml/data/300-change-file/data.osc |    19 +
 .../xml/data/300-change-file/description.txt       |     1 +
 .../osm-testdata/xml/data/300-change-file/result   |     1 +
 901 files changed, 35772 insertions(+), 10 deletions(-)

diff --git a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/CleanDuplicatePoints.java b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/CleanDuplicatePoints.java
new file mode 100644
index 00000000..457e0334
--- /dev/null
+++ b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/CleanDuplicatePoints.java
@@ -0,0 +1,103 @@
+package org.apache.baremaps.openstreetmap.function;
+
+import org.locationtech.jts.geom.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CleanDuplicatePoints {
+
+    public static Coordinate[] removeDuplicatePoints(Coordinate[] coord) {
+        List uniqueCoords = new ArrayList();
+        Coordinate lastPt = null;
+        for (int i = 0; i < coord.length; i++) {
+            if (lastPt == null || !lastPt.equals(coord[i])) {
+                lastPt = coord[i];
+                uniqueCoords.add(new Coordinate(lastPt));
+            }
+        }
+        return (Coordinate[]) uniqueCoords.toArray(new Coordinate[0]);
+    }
+
+    private GeometryFactory fact;
+
+    public CleanDuplicatePoints() {
+    }
+
+    public Geometry clean(Geometry g) {
+        fact = g.getFactory();
+        if (g.isEmpty()) {
+            return g;
+        }
+        if (g instanceof Point) {
+            return g;
+        } else if (g instanceof MultiPoint) {
+            return g;
+        }
+        // LineString also handles LinearRings
+        else if (g instanceof LinearRing) {
+            return clean((LinearRing) g);
+        } else if (g instanceof LineString) {
+            return clean((LineString) g);
+        } else if (g instanceof Polygon) {
+            return clean((Polygon) g);
+        } else if (g instanceof MultiLineString) {
+            return clean((MultiLineString) g);
+        } else if (g instanceof MultiPolygon) {
+            return clean((MultiPolygon) g);
+        } else if (g instanceof GeometryCollection) {
+            return clean((GeometryCollection) g);
+        } else {
+            throw new UnsupportedOperationException(g.getClass().getName());
+        }
+    }
+
+    private LinearRing clean(LinearRing g) {
+        Coordinate[] coords = removeDuplicatePoints(g.getCoordinates());
+        return fact.createLinearRing(coords);
+    }
+
+    private LineString clean(LineString g) {
+        Coordinate[] coords = removeDuplicatePoints(g.getCoordinates());
+        return fact.createLineString(coords);
+    }
+
+    private Polygon clean(Polygon poly) {
+        Coordinate[] shellCoords = removeDuplicatePoints(poly.getExteriorRing().getCoordinates());
+        LinearRing shell = fact.createLinearRing(shellCoords);
+        List holes = new ArrayList();
+        for (int i = 0; i < poly.getNumInteriorRing(); i++) {
+            Coordinate[] holeCoords = removeDuplicatePoints(poly.getInteriorRingN(i).getCoordinates());
+            holes.add(fact.createLinearRing(holeCoords));
+        }
+        return fact.createPolygon(shell, GeometryFactory.toLinearRingArray(holes));
+    }
+
+    private MultiPolygon clean(MultiPolygon g) {
+        List polys = new ArrayList();
+        for (int i = 0; i < g.getNumGeometries(); i++) {
+            Polygon poly = (Polygon) g.getGeometryN(i);
+            polys.add(clean(poly));
+        }
+        return fact.createMultiPolygon(GeometryFactory.toPolygonArray(polys));
+    }
+
+    private MultiLineString clean(MultiLineString g) {
+        List lines = new ArrayList();
+        for (int i = 0; i < g.getNumGeometries(); i++) {
+            LineString line = (LineString) g.getGeometryN(i);
+            lines.add(clean(line));
+        }
+        return fact.createMultiLineString(GeometryFactory.toLineStringArray(lines));
+    }
+
+    private GeometryCollection clean(GeometryCollection g) {
+        List geoms = new ArrayList();
+        for (int i = 0; i < g.getNumGeometries(); i++) {
+            Geometry geom = g.getGeometryN(i);
+            geoms.add(clean(geom));
+        }
+        return fact.createGeometryCollection(GeometryFactory.toGeometryArray(geoms));
+    }
+
+}
diff --git a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/EntityGeometryBuilder.java b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/EntityGeometryBuilder.java
index d014b448..350e8d09 100644
--- a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/EntityGeometryBuilder.java
+++ b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/EntityGeometryBuilder.java
@@ -19,6 +19,7 @@ package org.apache.baremaps.openstreetmap.function;
 
 
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
 import org.apache.baremaps.database.collection.DataMap;
@@ -26,7 +27,7 @@ import org.apache.baremaps.openstreetmap.model.Entity;
 import org.apache.baremaps.openstreetmap.model.Node;
 import org.apache.baremaps.openstreetmap.model.Relation;
 import org.apache.baremaps.openstreetmap.model.Way;
-import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.*;
 
 /** A consumer that builds and sets the geometry of OpenStreetMap entities via side effects. */
 public class EntityGeometryBuilder implements Consumer<Entity> {
@@ -59,4 +60,5 @@ public class EntityGeometryBuilder implements Consumer<Entity> {
       relationGeometryBuilder.accept(relation);
     }
   }
+
 }
diff --git a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/NodeGeometryBuilder.java b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/NodeGeometryBuilder.java
index e92f5d6c..94895e2c 100644
--- a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/NodeGeometryBuilder.java
+++ b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/NodeGeometryBuilder.java
@@ -19,10 +19,11 @@ package org.apache.baremaps.openstreetmap.function;
 
 import static org.apache.baremaps.utils.GeometryUtils.GEOMETRY_FACTORY_WGS84;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.function.Consumer;
 import org.apache.baremaps.openstreetmap.model.Node;
-import org.locationtech.jts.geom.Coordinate;
-import org.locationtech.jts.geom.Point;
+import org.locationtech.jts.geom.*;
 
 /**
  * A consumer that builds and sets a node geometry via side effects.
diff --git a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/RelationGeometryBuilder.java b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/RelationGeometryBuilder.java
index bf466125..21c8742d 100644
--- a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/RelationGeometryBuilder.java
+++ b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/RelationGeometryBuilder.java
@@ -65,13 +65,14 @@ public class RelationGeometryBuilder implements Consumer<Relation> {
       Map<String, Object> tags = relation.getTags();
 
       // Filter out type that are not multipolygon or boundary geometries
+      // TODO: filter out at the stream level
       if (!("multipolygon".equals(tags.get("type"))
           || "boundary".equals(tags.get("type")))) {
         return;
       }
 
       // Filter coastline geometries
-      // TODO: document motivation for filtering out.
+      // TODO: filter out at the stream level
       if ("coastline".equals(tags.get("natural"))) {
         return;
       }
@@ -92,7 +93,7 @@ public class RelationGeometryBuilder implements Consumer<Relation> {
         relation.setGeometry(polygon);
       } else if (polygons.size() > 1) {
         MultiPolygon multiPolygon =
-            GEOMETRY_FACTORY_WGS84.createMultiPolygon(polygons.toArray(new Polygon[0]));
+                GEOMETRY_FACTORY_WGS84.createMultiPolygon(polygons.toArray(new Polygon[0]));
         relation.setGeometry(multiPolygon);
       }
 
@@ -117,7 +118,7 @@ public class RelationGeometryBuilder implements Consumer<Relation> {
       Iterator<Polygon> it = innerPolygons.iterator();
       while (it.hasNext()) {
         Polygon innerPolygon = it.next();
-        if (prepared.containsProperly(innerPolygon)) {
+        if (prepared.contains(innerPolygon)) {
           holes.add(innerPolygon.getExteriorRing());
           it.remove();
         }
@@ -177,8 +178,19 @@ public class RelationGeometryBuilder implements Consumer<Relation> {
   private LineString createLine(Member member) {
     try {
       List<Long> refs = referenceMap.get(member.getRef());
-      List<Coordinate> coords = refs.stream().map(coordinateMap::get).toList();
-      Coordinate[] array = coords.toArray(new Coordinate[coords.size()]);
+
+      // Build the coordinate list and remove duplicates.
+      List<Coordinate> list = new ArrayList<>();
+      Coordinate previous = null;
+      for (Long id : refs) {
+        Coordinate coordinate = coordinateMap.get(id);
+        if (coordinate != null && !coordinate.equals(previous)) {
+          list.add(coordinate);
+          previous = coordinate;
+        }
+      }
+
+      Coordinate[] array = list.toArray(new Coordinate[0]);
       return GEOMETRY_FACTORY_WGS84.createLineString(array);
     } catch (Exception e) {
       throw new StreamException(e);
diff --git a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/WayGeometryBuilder.java b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/WayGeometryBuilder.java
index 9432eed7..cd1c3a0a 100644
--- a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/WayGeometryBuilder.java
+++ b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/function/WayGeometryBuilder.java
@@ -19,6 +19,7 @@ package org.apache.baremaps.openstreetmap.function;
 
 import static org.apache.baremaps.utils.GeometryUtils.GEOMETRY_FACTORY_WGS84;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.function.Consumer;
 import org.apache.baremaps.database.collection.DataMap;
@@ -51,9 +52,20 @@ public class WayGeometryBuilder implements Consumer<Way> {
   @Override
   public void accept(Way way) {
     try {
-      List<Coordinate> list = way.getNodes().stream().map(coordinateMap::get).toList();
+      // Build the coordinate list and remove duplicates.
+      List<Coordinate> list = new ArrayList<>();
+      Coordinate previous = null;
+      for (Long id : way.getNodes()) {
+        Coordinate coordinate = coordinateMap.get(id);
+        if (coordinate != null && !coordinate.equals(previous)) {
+          list.add(coordinate);
+          previous = coordinate;
+        }
+      }
+
       Coordinate[] array = list.toArray(new Coordinate[list.size()]);
       LineString line = GEOMETRY_FACTORY_WGS84.createLineString(array);
+
       if (!line.isEmpty()) {
         // Ways can be open or closed depending on the geometry or the tags:
         // https://wiki.openstreetmap.org/wiki/Way
diff --git a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlEntityReader.java b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlEntityReader.java
index 98f51b36..6a9d93db 100644
--- a/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlEntityReader.java
+++ b/baremaps-core/src/main/java/org/apache/baremaps/openstreetmap/xml/XmlEntityReader.java
@@ -20,14 +20,69 @@ package org.apache.baremaps.openstreetmap.xml;
 
 
 import java.io.InputStream;
+import java.util.List;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
+
+import org.apache.baremaps.database.collection.DataMap;
 import org.apache.baremaps.openstreetmap.OsmReader;
+import org.apache.baremaps.openstreetmap.function.CoordinateMapBuilder;
+import org.apache.baremaps.openstreetmap.function.EntityGeometryBuilder;
+import org.apache.baremaps.openstreetmap.function.EntityProjectionTransformer;
+import org.apache.baremaps.openstreetmap.function.ReferenceMapBuilder;
 import org.apache.baremaps.openstreetmap.model.Entity;
+import org.apache.baremaps.openstreetmap.pbf.PbfBlockReader;
+import org.locationtech.jts.geom.Coordinate;
+
+import static org.apache.baremaps.stream.ConsumerUtils.consumeThenReturn;
 
 /** A utility class for parsing an OpenStreetMap XML file. */
 public class XmlEntityReader implements OsmReader<Entity> {
 
+  private boolean geometry = false;
+
+  private int srid = 4326;
+
+  private DataMap<Long, Coordinate> coordinateMap;
+
+  private DataMap<Long, List<Long>> referenceMap;
+
+  public boolean geometries() {
+    return geometry;
+  }
+
+  public XmlEntityReader geometries(boolean geometries) {
+    this.geometry = geometries;
+    return this;
+  }
+
+  public int projection() {
+    return srid;
+  }
+
+  public XmlEntityReader projection(int srid) {
+    this.srid = srid;
+    return this;
+  }
+
+  public DataMap<Long, Coordinate> coordinateMap() {
+    return coordinateMap;
+  }
+
+  public XmlEntityReader coordinateMap(DataMap<Long, Coordinate> coordinateMap) {
+    this.coordinateMap = coordinateMap;
+    return this;
+  }
+
+  public DataMap<Long, List<Long>> referenceMap() {
+    return referenceMap;
+  }
+
+  public XmlEntityReader referenceMap(DataMap<Long, List<Long>> referenceMap) {
+    this.referenceMap = referenceMap;
+    return this;
+  }
+
   /**
    * Creates an ordered stream of OSM entities from a XML file.
    *
@@ -35,6 +90,19 @@ public class XmlEntityReader implements OsmReader<Entity> {
    * @return
    */
   public Stream<Entity> stream(InputStream input) {
-    return StreamSupport.stream(new XmlEntitySpliterator(input), false);
+    var entities = StreamSupport.stream(new XmlEntitySpliterator(input), false);
+    if (geometry) {
+      // Initialize and chain the entity handlers
+      var coordinateMapBuilder = new CoordinateMapBuilder(coordinateMap);
+      var referenceMapBuilder = new ReferenceMapBuilder(referenceMap);
+      var entityGeometryBuilder = new EntityGeometryBuilder(coordinateMap, referenceMap);
+      var entityProjectionTransformer = new EntityProjectionTransformer(4326, srid);
+      var entityHandler = coordinateMapBuilder
+              .andThen(referenceMapBuilder)
+              .andThen(entityGeometryBuilder)
+              .andThen(entityProjectionTransformer);
+      entities = entities.map(consumeThenReturn(entityHandler));
+    }
+    return entities;
   }
 }
diff --git a/baremaps-core/src/test/java/org/apache/baremaps/openstreetmap/OsmTestRunner.java b/baremaps-core/src/test/java/org/apache/baremaps/openstreetmap/OsmTestRunner.java
new file mode 100644
index 00000000..550cee9b
--- /dev/null
+++ b/baremaps-core/src/test/java/org/apache/baremaps/openstreetmap/OsmTestRunner.java
@@ -0,0 +1,224 @@
+package org.apache.baremaps.openstreetmap;
+
+import org.apache.baremaps.openstreetmap.model.Element;
+import org.apache.baremaps.openstreetmap.store.MockDataMap;
+import org.apache.baremaps.openstreetmap.xml.XmlEntityReader;
+import org.apache.baremaps.testing.TestFiles;
+import org.jetbrains.annotations.NotNull;
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.TestFactory;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.MultiPolygon;
+import org.locationtech.jts.io.WKTReader;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.DeserializationFeature;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.JsonNode;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+
+public class OsmTestRunner {
+
+    @TestFactory
+    public Stream<DynamicTest> runTestsFromFiles() throws IOException {
+        var directory = TestFiles.resolve("osm-testdata");
+        try (var files = Files.walk(directory)) {
+            return files.filter(f -> f.endsWith("test.json"))
+                    .map(OsmTest::new)
+                    .filter(OsmTest::isValid)
+                    .sorted()
+                    .map(this::createDynamicTest)
+                    .toList().stream();
+        }
+    }
+
+    @NotNull
+    private DynamicTest createDynamicTest(OsmTest testFile) {
+        var displayName = String.format("%s: %s", testFile.getId(), testFile.getDescription());
+        return DynamicTest.dynamicTest(displayName, () -> runTest(testFile));
+    }
+
+    public void runTest(OsmTest osmTest) {
+        try {
+            var elements = new XmlEntityReader()
+                    .coordinateMap(new MockDataMap<>())
+                    .referenceMap(new MockDataMap<>())
+                    .geometries(true)
+                    .stream(Files.newInputStream(osmTest.getOsmXml()))
+                    .filter(e -> e instanceof Element)
+                    .map(e -> (Element) e)
+                    .toList();
+
+            for (var element : elements) {
+                // Each element should have a geometry
+                var id = element.getId();
+                var fileGeometry = element.getGeometry();
+                assertNotNull(fileGeometry);
+
+                // Prepare the test geometry
+                var testWkt = osmTest.getWkts().get(id);
+                Geometry testGeometry = null;
+                try {
+                    testGeometry = new WKTReader().read(testWkt);
+                } catch (Exception e) {
+                    // ignore
+                }
+                if (testGeometry instanceof LineString lineString
+                        && lineString.isClosed()) {
+                    testGeometry = testGeometry.getFactory().createPolygon(lineString.getCoordinateSequence());
+                }
+                if (testGeometry instanceof MultiPolygon multiPolygon
+                    && multiPolygon.getNumGeometries() == 1) {
+                    testGeometry = multiPolygon.getGeometryN(0);
+                }
+
+                // The test geometry and the file geometry should be equal
+                assertTrue(String.format("The geometries are not equal\nExpected:\n%s\nActual:\n%s", testGeometry, fileGeometry), testGeometry.norm().equalsExact(fileGeometry.norm()));
+            }
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    private class OsmTest implements Comparable<OsmTest> {
+
+        private static final ObjectMapper objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+
+        private final Path jsonFile;
+
+        private final JsonNode testJson;
+
+        public OsmTest(Path jsonFile) {
+            this.jsonFile = jsonFile;
+            try {
+                this.testJson = objectMapper.readValue(jsonFile.toFile(), JsonNode.class);
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public Long getId() {
+            return testJson.get("test_id").asLong();
+        }
+
+        public String getDescription() {
+            return testJson.get("description").asText();
+        }
+
+        public Path getJsonFile() {
+            return jsonFile;
+        }
+
+        public Path getDirectory() {
+            return jsonFile.getParent();
+        }
+
+        public boolean isValid() {
+            try {
+                return Files.readString(getDirectory().resolve("result")).trim().equals("valid");
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public JsonNode getTestJson() {
+            return testJson;
+        }
+
+        public Map<Long, String> getWkts() {
+            var wkts = new HashMap<Long, String>();
+            wkts.putAll(getNodes());
+            wkts.putAll(getWays());
+            wkts.putAll(getRelations());
+            wkts.putAll(getAreas());
+            return wkts;
+        }
+
+        public Map<Long, String> getNodes() {
+            var wkts = new HashMap<Long, String>();
+            extractWktFile("nodes.wkt", wkts);
+            return wkts;
+        }
+
+        public Map<Long, String> getWays() {
+            var wkts = new HashMap<Long, String>();
+            extractWktFile("ways.wkt", wkts);
+            return wkts;
+        }
+
+        public Map<Long, String> getRelations() {
+            var wkts = new HashMap<Long, String>();
+            extractWktFile("relations.wkt", wkts);
+            return wkts;
+        }
+
+        public Map<Long, String> getAreas() {
+            var wkts = new HashMap<Long, String>();
+            if (testJson.has("areas")) {
+                var areas = testJson.get("areas");
+                extractAreas(areas, "default", wkts);
+                extractAreas(areas, "location", wkts);
+                extractAreas(areas, "fixed", wkts);
+                extractAreas(areas, "fix", wkts);
+            }
+            return wkts;
+        }
+
+        private void extractAreas(JsonNode areas, String name, Map<Long, String> wkts) {
+            if (areas.has(name)) {
+                var defaultAreas = areas.get(name);
+                if (defaultAreas.isArray()) {
+                    for (var area : defaultAreas) {
+                        if (area.has("wkt")) {
+                            var wkt = area.get("wkt").asText();
+                            var id = area.get("from_id").asLong();
+                            wkts.put(id, wkt);
+                        }
+                    }
+                }
+            }
+        }
+
+        private void extractWktFile(String wktFile, Map<Long, String> wkts) {
+            parseWkt(getDirectory().resolve(wktFile), wkts);
+        }
+
+        private void parseWkt(Path path, Map<Long, String> geometries) {
+            if (!Files.exists(path)) {
+                return;
+            }
+            try {
+                Files.lines(path).forEach(line -> {
+                    var needle = line.indexOf(' ');
+                    var id = Long.parseLong(line.substring(0, needle).strip());
+                    var wkt = line.substring(needle + 1).strip();
+                    geometries.put(id, wkt);
+                });
+            } catch (IOException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public Path getOsmXml() {
+            return getDirectory().resolve("data.osm");
+        }
+
+        public Path getOsmPbf() {
+            return getDirectory().resolve("data.osm.pbf");
+        }
+
+        @Override
+        public int compareTo(@NotNull OsmTestRunner.OsmTest o) {
+            return Long.compare(getId(), o.getId());
+        }
+    }
+}
diff --git a/baremaps-core/src/test/java/org/apache/baremaps/openstreetmap/store/MockDataMap.java b/baremaps-core/src/test/java/org/apache/baremaps/openstreetmap/store/MockDataMap.java
index 0b2477e6..f1059b50 100644
--- a/baremaps-core/src/test/java/org/apache/baremaps/openstreetmap/store/MockDataMap.java
+++ b/baremaps-core/src/test/java/org/apache/baremaps/openstreetmap/store/MockDataMap.java
@@ -19,6 +19,7 @@ package org.apache.baremaps.openstreetmap.store;
 
 
 
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 import org.apache.baremaps.database.collection.DataMap;
@@ -28,6 +29,10 @@ public class MockDataMap<K, T> extends DataMap<K, T> {
 
   private final Map<K, T> values;
 
+  public MockDataMap() {
+    this.values = new HashMap<>();
+  }
+
   public MockDataMap(Map<K, T> values) {
     this.values = values;
   }
diff --git a/baremaps-core/src/test/resources/osm-testdata/.github/workflows/ci.yml b/baremaps-core/src/test/resources/osm-testdata/.github/workflows/ci.yml
new file mode 100644
index 00000000..d8840712
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/.github/workflows/ci.yml
@@ -0,0 +1,19 @@
+name: CI
+
+on: [ push, pull_request ]
+
+jobs:
+  check:
+    name: Check
+    runs-on: ubuntu-20.04
+    steps:
+      - name: Install
+        run: sudo gem install json
+        shell: bash
+      - uses: actions/checkout@v2
+      - name: Test
+        run: |
+          ruby bin/concat-test-json.rb grid/data/*/*/test.json >/tmp/tests.json
+          diff -u grid/data/tests.json /tmp/tests.json
+        shell: bash
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/.gitignore b/baremaps-core/src/test/resources/osm-testdata/.gitignore
new file mode 100644
index 00000000..a01ee289
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/.gitignore
@@ -0,0 +1 @@
+.*.swp
diff --git a/baremaps-core/src/test/resources/osm-testdata/README.md b/baremaps-core/src/test/resources/osm-testdata/README.md
new file mode 100644
index 00000000..e8f8ee18
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/README.md
@@ -0,0 +1,34 @@
+
+# OpenStreetMap Test Data Repository
+
+OpenStreetMap data can be quite complex and software using the data difficult
+to test. This git repository contains various pieces of OSM data to be used for
+testing OSM software. The data is collected at this one location to help all
+OSM software projects. Each project still has to decide which tests to perform
+and how.
+
+## The Test Grid
+
+The `grid` directory contains OSM data organized by test category into a "grid".
+The tests are organized cleanly so that they can be easily used from automated
+tests. See that directory for more information.
+
+## XML Tests
+
+The `xml` directory contains OSM files to test OSM XML file parsers with.
+
+## Other Tests
+
+Other tests that don't fit into the "grid" schema are currently collected in
+the `misc` directory. In the future these tests might be organized better. As
+they are now, they are not really that useful for automated tests.
+
+## License
+
+All files are released into the public domain.
+
+## Author
+
+This repository was created and is maintained by Jochen Topf. Please use github
+issues to report bugs and request changes. Or better, send pull requests.
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/bin/compare-areas.rb b/baremaps-core/src/test/resources/osm-testdata/bin/compare-areas.rb
new file mode 100755
index 00000000..12b887a0
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/bin/compare-areas.rb
@@ -0,0 +1,256 @@
+#!/usr/bin/ruby
+#
+#  compare-areas.rb REFERENCE-JSON-FILE TEST-JSON-FILE
+#
+#  Compare the areas created by running the test program in the TEST-JSON-FILE
+#  to the areas described in the REFERENCE-JSON-FILE.
+#
+#  All geometries and tags from the reference data file are checked against
+#  geometries in the test data file. Results are printed in short form containing
+#  the test id and the word "OK" or "ERR" (in green or red, respectively).
+#
+#  More detailed (debug) output can be found in the file
+#  compare-areas.log.
+#
+
+require 'json'
+require 'open3'
+
+file = open(ARGV[0])
+reference_data = JSON.load(file, nil, {:symbolize_names => true, :create_additions => false})
+file.close
+
+file = open(ARGV[1])
+test_data = JSON.load(file, nil, {:symbolize_names => true, :create_additions => false})
+file.close
+
+LOG = open('compare-areas.log', 'w')
+LOG.puts "Running at #{Time.now}"
+
+def print_tags(tags)
+    tags.map{ |k,v|
+        "#{k}=#{v}"
+    }.join(', ')
+end
+
+# Compare set of reference and test tags given as hashes
+def compare_tags(ref, tst)
+    LOG.puts "    Comparing tags..."
+    if ref.nil?
+        if tst.nil?
+            LOG.puts "      No tags => OK"
+            return true
+        else
+            LOG.puts "      Has tags but ref does not => ERR"
+            return false
+        end
+    end
+
+    if tst.nil?
+        LOG.puts "      Missing tags (#{ print_tags(ref) }) => ERR"
+        return false
+    end
+
+    refcpy = ref
+    ref.each do |k,v|
+        if tst[k] != v
+            LOG.puts "      Tag key '#{k}' should be '#{v}' but is '#{tst[k]}' => ERR"
+            return false
+        end
+        tst.delete k
+        refcpy.delete k
+    end
+
+    if refcpy.size != 0
+        LOG.puts "      Missing tags (#{ print_tags(refcpy) }) => ERR"
+        return false
+    end
+
+    if tst.size != 0
+        LOG.puts "      Additional tags (#{ print_tags(tst) }) => ERR"
+        return false
+    end
+
+    LOG.puts '      Tags match => OK'
+    return true
+end
+
+def spatial_sql(query)
+    $sl_stdin.puts(query)
+    res = ''
+    err = ''
+    timeout = 10
+    while true do
+        r = IO.select([$sl_stdout ,$sl_stderr], [], [], timeout)
+        if r.nil?
+            if err != ''
+                LOG.puts err
+            end
+            return res.chomp!
+        end
+        begin
+            if r[0][0] == $sl_stdout
+                res += $sl_stdout.read_nonblock(10000)
+                timeout = 0.001
+            elsif r[0][0] == $sl_stderr
+                err += $sl_stderr.read_nonblock(10000)
+            end
+        rescue IO::WaitReadable, IO::EWOULDBLOCKWaitReadable
+            # ignore
+        end
+    end
+end
+
+def compare_wkt(ref, test)
+    if ref == 'INVALID' && test == 'INVALID'
+       return 0, "both INVALID => OK"
+    end
+    if ref == test
+       return 0, "geoms identical => OK"
+    end
+    if ref == 'INVALID'
+       return 2, "should be INVALID => ERR"
+    end
+    if test == 'INVALID'
+       return 2, "should not be INVALID => ERR"
+    end
+
+    LOG.puts "Testing reference WKT [#{ref}]:"
+    rwkt_ref = spatial_sql("SELECT IsValid(GeomFromText('#{ref}', 4326));")
+    if rwkt_ref != "1"
+      LOG.puts "  Reference geometry is invalid. result: #{rwkt_ref}"
+      return 3, "reference geometry is invalid => ERR"
+    end
+    LOG.puts "  Geometry valid"
+
+    LOG.puts "Testing test WKT [#{test}]:"
+    rwkt_test = spatial_sql("SELECT IsValid(GeomFromText('#{test}', 4326));")
+    if rwkt_test != "1"
+      LOG.puts "  Test geometry is invalid. result: #{rwkt_test}"
+      return 3, "test geometry is invalid => ERR"
+    end
+    LOG.puts "  Geometry valid"
+
+    result = spatial_sql("SELECT Equals(GeomFromText('#{ref}', 4326), GeomFromText('#{test}', 4326));")
+    return 1, "geoms equal => OK" if result == "1"
+    return 2, "geoms different => ERR" if result == "0"
+    return 3, "unknown failure => ERR"
+end
+
+# Compare reference and test geometries given as WKT
+def compare_geom(ref, tst)
+    LOG.puts "    Comparing geometries..."
+    result, msg = compare_wkt(ref, tst)
+    LOG.puts "      #{msg}"
+    return result <= 1
+end
+
+# Compare all aspects of reference to test area
+def compare_area(area, t)
+    geom_okay = compare_geom(area[:wkt], t[:wkt])
+    tags_okay = compare_tags(area[:tags], t[:tags])
+    from_okay = (area[:from_id] == t[:from_id] && area[:from_type] == t[:from_type])
+
+    return geom_okay && tags_okay && from_okay
+end
+
+
+def check_variant(variant, areas, td)
+    LOG.puts "  Checking variant #{variant}:"
+
+    used_areas = {}
+
+    td.each_with_index do |t, tindex|
+        areas.select{ |area| !used_areas[area] }.each do |area|
+            LOG.puts "    Checking test area ##{tindex} against reference area ##{area[:index]}..."
+            result = compare_area(area, t)
+            if result
+                used_areas[area] = true
+                break
+            end
+        end
+    end
+
+    if used_areas.size != areas.size
+        LOG.puts "    Not all areas created => ERR"
+        return false
+    end
+
+    if td.size != areas.size
+        LOG.puts "    More areas in test data than in reference data => ERR"
+        return false
+    end
+
+    true
+end
+
+result_all = true
+
+$sl_stdin, $sl_stdout, $sl_stderr, $wait_thr = Open3.popen3('spatialite', '-batch', '-bail', ':memory:')
+
+# spatialite will print put some stuff when starting up, ignore it
+$sl_stdin.puts("SELECT 'COMPARE_AREAS_START';");
+while ($sl_stdout.gets() !~ /COMPARE_AREAS_START/) do
+end
+
+begin
+    $sl_stderr.read_nonblock(10000);
+rescue IO::WaitReadable, IO::EWOULDBLOCKWaitReadable
+    # ignore
+end
+
+# Get all the test cases from the reference data and check all that
+# have area information in turn
+reference_data.select{ |ref| ref[:areas] }.each do |ref|
+
+    # Number each area in each variant (for debugging output)
+    ref[:areas].each do |variant, areas|
+        areas.each_with_index do |area, index|
+            area[:index] = index
+        end
+    end
+
+    LOG.puts "\n============================\nTesting id #{ref[:test_id]}:"
+    if ref[:test_id] % 100 == 0
+        puts
+    end
+    if ref[:test_id] % 10 == 0
+        puts
+    end
+    print "#{ref[:test_id]}..."
+
+    # find all test data for this test id
+    td = test_data.select do |td|
+        td[:test_id] == ref[:test_id]
+    end
+
+    if !td
+        STDERR.puts "Missing test data for test id #{ref[:id]}\n"
+        exit 1
+    end
+
+    # check each variant
+    result = ref[:areas].map{ |variant, areas|
+        variant_result = check_variant(variant, areas, td)
+        LOG.puts "  Variant result: #{ variant_result ? 'OK' : 'ERR' }"
+        variant_result
+    }.include?(true)
+
+    LOG.puts "Final result: #{ result ? 'OK ' : 'ERR' }"
+    if ENV['OS']=~/Windows.*/ then
+       print "#{ result ? 'OK ' : 'ERR' }  "
+    else
+       print "\033[1;#{ result ? '32mOK ' : '31mERR' }\033[0m  "
+    end
+    result_all = result_all && result
+end
+
+$sl_stdin.close
+$sl_stdout.close
+$sl_stderr.close
+
+puts
+
+LOG.close
+
+exit 1 unless result_all
diff --git a/baremaps-core/src/test/resources/osm-testdata/bin/compare-wkt.sh b/baremaps-core/src/test/resources/osm-testdata/bin/compare-wkt.sh
new file mode 100755
index 00000000..3a6c3f99
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/bin/compare-wkt.sh
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+#  compare-wkt.sh WKT_REF WKT_TEST
+#
+#  Compares the reference and the test geometries given on the command line
+#  in WKT format.
+#
+#  Outputs a line to STDOUT ending in "OK" or "ERR" to show whether the test
+#  succeeded or failed. More detailed information is written to STDERR.
+#
+#  Returns
+#  0 - if the geometries are identical
+#  1 - if the geometries are geometrically equivalent
+#  2 - if the geometries are different
+#  3 - if at least one of the geometries is broken
+#
+#  Instead of a WKT geometry the string "INVALID" can also be given which only
+#  compares equal to another "INVALID".
+#
+
+set -e
+#set -x
+
+WKT_REF=$1
+WKT_TEST=$2
+
+DATABASE=compare-wkt-tmp-$$.db
+
+if [ "$WKT_REF" = "INVALID" -a "$WKT_TEST" = "INVALID" ]; then
+    echo "both INVALID => OK"
+    exit 0
+fi
+
+if [ "$WKT_REF" = "$WKT_TEST" ]; then
+    echo "geoms identical => OK"
+    exit 0
+fi
+
+if [ "$WKT_REF" = "INVALID" ]; then
+    echo "should be INVALID => ERR"
+    exit 2
+fi
+
+if [ "$WKT_TEST" = "INVALID" ]; then
+    echo "should not be INVALID => ERR"
+    exit 2
+fi
+
+echo "Testing reference WKT [$WKT_REF]:" 1>&2
+rwkt_ref=`spatialite -batch -bail $DATABASE "SELECT IsValid(GeomFromText('$WKT_REF', 4326));" | tail -1`
+if [ "$rwkt_ref" != "1" ]; then
+    echo "reference geometry is invalid => ERR"
+    echo "  Reference geometry is invalid. result: $rwkt_ref" 1>&2
+    rm -f $DATABASE
+    exit 3
+fi
+
+echo "  Geometry valid" 1>&2
+
+echo "Testing test WKT [$WKT_TEST]:" 1>&2
+rwkt_test=`spatialite -batch -bail $DATABASE "SELECT IsValid(GeomFromText('$WKT_TEST', 4326));" | tail -1`
+if [ "$rwkt_test" != "1" ]; then
+    echo "test geometry is invalid => ERR"
+    echo "  Test geometry is invalid. result: $rwkt_test" 1>&2
+    rm -f $DATABASE
+    exit 3
+fi
+
+echo "  Geometry valid" 1>&2
+
+result=`spatialite -batch -bail $DATABASE "SELECT Equals(GeomFromText('$WKT_REF', 4326), GeomFromText('$WKT_TEST', 4326));" | tail -1`
+rm -f $DATABASE
+
+if [ "$result" = "1" ]; then
+    echo "geoms equal => OK"
+    exit 1
+fi
+
+if [ "$result" = "0" ]; then
+    echo "geoms different => ERR"
+    exit 2
+fi
+
+echo "unknown failure => ERR"
+exit 3
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/bin/concat-test-json.rb b/baremaps-core/src/test/resources/osm-testdata/bin/concat-test-json.rb
new file mode 100755
index 00000000..bc0f8dc4
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/bin/concat-test-json.rb
@@ -0,0 +1,31 @@
+#!/usr/bin/ruby
+#
+#  concat-test-json.rb JSON-FILE..
+#
+#  Concatenate given files in JSON format into one big JSON file containing an
+#  array of the contents of the input files. The result is written to stdout.
+#  This also checks that the test_id in the input files matches the file name.
+#
+
+require 'json'
+
+array = ARGV.sort.map do |filename|
+    id = filename.sub(%r{/test\.json$}, '').sub(%r{.*/}, '').to_i
+    open(filename) do |file|
+        data = JSON.load(file)
+
+        if data['test_id'] != id
+            STDERR.puts "File #{filename} should contain test with id #{id}, but instead contains test_id: #{data['test_id']}"
+            exit 1
+        end
+
+        if ! data['description']
+            STDERR.puts "WARNING! Missing description for test #{id}."
+        end
+
+        data
+    end
+end
+
+puts JSON.pretty_generate(array)
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/.gitignore b/baremaps-core/src/test/resources/osm-testdata/grid/.gitignore
new file mode 100644
index 00000000..0f528e7b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/.gitignore
@@ -0,0 +1,7 @@
+data-files.xml
+data-labels.sql
+data-multipolygons.sql
+data-nodes.sql
+data-ways.sql
+grid.sql
+tests.qgs~
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/Makefile b/baremaps-core/src/test/resources/osm-testdata/grid/Makefile
new file mode 100644
index 00000000..92436734
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/Makefile
@@ -0,0 +1,53 @@
+
+# You need osmium tool from https://github.com/osmcode/osmium-tool for this
+OSMIUM := ../../osmium-tool/osmium
+
+SQL_FILES := grid.sql data-nodes.sql data-ways.sql data-multipolygons.sql data-labels.sql
+
+.PHONY: grid data all clean show create-wkt
+
+all: grid data
+
+grid: grid.db
+
+grid.sql: data/? bin/create-grid.sh
+	bin/create-grid.sh `find data -mindepth 1 -maxdepth 1 -type d | cut -d/ -f2 | cut -d- -f1 | sort` >$@
+
+data-nodes.sql: data/*/*/nodes.wkt
+	cat $^ | sed -re "s/^([0-9][0-9][0-9])([0-9][0-9][0-9]) (.*)/INSERT INTO nodes (test_id, id, geom) VALUES (\1, \1\2, PointFromText('\3', 4326));/" >$@
+
+data-ways.sql: data/*/*/ways.wkt
+	cat $^ | sed -re "s/^([0-9][0-9][0-9])([0-9][0-9][0-9]) (.*)/INSERT INTO ways (test_id, id, geom) VALUES (\1, \1\2, LineFromText('\3', 4326));/" >$@
+
+data-multipolygons.sql: data/tests.json
+	bin/create-sql-for-multipolygons.rb $< >$@
+
+data-labels.sql: data/*/*/labels.wkt
+	cat $^ | sed -re "s/^(POINT\([0-9. ]+\)) (.*)/INSERT INTO labels (label, geom) VALUES ('\2', PointFromText('\1', 4326));/" >$@
+
+grid.db: setup.sql $(SQL_FILES)
+	rm -f $@
+	cat $^ | spatialite -batch -bail $@
+
+data: data/all.osm data/tests.json
+
+data-files.xml: data/*/*/data.osm
+	echo '<?xml version="1.0" encoding="utf-8"?><files>' >$@
+	find data -name data.osm | sort | sed -e 's/^/<file name="/' -e 's/$$/"\/>/' >>$@
+	echo "</files>" >>$@
+
+data/tests.json: data/*/*/test.json
+	../bin/concat-test-json.rb $^ >$@
+
+data/all.osm: data/*/*/data.osm data-files.xml
+	xsltproc --output $@ bin/concat.xsl data-files.xml
+
+show:
+	bin/show-tests.sh
+
+create-wkt:
+	bin/create-wkt.sh
+
+clean:
+	rm -f grid.db $(SQL_FILES) data-files.xml data/all.osm data/tests.json tests.qgs~
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/README.md b/baremaps-core/src/test/resources/osm-testdata/grid/README.md
new file mode 100644
index 00000000..22388b03
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/README.md
@@ -0,0 +1,154 @@
+
+# Test Grid
+
+This directory contains syntactically valid OSM data files with semantically
+valid and invalid objects. It can be used to test any OSM software.
+
+![The multipolygon tests in the grid](multipolygon-tests.png)
+
+## Organization of the Test Files
+
+All test data is in the `data` directory. In it you'll find subdirectories for
+different categories of tests. Below them there is a numbered directory for each
+test.
+
+Test data from different tests uses different ID spaces and distinct geographic
+areas. So when tests are used together their data must never interfere with
+each other.
+
+## Test Categories
+
+Currently there are the following test categories, more will be added in the
+future.
+
+* 1 - Basic Geometry Tests
+* 3 - Attribute Tests
+* 7 - Multipolygon Geometry Tests
+* 9 - Multipolygon Roles/Tags Tests. Some of these test contain old-style
+      multipolygons. They will fail against newer code that doesn't know
+      about them.
+
+## Test Cases
+
+Each test case is in its own directory. It contains the following files:
+
+* `data.osm` - the test data itself
+* `test.json` - description and further data about the testcase
+* `result` - contains either the word "valid" or "invalid" to signify
+  whether the data in the file is valid, ie it must be parseable by any OSM
+  software, or invalid, in which case the handling of the data is unspecified.
+* `nodes.wkt` (optional) - geometry of all nodes in data.osm in WKT format
+* `ways.wkt` (optional) - geometry of all ways in data.osm in WKT format
+* `labels.wkt` (optional) - labels for documentation of test cases
+
+## ID Space Used
+
+OSM IDs in the tests are used as follows:
+
+All IDs start with the three-digit test number, for instance 711 and end with
+the three-digit object ID. Nodes are numbered from 000, ways from 800 and
+relations from 900. So there are enough IDs in each test for 800 nodes, 100
+ways, and 100 relations.
+
+## Geometries
+
+Node coordinates for all tests in one test category are always inside a
+bounding box with one degree width and height. The position of the bounding box
+is given by the test number.
+
+Example: All tests numbered 7xx are inside the bounding box (7.0 1.0, 8.0 2.0).
+
+Individual tests are inside those in a bounding box with 0.1 degree width and
+height. They are arranged in a 10x10 square. So test 700 is in
+(7.0 1.0, 7.1 1.1), 701 is in (7.1 1.0, 7.2 1.1), 710 is in (7.0 1.1, 7.1 1.2).
+
+## The `test.json` File
+
+Each test directory contains a `test.json` file which contains the metadata
+describing the test. It always contains the unique `test_id` and a
+`description` field which contains a human language description of the test.
+
+For multipolygon tests (7xx and 9xx) this JSON file also contains an `area`
+field with further details. Multipolygons are complex and often broken in OSM.
+Any software working with OSM data can decide whether to be strict and only
+work with properly formatted data, or it can work with with the existing data
+and fix it as best as it can. Some test cases that have broken data, take this
+into account and provide both, a description of the test results when
+interpreting the test case strictly and one description describing the results
+after some clever fixing of the data. These are the `default` case and the
+`fix` or `location` case. You can find them in the `areas` section of the JSON
+file. (The difference between the `fix` and the `location` case is that
+`location` cases are easily fixable if the software compares node locations
+instead of only node IDs.)
+
+Each of those `default` and `fix` cases contains an array of objects describing
+the areas that the test case will generate with the following information:
+
+* `from_type` - The type of top-level object this areas was created from (`way`
+  or `relation`)
+* `from_id` - The ID of the object this area was created from.
+* `wkt` - The geometry of the multipolygon in WKT format. You have to take
+  into account that there are several possible WKT descriptions for
+  geometrically identical geometries. So a simple text comparison with the
+  results of your text run is not enough. This can also be the special word
+  `INVALID` if a correct geometry can not be built.
+* `tags` - The OSM tags the resulting area will have.
+
+## WKT Files
+
+Each test case can contain its nodes and ways in WKT format. To generate those
+`nodes.wkt` and `ways.wkt` files, run `make create-wkt`. This will read the
+`data.osm` files and create the WKT files. Note that the output may not be
+correct so you should check those files!
+
+## Label Nodes
+
+Interesting points in the data can be labeled by adding an optional
+`labels.wkt` file containing a point in WKT format and a label. Test software
+is not required to read these, but they can be used when visualizing tests for
+instance. Format example:
+
+`POINT(1.2 4.3) This is an important point`
+
+## Concatenated Test Files
+
+For your convenience the `data` directory contains the files `all.osm` and
+`tests.json` which are a concatenation of all the individual `data.osm` and
+`test.json` files, respectively. Depending on your test setup, this might make
+it easier to work with many (or all) tests at the same time.
+
+If you change any of the tests or add new ones, you can re-create those files
+by running `make data/all.osm` and `make data/tests.json`.
+
+## Spatialite Database
+
+A Spatialite file `grid.db` is provided that contains this grid for the existing
+test cases, test title, labels from `labels.wkt` files and all nodes, ways, and
+multipolygons from the `nodes.wkt`, `ways.wkt`, and `multipolygons.wkt` files,
+respectively.
+
+It can be re-created by calling `make grid`.
+
+## QGIS Project File
+
+A QGIS project file is provided at `tests.qgs`. It shows the data from `grid.db`.
+
+## Creating Tests
+
+Unfortunately there is no easy way to create tests with JOSM or other software.
+You just don't have enough control over the contents of the data file unless
+you write it by hand.
+
+The easiest way is probably something like this:
+* draw the test case on a piece of paper with grid lines
+* number all nodes
+* number all used grid lines on x and y axis
+* create directory for new test
+* copy over `data.osm` from another test, globally search-and-replace test id
+* add/edit nodes, ways, relations as needed
+* add `test.json`, `result`, and wkt files
+
+## License
+
+All files are released into the public domain.
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/bin/concat.xsl b/baremaps-core/src/test/resources/osm-testdata/grid/bin/concat.xsl
new file mode 100644
index 00000000..3e612889
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/bin/concat.xsl
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+    <xsl:output method="xml" encoding="utf-8" indent="yes"/>
+
+    <xsl:template match="/">
+<osm version="0.6" generator="testdata" upload="false">
+        <xsl:apply-templates select="files/file" mode="nodes"/>
+        <xsl:apply-templates select="files/file" mode="ways"/>
+        <xsl:apply-templates select="files/file" mode="relations"/>
+</osm>
+    </xsl:template>
+
+    <xsl:template match="files/file" mode="nodes">
+        <xsl:copy-of select="document(@name)/osm/node"/>
+    </xsl:template>
+
+    <xsl:template match="files/file" mode="ways">
+        <xsl:copy-of select="document(@name)/osm/way"/>
+    </xsl:template>
+
+    <xsl:template match="files/file" mode="relations">
+        <xsl:copy-of select="document(@name)/osm/relation"/>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/bin/create-grid.sh b/baremaps-core/src/test/resources/osm-testdata/grid/bin/create-grid.sh
new file mode 100755
index 00000000..0539e314
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/bin/create-grid.sh
@@ -0,0 +1,40 @@
+#!/bin/sh
+#
+#  create-grid.sh TEST-CATEGORY...
+#
+#  Create "grid" of polygons showing the areas of the tests.
+#
+#  Call with the numbers of the test categories the grid
+#  shall show, for instance:
+#
+#  bin/create-grid.sh 1 7
+#
+
+for t in $*; do
+    title=`cat data/$t/description.txt`
+    echo "INSERT INTO titles (title, geom) VALUES ('${t}. ${title}', LineFromText('LINESTRING(${t}.0 2.1,${t}.9999 2.1)', 4326));\n"
+    for y in `seq 0 9`; do
+        for x in `seq 0 9`; do
+            if [ -d data/$t/$t$y$x ]; then
+                available=1
+                if [ -f data/$t/$t$y$x/result ]; then
+                    result=`cat data/$t/$t$y$x/result`
+                else
+                    result=""
+                fi
+                if [ -f data/$t/$t$y$x/description.txt ]; then
+                    description=`cat data/$t/$t$y$x/description.txt`
+                else
+                    description=""
+                fi
+            else
+                available=0
+                result=""
+                description=""
+            fi
+            echo "INSERT INTO grid (test_id, geom, available, result, description) VALUES ($t$y$x, Envelope(LineFromText('LINESTRING(${t}.${x} 1.${y},${t}.${x}9999 1.${y}9999)', 4326)), ${available}, '${result}', '${description}');"
+        done
+        echo
+    done
+done
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/bin/create-sql-for-multipolygons.rb b/baremaps-core/src/test/resources/osm-testdata/grid/bin/create-sql-for-multipolygons.rb
new file mode 100755
index 00000000..45818899
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/bin/create-sql-for-multipolygons.rb
@@ -0,0 +1,26 @@
+#!/usr/bin/ruby
+#
+#  create-sql-for-multipolygons.rb REFERENCE-JSON-FILE
+#
+#  Reads the given reference JSON file and creates the
+#  SQL commands to create all multipolygons contained
+#  in the file. The SQL commands are written to stdout.
+#
+
+require 'json'
+
+open(ARGV[0]) do |file|
+    reference_data = JSON.load(file, nil)
+    reference_data.each do |test|
+        if test['areas']
+            test['areas'].each do |k,v|
+                v.each do |result|
+                    if result['wkt'] != 'INVALID'
+                        puts "INSERT INTO multipolygons (test_id, id, from_type, variant, geom) VALUES (#{test['test_id']}, #{result['from_id']}, '#{result['from_type'][0]}', '#{k}', MultiPolygonFromText('#{result['wkt']}', 4326));"
+                    end
+                end
+            end
+        end
+    end
+end
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/bin/create-wkt.sh b/baremaps-core/src/test/resources/osm-testdata/grid/bin/create-wkt.sh
new file mode 100755
index 00000000..081a5f69
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/bin/create-wkt.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+#  create-wkt.sh
+#
+#  This script will generate possible nodes.wkt and ways.wkt files
+#  from the data.osm file. YOU HAVE TO CHECK THE OUTPUT, BECAUSE
+#  THIS SCRIPT MIGHT NOT ALWAYS DO THE RIGHT THING!
+#
+
+for t in data/?/???; do
+    xsltproc bin/osm2nodes_wkt.xsl $t/data.osm >$t/nodes.wkt
+
+    if [ ! -s $t/nodes.wkt ]; then
+        rm $t/nodes.wkt
+    fi
+
+    xsltproc bin/osm2ways_wkt.xsl $t/data.osm | \
+        # remove duplicate coordinates
+        sed -re 's/([0-9.]+ [0-9.]+),\1/\1/' | \
+        # remove linestrings with single coordinate
+        egrep -v 'LINESTRING\([0-9.]+ [0-9.]+\)' \
+        >$t/ways.wkt
+
+    if [ ! -s $t/ways.wkt ]; then
+        rm $t/ways.wkt
+    fi
+done
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/bin/osm2nodes_wkt.xsl b/baremaps-core/src/test/resources/osm-testdata/grid/bin/osm2nodes_wkt.xsl
new file mode 100644
index 00000000..2842a8db
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/bin/osm2nodes_wkt.xsl
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+    <xsl:output method="text" encoding="utf-8" indent="no"/>
+
+    <xsl:template match="/">
+        <xsl:apply-templates select="/osm/node"/>
+    </xsl:template>
+
+    <xsl:template match="/osm/node">
+        <xsl:value-of select="@id"/>
+        <xsl:text> POINT(</xsl:text>
+        <xsl:value-of select="@lon"/>
+        <xsl:text> </xsl:text>
+        <xsl:value-of select="@lat"/>
+        <xsl:text>)
+</xsl:text>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/bin/osm2ways_wkt.xsl b/baremaps-core/src/test/resources/osm-testdata/grid/bin/osm2ways_wkt.xsl
new file mode 100644
index 00000000..8b9e5130
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/bin/osm2ways_wkt.xsl
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+
+    <xsl:output method="text" encoding="utf-8" indent="no"/>
+
+    <xsl:key name="nodes" match="/osm/node" use="@id"/>
+
+    <xsl:template match="/">
+        <xsl:apply-templates select="/osm/way"/>
+    </xsl:template>
+
+    <xsl:template match="/osm/way">
+        <xsl:if test="count(nd) &gt; 1">
+            <xsl:value-of select="@id"/>
+            <xsl:text> LINESTRING(</xsl:text>
+            <xsl:apply-templates select="nd"/>
+            <xsl:text>)
+</xsl:text>
+        </xsl:if>
+    </xsl:template>
+
+    <xsl:template match="/osm/way/nd">
+        <xsl:value-of select="key('nodes', @ref)/@lon"/>
+        <xsl:text> </xsl:text>
+        <xsl:value-of select="key('nodes', @ref)/@lat"/>
+        <xsl:if test="position()!=last()">
+            <xsl:text>,</xsl:text>
+        </xsl:if>
+    </xsl:template>
+
+</xsl:stylesheet>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/bin/show-tests.sh b/baremaps-core/src/test/resources/osm-testdata/grid/bin/show-tests.sh
new file mode 100755
index 00000000..051b5d92
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/bin/show-tests.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+#  show-tests.sh
+#
+
+set -e
+
+tests=`find data -mindepth 2 -maxdepth 2 -type d | sed -s 's/data\///' | sort`
+
+for t in $tests; do
+    cat_no=${t%%/*}
+    test_id=${t#*/}
+    if [ -f data/$t/result ]; then
+        result=`cat data/$t/result`
+    else
+        result="UNKNOWN RESULT"
+    fi
+    printf "%1s %3s %-7s %s\n" $cat_no $test_id $result
+done
+
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/data.osm
new file mode 100644
index 00000000..6faa0199
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="100000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.02" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/data.osm.pbf
new file mode 100644
index 00000000..e37aaf43
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/nodes.wkt
new file mode 100644
index 00000000..208ba996
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/nodes.wkt
@@ -0,0 +1 @@
+100000 POINT(1.02 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/test.json
new file mode 100644
index 00000000..95b75173
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/100/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 100,
+    "description": "A single node"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/data.osm
new file mode 100644
index 00000000..21ead2c2
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/data.osm
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="101000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.12" lat="1.02"/>
+    <node id="101001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.12" lat="1.03"/>
+    <node id="101002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.14" lat="1.04"/>
+    <node id="101003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.15" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/data.osm.pbf
new file mode 100644
index 00000000..0e0dc2ce
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/nodes.wkt
new file mode 100644
index 00000000..3359c731
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/nodes.wkt
@@ -0,0 +1,4 @@
+101000 POINT(1.12 1.02)
+101001 POINT(1.12 1.03)
+101002 POINT(1.14 1.04)
+101003 POINT(1.15 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/test.json
new file mode 100644
index 00000000..1baf5b37
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/101/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 101,
+    "description": "Four nodes"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/data.osm
new file mode 100644
index 00000000..4655f3ab
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/data.osm
@@ -0,0 +1,5 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="102000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.24" lat="1.02"/>
+    <node id="102001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.24" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/data.osm.pbf
new file mode 100644
index 00000000..c4185cb1
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/nodes.wkt
new file mode 100644
index 00000000..ca5f0c5c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/nodes.wkt
@@ -0,0 +1,2 @@
+102000 POINT(1.24 1.02)
+102001 POINT(1.24 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/test.json
new file mode 100644
index 00000000..b84d9874
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/102/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 102,
+    "description": "Two nodes at same location"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/data.osm
new file mode 100644
index 00000000..f9c5bb59
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/data.osm
@@ -0,0 +1,11 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="110000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.02" lat="1.12"/>
+    <node id="110001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.07" lat="1.13"/>
+    <way id="110800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="110000"/>
+        <nd ref="110001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="110"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/data.osm.pbf
new file mode 100644
index 00000000..94315726
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/nodes.wkt
new file mode 100644
index 00000000..3f2bd998
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/nodes.wkt
@@ -0,0 +1,2 @@
+110000 POINT(1.02 1.12)
+110001 POINT(1.07 1.13)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/test.json
new file mode 100644
index 00000000..042d8e9a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 110,
+    "description": "Way with two nodes"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/ways.wkt
new file mode 100644
index 00000000..25ef0880
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/110/ways.wkt
@@ -0,0 +1 @@
+110800 LINESTRING(1.02 1.12,1.07 1.13)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/data.osm
new file mode 100644
index 00000000..cb6c7178
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/data.osm
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="111000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.11" lat="1.11"/>
+    <node id="111001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.12" lat="1.13"/>
+    <node id="111002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.13" lat="1.12"/>
+    <node id="111003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.19" lat="1.15"/>
+    <way id="111800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="111000"/>
+        <nd ref="111001"/>
+        <nd ref="111002"/>
+        <nd ref="111003"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="111"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/data.osm.pbf
new file mode 100644
index 00000000..3e0b5532
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/nodes.wkt
new file mode 100644
index 00000000..65f888ac
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/nodes.wkt
@@ -0,0 +1,4 @@
+111000 POINT(1.11 1.11)
+111001 POINT(1.12 1.13)
+111002 POINT(1.13 1.12)
+111003 POINT(1.19 1.15)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/test.json
new file mode 100644
index 00000000..612c5e93
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 111,
+    "description": "Way with four nodes"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/ways.wkt
new file mode 100644
index 00000000..496e3a5a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/111/ways.wkt
@@ -0,0 +1 @@
+111800 LINESTRING(1.11 1.11,1.12 1.13,1.13 1.12,1.19 1.15)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/data.osm
new file mode 100644
index 00000000..ac8e7342
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/data.osm
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="112000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.21" lat="1.11"/>
+    <node id="112001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.21" lat="1.17"/>
+    <node id="112002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.27" lat="1.17"/>
+    <node id="112003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.27" lat="1.12"/>
+    <way id="112800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="112000"/>
+        <nd ref="112001"/>
+        <nd ref="112002"/>
+        <nd ref="112003"/>
+        <nd ref="112000"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="112"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/data.osm.pbf
new file mode 100644
index 00000000..b41cf2a1
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/nodes.wkt
new file mode 100644
index 00000000..79299b31
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/nodes.wkt
@@ -0,0 +1,4 @@
+112000 POINT(1.21 1.11)
+112001 POINT(1.21 1.17)
+112002 POINT(1.27 1.17)
+112003 POINT(1.27 1.12)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/test.json
new file mode 100644
index 00000000..b0b19a60
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 112,
+    "description": "Closed way with four nodes"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/ways.wkt
new file mode 100644
index 00000000..07ec9018
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/112/ways.wkt
@@ -0,0 +1 @@
+112800 LINESTRING(1.21 1.11,1.21 1.17,1.27 1.17,1.27 1.12,1.21 1.11)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/data.osm
new file mode 100644
index 00000000..0641a7eb
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/data.osm
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="113000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.32" lat="1.12"/>
+    <node id="113001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.34" lat="1.13"/>
+    <node id="113002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.37" lat="1.12"/>
+    <node id="113003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.38" lat="1.18"/>
+    <way id="113800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="113000"/>
+        <nd ref="113001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="113"/>
+    </way>
+    <way id="113801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="113002"/>
+        <nd ref="113003"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="113"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/data.osm.pbf
new file mode 100644
index 00000000..c1b33fc3
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/nodes.wkt
new file mode 100644
index 00000000..ff17b205
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/nodes.wkt
@@ -0,0 +1,4 @@
+113000 POINT(1.32 1.12)
+113001 POINT(1.34 1.13)
+113002 POINT(1.37 1.12)
+113003 POINT(1.38 1.18)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/test.json
new file mode 100644
index 00000000..407a77cc
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 113,
+    "description": "Two separate ways"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/ways.wkt
new file mode 100644
index 00000000..9363f338
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/113/ways.wkt
@@ -0,0 +1,2 @@
+113800 LINESTRING(1.32 1.12,1.34 1.13)
+113801 LINESTRING(1.37 1.12,1.38 1.18)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/data.osm
new file mode 100644
index 00000000..3e933a74
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/data.osm
@@ -0,0 +1,18 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="114000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.42" lat="1.12"/>
+    <node id="114001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.44" lat="1.13"/>
+    <node id="114002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.48" lat="1.11"/>
+    <way id="114800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="114000"/>
+        <nd ref="114001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="114"/>
+    </way>
+    <way id="114801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="114001"/>
+        <nd ref="114002"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="114"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/data.osm.pbf
new file mode 100644
index 00000000..f15d5032
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/nodes.wkt
new file mode 100644
index 00000000..e260f0af
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/nodes.wkt
@@ -0,0 +1,3 @@
+114000 POINT(1.42 1.12)
+114001 POINT(1.44 1.13)
+114002 POINT(1.48 1.11)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/test.json
new file mode 100644
index 00000000..c8fbf562
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 114,
+    "description": "Two ways connected end-to-beginning"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/ways.wkt
new file mode 100644
index 00000000..70386fcd
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/114/ways.wkt
@@ -0,0 +1,2 @@
+114800 LINESTRING(1.42 1.12,1.44 1.13)
+114801 LINESTRING(1.44 1.13,1.48 1.11)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/data.osm
new file mode 100644
index 00000000..c76dcafc
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/data.osm
@@ -0,0 +1,18 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="115000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.52" lat="1.12"/>
+    <node id="115001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.54" lat="1.13"/>
+    <node id="115002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.58" lat="1.11"/>
+    <way id="115800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="115000"/>
+        <nd ref="115001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="115"/>
+    </way>
+    <way id="115801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="115002"/>
+        <nd ref="115001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="115"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/data.osm.pbf
new file mode 100644
index 00000000..d6ac03ef
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/nodes.wkt
new file mode 100644
index 00000000..eca95d95
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/nodes.wkt
@@ -0,0 +1,3 @@
+115000 POINT(1.52 1.12)
+115001 POINT(1.54 1.13)
+115002 POINT(1.58 1.11)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/test.json
new file mode 100644
index 00000000..997c565b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 115,
+    "description": "Two ways connected end-to-end"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/ways.wkt
new file mode 100644
index 00000000..0564f613
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/115/ways.wkt
@@ -0,0 +1,2 @@
+115800 LINESTRING(1.52 1.12,1.54 1.13)
+115801 LINESTRING(1.58 1.11,1.54 1.13)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/data.osm
new file mode 100644
index 00000000..837cb021
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/data.osm
@@ -0,0 +1,28 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="116000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.62" lat="1.12"/>
+    <node id="116001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.64" lat="1.13"/>
+    <node id="116002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.68" lat="1.11"/>
+    <node id="116003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.68" lat="1.17"/>
+    <node id="116004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.62" lat="1.17"/>
+    <way id="116800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="116000"/>
+        <nd ref="116001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="116"/>
+    </way>
+    <way id="116801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="116001"/>
+        <nd ref="116002"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="116"/>
+    </way>
+    <way id="116802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="116002"/>
+        <nd ref="116003"/>
+        <nd ref="116004"/>
+        <nd ref="116000"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="116"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/data.osm.pbf
new file mode 100644
index 00000000..1ab51159
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/nodes.wkt
new file mode 100644
index 00000000..43908652
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/nodes.wkt
@@ -0,0 +1,5 @@
+116000 POINT(1.62 1.12)
+116001 POINT(1.64 1.13)
+116002 POINT(1.68 1.11)
+116003 POINT(1.68 1.17)
+116004 POINT(1.62 1.17)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/test.json
new file mode 100644
index 00000000..a67dea0c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 116,
+    "description": "Three ways connected in a closed loop."
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/ways.wkt
new file mode 100644
index 00000000..dde9bf7c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/116/ways.wkt
@@ -0,0 +1,3 @@
+116800 LINESTRING(1.62 1.12,1.64 1.13)
+116801 LINESTRING(1.64 1.13,1.68 1.11)
+116802 LINESTRING(1.68 1.11,1.68 1.17,1.62 1.17,1.62 1.12)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/data.osm
new file mode 100644
index 00000000..16a7843b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/data.osm
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <way id="120800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="120"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/data.osm.pbf
new file mode 100644
index 00000000..b371cfd6
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/test.json
new file mode 100644
index 00000000..f5cce42c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/120/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 120,
+    "description": "Way without any nodes"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/data.osm
new file mode 100644
index 00000000..f61eba77
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/data.osm
@@ -0,0 +1,9 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="121000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.12" lat="1.22"/>
+    <way id="121800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="121000"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="121"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/data.osm.pbf
new file mode 100644
index 00000000..2e5d9efb
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/nodes.wkt
new file mode 100644
index 00000000..7464217e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/nodes.wkt
@@ -0,0 +1 @@
+121000 POINT(1.12 1.22)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/test.json
new file mode 100644
index 00000000..91ef77ae
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 121,
+    "description": "Way with a single node"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/ways.wkt
new file mode 100644
index 00000000..ff5458f6
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/121/ways.wkt
@@ -0,0 +1 @@
+121800 NULL
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/data.osm
new file mode 100644
index 00000000..a4532eab
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/data.osm
@@ -0,0 +1,10 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="122000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.22" lat="1.22"/>
+    <way id="122800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="122000"/>
+        <nd ref="122000"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="122"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/data.osm.pbf
new file mode 100644
index 00000000..6033ca1b
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/nodes.wkt
new file mode 100644
index 00000000..6bd5abfe
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/nodes.wkt
@@ -0,0 +1 @@
+122000 POINT(1.22 1.22)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/test.json
new file mode 100644
index 00000000..6834a04b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 122,
+    "description": "Same node twice in way"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/ways.wkt
new file mode 100644
index 00000000..2b65ad6e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/122/ways.wkt
@@ -0,0 +1 @@
+122800 NULL
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/data.osm
new file mode 100644
index 00000000..8cb736b4
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/data.osm
@@ -0,0 +1,11 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="123000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.32" lat="1.22"/>
+    <node id="123001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.32" lat="1.22"/>
+    <way id="123800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="123000"/>
+        <nd ref="123001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="123"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/data.osm.pbf
new file mode 100644
index 00000000..a8481934
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/nodes.wkt
new file mode 100644
index 00000000..0a20a0c1
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/nodes.wkt
@@ -0,0 +1,2 @@
+123000 POINT(1.32 1.22)
+123001 POINT(1.32 1.22)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/test.json
new file mode 100644
index 00000000..6032b744
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 123,
+    "description": "Way with two nodes at same position"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/ways.wkt
new file mode 100644
index 00000000..aeb4efee
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/123/ways.wkt
@@ -0,0 +1 @@
+123800 NULL
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/data.osm
new file mode 100644
index 00000000..12ecd91f
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/data.osm
@@ -0,0 +1,13 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="124000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.42" lat="1.22"/>
+    <node id="124001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.42" lat="1.22"/>
+    <node id="124002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.42" lat="1.24"/>
+    <way id="124800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="124000"/>
+        <nd ref="124001"/>
+        <nd ref="124002"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="124"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/data.osm.pbf
new file mode 100644
index 00000000..9a6aa42d
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/nodes.wkt
new file mode 100644
index 00000000..445677e8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/nodes.wkt
@@ -0,0 +1,3 @@
+124000 POINT(1.42 1.22)
+124001 POINT(1.42 1.22)
+124002 POINT(1.42 1.24)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/test.json
new file mode 100644
index 00000000..cf8135e0
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 124,
+    "description": "Way with three nodes, first two nodes have the same position"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/ways.wkt
new file mode 100644
index 00000000..2571a282
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/124/ways.wkt
@@ -0,0 +1 @@
+124800 LINESTRING(1.42 1.22,1.42 1.24)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/data.osm
new file mode 100644
index 00000000..ff8fd1e9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/data.osm
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="130000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.02" lat="1.32"/>
+    <node id="130001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.04" lat="1.34"/>
+    <node id="130002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.02" lat="1.34"/>
+    <node id="130003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.04" lat="1.32"/>
+    <way id="130800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="130000"/>
+        <nd ref="130001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="130"/>
+    </way>
+    <way id="130801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="130002"/>
+        <nd ref="130003"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="130"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/data.osm.pbf
new file mode 100644
index 00000000..ae5ca7b6
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/nodes.wkt
new file mode 100644
index 00000000..8c33b780
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/nodes.wkt
@@ -0,0 +1,4 @@
+130000 POINT(1.02 1.32)
+130001 POINT(1.04 1.34)
+130002 POINT(1.02 1.34)
+130003 POINT(1.04 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/test.json
new file mode 100644
index 00000000..b2fc2934
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 130,
+    "description": "Crossing ways without common node"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/ways.wkt
new file mode 100644
index 00000000..229767e8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/130/ways.wkt
@@ -0,0 +1,2 @@
+130800 LINESTRING(1.02 1.32,1.04 1.34)
+130801 LINESTRING(1.02 1.34,1.04 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/data.osm
new file mode 100644
index 00000000..f42552e6
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/data.osm
@@ -0,0 +1,22 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="131000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.12" lat="1.32"/>
+    <node id="131001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.14" lat="1.34"/>
+    <node id="131002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.12" lat="1.34"/>
+    <node id="131003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.14" lat="1.32"/>
+    <node id="131004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.13" lat="1.33"/>
+    <way id="131800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="131000"/>
+        <nd ref="131004"/>
+        <nd ref="131001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="131"/>
+    </way>
+    <way id="131801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="131002"/>
+        <nd ref="131004"/>
+        <nd ref="131003"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="131"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/data.osm.pbf
new file mode 100644
index 00000000..5af2fdfc
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/nodes.wkt
new file mode 100644
index 00000000..42f71554
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/nodes.wkt
@@ -0,0 +1,5 @@
+131000 POINT(1.12 1.32)
+131001 POINT(1.14 1.34)
+131002 POINT(1.12 1.34)
+131003 POINT(1.14 1.32)
+131004 POINT(1.13 1.33)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/test.json
new file mode 100644
index 00000000..893e2928
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 131,
+    "description": "Crossing ways with common node"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/ways.wkt
new file mode 100644
index 00000000..8330f76c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/131/ways.wkt
@@ -0,0 +1,2 @@
+131800 LINESTRING(1.12 1.32,1.13 1.33,1.14 1.34)
+131801 LINESTRING(1.12 1.34,1.13 1.33,1.14 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/data.osm
new file mode 100644
index 00000000..45b2d45c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/data.osm
@@ -0,0 +1,23 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="132000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.22" lat="1.32"/>
+    <node id="132001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.24" lat="1.34"/>
+    <node id="132002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.22" lat="1.34"/>
+    <node id="132003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.24" lat="1.32"/>
+    <node id="132004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.23" lat="1.33"/>
+    <node id="132005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.23" lat="1.33"/>
+    <way id="132800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="132000"/>
+        <nd ref="132004"/>
+        <nd ref="132001"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="132"/>
+    </way>
+    <way id="132801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="132002"/>
+        <nd ref="132005"/>
+        <nd ref="132003"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="132"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/data.osm.pbf
new file mode 100644
index 00000000..3c2375b2
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/nodes.wkt
new file mode 100644
index 00000000..be62b3ff
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/nodes.wkt
@@ -0,0 +1,6 @@
+132000 POINT(1.22 1.32)
+132001 POINT(1.24 1.34)
+132002 POINT(1.22 1.34)
+132003 POINT(1.24 1.32)
+132004 POINT(1.23 1.33)
+132005 POINT(1.23 1.33)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/test.json
new file mode 100644
index 00000000..aa10f924
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 132,
+    "description": "Crossing ways without common node, but crossing node at same position"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/ways.wkt
new file mode 100644
index 00000000..7cfedf75
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/132/ways.wkt
@@ -0,0 +1,2 @@
+132800 LINESTRING(1.22 1.32,1.23 1.33,1.24 1.34)
+132801 LINESTRING(1.22 1.34,1.23 1.33,1.24 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/data.osm
new file mode 100644
index 00000000..e547a753
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/data.osm
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="133000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.32" lat="1.32"/>
+    <node id="133001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.34" lat="1.34"/>
+    <node id="133002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.32" lat="1.34"/>
+    <node id="133003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.34" lat="1.32"/>
+    <way id="133800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="133000"/>
+        <nd ref="133001"/>
+        <nd ref="133002"/>
+        <nd ref="133003"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="133"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/data.osm.pbf
new file mode 100644
index 00000000..7e911ca1
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/nodes.wkt
new file mode 100644
index 00000000..156a03af
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/nodes.wkt
@@ -0,0 +1,4 @@
+133000 POINT(1.32 1.32)
+133001 POINT(1.34 1.34)
+133002 POINT(1.32 1.34)
+133003 POINT(1.34 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/test.json
new file mode 100644
index 00000000..07d43611
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 133,
+    "description": "Self-crossing way without common node"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/ways.wkt
new file mode 100644
index 00000000..9c71bbf4
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/133/ways.wkt
@@ -0,0 +1 @@
+133800 LINESTRING(1.32 1.32,1.34 1.34,1.32 1.34,1.34 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/data.osm
new file mode 100644
index 00000000..8affd3a3
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/data.osm
@@ -0,0 +1,18 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="134000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.42" lat="1.32"/>
+    <node id="134001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.44" lat="1.34"/>
+    <node id="134002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.42" lat="1.34"/>
+    <node id="134003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.43" lat="1.33"/>
+    <node id="134004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="1.44" lat="1.32"/>
+    <way id="134800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="134000"/>
+        <nd ref="134003"/>
+        <nd ref="134001"/>
+        <nd ref="134002"/>
+        <nd ref="134003"/>
+        <nd ref="134004"/>
+        <tag k="test:section" v="basic-geom"/>
+        <tag k="test:id" v="134"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/data.osm.pbf
new file mode 100644
index 00000000..fd645b83
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/nodes.wkt
new file mode 100644
index 00000000..c2674abc
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/nodes.wkt
@@ -0,0 +1,5 @@
+134000 POINT(1.42 1.32)
+134001 POINT(1.44 1.34)
+134002 POINT(1.42 1.34)
+134003 POINT(1.43 1.33)
+134004 POINT(1.44 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/test.json
new file mode 100644
index 00000000..8194e77e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 134,
+    "description": "Self-crossing way with common node"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/ways.wkt
new file mode 100644
index 00000000..68cb64be
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/134/ways.wkt
@@ -0,0 +1 @@
+134800 LINESTRING(1.42 1.32,1.43 1.33,1.44 1.34,1.42 1.34,1.43 1.33,1.44 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/1/description.txt b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/description.txt
new file mode 100644
index 00000000..73f0e6e3
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/1/description.txt
@@ -0,0 +1 @@
+Basic Geometry Tests
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/data.osm
new file mode 100644
index 00000000..244813bf
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="200000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="3.02" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/data.osm.pbf
new file mode 100644
index 00000000..07b406cf
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/nodes.wkt
new file mode 100644
index 00000000..16d60515
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/nodes.wkt
@@ -0,0 +1 @@
+200000 POINT(3.02 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/test.json
new file mode 100644
index 00000000..182b2742
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/300/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 300,
+    "description": "Normal node with uid and user name"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/data.osm
new file mode 100644
index 00000000..96da8631
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="201000" version="1" timestamp="2014-01-01T00:00:00Z" uid="2" user="" changeset="1" lon="3.12" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/data.osm.pbf
new file mode 100644
index 00000000..b93ce446
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/nodes.wkt
new file mode 100644
index 00000000..1962f996
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/nodes.wkt
@@ -0,0 +1 @@
+201000 POINT(3.12 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/test.json
new file mode 100644
index 00000000..e694909c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/301/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 301,
+    "description": "Empty username on node should not happen"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/data.osm
new file mode 100644
index 00000000..dc99e1bc
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="202000" version="1" timestamp="2014-01-01T00:00:00Z" changeset="1" lon="3.22" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/data.osm.pbf
new file mode 100644
index 00000000..80a59af4
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/nodes.wkt
new file mode 100644
index 00000000..1e2a670d
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/nodes.wkt
@@ -0,0 +1 @@
+202000 POINT(3.22 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/test.json
new file mode 100644
index 00000000..94ec4610
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/302/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 302,
+    "description": "No uid and no user name means user is anonymous"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/data.osm
new file mode 100644
index 00000000..b16aad04
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="203000" version="1" timestamp="2014-01-01T00:00:00Z" uid="0" user="" changeset="1" lon="3.32" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/data.osm.pbf
new file mode 100644
index 00000000..5704115f
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/nodes.wkt
new file mode 100644
index 00000000..15dc57c4
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/nodes.wkt
@@ -0,0 +1 @@
+203000 POINT(3.32 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/test.json
new file mode 100644
index 00000000..f2a2fcaf
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/303/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 303,
+    "description": "uid 0 is the anonymous user"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/data.osm
new file mode 100644
index 00000000..73eb74fe
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="204000" version="1" timestamp="2014-01-01T00:00:00Z" uid="-1" user="" changeset="1" lon="3.42" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/data.osm.pbf
new file mode 100644
index 00000000..c6eaa393
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/nodes.wkt
new file mode 100644
index 00000000..1192f9b9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/nodes.wkt
@@ -0,0 +1 @@
+204000 POINT(3.42 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/test.json
new file mode 100644
index 00000000..57f733d3
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/304/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 304,
+    "description": "negative user ids are not allowed (but -1 could have been meant as anonymous user)"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/data.osm
new file mode 100644
index 00000000..41e95bc7
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="205000" version="1" timestamp="2014-01-01T00:00:00Z" uid="-1" user="abc" changeset="1" lon="3.52" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/data.osm.pbf
new file mode 100644
index 00000000..61025087
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/nodes.wkt
new file mode 100644
index 00000000..7b528805
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/nodes.wkt
@@ -0,0 +1 @@
+205000 POINT(3.52 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/test.json
new file mode 100644
index 00000000..9d61fc30
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/305/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 305,
+    "description": "uid < 0 and username is inconsistent and definitely wrong"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/data.osm
new file mode 100644
index 00000000..dbbbe5f3
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="206000" version="1" timestamp="2014-01-01T00:00:00Z" uid="3" user="_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789" changeset="1" lon="3.62" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/data.osm.pbf
new file mode 100644
index 00000000..bad365b3
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/nodes.wkt
new file mode 100644
index 00000000..6ea99b92
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/nodes.wkt
@@ -0,0 +1 @@
+206000 POINT(3.62 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/test.json
new file mode 100644
index 00000000..4e85a7e2
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/306/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 306,
+    "description": "250 characters in username is okay"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/data.osm
new file mode 100644
index 00000000..88448b50
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/data.osm
@@ -0,0 +1,4 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="207000" version="1" timestamp="2014-01-01T00:00:00Z" uid="4" user="_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789" changeset="1" lon="3.72" lat="1.02"/>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/data.osm.pbf
new file mode 100644
index 00000000..7ecc9e55
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/nodes.wkt
new file mode 100644
index 00000000..7c0c036a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/nodes.wkt
@@ -0,0 +1 @@
+207000 POINT(3.72 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/test.json
new file mode 100644
index 00000000..fef30956
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/307/test.json
@@ -0,0 +1,4 @@
+{
+    "test_id": 307,
+    "description": "260 characters in username is too long"
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/3/description.txt b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/description.txt
new file mode 100644
index 00000000..d9ccf544
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/3/description.txt
@@ -0,0 +1 @@
+Attribute Tests
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/data.osm
new file mode 100644
index 00000000..1329043b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/data.osm
@@ -0,0 +1,17 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="700000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.01"/>
+    <node id="700001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.04"/>
+    <node id="700002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.04"/>
+    <node id="700003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.01"/>
+    <way id="700800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="700000"/>
+        <nd ref="700001"/>
+        <nd ref="700002"/>
+        <nd ref="700003"/>
+        <nd ref="700000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="700"/>
+        <tag k="area" v="yes"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/data.osm.pbf
new file mode 100644
index 00000000..e7d38548
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/nodes.wkt
new file mode 100644
index 00000000..93ed8951
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/nodes.wkt
@@ -0,0 +1,4 @@
+700000 POINT(7.01 1.01)
+700001 POINT(7.01 1.04)
+700002 POINT(7.04 1.04)
+700003 POINT(7.04 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/test.json
new file mode 100644
index 00000000..05273803
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 700,
+    "description": "Polygon with one closed way.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 700800,
+                "from_type": "way",
+                "wkt": "MULTIPOLYGON(((7.01 1.01,7.01 1.04,7.04 1.04,7.04 1.01,7.01 1.01)))",
+                "tags": {
+                    "test:section": "mp-geom",
+                    "test:id": "700",
+                    "area": "yes"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/ways.wkt
new file mode 100644
index 00000000..6a658d2e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/700/ways.wkt
@@ -0,0 +1 @@
+700800 LINESTRING(7.01 1.01,7.01 1.04,7.04 1.04,7.04 1.01,7.01 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/data.osm
new file mode 100644
index 00000000..98462b61
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/data.osm
@@ -0,0 +1,29 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="701000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.01"/>
+    <node id="701001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.04"/>
+    <node id="701002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.04"/>
+    <node id="701003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.01"/>
+    <way id="701800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="701000"/>
+        <nd ref="701001"/>
+        <nd ref="701002"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="701"/>
+    </way>
+    <way id="701801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="701002"/>
+        <nd ref="701003"/>
+        <nd ref="701000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="701"/>
+    </way>
+    <relation id="701900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="701800" role="outer"/>
+        <member type="way" ref="701801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="701"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/data.osm.pbf
new file mode 100644
index 00000000..1d91e64c
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/nodes.wkt
new file mode 100644
index 00000000..120b7540
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/nodes.wkt
@@ -0,0 +1,4 @@
+701000 POINT(7.11 1.01)
+701001 POINT(7.11 1.04)
+701002 POINT(7.14 1.04)
+701003 POINT(7.14 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/test.json
new file mode 100644
index 00000000..61ed2687
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 701,
+    "description": "Valid multipolygon relation with two ways making up an outer ring.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 701900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.14 1.01,7.11 1.01,7.11 1.04,7.14 1.04,7.14 1.01)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "701"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/ways.wkt
new file mode 100644
index 00000000..e43f615b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/701/ways.wkt
@@ -0,0 +1,2 @@
+701800 LINESTRING(7.11 1.01,7.11 1.04,7.14 1.04)
+701801 LINESTRING(7.14 1.04,7.14 1.01,7.11 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/data.osm
new file mode 100644
index 00000000..641968e9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/data.osm
@@ -0,0 +1,37 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="702000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.01"/>
+    <node id="702001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.24" lat="1.01"/>
+    <node id="702002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.24" lat="1.05"/>
+    <node id="702003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.05"/>
+    <node id="702004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.04"/>
+    <node id="702005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.23" lat="1.04"/>
+    <node id="702006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.23" lat="1.03"/>
+    <node id="702007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.02"/>
+    <way id="702800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="702000"/>
+        <nd ref="702001"/>
+        <nd ref="702002"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="702"/>
+    </way>
+    <way id="702801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="702002"/>
+        <nd ref="702003"/>
+        <nd ref="702004"/>
+        <nd ref="702005"/>
+        <nd ref="702006"/>
+        <nd ref="702007"/>
+        <nd ref="702000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="702"/>
+    </way>
+    <relation id="702900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="702800" role="outer"/>
+        <member type="way" ref="702801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="702"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/data.osm.pbf
new file mode 100644
index 00000000..eb35a996
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/nodes.wkt
new file mode 100644
index 00000000..caacec5a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/nodes.wkt
@@ -0,0 +1,8 @@
+702000 POINT(7.21 1.01)
+702001 POINT(7.24 1.01)
+702002 POINT(7.24 1.05)
+702003 POINT(7.21 1.05)
+702004 POINT(7.21 1.04)
+702005 POINT(7.23 1.04)
+702006 POINT(7.23 1.03)
+702007 POINT(7.21 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/test.json
new file mode 100644
index 00000000..f2060ca9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 702,
+    "description": "Valid multipolygon relation with two ways making up an outer ring.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 702900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.24 1.01,7.21 1.01,7.21 1.02,7.23 1.03,7.23 1.04,7.21 1.04,7.21 1.05,7.24 1.05,7.24 1.01)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "702"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/ways.wkt
new file mode 100644
index 00000000..de39732c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/702/ways.wkt
@@ -0,0 +1,2 @@
+702800 LINESTRING(7.21 1.01,7.24 1.01,7.24 1.05)
+702801 LINESTRING(7.24 1.05,7.21 1.05,7.21 1.04,7.23 1.04,7.23 1.03,7.21 1.02,7.21 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/data.osm
new file mode 100644
index 00000000..9fddc78f
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/data.osm
@@ -0,0 +1,37 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="703000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.01"/>
+    <node id="703001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.34" lat="1.01"/>
+    <node id="703002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.34" lat="1.05"/>
+    <node id="703003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.05"/>
+    <node id="703004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.04"/>
+    <node id="703005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.04"/>
+    <node id="703006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.03"/>
+    <node id="703007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.02"/>
+    <way id="703800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="703000"/>
+        <nd ref="703001"/>
+        <nd ref="703002"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="703"/>
+    </way>
+    <way id="703801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="703002"/>
+        <nd ref="703003"/>
+        <nd ref="703004"/>
+        <nd ref="703005"/>
+        <nd ref="703006"/>
+        <nd ref="703007"/>
+        <nd ref="703000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="703"/>
+    </way>
+    <relation id="703900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="703800" role="outer"/>
+        <member type="way" ref="703801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="703"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/data.osm.pbf
new file mode 100644
index 00000000..dfe9ead2
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/nodes.wkt
new file mode 100644
index 00000000..d50b6a25
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/nodes.wkt
@@ -0,0 +1,8 @@
+703000 POINT(7.31 1.01)
+703001 POINT(7.34 1.01)
+703002 POINT(7.34 1.05)
+703003 POINT(7.32 1.05)
+703004 POINT(7.32 1.04)
+703005 POINT(7.33 1.04)
+703006 POINT(7.33 1.03)
+703007 POINT(7.31 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/test.json
new file mode 100644
index 00000000..6d58119a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 703,
+    "description": "Valid multipolygon relation with two ways making up an outer ring.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 703900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.34 1.01,7.31 1.01,7.31 1.02,7.33 1.03,7.33 1.04,7.32 1.04,7.32 1.05,7.34 1.05,7.34 1.01)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "703"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/ways.wkt
new file mode 100644
index 00000000..d53626a5
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/703/ways.wkt
@@ -0,0 +1,2 @@
+703800 LINESTRING(7.31 1.01,7.34 1.01,7.34 1.05)
+703801 LINESTRING(7.34 1.05,7.32 1.05,7.32 1.04,7.33 1.04,7.33 1.03,7.31 1.02,7.31 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/data.osm
new file mode 100644
index 00000000..f09cafdf
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/data.osm
@@ -0,0 +1,51 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="704000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.02"/>
+    <node id="704001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.03"/>
+    <node id="704002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.03"/>
+    <node id="704003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.04"/>
+    <node id="704004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.04"/>
+    <node id="704005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.03"/>
+    <node id="704006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.44" lat="1.03"/>
+    <node id="704007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.44" lat="1.02"/>
+    <node id="704008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.02"/>
+    <node id="704009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.01"/>
+    <node id="704010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.01"/>
+    <node id="704011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.02"/>
+    <way id="704800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="704000"/>
+        <nd ref="704001"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="704"/>
+    </way>
+    <way id="704801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="704001"/>
+        <nd ref="704002"/>
+        <nd ref="704003"/>
+        <nd ref="704004"/>
+        <nd ref="704005"/>
+        <nd ref="704006"/>
+        <nd ref="704007"/>
+        <nd ref="704008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="704"/>
+    </way>
+    <way id="704802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="704008"/>
+        <nd ref="704009"/>
+        <nd ref="704010"/>
+        <nd ref="704011"/>
+        <nd ref="704000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="704"/>
+    </way>
+    <relation id="704900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="704800" role="outer"/>
+        <member type="way" ref="704801" role="outer"/>
+        <member type="way" ref="704802" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="704"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/data.osm.pbf
new file mode 100644
index 00000000..35092386
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/nodes.wkt
new file mode 100644
index 00000000..f1438259
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/nodes.wkt
@@ -0,0 +1,12 @@
+704000 POINT(7.41 1.02)
+704001 POINT(7.41 1.03)
+704002 POINT(7.42 1.03)
+704003 POINT(7.42 1.04)
+704004 POINT(7.43 1.04)
+704005 POINT(7.43 1.03)
+704006 POINT(7.44 1.03)
+704007 POINT(7.44 1.02)
+704008 POINT(7.43 1.02)
+704009 POINT(7.43 1.01)
+704010 POINT(7.42 1.01)
+704011 POINT(7.42 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/test.json
new file mode 100644
index 00000000..9338269d
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 704,
+    "description": "Valid multipolygon relation with three ways making up an outer ring in the form of a cross.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 704900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.41 1.02,7.41 1.03,7.42 1.03,7.42 1.04,7.43 1.04,7.43 1.03,7.44 1.03,7.44 1.02,7.43 1.02,7.43 1.01,7.42 1.01,7.42 1.02,7.41 1.02)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "704"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/ways.wkt
new file mode 100644
index 00000000..d16009cf
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/704/ways.wkt
@@ -0,0 +1,3 @@
+704800 LINESTRING(7.41 1.02,7.41 1.03)
+704801 LINESTRING(7.41 1.03,7.42 1.03,7.42 1.04,7.43 1.04,7.43 1.03,7.44 1.03,7.44 1.02,7.43 1.02)
+704802 LINESTRING(7.43 1.02,7.43 1.01,7.42 1.01,7.42 1.02,7.41 1.02)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/data.osm
new file mode 100644
index 00000000..abc79caf
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/data.osm
@@ -0,0 +1,53 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="705000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.53" lat="1.03"/>
+    <node id="705001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.51" lat="1.04"/>
+    <node id="705002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.52" lat="1.08"/>
+    <node id="705003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.54" lat="1.07"/>
+    <node id="705004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.09"/>
+    <node id="705005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.56" lat="1.09"/>
+    <node id="705006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.59" lat="1.06"/>
+    <node id="705007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.58" lat="1.02"/>
+    <node id="705008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.56" lat="1.03"/>
+    <node id="705009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.56" lat="1.04"/>
+    <node id="705010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.04"/>
+    <node id="705011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.54" lat="1.01"/>
+    <node id="705012" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.52" lat="1.01"/>
+    <way id="705800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="705000"/>
+        <nd ref="705001"/>
+        <nd ref="705002"/>
+        <nd ref="705003"/>
+        <nd ref="705004"/>
+        <nd ref="705005"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="705"/>
+    </way>
+    <way id="705801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="705005"/>
+        <nd ref="705006"/>
+        <nd ref="705007"/>
+        <nd ref="705008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="705"/>
+    </way>
+    <way id="705802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="705008"/>
+        <nd ref="705009"/>
+        <nd ref="705010"/>
+        <nd ref="705011"/>
+        <nd ref="705012"/>
+        <nd ref="705000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="705"/>
+    </way>
+    <relation id="705900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="705800" role="outer"/>
+        <member type="way" ref="705801" role="outer"/>
+        <member type="way" ref="705802" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="705"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/data.osm.pbf
new file mode 100644
index 00000000..c5dbe246
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/nodes.wkt
new file mode 100644
index 00000000..09454165
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/nodes.wkt
@@ -0,0 +1,13 @@
+705000 POINT(7.53 1.03)
+705001 POINT(7.51 1.04)
+705002 POINT(7.52 1.08)
+705003 POINT(7.54 1.07)
+705004 POINT(7.55 1.09)
+705005 POINT(7.56 1.09)
+705006 POINT(7.59 1.06)
+705007 POINT(7.58 1.02)
+705008 POINT(7.56 1.03)
+705009 POINT(7.56 1.04)
+705010 POINT(7.55 1.04)
+705011 POINT(7.54 1.01)
+705012 POINT(7.52 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/test.json
new file mode 100644
index 00000000..7b6f8f65
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 705,
+    "description": "Valid multipolygon relation with three ways making up an outer ring. Contains concave and convex parts.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 705900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.58 1.02,7.56 1.03,7.56 1.04,7.55 1.04,7.54 1.01,7.52 1.01,7.53 1.03,7.51 1.04,7.52 1.08,7.54 1.07,7.55 1.09,7.56 1.09,7.59 1.06,7.58 1.02)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "705"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/ways.wkt
new file mode 100644
index 00000000..1ede5d6e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/705/ways.wkt
@@ -0,0 +1,3 @@
+705800 LINESTRING(7.53 1.03,7.51 1.04,7.52 1.08,7.54 1.07,7.55 1.09,7.56 1.09)
+705801 LINESTRING(7.56 1.09,7.59 1.06,7.58 1.02,7.56 1.03)
+705802 LINESTRING(7.56 1.03,7.56 1.04,7.55 1.04,7.54 1.01,7.52 1.01,7.53 1.03)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/data.osm
new file mode 100644
index 00000000..ec2264b4
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/data.osm
@@ -0,0 +1,44 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="706000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.61" lat="1.04"/>
+    <node id="706001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.62" lat="1.06"/>
+    <node id="706002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.05"/>
+    <node id="706003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.63" lat="1.02"/>
+    <node id="706004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.64" lat="1.03"/>
+    <node id="706005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.67" lat="1.03"/>
+    <node id="706006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.67" lat="1.01"/>
+    <node id="706007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.64" lat="1.01"/>
+    <way id="706800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="706000"/>
+        <nd ref="706001"/>
+        <nd ref="706002"/>
+        <nd ref="706004"/>
+        <nd ref="706003"/>
+        <nd ref="706000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="706"/>
+    </way>
+    <way id="706801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="706004"/>
+        <nd ref="706005"/>
+        <nd ref="706006"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="706"/>
+    </way>
+    <way id="706802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="706006"/>
+        <nd ref="706007"/>
+        <nd ref="706004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="706"/>
+    </way>
+    <relation id="706900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="706800" role="outer"/>
+        <member type="way" ref="706801" role="outer"/>
+        <member type="way" ref="706802" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="706"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/data.osm.pbf
new file mode 100644
index 00000000..45ff1c96
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/nodes.wkt
new file mode 100644
index 00000000..44984fc8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/nodes.wkt
@@ -0,0 +1,8 @@
+706000 POINT(7.61 1.04)
+706001 POINT(7.62 1.06)
+706002 POINT(7.65 1.05)
+706003 POINT(7.63 1.02)
+706004 POINT(7.64 1.03)
+706005 POINT(7.67 1.03)
+706006 POINT(7.67 1.01)
+706007 POINT(7.64 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/test.json
new file mode 100644
index 00000000..b71effcd
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 706,
+    "description": "Valid multipolygon relation with three ways making up two outer rings that touch in one point.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 706900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.61 1.04,7.62 1.06,7.65 1.05,7.64 1.03,7.63 1.02,7.61 1.04)),((7.64 1.03,7.67 1.03,7.67 1.01,7.64 1.01,7.64 1.03)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "706"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/ways.wkt
new file mode 100644
index 00000000..459c47b6
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/706/ways.wkt
@@ -0,0 +1,3 @@
+706800 LINESTRING(7.61 1.04,7.62 1.06,7.65 1.05,7.64 1.03,7.63 1.02,7.61 1.04)
+706801 LINESTRING(7.64 1.03,7.67 1.03,7.67 1.01)
+706802 LINESTRING(7.67 1.01,7.64 1.01,7.64 1.03)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/data.osm
new file mode 100644
index 00000000..c358c88f
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/data.osm
@@ -0,0 +1,43 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="707000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.71" lat="1.04"/>
+    <node id="707001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.72" lat="1.06"/>
+    <node id="707002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.75" lat="1.05"/>
+    <node id="707003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.73" lat="1.02"/>
+    <node id="707004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.74" lat="1.03"/>
+    <node id="707005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.77" lat="1.03"/>
+    <node id="707006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.77" lat="1.01"/>
+    <node id="707007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.74" lat="1.01"/>
+    <way id="707800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="707000"/>
+        <nd ref="707001"/>
+        <nd ref="707002"/>
+        <nd ref="707003"/>
+        <nd ref="707000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="707"/>
+    </way>
+    <way id="707801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="707004"/>
+        <nd ref="707005"/>
+        <nd ref="707006"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="707"/>
+    </way>
+    <way id="707802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="707006"/>
+        <nd ref="707007"/>
+        <nd ref="707004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="707"/>
+    </way>
+    <relation id="707900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="707800" role="outer"/>
+        <member type="way" ref="707801" role="outer"/>
+        <member type="way" ref="707802" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="707"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/data.osm.pbf
new file mode 100644
index 00000000..2d417349
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/nodes.wkt
new file mode 100644
index 00000000..71501fb3
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/nodes.wkt
@@ -0,0 +1,8 @@
+707000 POINT(7.71 1.04)
+707001 POINT(7.72 1.06)
+707002 POINT(7.75 1.05)
+707003 POINT(7.73 1.02)
+707004 POINT(7.74 1.03)
+707005 POINT(7.77 1.03)
+707006 POINT(7.77 1.01)
+707007 POINT(7.74 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/test.json
new file mode 100644
index 00000000..1513be6b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 707,
+    "description": "Valid multipolygon relation with three ways making up two separate outer rings.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 707900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.71 1.04,7.72 1.06,7.75 1.05,7.73 1.02,7.71 1.04)),((7.74 1.03,7.77 1.03,7.77 1.01,7.74 1.01,7.74 1.03)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "707"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/ways.wkt
new file mode 100644
index 00000000..397b69ff
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/707/ways.wkt
@@ -0,0 +1,3 @@
+707800 LINESTRING(7.71 1.04,7.72 1.06,7.75 1.05,7.73 1.02,7.71 1.04)
+707801 LINESTRING(7.74 1.03,7.77 1.03,7.77 1.01)
+707802 LINESTRING(7.77 1.01,7.74 1.01,7.74 1.03)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/data.osm
new file mode 100644
index 00000000..c1b59773
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/data.osm
@@ -0,0 +1,59 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="708000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.81" lat="1.03"/>
+    <node id="708001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.82" lat="1.06"/>
+    <node id="708002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.85" lat="1.06"/>
+    <node id="708003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.86" lat="1.03"/>
+    <node id="708004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.85" lat="1.03"/>
+    <node id="708005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.84" lat="1.05"/>
+    <node id="708006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.83" lat="1.05"/>
+    <node id="708007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.82" lat="1.02"/>
+    <node id="708008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.83" lat="1.04"/>
+    <node id="708009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.84" lat="1.04"/>
+    <node id="708010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.84" lat="1.02"/>
+    <node id="708011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.87" lat="1.02"/>
+    <node id="708012" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.87" lat="1.03"/>
+    <node id="708013" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.88" lat="1.03"/>
+    <node id="708014" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.88" lat="1.01"/>
+    <node id="708015" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.83" lat="1.01"/>
+    <way id="708800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="708000"/>
+        <nd ref="708001"/>
+        <nd ref="708002"/>
+        <nd ref="708003"/>
+        <nd ref="708004"/>
+        <nd ref="708005"/>
+        <nd ref="708006"/>
+        <nd ref="708007"/>
+        <nd ref="708000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="708"/>
+    </way>
+    <way id="708801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="708008"/>
+        <nd ref="708009"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="708"/>
+    </way>
+    <way id="708802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="708009"/>
+        <nd ref="708010"/>
+        <nd ref="708011"/>
+        <nd ref="708012"/>
+        <nd ref="708013"/>
+        <nd ref="708014"/>
+        <nd ref="708015"/>
+        <nd ref="708008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="708"/>
+    </way>
+    <relation id="708900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="708800" role="outer"/>
+        <member type="way" ref="708801" role="outer"/>
+        <member type="way" ref="708802" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="708"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/data.osm.pbf
new file mode 100644
index 00000000..86602a07
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/nodes.wkt
new file mode 100644
index 00000000..67fff7f0
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/nodes.wkt
@@ -0,0 +1,16 @@
+708000 POINT(7.81 1.03)
+708001 POINT(7.82 1.06)
+708002 POINT(7.85 1.06)
+708003 POINT(7.86 1.03)
+708004 POINT(7.85 1.03)
+708005 POINT(7.84 1.05)
+708006 POINT(7.83 1.05)
+708007 POINT(7.82 1.02)
+708008 POINT(7.83 1.04)
+708009 POINT(7.84 1.04)
+708010 POINT(7.84 1.02)
+708011 POINT(7.87 1.02)
+708012 POINT(7.87 1.03)
+708013 POINT(7.88 1.03)
+708014 POINT(7.88 1.01)
+708015 POINT(7.83 1.01)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/test.json
new file mode 100644
index 00000000..55a8b2b0
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 708,
+    "description": "Valid multipolygon relation with three ways making up two separate outer rings.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 708900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.81 1.03,7.82 1.06,7.85 1.06,7.86 1.03,7.85 1.03,7.84 1.05,7.83 1.05,7.82 1.02,7.81 1.03)),((7.83 1.04,7.84 1.04,7.84 1.02,7.87 1.02,7.87 1.03,7.88 1.03,7.88 1.01,7.83 1.01,7.83 1.04)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "708"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/ways.wkt
new file mode 100644
index 00000000..f716c08c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/708/ways.wkt
@@ -0,0 +1,3 @@
+708800 LINESTRING(7.81 1.03,7.82 1.06,7.85 1.06,7.86 1.03,7.85 1.03,7.84 1.05,7.83 1.05,7.82 1.02,7.81 1.03)
+708801 LINESTRING(7.83 1.04,7.84 1.04)
+708802 LINESTRING(7.84 1.04,7.84 1.02,7.87 1.02,7.87 1.03,7.88 1.03,7.88 1.01,7.83 1.01,7.83 1.04)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/data.osm
new file mode 100644
index 00000000..bc899cb7
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/data.osm
@@ -0,0 +1,54 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="709000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.91" lat="1.04"/>
+    <node id="709001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.92" lat="1.06"/>
+    <node id="709002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.95" lat="1.05"/>
+    <node id="709003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.93" lat="1.02"/>
+    <node id="709004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.94" lat="1.03"/>
+    <node id="709005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.97" lat="1.03"/>
+    <node id="709006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.97" lat="1.01"/>
+    <node id="709007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.94" lat="1.01"/>
+    <node id="709008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.98" lat="1.08"/>
+    <way id="709800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="709000"/>
+        <nd ref="709001"/>
+        <nd ref="709002"/>
+        <nd ref="709004"/>
+        <nd ref="709003"/>
+        <nd ref="709000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="709"/>
+    </way>
+    <way id="709801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="709004"/>
+        <nd ref="709005"/>
+        <nd ref="709006"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="709"/>
+    </way>
+    <way id="709802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="709006"/>
+        <nd ref="709007"/>
+        <nd ref="709004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="709"/>
+    </way>
+    <way id="709803" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="709008"/>
+        <nd ref="709002"/>
+        <nd ref="709005"/>
+        <nd ref="709008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="709"/>
+    </way>
+    <relation id="709900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="709800" role="outer"/>
+        <member type="way" ref="709801" role="outer"/>
+        <member type="way" ref="709802" role="outer"/>
+        <member type="way" ref="709803" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="709"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/data.osm.pbf
new file mode 100644
index 00000000..5ea10166
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/nodes.wkt
new file mode 100644
index 00000000..a2d1b5c9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/nodes.wkt
@@ -0,0 +1,9 @@
+709000 POINT(7.91 1.04)
+709001 POINT(7.92 1.06)
+709002 POINT(7.95 1.05)
+709003 POINT(7.93 1.02)
+709004 POINT(7.94 1.03)
+709005 POINT(7.97 1.03)
+709006 POINT(7.97 1.01)
+709007 POINT(7.94 1.01)
+709008 POINT(7.98 1.08)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/test.json
new file mode 100644
index 00000000..5d166f48
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 709,
+    "description": "Valid multipolygon relation with four ways making up three outer rings touching in three points.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 709900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.91 1.04,7.92 1.06,7.95 1.05,7.94 1.03,7.93 1.02,7.91 1.04)),((7.94 1.03,7.97 1.03,7.97 1.01,7.94 1.01,7.94 1.03)),((7.95 1.05,7.97 1.03,7.98 1.08,7.95 1.05)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "709"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/ways.wkt
new file mode 100644
index 00000000..d200f25c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/709/ways.wkt
@@ -0,0 +1,4 @@
+709800 LINESTRING(7.91 1.04,7.92 1.06,7.95 1.05,7.94 1.03,7.93 1.02,7.91 1.04)
+709801 LINESTRING(7.94 1.03,7.97 1.03,7.97 1.01)
+709802 LINESTRING(7.97 1.01,7.94 1.01,7.94 1.03)
+709803 LINESTRING(7.98 1.08,7.95 1.05,7.97 1.03,7.98 1.08)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/data.osm
new file mode 100644
index 00000000..3d33b6d5
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/data.osm
@@ -0,0 +1,43 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="710000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.14"/>
+    <node id="710001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.02" lat="1.16"/>
+    <node id="710002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.15"/>
+    <node id="710003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.12"/>
+    <node id="710004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.13"/>
+    <node id="710005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.07" lat="1.13"/>
+    <node id="710006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.07" lat="1.11"/>
+    <node id="710007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.11"/>
+    <way id="710800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="710000"/>
+        <nd ref="710001"/>
+        <nd ref="710002"/>
+        <nd ref="710003"/>
+        <nd ref="710000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="710"/>
+    </way>
+    <way id="710801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="710004"/>
+        <nd ref="710005"/>
+        <nd ref="710006"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="710"/>
+    </way>
+    <way id="710802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="710006"/>
+        <nd ref="710007"/>
+        <nd ref="710004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="710"/>
+    </way>
+    <relation id="710900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="710800" role="outer"/>
+        <member type="way" ref="710801" role="outer"/>
+        <member type="way" ref="710802" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="710"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/data.osm.pbf
new file mode 100644
index 00000000..5cdb7028
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/labels.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/labels.wkt
new file mode 100644
index 00000000..45b45f7a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/labels.wkt
@@ -0,0 +1 @@
+POINT(7.032 1.126) overlapping polygons
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/nodes.wkt
new file mode 100644
index 00000000..ddf5565c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/nodes.wkt
@@ -0,0 +1,8 @@
+710000 POINT(7.01 1.14)
+710001 POINT(7.02 1.16)
+710002 POINT(7.05 1.15)
+710003 POINT(7.03 1.12)
+710004 POINT(7.03 1.13)
+710005 POINT(7.07 1.13)
+710006 POINT(7.07 1.11)
+710007 POINT(7.03 1.11)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/test.json
new file mode 100644
index 00000000..d08fe553
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/test.json
@@ -0,0 +1,13 @@
+{
+    "test_id": 710,
+    "description": "Invalid multipolygon relation: Three ways make up two outer rings, but the outer rings overlap.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 710900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/ways.wkt
new file mode 100644
index 00000000..55c01a5b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/710/ways.wkt
@@ -0,0 +1,3 @@
+710800 LINESTRING(7.01 1.14,7.02 1.16,7.05 1.15,7.03 1.12,7.01 1.14)
+710801 LINESTRING(7.03 1.13,7.07 1.13,7.07 1.11)
+710802 LINESTRING(7.07 1.11,7.03 1.11,7.03 1.13)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/data.osm
new file mode 100644
index 00000000..4c251988
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/data.osm
@@ -0,0 +1,30 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="711000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.11"/>
+    <node id="711001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.14"/>
+    <node id="711002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.14"/>
+    <node id="711003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.11"/>
+    <way id="711800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="711000"/>
+        <nd ref="711001"/>
+        <nd ref="711002"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="711"/>
+    </way>
+    <way id="711801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="711001"/>
+        <nd ref="711002"/>
+        <nd ref="711003"/>
+        <nd ref="711000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="711"/>
+    </way>
+    <relation id="711900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="711800" role="outer"/>
+        <member type="way" ref="711801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="711"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/data.osm.pbf
new file mode 100644
index 00000000..ff8628ff
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/nodes.wkt
new file mode 100644
index 00000000..4d64e623
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/nodes.wkt
@@ -0,0 +1,4 @@
+711000 POINT(7.11 1.11)
+711001 POINT(7.11 1.14)
+711002 POINT(7.14 1.14)
+711003 POINT(7.14 1.11)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/test.json
new file mode 100644
index 00000000..0f438f0c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 711,
+    "description": "Invalid multipolygon relation: Two ways, both containing one of the segments.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 711900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fix": [
+            {
+                "from_id": 711900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.11 1.11,7.11 1.14,7.14 1.14,7.14 1.11,7.11 1.11)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "711"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/ways.wkt
new file mode 100644
index 00000000..557291b5
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/711/ways.wkt
@@ -0,0 +1,2 @@
+711800 LINESTRING(7.11 1.11,7.11 1.14,7.14 1.14)
+711801 LINESTRING(7.11 1.14,7.14 1.14,7.14 1.11,7.11 1.11)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/data.osm
new file mode 100644
index 00000000..957720c0
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/data.osm
@@ -0,0 +1,24 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="714000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.45" lat="1.11"/>
+    <node id="714001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.11"/>
+    <node id="714002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.15"/>
+    <node id="714003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.45" lat="1.15"/>
+    <node id="714004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.45" lat="1.12"/>
+    <way id="714800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="714000"/>
+        <nd ref="714001"/>
+        <nd ref="714002"/>
+        <nd ref="714003"/>
+        <nd ref="714004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="714"/>
+    </way>
+    <relation id="714900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="714800" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="714"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/data.osm.pbf
new file mode 100644
index 00000000..9d14e38b
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/nodes.wkt
new file mode 100644
index 00000000..1943335e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/nodes.wkt
@@ -0,0 +1,5 @@
+714000 POINT(7.45 1.11)
+714001 POINT(7.41 1.11)
+714002 POINT(7.41 1.15)
+714003 POINT(7.45 1.15)
+714004 POINT(7.45 1.12)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/test.json
new file mode 100644
index 00000000..990a9c36
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 714,
+    "description": "Invalid multipolygon relation: Open ring.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 714900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fixed": [
+            {
+                "from_id": 714900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.41 1.11,7.41 1.15,7.45 1.15,7.45 1.11,7.41 1.11)))",
+                "tags": {
+                    "test:section": "mp-geom",
+                    "test:id": "714",
+                    "landuse": "forest"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/ways.wkt
new file mode 100644
index 00000000..dba76207
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/714/ways.wkt
@@ -0,0 +1 @@
+714800 LINESTRING(7.45 1.11,7.41 1.11,7.41 1.15,7.45 1.15,7.45 1.12)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/data.osm
new file mode 100644
index 00000000..037f6fdd
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/data.osm
@@ -0,0 +1,31 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="715000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.11"/>
+    <node id="715001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.51" lat="1.11"/>
+    <node id="715002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.51" lat="1.14"/>
+    <node id="715003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.51" lat="1.15"/>
+    <node id="715004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.15"/>
+    <node id="715005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.12"/>
+    <way id="715800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="715000"/>
+        <nd ref="715001"/>
+        <nd ref="715002"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="715"/>
+    </way>
+    <way id="715801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="715003"/>
+        <nd ref="715004"/>
+        <nd ref="715005"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="715"/>
+    </way>
+    <relation id="715900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="715800" role="outer"/>
+        <member type="way" ref="715801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="715"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/data.osm.pbf
new file mode 100644
index 00000000..5f0397e5
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/nodes.wkt
new file mode 100644
index 00000000..a73c25a0
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/nodes.wkt
@@ -0,0 +1,6 @@
+715000 POINT(7.55 1.11)
+715001 POINT(7.51 1.11)
+715002 POINT(7.51 1.14)
+715003 POINT(7.51 1.15)
+715004 POINT(7.55 1.15)
+715005 POINT(7.55 1.12)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/test.json
new file mode 100644
index 00000000..71d8393f
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 715,
+    "description": "Invalid multipolygon relation: Two open rings.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 715900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fixed": [
+            {
+                "from_id": 715900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.51 1.11,7.51 1.15,7.55 1.15,7.55 1.11,7.51 1.11)))",
+                "tags": {
+                    "test:section": "mp-geom",
+                    "test:id": "715",
+                    "landuse": "forest"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/ways.wkt
new file mode 100644
index 00000000..9310a0bc
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/715/ways.wkt
@@ -0,0 +1,2 @@
+715800 LINESTRING(7.55 1.11,7.51 1.11,7.51 1.14)
+715801 LINESTRING(7.51 1.15,7.55 1.15,7.55 1.12)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/data.osm
new file mode 100644
index 00000000..db1ef0b4
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/data.osm
@@ -0,0 +1,37 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="720000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.25"/>
+    <node id="720001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.21"/>
+    <node id="720002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.21"/>
+    <node id="720003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.25"/>
+    <node id="720004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.24"/>
+    <node id="720005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.02" lat="1.24"/>
+    <node id="720006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.02" lat="1.22"/>
+    <node id="720007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.22"/>
+    <way id="720800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="720000"/>
+        <nd ref="720001"/>
+        <nd ref="720002"/>
+        <nd ref="720003"/>
+        <nd ref="720000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="720"/>
+    </way>
+    <way id="720801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="720004"/>
+        <nd ref="720005"/>
+        <nd ref="720006"/>
+        <nd ref="720007"/>
+        <nd ref="720004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="720"/>
+    </way>
+    <relation id="720900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="720800" role="outer"/>
+        <member type="way" ref="720801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="720"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/data.osm.pbf
new file mode 100644
index 00000000..fd30d6ea
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/nodes.wkt
new file mode 100644
index 00000000..dbc5ef50
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/nodes.wkt
@@ -0,0 +1,8 @@
+720000 POINT(7.05 1.25)
+720001 POINT(7.05 1.21)
+720002 POINT(7.01 1.21)
+720003 POINT(7.01 1.25)
+720004 POINT(7.04 1.24)
+720005 POINT(7.02 1.24)
+720006 POINT(7.02 1.22)
+720007 POINT(7.04 1.22)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/test.json
new file mode 100644
index 00000000..835f64d2
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 720,
+    "description": "Multipolygon with one outer and one inner ring. They are both oriented clockwise and have the correct role.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 720900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.05 1.21,7.01 1.21,7.01 1.25,7.05 1.25,7.05 1.21),(7.04 1.22,7.02 1.22,7.02 1.24,7.04 1.24,7.04 1.22)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "720"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/ways.wkt
new file mode 100644
index 00000000..9affc536
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/720/ways.wkt
@@ -0,0 +1,2 @@
+720800 LINESTRING(7.05 1.25,7.05 1.21,7.01 1.21,7.01 1.25,7.05 1.25)
+720801 LINESTRING(7.04 1.24,7.02 1.24,7.02 1.22,7.04 1.22,7.04 1.24)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/data.osm
new file mode 100644
index 00000000..f30ff36f
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/data.osm
@@ -0,0 +1,36 @@
+<?xml version='1.0' encoding='UTF-8'?> <osm version="0.6" generator="testdata" upload="false">
+    <node id="721000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.25"/>
+    <node id="721001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.21"/>
+    <node id="721002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.21"/>
+    <node id="721003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.25"/>
+    <node id="721004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.24"/>
+    <node id="721005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.12" lat="1.24"/>
+    <node id="721006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.12" lat="1.22"/>
+    <node id="721007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.22"/>
+    <way id="721800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="721000"/>
+        <nd ref="721003"/>
+        <nd ref="721002"/>
+        <nd ref="721001"/>
+        <nd ref="721000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="721"/>
+    </way>
+    <way id="721801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="721004"/>
+        <nd ref="721007"/>
+        <nd ref="721006"/>
+        <nd ref="721005"/>
+        <nd ref="721004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="721"/>
+    </way>
+    <relation id="721900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="721800" role="outer"/>
+        <member type="way" ref="721801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="721"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/data.osm.pbf
new file mode 100644
index 00000000..bb708d09
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/nodes.wkt
new file mode 100644
index 00000000..052bebe9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/nodes.wkt
@@ -0,0 +1,8 @@
+721000 POINT(7.15 1.25)
+721001 POINT(7.15 1.21)
+721002 POINT(7.11 1.21)
+721003 POINT(7.11 1.25)
+721004 POINT(7.14 1.24)
+721005 POINT(7.12 1.24)
+721006 POINT(7.12 1.22)
+721007 POINT(7.14 1.22)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/test.json
new file mode 100644
index 00000000..5df77817
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 721,
+    "description": "Multipolygon with one outer and one inner ring. They are both oriented anti-clockwise and have the correct role.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 721900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.15 1.21,7.11 1.21,7.11 1.25,7.15 1.25,7.15 1.21),(7.14 1.22,7.12 1.22,7.12 1.24,7.14 1.24,7.14 1.22)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "721"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/ways.wkt
new file mode 100644
index 00000000..600e1050
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/721/ways.wkt
@@ -0,0 +1,2 @@
+721800 LINESTRING(7.15 1.25,7.11 1.25,7.11 1.21,7.15 1.21,7.15 1.25)
+721801 LINESTRING(7.14 1.24,7.14 1.22,7.12 1.22,7.12 1.24,7.14 1.24)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/data.osm
new file mode 100644
index 00000000..aa80c42a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/data.osm
@@ -0,0 +1,37 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="722000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.25" lat="1.25"/>
+    <node id="722001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.25" lat="1.21"/>
+    <node id="722002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.21"/>
+    <node id="722003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.25"/>
+    <node id="722004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.24" lat="1.24"/>
+    <node id="722005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.22" lat="1.24"/>
+    <node id="722006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.22" lat="1.22"/>
+    <node id="722007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.24" lat="1.22"/>
+    <way id="722800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="722000"/>
+        <nd ref="722001"/>
+        <nd ref="722002"/>
+        <nd ref="722003"/>
+        <nd ref="722000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="722"/>
+    </way>
+    <way id="722801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="722004"/>
+        <nd ref="722007"/>
+        <nd ref="722006"/>
+        <nd ref="722005"/>
+        <nd ref="722004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="722"/>
+    </way>
+    <relation id="722900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="722800" role="outer"/>
+        <member type="way" ref="722801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="722"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/data.osm.pbf
new file mode 100644
index 00000000..d2c37dea
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/nodes.wkt
new file mode 100644
index 00000000..a6fa39bb
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/nodes.wkt
@@ -0,0 +1,8 @@
+722000 POINT(7.25 1.25)
+722001 POINT(7.25 1.21)
+722002 POINT(7.21 1.21)
+722003 POINT(7.21 1.25)
+722004 POINT(7.24 1.24)
+722005 POINT(7.22 1.24)
+722006 POINT(7.22 1.22)
+722007 POINT(7.24 1.22)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/test.json
new file mode 100644
index 00000000..0b357402
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 722,
+    "description": "Multipolygon with one outer and one inner ring. The outer ring is oriented clockwise, the inner anti-clockwise. They have both the correct role.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 722900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.25 1.21,7.21 1.21,7.21 1.25,7.25 1.25,7.25 1.21),(7.24 1.22,7.22 1.22,7.22 1.24,7.24 1.24,7.24 1.22)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "722"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/ways.wkt
new file mode 100644
index 00000000..ff6d6d44
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/722/ways.wkt
@@ -0,0 +1,2 @@
+722800 LINESTRING(7.25 1.25,7.25 1.21,7.21 1.21,7.21 1.25,7.25 1.25)
+722801 LINESTRING(7.24 1.24,7.24 1.22,7.22 1.22,7.22 1.24,7.24 1.24)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/data.osm
new file mode 100644
index 00000000..3d45d182
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/data.osm
@@ -0,0 +1,37 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="723000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.35" lat="1.25"/>
+    <node id="723001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.35" lat="1.21"/>
+    <node id="723002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.21"/>
+    <node id="723003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.25"/>
+    <node id="723004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.34" lat="1.24"/>
+    <node id="723005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.24"/>
+    <node id="723006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.22"/>
+    <node id="723007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.34" lat="1.22"/>
+    <way id="723800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="723000"/>
+        <nd ref="723003"/>
+        <nd ref="723002"/>
+        <nd ref="723001"/>
+        <nd ref="723000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="723"/>
+    </way>
+    <way id="723801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="723004"/>
+        <nd ref="723005"/>
+        <nd ref="723006"/>
+        <nd ref="723007"/>
+        <nd ref="723004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="723"/>
+    </way>
+    <relation id="723900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="723800" role="outer"/>
+        <member type="way" ref="723801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="723"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/data.osm.pbf
new file mode 100644
index 00000000..b0f9ee5d
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/nodes.wkt
new file mode 100644
index 00000000..8aa10d86
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/nodes.wkt
@@ -0,0 +1,8 @@
+723000 POINT(7.35 1.25)
+723001 POINT(7.35 1.21)
+723002 POINT(7.31 1.21)
+723003 POINT(7.31 1.25)
+723004 POINT(7.34 1.24)
+723005 POINT(7.32 1.24)
+723006 POINT(7.32 1.22)
+723007 POINT(7.34 1.22)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/test.json
new file mode 100644
index 00000000..45a3a40d
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 723,
+    "description": "Multipolygon with one outer and one inner ring. The outer ring is oriented anti-clockwise, the inner clockwise. They have both the correct role.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 723900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.35 1.21,7.31 1.21,7.31 1.25,7.35 1.25,7.35 1.21),(7.34 1.22,7.32 1.22,7.32 1.24,7.34 1.24,7.34 1.22)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "723"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/ways.wkt
new file mode 100644
index 00000000..bca065d8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/723/ways.wkt
@@ -0,0 +1,2 @@
+723800 LINESTRING(7.35 1.25,7.31 1.25,7.31 1.21,7.35 1.21,7.35 1.25)
+723801 LINESTRING(7.34 1.24,7.32 1.24,7.32 1.22,7.34 1.22,7.34 1.24)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/data.osm
new file mode 100644
index 00000000..0199d7f4
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/data.osm
@@ -0,0 +1,44 @@
+<?xml version='1.0' encoding='UTF-8'?> <osm version="0.6" generator="testdata" upload="false">
+    <node id="724000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.22"/>
+    <node id="724001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.24"/>
+    <node id="724002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.44" lat="1.22"/>
+    <node id="724003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.45" lat="1.23"/>
+    <node id="724004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.47" lat="1.21"/>
+    <node id="724005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.21"/>
+    <node id="724006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.22"/>
+    <node id="724007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.26"/>
+    <node id="724008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.46" lat="1.26"/>
+    <node id="724009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.24"/>
+    <node id="724010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.44" lat="1.25"/>
+    <node id="724011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.45" lat="1.24"/>
+    <way id="724800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="724000"/>
+        <nd ref="724001"/>
+        <nd ref="724010"/>
+        <nd ref="724011"/>
+        <nd ref="724000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="724"/>
+    </way>
+    <way id="724801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="724008"/>
+        <nd ref="724003"/>
+        <nd ref="724002"/>
+        <nd ref="724004"/>
+        <nd ref="724005"/>
+        <nd ref="724006"/>
+        <nd ref="724009"/>
+        <nd ref="724007"/>
+        <nd ref="724008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="724"/>
+    </way>
+    <relation id="724900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="724801" role="outer"/>
+        <member type="way" ref="724800" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="724"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/data.osm.pbf
new file mode 100644
index 00000000..4286ffc3
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/nodes.wkt
new file mode 100644
index 00000000..909a83b1
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/nodes.wkt
@@ -0,0 +1,12 @@
+724000 POINT(7.43 1.22)
+724001 POINT(7.42 1.24)
+724002 POINT(7.44 1.22)
+724003 POINT(7.45 1.23)
+724004 POINT(7.47 1.21)
+724005 POINT(7.41 1.21)
+724006 POINT(7.42 1.22)
+724007 POINT(7.43 1.26)
+724008 POINT(7.46 1.26)
+724009 POINT(7.41 1.24)
+724010 POINT(7.44 1.25)
+724011 POINT(7.45 1.24)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/test.json
new file mode 100644
index 00000000..55b70109
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 724,
+    "description": "Multipolygon with one outer and one inner ring and a bit more complex geometry and nodes not in order.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 724900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.44 1.22,7.47 1.21,7.41 1.21,7.42 1.22,7.41 1.24,7.43 1.26,7.46 1.26,7.45 1.23,7.44 1.22),(7.43 1.22,7.42 1.24,7.44 1.25,7.45 1.24,7.43 1.22)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "724"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/ways.wkt
new file mode 100644
index 00000000..3559f931
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/724/ways.wkt
@@ -0,0 +1,2 @@
+724800 LINESTRING(7.43 1.22,7.42 1.24,7.44 1.25,7.45 1.24,7.43 1.22)
+724801 LINESTRING(7.46 1.26,7.45 1.23,7.44 1.22,7.47 1.21,7.41 1.21,7.42 1.22,7.41 1.24,7.43 1.26,7.46 1.26)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/data.osm
new file mode 100644
index 00000000..d742d9a8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/data.osm
@@ -0,0 +1,33 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="725000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.53" lat="1.21"/>
+    <node id="725001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.54" lat="1.21"/>
+    <node id="725002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.51" lat="1.23"/>
+    <node id="725003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.52" lat="1.23"/>
+    <node id="725004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.53" lat="1.25"/>
+    <node id="725005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.54" lat="1.25"/>
+    <way id="725800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="725001"/>
+        <nd ref="725000"/>
+        <nd ref="725002"/>
+        <nd ref="725004"/>
+        <nd ref="725005"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="725"/>
+    </way>
+    <way id="725801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="725005"/>
+        <nd ref="725003"/>
+        <nd ref="725001"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="725"/>
+    </way>
+    <relation id="725900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="725800" role="outer"/>
+        <member type="way" ref="725801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="725"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/data.osm.pbf
new file mode 100644
index 00000000..60ad75df
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/nodes.wkt
new file mode 100644
index 00000000..517dcabf
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/nodes.wkt
@@ -0,0 +1,6 @@
+725000 POINT(7.53 1.21)
+725001 POINT(7.54 1.21)
+725002 POINT(7.51 1.23)
+725003 POINT(7.52 1.23)
+725004 POINT(7.53 1.25)
+725005 POINT(7.54 1.25)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/test.json
new file mode 100644
index 00000000..8da50433
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 725,
+    "description": "Valid multipolygon with one concave outer ring and no inner ring.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 725900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.53 1.21,7.54 1.21,7.52 1.23,7.54 1.25,7.53 1.25,7.51 1.23,7.53 1.21)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "725"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/ways.wkt
new file mode 100644
index 00000000..2ecfaace
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/725/ways.wkt
@@ -0,0 +1,2 @@
+725800 LINESTRING(7.54 1.21,7.53 1.21,7.51 1.23,7.53 1.25,7.54 1.25)
+725801 LINESTRING(7.54 1.25,7.52 1.23,7.54 1.21)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/data.osm
new file mode 100644
index 00000000..3e303740
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/data.osm
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="726000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.62" lat="1.23"/>
+    <node id="726001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.63" lat="1.23"/>
+    <node id="726002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.63" lat="1.22"/>
+    <node id="726003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.67" lat="1.23"/>
+    <node id="726004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.67" lat="1.27"/>
+    <node id="726005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.64" lat="1.27"/>
+    <node id="726006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.64" lat="1.26"/>
+    <node id="726007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.63" lat="1.26"/>
+    <node id="726008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.26"/>
+    <node id="726009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.66" lat="1.26"/>
+    <node id="726010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.66" lat="1.23"/>
+    <node id="726011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.23"/>
+    <way id="726800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="726000"/>
+        <nd ref="726001"/>
+        <nd ref="726002"/>
+        <nd ref="726003"/>
+        <nd ref="726004"/>
+        <nd ref="726005"/>
+        <nd ref="726006"/>
+        <nd ref="726007"/>
+        <nd ref="726000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="726"/>
+    </way>
+    <way id="726801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="726008"/>
+        <nd ref="726009"/>
+        <nd ref="726010"/>
+        <nd ref="726011"/>
+        <nd ref="726008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="726"/>
+    </way>
+    <relation id="726900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="726800" role="outer"/>
+        <member type="way" ref="726801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="726"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/data.osm.pbf
new file mode 100644
index 00000000..d468f276
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/nodes.wkt
new file mode 100644
index 00000000..3d56ee43
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/nodes.wkt
@@ -0,0 +1,12 @@
+726000 POINT(7.62 1.23)
+726001 POINT(7.63 1.23)
+726002 POINT(7.63 1.22)
+726003 POINT(7.67 1.23)
+726004 POINT(7.67 1.27)
+726005 POINT(7.64 1.27)
+726006 POINT(7.64 1.26)
+726007 POINT(7.63 1.26)
+726008 POINT(7.65 1.26)
+726009 POINT(7.66 1.26)
+726010 POINT(7.66 1.23)
+726011 POINT(7.65 1.23)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/test.json
new file mode 100644
index 00000000..03fb2a3c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 726,
+    "description": "Valid multipolygon with one inner and one outer.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 726900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.62 1.23,7.63 1.23,7.63 1.22,7.67 1.23,7.67 1.27,7.64 1.27,7.64 1.26,7.63 1.26,7.62 1.23),(7.65 1.26,7.66 1.26,7.66 1.23,7.65 1.23,7.65 1.26)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "726"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/ways.wkt
new file mode 100644
index 00000000..6d3536a8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/726/ways.wkt
@@ -0,0 +1,2 @@
+726800 LINESTRING(7.62 1.23,7.63 1.23,7.63 1.22,7.67 1.23,7.67 1.27,7.64 1.27,7.64 1.26,7.63 1.26,7.62 1.23)
+726801 LINESTRING(7.65 1.26,7.66 1.26,7.66 1.23,7.65 1.23,7.65 1.26)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/data.osm
new file mode 100644
index 00000000..bff6f9fe
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/data.osm
@@ -0,0 +1,45 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="727000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.72" lat="1.23"/>
+    <node id="727001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.73" lat="1.23"/>
+    <node id="727002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.73" lat="1.22"/>
+    <node id="727003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.77" lat="1.23"/>
+    <node id="727004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.77" lat="1.27"/>
+    <node id="727005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.74" lat="1.27"/>
+    <node id="727006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.74" lat="1.26"/>
+    <node id="727007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.73" lat="1.26"/>
+    <node id="727008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.71" lat="1.21"/>
+    <node id="727009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.71" lat="1.29"/>
+    <node id="727010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.79" lat="1.29"/>
+    <node id="727011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.79" lat="1.21"/>
+    <way id="727800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="727000"/>
+        <nd ref="727001"/>
+        <nd ref="727002"/>
+        <nd ref="727003"/>
+        <nd ref="727004"/>
+        <nd ref="727005"/>
+        <nd ref="727006"/>
+        <nd ref="727007"/>
+        <nd ref="727000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="727"/>
+    </way>
+    <way id="727801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="727008"/>
+        <nd ref="727009"/>
+        <nd ref="727010"/>
+        <nd ref="727011"/>
+        <nd ref="727008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="727"/>
+    </way>
+    <relation id="727900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="727800" role="inner"/>
+        <member type="way" ref="727801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="727"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/data.osm.pbf
new file mode 100644
index 00000000..165eb3a8
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/nodes.wkt
new file mode 100644
index 00000000..17293786
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/nodes.wkt
@@ -0,0 +1,12 @@
+727000 POINT(7.72 1.23)
+727001 POINT(7.73 1.23)
+727002 POINT(7.73 1.22)
+727003 POINT(7.77 1.23)
+727004 POINT(7.77 1.27)
+727005 POINT(7.74 1.27)
+727006 POINT(7.74 1.26)
+727007 POINT(7.73 1.26)
+727008 POINT(7.71 1.21)
+727009 POINT(7.71 1.29)
+727010 POINT(7.79 1.29)
+727011 POINT(7.79 1.21)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/test.json
new file mode 100644
index 00000000..fc6f9bee
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 727,
+    "description": "Valid multipolygon with one inner and one outer.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 727900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.71 1.21,7.71 1.29,7.79 1.29,7.79 1.21,7.71 1.21),(7.72 1.23,7.73 1.23,7.73 1.22,7.77 1.23,7.77 1.27,7.74 1.27,7.74 1.26,7.73 1.26,7.72 1.23)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "727"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/ways.wkt
new file mode 100644
index 00000000..4b253eec
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/727/ways.wkt
@@ -0,0 +1,2 @@
+727800 LINESTRING(7.72 1.23,7.73 1.23,7.73 1.22,7.77 1.23,7.77 1.27,7.74 1.27,7.74 1.26,7.73 1.26,7.72 1.23)
+727801 LINESTRING(7.71 1.21,7.71 1.29,7.79 1.29,7.79 1.21,7.71 1.21)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/data.osm
new file mode 100644
index 00000000..301e7015
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/data.osm
@@ -0,0 +1,33 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="728000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.85" lat="1.23"/>
+    <node id="728001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.86" lat="1.22"/>
+    <node id="728002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.87" lat="1.22"/>
+    <node id="728003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.87" lat="1.24"/>
+    <node id="728004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.86" lat="1.25"/>
+    <node id="728005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.83" lat="1.25"/>
+    <node id="728006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.82" lat="1.26"/>
+    <node id="728007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.84" lat="1.23"/>
+    <node id="728008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.89" lat="1.29"/>
+    <way id="728800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="728000"/>
+        <nd ref="728001"/>
+        <nd ref="728002"/>
+        <nd ref="728003"/>
+        <nd ref="728004"/>
+        <nd ref="728005"/>
+        <nd ref="728006"/>
+        <nd ref="728007"/>
+        <nd ref="728000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="728"/>
+    </way>
+    <relation id="728900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="728800" role="outer"/>
+        <member type="node" ref="728008" role=""/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="728"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/data.osm.pbf
new file mode 100644
index 00000000..df5884f2
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/nodes.wkt
new file mode 100644
index 00000000..d33a7ab6
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/nodes.wkt
@@ -0,0 +1,9 @@
+728000 POINT(7.85 1.23)
+728001 POINT(7.86 1.22)
+728002 POINT(7.87 1.22)
+728003 POINT(7.87 1.24)
+728004 POINT(7.86 1.25)
+728005 POINT(7.83 1.25)
+728006 POINT(7.82 1.26)
+728007 POINT(7.84 1.23)
+728008 POINT(7.89 1.29)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/test.json
new file mode 100644
index 00000000..09bb9eb7
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 728,
+    "description": "Multipolygon with one simple outer ring and a node member.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 728900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.85 1.23,7.86 1.22,7.87 1.22,7.87 1.24,7.86 1.25,7.83 1.25,7.82 1.26,7.84 1.23,7.85 1.23)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "728"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/ways.wkt
new file mode 100644
index 00000000..0fc1e4f9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/728/ways.wkt
@@ -0,0 +1 @@
+728800 LINESTRING(7.85 1.23,7.86 1.22,7.87 1.22,7.87 1.24,7.86 1.25,7.83 1.25,7.82 1.26,7.84 1.23,7.85 1.23)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/data.osm
new file mode 100644
index 00000000..35b02250
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/data.osm
@@ -0,0 +1,51 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="729000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.97" lat="1.27"/>
+    <node id="729001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.97" lat="1.23"/>
+    <node id="729002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.93" lat="1.23"/>
+    <node id="729003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.93" lat="1.27"/>
+    <node id="729004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.96" lat="1.26"/>
+    <node id="729005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.94" lat="1.26"/>
+    <node id="729006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.94" lat="1.24"/>
+    <node id="729007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.96" lat="1.24"/>
+    <node id="729008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.91" lat="1.21"/>
+    <node id="729009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.91" lat="1.29"/>
+    <node id="729010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.99" lat="1.29"/>
+    <node id="729011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.99" lat="1.21"/>
+    <way id="729800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="729000"/>
+        <nd ref="729001"/>
+        <nd ref="729002"/>
+        <nd ref="729003"/>
+        <nd ref="729000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="729"/>
+    </way>
+    <way id="729801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="729004"/>
+        <nd ref="729005"/>
+        <nd ref="729006"/>
+        <nd ref="729007"/>
+        <nd ref="729004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="729"/>
+    </way>
+    <way id="729802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="729008"/>
+        <nd ref="729009"/>
+        <nd ref="729010"/>
+        <nd ref="729011"/>
+        <nd ref="729008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="729"/>
+    </way>
+    <relation id="729900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="729801" role="outer"/>
+        <member type="way" ref="729800" role="inner"/>
+        <member type="way" ref="729802" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="729"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/data.osm.pbf
new file mode 100644
index 00000000..8dcb05bf
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/nodes.wkt
new file mode 100644
index 00000000..69f6a103
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/nodes.wkt
@@ -0,0 +1,12 @@
+729000 POINT(7.97 1.27)
+729001 POINT(7.97 1.23)
+729002 POINT(7.93 1.23)
+729003 POINT(7.93 1.27)
+729004 POINT(7.96 1.26)
+729005 POINT(7.94 1.26)
+729006 POINT(7.94 1.24)
+729007 POINT(7.96 1.24)
+729008 POINT(7.91 1.21)
+729009 POINT(7.91 1.29)
+729010 POINT(7.99 1.29)
+729011 POINT(7.99 1.21)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/test.json
new file mode 100644
index 00000000..6215ede9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 729,
+    "description": "Valid multipolygon with second outer ring in inner ring.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 729900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.91 1.21,7.91 1.29,7.99 1.29,7.99 1.21,7.91 1.21),(7.97 1.27,7.97 1.23,7.93 1.23,7.93 1.27,7.97 1.27)),((7.96 1.26,7.94 1.26,7.94 1.24,7.96 1.24,7.96 1.26)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "729"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/ways.wkt
new file mode 100644
index 00000000..8951eeee
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/729/ways.wkt
@@ -0,0 +1,3 @@
+729800 LINESTRING(7.97 1.27,7.97 1.23,7.93 1.23,7.93 1.27,7.97 1.27)
+729801 LINESTRING(7.96 1.26,7.94 1.26,7.94 1.24,7.96 1.24,7.96 1.26)
+729802 LINESTRING(7.91 1.21,7.91 1.29,7.99 1.29,7.99 1.21,7.91 1.21)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/data.osm
new file mode 100644
index 00000000..f4f4b99a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/data.osm
@@ -0,0 +1,71 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="730000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.02" lat="1.33"/>
+    <node id="730001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.33"/>
+    <node id="730002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.02" lat="1.32"/>
+    <node id="730003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.32"/>
+
+    <node id="730004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.35"/>
+    <node id="730005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.35"/>
+    <node id="730006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.34"/>
+    <node id="730007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.34"/>
+
+    <node id="730008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.33"/>
+    <node id="730009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.33"/>
+    <node id="730010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.32"/>
+    <node id="730011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.32"/>
+
+    <node id="730012" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.06" lat="1.31"/>
+    <node id="730013" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.31"/>
+    <node id="730014" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.34"/>
+    <node id="730015" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.37"/>
+    <node id="730016" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.06" lat="1.34"/>
+
+    <way id="730800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="730000"/>
+        <nd ref="730001"/>
+        <nd ref="730003"/>
+        <nd ref="730002"/>
+        <nd ref="730000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="730"/>
+    </way>
+    <way id="730801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="730004"/>
+        <nd ref="730005"/>
+        <nd ref="730006"/>
+        <nd ref="730007"/>
+        <nd ref="730004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="730"/>
+    </way>
+    <way id="730802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="730009"/>
+        <nd ref="730010"/>
+        <nd ref="730011"/>
+        <nd ref="730008"/>
+        <nd ref="730009"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="730"/>
+    </way>
+    <way id="730803" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="730016"/>
+        <nd ref="730012"/>
+        <nd ref="730013"/>
+        <nd ref="730014"/>
+        <nd ref="730015"/>
+        <nd ref="730016"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="730"/>
+    </way>
+    <relation id="730900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="730800" role="inner"/>
+        <member type="way" ref="730801" role="inner"/>
+        <member type="way" ref="730802" role="inner"/>
+        <member type="way" ref="730803" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="730"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/data.osm.pbf
new file mode 100644
index 00000000..79f70051
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/nodes.wkt
new file mode 100644
index 00000000..4f9ae756
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/nodes.wkt
@@ -0,0 +1,17 @@
+730000 POINT(7.02 1.33)
+730001 POINT(7.03 1.33)
+730002 POINT(7.02 1.32)
+730003 POINT(7.03 1.32)
+730004 POINT(7.03 1.35)
+730005 POINT(7.04 1.35)
+730006 POINT(7.04 1.34)
+730007 POINT(7.03 1.34)
+730008 POINT(7.05 1.33)
+730009 POINT(7.04 1.33)
+730010 POINT(7.04 1.32)
+730011 POINT(7.05 1.32)
+730012 POINT(7.06 1.31)
+730013 POINT(7.01 1.31)
+730014 POINT(7.01 1.34)
+730015 POINT(7.04 1.37)
+730016 POINT(7.06 1.34)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/test.json
new file mode 100644
index 00000000..5dd7b254
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 730,
+    "description": "Valid multipolygon with one outer and three inner rings with correct roles.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 730900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.06 1.31,7.01 1.31,7.01 1.34,7.04 1.37,7.06 1.34,7.06 1.31),(7.02 1.33,7.03 1.33,7.03 1.32,7.02 1.32,7.02 1.33),(7.03 1.35,7.04 1.35,7.04 1.34,7.03 1.34,7.03 1.35),(7.05 1.33,7.04 1.33,7.04 1.32,7.05 1.32,7.05 1.33)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "730"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/ways.wkt
new file mode 100644
index 00000000..e9d7633c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/730/ways.wkt
@@ -0,0 +1,4 @@
+730800 LINESTRING(7.02 1.33,7.03 1.33,7.03 1.32,7.02 1.32,7.02 1.33)
+730801 LINESTRING(7.03 1.35,7.04 1.35,7.04 1.34,7.03 1.34,7.03 1.35)
+730802 LINESTRING(7.04 1.33,7.04 1.32,7.05 1.32,7.05 1.33,7.04 1.33)
+730803 LINESTRING(7.06 1.34,7.06 1.31,7.01 1.31,7.01 1.34,7.04 1.37,7.06 1.34)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/data.osm
new file mode 100644
index 00000000..ede7b6e9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/data.osm
@@ -0,0 +1,96 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="731000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.17" lat="1.31"/>
+    <node id="731001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.12" lat="1.31"/>
+    <!-- 731002 intentionally missing --> 
+    <node id="731003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.33"/>
+    <node id="731004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.38"/>
+    <node id="731005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.18" lat="1.38"/>
+    <node id="731006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.18" lat="1.33"/>
+
+    <node id="731007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.16" lat="1.35"/>
+    <node id="731008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.16" lat="1.36"/> <!-- geometrically superfluous node -->
+    <node id="731009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.16" lat="1.37"/>
+    <node id="731010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.37"/>
+    <node id="731011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.36"/>
+    <node id="731012" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.35"/>
+    <node id="731013" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.34"/>
+    <node id="731014" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.34"/>
+
+    <node id="731015" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.17" lat="1.32"/>
+    <node id="731016" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.17" lat="1.35"/>
+    <node id="731017" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.16" lat="1.34"/>
+    <node id="731018" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.16" lat="1.33"/>
+    <node id="731019" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.13" lat="1.33"/>
+    <node id="731020" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.13" lat="1.36"/>
+    <node id="731021" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.12" lat="1.36"/>
+    <node id="731022" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.12" lat="1.32"/>
+
+    <way id="731800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="731000"/>
+        <nd ref="731001"/>
+        <nd ref="731003"/>
+        <nd ref="731004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="731"/>
+    </way>
+    <way id="731801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="731004"/>
+        <nd ref="731005"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="731"/>
+    </way>
+    <way id="731802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="731005"/>
+        <nd ref="731006"/>
+        <nd ref="731000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="731"/>
+    </way>
+
+    <way id="731803" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="731010"/>
+        <nd ref="731009"/>
+        <nd ref="731008"/>
+        <nd ref="731007"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="731"/>
+    </way>
+    <way id="731804" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="731010"/>
+        <nd ref="731011"/>
+        <nd ref="731012"/>
+        <nd ref="731013"/>
+        <nd ref="731014"/>
+        <nd ref="731007"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="731"/>
+    </way>
+
+    <way id="731805" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="731015"/>
+        <nd ref="731016"/>
+        <nd ref="731017"/>
+        <nd ref="731018"/>
+        <nd ref="731019"/>
+        <nd ref="731020"/>
+        <nd ref="731021"/>
+        <nd ref="731022"/>
+        <nd ref="731015"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="731"/>
+    </way>
+
+    <relation id="731900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="731800" role="outer"/>
+        <member type="way" ref="731801" role="outer"/>
+        <member type="way" ref="731802" role="outer"/>
+        <member type="way" ref="731803" role="inner"/>
+        <member type="way" ref="731804" role="inner"/>
+        <member type="way" ref="731805" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="731"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/data.osm.pbf
new file mode 100644
index 00000000..9d52b551
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/nodes.wkt
new file mode 100644
index 00000000..082ec1a2
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/nodes.wkt
@@ -0,0 +1,22 @@
+731000 POINT(7.17 1.31)
+731001 POINT(7.12 1.31)
+731003 POINT(7.11 1.33)
+731004 POINT(7.11 1.38)
+731005 POINT(7.18 1.38)
+731006 POINT(7.18 1.33)
+731007 POINT(7.16 1.35)
+731008 POINT(7.16 1.36)
+731009 POINT(7.16 1.37)
+731010 POINT(7.15 1.37)
+731011 POINT(7.15 1.36)
+731012 POINT(7.14 1.35)
+731013 POINT(7.14 1.34)
+731014 POINT(7.15 1.34)
+731015 POINT(7.17 1.32)
+731016 POINT(7.17 1.35)
+731017 POINT(7.16 1.34)
+731018 POINT(7.16 1.33)
+731019 POINT(7.13 1.33)
+731020 POINT(7.13 1.36)
+731021 POINT(7.12 1.36)
+731022 POINT(7.12 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/test.json
new file mode 100644
index 00000000..0dc88e47
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 731,
+    "description": "Valid complex multipolygon with one outer and two inner rings made up of several ways. Roles are tagged correctly.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 731900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.18 1.33,7.17 1.31,7.12 1.31,7.11 1.33,7.11 1.38,7.18 1.38,7.18 1.33),(7.17 1.32,7.12 1.32,7.12 1.36,7.13 1.36,7.13 1.33,7.16 1.33,7.16 1.34,7.17 1.35,7.17 1.32),(7.16 1.36,7.16 1.35,7.15 1.34,7.14 1.34,7.14 1.35,7.15 1.36,7.15 1.37,7.16 1.37,7.16 1.36)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "731"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/ways.wkt
new file mode 100644
index 00000000..74da0585
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/731/ways.wkt
@@ -0,0 +1,6 @@
+731800 LINESTRING(7.17 1.31,7.12 1.31,7.11 1.33,7.11 1.38)
+731801 LINESTRING(7.11 1.38,7.18 1.38)
+731802 LINESTRING(7.18 1.38,7.18 1.33,7.17 1.31)
+731803 LINESTRING(7.15 1.37,7.16 1.37,7.16 1.36,7.16 1.35)
+731804 LINESTRING(7.15 1.37,7.15 1.36,7.14 1.35,7.14 1.34,7.15 1.34,7.16 1.35)
+731805 LINESTRING(7.17 1.32,7.17 1.35,7.16 1.34,7.16 1.33,7.13 1.33,7.13 1.36,7.12 1.36,7.12 1.32,7.17 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/data.osm
new file mode 100644
index 00000000..bb42301b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/data.osm
@@ -0,0 +1,56 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="732000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.36"/>
+    <node id="732001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.22" lat="1.37"/>
+    <node id="732002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.23" lat="1.36"/>
+    <node id="732003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.22" lat="1.35"/>
+
+    <node id="732004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.33"/>
+    <node id="732005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.31"/>
+    <node id="732006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.26" lat="1.31"/>
+    <node id="732007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.26" lat="1.34"/>
+    <node id="732008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.24" lat="1.36"/>
+
+    <node id="732009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.24" lat="1.34"/>
+    <node id="732010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.22" lat="1.32"/>
+    <node id="732011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.25" lat="1.32"/>
+
+    <way id="732800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="732000"/>
+        <nd ref="732001"/>
+        <nd ref="732002"/>
+        <nd ref="732003"/>
+        <nd ref="732000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="732"/>
+    </way>
+    <way id="732801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="732004"/>
+        <nd ref="732005"/>
+        <nd ref="732005"/>
+        <nd ref="732006"/>
+        <nd ref="732007"/>
+        <nd ref="732008"/>
+        <nd ref="732004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="732"/>
+    </way>
+    <way id="732802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="732009"/>
+        <nd ref="732010"/>
+        <nd ref="732011"/>
+        <nd ref="732009"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="732"/>
+    </way>
+
+    <relation id="732900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="732800" role="outer"/>
+        <member type="way" ref="732801" role="outer"/>
+        <member type="way" ref="732802" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="732"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/data.osm.pbf
new file mode 100644
index 00000000..436af624
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/labels.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/labels.wkt
new file mode 100644
index 00000000..dde4c6b1
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/labels.wkt
@@ -0,0 +1 @@
+POINT(7.212 1.312) Node twice in the 732801 ring.
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/nodes.wkt
new file mode 100644
index 00000000..56f75830
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/nodes.wkt
@@ -0,0 +1,12 @@
+732000 POINT(7.21 1.36)
+732001 POINT(7.22 1.37)
+732002 POINT(7.23 1.36)
+732003 POINT(7.22 1.35)
+732004 POINT(7.21 1.33)
+732005 POINT(7.21 1.31)
+732006 POINT(7.26 1.31)
+732007 POINT(7.26 1.34)
+732008 POINT(7.24 1.36)
+732009 POINT(7.24 1.34)
+732010 POINT(7.22 1.32)
+732011 POINT(7.25 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/test.json
new file mode 100644
index 00000000..8a0eab70
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 732,
+    "description": "Valid multipolygon with two outer rings, one containing an inner. One ring contains a node twice in succession.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 732900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.21 1.36,7.22 1.37,7.23 1.36,7.22 1.35,7.21 1.36)),((7.21 1.33,7.21 1.31,7.26 1.31,7.26 1.34,7.24 1.36,7.21 1.33),(7.24 1.34,7.22 1.32,7.25 1.32,7.24 1.34)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "732"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/ways.wkt
new file mode 100644
index 00000000..1c8d805b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/732/ways.wkt
@@ -0,0 +1,3 @@
+732800 LINESTRING(7.21 1.36,7.22 1.37,7.23 1.36,7.22 1.35,7.21 1.36)
+732801 LINESTRING(7.21 1.33,7.21 1.31,7.26 1.31,7.26 1.34,7.24 1.36,7.21 1.33)
+732802 LINESTRING(7.24 1.34,7.22 1.32,7.25 1.32,7.24 1.34)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/data.osm
new file mode 100644
index 00000000..8af2298f
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/data.osm
@@ -0,0 +1,37 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="733000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.31"/>
+    <node id="733001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.34"/>
+    <node id="733002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.35" lat="1.35"/>
+    <node id="733003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.36" lat="1.32"/>
+
+    <node id="733004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.35"/>
+    <node id="733005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.34" lat="1.36"/>
+
+    <way id="733800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="733000"/>
+        <nd ref="733001"/>
+        <nd ref="733002"/>
+        <nd ref="733003"/>
+        <nd ref="733000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="733"/>
+    </way>
+    <way id="733801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="733001"/>
+        <nd ref="733004"/>
+        <nd ref="733005"/>
+        <nd ref="733001"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="733"/>
+    </way>
+
+    <relation id="733900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="733800" role="outer"/>
+        <member type="way" ref="733801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="733"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/data.osm.pbf
new file mode 100644
index 00000000..57637746
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/nodes.wkt
new file mode 100644
index 00000000..d26d92fb
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/nodes.wkt
@@ -0,0 +1,6 @@
+733000 POINT(7.33 1.31)
+733001 POINT(7.32 1.34)
+733002 POINT(7.35 1.35)
+733003 POINT(7.36 1.32)
+733004 POINT(7.31 1.35)
+733005 POINT(7.34 1.36)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/test.json
new file mode 100644
index 00000000..8a4d1baf
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 733,
+    "description": "Valid multipolygon with two outer rings.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 733900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.33 1.31,7.32 1.34,7.35 1.35,7.36 1.32,7.33 1.31)),((7.32 1.34,7.31 1.35,7.34 1.36,7.32 1.34)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "733"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/ways.wkt
new file mode 100644
index 00000000..a3f7dad1
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/733/ways.wkt
@@ -0,0 +1,2 @@
+733800 LINESTRING(7.33 1.31,7.32 1.34,7.35 1.35,7.36 1.32,7.33 1.31)
+733801 LINESTRING(7.32 1.34,7.31 1.35,7.34 1.36,7.32 1.34)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/data.osm
new file mode 100644
index 00000000..aefdb34a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/data.osm
@@ -0,0 +1,53 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="734000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.34"/>
+    <node id="734001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.34"/>
+    <node id="734002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.44" lat="1.32"/>
+    <node id="734003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.32"/>
+
+    <node id="734004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.44" lat="1.36"/>
+    <node id="734005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.46" lat="1.36"/>
+    <node id="734006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.46" lat="1.34"/>
+
+    <node id="734007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.48" lat="1.34"/>
+    <node id="734008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.47" lat="1.32"/>
+    <node id="734009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.45" lat="1.32"/>
+
+    <way id="734800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="734000"/>
+        <nd ref="734001"/>
+        <nd ref="734002"/>
+        <nd ref="734003"/>
+        <nd ref="734000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="734"/>
+    </way>
+    <way id="734801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="734002"/>
+        <nd ref="734004"/>
+        <nd ref="734005"/>
+        <nd ref="734006"/>
+        <nd ref="734002"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="734"/>
+    </way>
+    <way id="734802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="734006"/>
+        <nd ref="734007"/>
+        <nd ref="734008"/>
+        <nd ref="734009"/>
+        <nd ref="734006"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="734"/>
+    </way>
+
+    <relation id="734900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="734800" role="outer"/>
+        <member type="way" ref="734801" role="outer"/>
+        <member type="way" ref="734802" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="734"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/data.osm.pbf
new file mode 100644
index 00000000..271e5d25
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/nodes.wkt
new file mode 100644
index 00000000..03e80f10
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/nodes.wkt
@@ -0,0 +1,10 @@
+734000 POINT(7.41 1.34)
+734001 POINT(7.43 1.34)
+734002 POINT(7.44 1.32)
+734003 POINT(7.42 1.32)
+734004 POINT(7.44 1.36)
+734005 POINT(7.46 1.36)
+734006 POINT(7.46 1.34)
+734007 POINT(7.48 1.34)
+734008 POINT(7.47 1.32)
+734009 POINT(7.45 1.32)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/test.json
new file mode 100644
index 00000000..8b15a9ba
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 734,
+    "description": "Valid multipolygon with three outer rings.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 734900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.41 1.34,7.43 1.34,7.44 1.32,7.42 1.32,7.41 1.34)),((7.44 1.32,7.44 1.36,7.46 1.36,7.46 1.34,7.44 1.32)),((7.46 1.34,7.48 1.34,7.47 1.32,7.45 1.32,7.46 1.34)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "734"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/ways.wkt
new file mode 100644
index 00000000..f6eb3277
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/734/ways.wkt
@@ -0,0 +1,3 @@
+734800 LINESTRING(7.41 1.34,7.43 1.34,7.44 1.32,7.42 1.32,7.41 1.34)
+734801 LINESTRING(7.44 1.32,7.44 1.36,7.46 1.36,7.46 1.34,7.44 1.32)
+734802 LINESTRING(7.46 1.34,7.48 1.34,7.47 1.32,7.45 1.32,7.46 1.34)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/data.osm
new file mode 100644
index 00000000..4bd4e57b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/data.osm
@@ -0,0 +1,29 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="740000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.41"/>
+    <node id="740001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.41"/>
+    <node id="740002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.45"/>
+    <node id="740003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.45"/>
+    <way id="740800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="740000"/>
+        <nd ref="740001"/>
+        <nd ref="740002"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="740"/>
+    </way>
+    <way id="740801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="740002"/>
+        <nd ref="740003"/>
+        <nd ref="740000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="740"/>
+    </way>
+    <relation id="740900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="740800" role="outer"/>
+        <member type="way" ref="740801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="740"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/data.osm.pbf
new file mode 100644
index 00000000..687839de
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/nodes.wkt
new file mode 100644
index 00000000..3eb75f40
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/nodes.wkt
@@ -0,0 +1,4 @@
+740000 POINT(7.01 1.41)
+740001 POINT(7.05 1.41)
+740002 POINT(7.01 1.45)
+740003 POINT(7.05 1.45)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/test.json
new file mode 100644
index 00000000..a3204b8b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/test.json
@@ -0,0 +1,13 @@
+{
+    "test_id": 740,
+    "description": "Invalid multipolygon because the outer ring crosses itself.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 740900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/ways.wkt
new file mode 100644
index 00000000..4d16c664
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/740/ways.wkt
@@ -0,0 +1,2 @@
+740800 LINESTRING(7.01 1.41,7.05 1.41,7.01 1.45)
+740801 LINESTRING(7.01 1.45,7.05 1.45,7.01 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/data.osm
new file mode 100644
index 00000000..1f5f04df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/data.osm
@@ -0,0 +1,25 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="741000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.13" lat="1.41"/>
+    <node id="741001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.13" lat="1.45"/>
+    <way id="741800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="741000"/>
+        <nd ref="741001"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="741"/>
+    </way>
+    <way id="741801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="741001"/>
+        <nd ref="741000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="741"/>
+    </way>
+    <relation id="741900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="741800" role="outer"/>
+        <member type="way" ref="741801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="741"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/data.osm.pbf
new file mode 100644
index 00000000..55de8e07
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/nodes.wkt
new file mode 100644
index 00000000..fe0d5f0b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/nodes.wkt
@@ -0,0 +1,2 @@
+741000 POINT(7.13 1.41)
+741001 POINT(7.13 1.45)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/test.json
new file mode 100644
index 00000000..51178049
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/test.json
@@ -0,0 +1,13 @@
+{
+    "test_id": 741,
+    "description": "Invalid multipolygon with a line only as 'outer ring'.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 741900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/ways.wkt
new file mode 100644
index 00000000..581bb7e9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/741/ways.wkt
@@ -0,0 +1,2 @@
+741800 LINESTRING(7.13 1.41,7.13 1.45)
+741801 LINESTRING(7.13 1.45,7.13 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/data.osm
new file mode 100644
index 00000000..728db387
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/data.osm
@@ -0,0 +1,32 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="742000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.41"/>
+    <node id="742001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.43"/>
+    <node id="742002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.45"/>
+    <node id="742003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.23" lat="1.43"/>
+    <node id="742004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.23" lat="1.41"/>
+    <way id="742800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="742000"/>
+        <nd ref="742001"/>
+        <nd ref="742002"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="742"/>
+    </way>
+    <way id="742801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="742002"/>
+        <nd ref="742001"/>
+        <nd ref="742003"/>
+        <nd ref="742004"/>
+        <nd ref="742000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="742"/>
+    </way>
+    <relation id="742900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="742800" role="outer"/>
+        <member type="way" ref="742801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="742"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/data.osm.pbf
new file mode 100644
index 00000000..696f15c4
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/nodes.wkt
new file mode 100644
index 00000000..cd443eb0
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/nodes.wkt
@@ -0,0 +1,5 @@
+742000 POINT(7.21 1.41)
+742001 POINT(7.21 1.43)
+742002 POINT(7.21 1.45)
+742003 POINT(7.23 1.43)
+742004 POINT(7.23 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/test.json
new file mode 100644
index 00000000..0e5a85f9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 742,
+    "description": "Invalid multipolygon because of a 'spike'.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 742900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fix": [
+            {
+                "from_id": 742900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.21 1.41,7.21 1.43,7.23 1.43,7.23 1.41,7.21 1.41)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "742"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/ways.wkt
new file mode 100644
index 00000000..6f4ca588
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/742/ways.wkt
@@ -0,0 +1,2 @@
+742800 LINESTRING(7.21 1.41,7.21 1.43,7.21 1.45)
+742801 LINESTRING(7.21 1.45,7.21 1.43,7.23 1.43,7.23 1.41,7.21 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/data.osm
new file mode 100644
index 00000000..0495baf3
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/data.osm
@@ -0,0 +1,31 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="743000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.41"/>
+    <node id="743001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.43"/>
+    <node id="743002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.45"/>
+    <node id="743003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.43"/>
+    <node id="743004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.41"/>
+    <way id="743800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="743000"/>
+        <nd ref="743002"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="743"/>
+    </way>
+    <way id="743801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="743002"/>
+        <nd ref="743001"/>
+        <nd ref="743003"/>
+        <nd ref="743004"/>
+        <nd ref="743000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="743"/>
+    </way>
+    <relation id="743900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="743800" role="outer"/>
+        <member type="way" ref="743801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="743"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/data.osm.pbf
new file mode 100644
index 00000000..6c11a4a4
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/nodes.wkt
new file mode 100644
index 00000000..c898cf05
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/nodes.wkt
@@ -0,0 +1,5 @@
+743000 POINT(7.31 1.41)
+743001 POINT(7.31 1.43)
+743002 POINT(7.31 1.45)
+743003 POINT(7.33 1.43)
+743004 POINT(7.33 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/test.json
new file mode 100644
index 00000000..29c7bf72
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 743,
+    "description": "Invalid multipolygon because of a 'spike'.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 743900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fix": [
+            {
+                "from_id": 743900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.31 1.41,7.31 1.43,7.33 1.43,7.33 1.41,7.31 1.41)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "743"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/ways.wkt
new file mode 100644
index 00000000..443b2ece
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/743/ways.wkt
@@ -0,0 +1,2 @@
+743800 LINESTRING(7.31 1.41,7.31 1.45)
+743801 LINESTRING(7.31 1.45,7.31 1.43,7.33 1.43,7.33 1.41,7.31 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/data.osm
new file mode 100644
index 00000000..5313c4ea
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/data.osm
@@ -0,0 +1,28 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="744000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.41"/>
+    <node id="744001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.43"/>
+    <node id="744002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.43"/>
+    <node id="744003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.41"/>
+    <way id="744800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="744000"/>
+        <nd ref="744001"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="744"/>
+    </way>
+    <way id="744801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="744001"/>
+        <nd ref="744002"/>
+        <nd ref="744003"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="744"/>
+    </way>
+    <relation id="744900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="744800" role="outer"/>
+        <member type="way" ref="744801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="744"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/data.osm.pbf
new file mode 100644
index 00000000..9d5c86dc
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/nodes.wkt
new file mode 100644
index 00000000..b6541591
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/nodes.wkt
@@ -0,0 +1,4 @@
+744000 POINT(7.41 1.41)
+744001 POINT(7.41 1.43)
+744002 POINT(7.43 1.43)
+744003 POINT(7.43 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/test.json
new file mode 100644
index 00000000..39c2e70d
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/test.json
@@ -0,0 +1,13 @@
+{
+    "test_id": 744,
+    "description": "Invalid multpolygon with single outer ring not closed.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 744900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/ways.wkt
new file mode 100644
index 00000000..1cd4fed8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/744/ways.wkt
@@ -0,0 +1,2 @@
+744800 LINESTRING(7.41 1.41,7.41 1.43)
+744801 LINESTRING(7.41 1.43,7.43 1.43,7.43 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/data.osm
new file mode 100644
index 00000000..4d7ae7bb
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/data.osm
@@ -0,0 +1,36 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="745000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.53" lat="1.42"/>
+    <node id="745001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.52" lat="1.41"/>
+    <node id="745002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.51" lat="1.42"/>
+    <node id="745003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.51" lat="1.44"/>
+    <node id="745004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.52" lat="1.45"/>
+    <node id="745005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.53" lat="1.44"/>
+    <node id="745006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.54" lat="1.41"/>
+    <node id="745007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.42"/>
+    <node id="745008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.44"/>
+    <node id="745009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.54" lat="1.45"/>
+    <way id="745800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="745000"/>
+        <nd ref="745001"/>
+        <nd ref="745002"/>
+        <nd ref="745003"/>
+        <nd ref="745004"/>
+        <nd ref="745005"/>
+        <nd ref="745000"/>
+        <nd ref="745006"/>
+        <nd ref="745007"/>
+        <nd ref="745008"/>
+        <nd ref="745009"/>
+        <nd ref="745005"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="745"/>
+    </way>
+    <relation id="745900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="745800" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="745"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/data.osm.pbf
new file mode 100644
index 00000000..7350072c
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/nodes.wkt
new file mode 100644
index 00000000..9ba45f37
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/nodes.wkt
@@ -0,0 +1,10 @@
+745000 POINT(7.53 1.42)
+745001 POINT(7.52 1.41)
+745002 POINT(7.51 1.42)
+745003 POINT(7.51 1.44)
+745004 POINT(7.52 1.45)
+745005 POINT(7.53 1.44)
+745006 POINT(7.54 1.41)
+745007 POINT(7.55 1.42)
+745008 POINT(7.55 1.44)
+745009 POINT(7.54 1.45)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/test.json
new file mode 100644
index 00000000..f1db3bb7
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/test.json
@@ -0,0 +1,13 @@
+{
+    "test_id": 745,
+    "description": "Impossible multipolygon out of one way.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 745900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/ways.wkt
new file mode 100644
index 00000000..5687c4c2
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/745/ways.wkt
@@ -0,0 +1 @@
+745800 LINESTRING(7.53 1.42,7.52 1.41,7.51 1.42,7.51 1.44,7.52 1.45,7.53 1.44,7.53 1.42,7.54 1.41,7.55 1.42,7.55 1.44,7.54 1.45,7.53 1.44)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/data.osm
new file mode 100644
index 00000000..fbc0122c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/data.osm
@@ -0,0 +1,42 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="746000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.63" lat="1.42"/>
+    <node id="746001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.62" lat="1.41"/>
+    <node id="746002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.61" lat="1.42"/>
+    <node id="746003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.61" lat="1.44"/>
+    <node id="746004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.62" lat="1.45"/>
+    <node id="746005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.63" lat="1.44"/>
+    <node id="746006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.64" lat="1.41"/>
+    <node id="746007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.42"/>
+    <node id="746008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.44"/>
+    <node id="746009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.64" lat="1.45"/>
+    <way id="746800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="746000"/>
+        <nd ref="746001"/>
+        <nd ref="746002"/>
+        <nd ref="746003"/>
+        <nd ref="746004"/>
+        <nd ref="746005"/>
+        <nd ref="746000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="746"/>
+    </way>
+    <way id="746801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="746000"/>
+        <nd ref="746006"/>
+        <nd ref="746007"/>
+        <nd ref="746008"/>
+        <nd ref="746009"/>
+        <nd ref="746005"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="746"/>
+    </way>
+    <relation id="746900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="746800" role="outer"/>
+        <member type="way" ref="746801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="746"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/data.osm.pbf
new file mode 100644
index 00000000..9d3cb263
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/nodes.wkt
new file mode 100644
index 00000000..19c069e2
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/nodes.wkt
@@ -0,0 +1,10 @@
+746000 POINT(7.63 1.42)
+746001 POINT(7.62 1.41)
+746002 POINT(7.61 1.42)
+746003 POINT(7.61 1.44)
+746004 POINT(7.62 1.45)
+746005 POINT(7.63 1.44)
+746006 POINT(7.64 1.41)
+746007 POINT(7.65 1.42)
+746008 POINT(7.65 1.44)
+746009 POINT(7.64 1.45)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/test.json
new file mode 100644
index 00000000..88759586
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/test.json
@@ -0,0 +1,13 @@
+{
+    "test_id": 746,
+    "description": "Impossible multipolygon out of two ways.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 746900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/ways.wkt
new file mode 100644
index 00000000..50d7c74a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/746/ways.wkt
@@ -0,0 +1,2 @@
+746800 LINESTRING(7.63 1.42,7.62 1.41,7.61 1.42,7.61 1.44,7.62 1.45,7.63 1.44,7.63 1.42)
+746801 LINESTRING(7.63 1.42,7.64 1.41,7.65 1.42,7.65 1.44,7.64 1.45,7.63 1.44)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/data.osm
new file mode 100644
index 00000000..3b16ae0e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/data.osm
@@ -0,0 +1,25 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="747000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.71" lat="1.41"/>
+    <node id="747001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.71" lat="1.45"/>
+    <node id="747002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.75" lat="1.45"/>
+    <node id="747003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.75" lat="1.45"/>
+    <node id="747004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.75" lat="1.41"/>
+    <way id="747800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="747000"/>
+        <nd ref="747001"/>
+        <nd ref="747002"/>
+        <nd ref="747003"/>
+        <nd ref="747004"/>
+        <nd ref="747000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="747"/>
+    </way>
+    <relation id="747900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="747800" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="747"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/data.osm.pbf
new file mode 100644
index 00000000..6842b827
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/nodes.wkt
new file mode 100644
index 00000000..9d1a2596
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/nodes.wkt
@@ -0,0 +1,5 @@
+747000 POINT(7.71 1.41)
+747001 POINT(7.71 1.45)
+747002 POINT(7.75 1.45)
+747003 POINT(7.75 1.45)
+747004 POINT(7.75 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/test.json
new file mode 100644
index 00000000..f9a2a4d8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 747,
+    "description": "Invalid multipolygon because there are two nodes with same location. Created from relation.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 747900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "location": [
+            {
+                "from_id": 747900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.71 1.41,7.71 1.45,7.75 1.45,7.75 1.41,7.71 1.41)))",
+                "tags": {
+                    "test:section": "mp-geom",
+                    "test:id": "747",
+                    "landuse": "forest"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/ways.wkt
new file mode 100644
index 00000000..fd1298fa
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/747/ways.wkt
@@ -0,0 +1 @@
+747800 LINESTRING(7.71 1.41,7.71 1.45,7.75 1.45,7.75 1.41,7.71 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/data.osm
new file mode 100644
index 00000000..fc9c11a8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/data.osm
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="748000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.81" lat="1.41"/>
+    <node id="748001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.81" lat="1.45"/>
+    <node id="748002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.85" lat="1.45"/>
+    <node id="748003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.85" lat="1.45"/>
+    <node id="748004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.85" lat="1.41"/>
+    <way id="748800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="748000"/>
+        <nd ref="748001"/>
+        <nd ref="748002"/>
+        <nd ref="748003"/>
+        <nd ref="748004"/>
+        <nd ref="748000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="748"/>
+        <tag k="landuse" v="forest"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/data.osm.pbf
new file mode 100644
index 00000000..32cc145b
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/nodes.wkt
new file mode 100644
index 00000000..2a7c00d2
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/nodes.wkt
@@ -0,0 +1,5 @@
+748000 POINT(7.81 1.41)
+748001 POINT(7.81 1.45)
+748002 POINT(7.85 1.45)
+748003 POINT(7.85 1.45)
+748004 POINT(7.85 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/test.json
new file mode 100644
index 00000000..284e0033
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 748,
+    "description": "Invalid multipolygon because there are two nodes with same location. Created from way.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 748800,
+                "from_type": "way",
+                "wkt": "INVALID"
+            }
+        ],
+        "location": [
+            {
+                "from_id": 748800,
+                "from_type": "way",
+                "wkt": "MULTIPOLYGON(((7.81 1.41,7.81 1.45,7.85 1.45,7.85 1.41,7.81 1.41)))",
+                "tags": {
+                    "test:section": "mp-geom",
+                    "test:id": "748",
+                    "landuse": "forest"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/ways.wkt
new file mode 100644
index 00000000..2a1ad090
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/748/ways.wkt
@@ -0,0 +1 @@
+748800 LINESTRING(7.81 1.41,7.81 1.45,7.85 1.45,7.85 1.41,7.81 1.41)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/data.osm
new file mode 100644
index 00000000..a6bb7e94
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/data.osm
@@ -0,0 +1,24 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="749000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.93" lat="1.46"/>
+    <node id="749001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.95" lat="1.47"/>
+    <node id="749002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.97" lat="1.43"/>
+    <node id="749003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.95" lat="1.42"/>
+    <node id="749004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.91" lat="1.45"/>
+    <node id="749005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.92" lat="1.43"/>
+    <node id="749006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.93999" lat="1.44"/>
+    <way id="749800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="749000"/>
+        <nd ref="749001"/>
+        <nd ref="749002"/>
+        <nd ref="749003"/>
+        <nd ref="749000"/>
+        <nd ref="749004"/>
+        <nd ref="749005"/>
+        <nd ref="749006"/>
+        <nd ref="749000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="749"/>
+        <tag k="landuse" v="forest"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/data.osm.pbf
new file mode 100644
index 00000000..9cd4a1e0
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/nodes.wkt
new file mode 100644
index 00000000..e84a7d70
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/nodes.wkt
@@ -0,0 +1,7 @@
+749000 POINT(7.93 1.46)
+749001 POINT(7.95 1.47)
+749002 POINT(7.97 1.43)
+749003 POINT(7.95 1.42)
+749004 POINT(7.91 1.45)
+749005 POINT(7.92 1.43)
+749006 POINT(7.93999 1.44)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/test.json
new file mode 100644
index 00000000..585b46a6
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 749,
+    "description": "Valid multipolygon with two outer rings.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 749800,
+                "from_type": "way",
+                "wkt": "MULTIPOLYGON(((7.93 1.46,7.95 1.47,7.97 1.43,7.95 1.42,7.93 1.46)),((7.93 1.46,7.91 1.45,7.92 1.43,7.93999 1.44,7.93 1.46)))",
+                "tags": {
+                    "test:section": "mp-geom",
+                    "test:id": "749",
+                    "landuse": "forest"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/ways.wkt
new file mode 100644
index 00000000..5fcc532a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/749/ways.wkt
@@ -0,0 +1 @@
+749800 LINESTRING(7.93 1.46,7.95 1.47,7.97 1.43,7.95 1.42,7.93 1.46,7.91 1.45,7.92 1.43,7.93999 1.44,7.93 1.46)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/data.osm
new file mode 100644
index 00000000..49232249
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/data.osm
@@ -0,0 +1,57 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="750000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.51"/>
+    <node id="750001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.57"/>
+    <node id="750002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.06" lat="1.57"/>
+    <node id="750003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.06" lat="1.51"/>
+
+    <node id="750004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.02" lat="1.52"/>
+    <node id="750005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.02" lat="1.55"/>
+    <node id="750006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.55"/>
+    <node id="750007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.55"/>
+    <node id="750008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.52"/>
+    <node id="750009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.52"/>
+    <node id="750010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.54"/>
+    <node id="750011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.04" lat="1.54"/>
+
+    <way id="750800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="750000"/>
+        <nd ref="750001"/>
+        <nd ref="750002"/>
+        <nd ref="750003"/>
+        <nd ref="750000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="750"/>
+    </way>
+    <way id="750801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="750004"/>
+        <nd ref="750005"/>
+        <nd ref="750006"/>
+        <nd ref="750011"/>
+        <nd ref="750010"/>
+        <nd ref="750009"/>
+        <nd ref="750004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="750"/>
+    </way>
+    <way id="750802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="750009"/>
+        <nd ref="750010"/>
+        <nd ref="750011"/>
+        <nd ref="750006"/>
+        <nd ref="750007"/>
+        <nd ref="750008"/>
+        <nd ref="750009"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="750"/>
+    </way>
+    <relation id="750900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="750800" role="outer"/>
+        <member type="way" ref="750801" role="inner"/>
+        <member type="way" ref="750802" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="750"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/data.osm.pbf
new file mode 100644
index 00000000..d9c2bd58
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/nodes.wkt
new file mode 100644
index 00000000..ef89f152
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/nodes.wkt
@@ -0,0 +1,12 @@
+750000 POINT(7.01 1.51)
+750001 POINT(7.01 1.57)
+750002 POINT(7.06 1.57)
+750003 POINT(7.06 1.51)
+750004 POINT(7.02 1.52)
+750005 POINT(7.02 1.55)
+750006 POINT(7.04 1.55)
+750007 POINT(7.05 1.55)
+750008 POINT(7.05 1.52)
+750009 POINT(7.03 1.52)
+750010 POINT(7.03 1.54)
+750011 POINT(7.04 1.54)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/test.json
new file mode 100644
index 00000000..a5ed9420
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 750,
+    "description": "Valid OSM multipolygon with touching inner rings.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 750900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.01 1.51,7.01 1.57,7.06 1.57,7.06 1.51,7.01 1.51),(7.02 1.52,7.02 1.55,7.04 1.55,7.05 1.55,7.05 1.52,7.03 1.52,7.02 1.52)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "750"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/ways.wkt
new file mode 100644
index 00000000..5f3581c8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/750/ways.wkt
@@ -0,0 +1,3 @@
+750800 LINESTRING(7.01 1.51,7.01 1.57,7.06 1.57,7.06 1.51,7.01 1.51)
+750801 LINESTRING(7.02 1.52,7.02 1.55,7.04 1.55,7.04 1.54,7.03 1.54,7.03 1.52,7.02 1.52)
+750802 LINESTRING(7.03 1.52,7.03 1.54,7.04 1.54,7.04 1.55,7.05 1.55,7.05 1.52,7.03 1.52)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/data.osm
new file mode 100644
index 00000000..df020133
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/data.osm
@@ -0,0 +1,52 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="751000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.12" lat="1.51"/>
+    <node id="751001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.51"/>
+    <node id="751002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.16" lat="1.57"/>
+    <node id="751003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.13" lat="1.57"/>
+    <node id="751004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.54"/>
+
+    <node id="751005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.12" lat="1.54"/>
+    <node id="751006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.52"/>
+    <node id="751007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.55"/>
+    <node id="751008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.13" lat="1.56"/>
+    <node id="751009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.14" lat="1.55"/>
+
+    <way id="751800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="751000"/>
+        <nd ref="751001"/>
+        <nd ref="751002"/>
+        <nd ref="751003"/>
+        <nd ref="751004"/>
+        <nd ref="751000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="751"/>
+    </way>
+    <way id="751801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="751005"/>
+        <nd ref="751006"/>
+        <nd ref="751009"/>
+        <nd ref="751005"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="751"/>
+    </way>
+    <way id="751802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="751009"/>
+        <nd ref="751005"/>
+        <nd ref="751008"/>
+        <nd ref="751007"/>
+        <nd ref="751006"/>
+        <nd ref="751009"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="751"/>
+    </way>
+    <relation id="751900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="751800" role="outer"/>
+        <member type="way" ref="751801" role="inner"/>
+        <member type="way" ref="751802" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="751"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/data.osm.pbf
new file mode 100644
index 00000000..999954af
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/nodes.wkt
new file mode 100644
index 00000000..aa372861
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/nodes.wkt
@@ -0,0 +1,10 @@
+751000 POINT(7.12 1.51)
+751001 POINT(7.15 1.51)
+751002 POINT(7.16 1.57)
+751003 POINT(7.13 1.57)
+751004 POINT(7.11 1.54)
+751005 POINT(7.12 1.54)
+751006 POINT(7.14 1.52)
+751007 POINT(7.15 1.55)
+751008 POINT(7.13 1.56)
+751009 POINT(7.14 1.55)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/test.json
new file mode 100644
index 00000000..d2f29b42
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 751,
+    "description": "Valid OSM multipolygon with touching inner rings.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 751900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.12 1.51,7.15 1.51,7.16 1.57,7.13 1.57,7.11 1.54,7.12 1.51),(7.12 1.54,7.14 1.52,7.15 1.55,7.13 1.56,7.12 1.54)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "751"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/ways.wkt
new file mode 100644
index 00000000..3495b277
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/751/ways.wkt
@@ -0,0 +1,3 @@
+751800 LINESTRING(7.12 1.51,7.15 1.51,7.16 1.57,7.13 1.57,7.11 1.54,7.12 1.51)
+751801 LINESTRING(7.12 1.54,7.14 1.52,7.14 1.55,7.12 1.54)
+751802 LINESTRING(7.14 1.55,7.12 1.54,7.13 1.56,7.15 1.55,7.14 1.52,7.14 1.55)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/data.osm
new file mode 100644
index 00000000..f104a43b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/data.osm
@@ -0,0 +1,54 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="752000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.51"/>
+    <node id="752001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.29" lat="1.51"/>
+    <node id="752002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.29" lat="1.59"/>
+    <node id="752003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.59"/>
+
+    <node id="752004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.25" lat="1.56"/>
+    <node id="752005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.27" lat="1.56"/>
+    <node id="752006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.25" lat="1.52"/>
+    <node id="752007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.23" lat="1.52"/>
+
+    <node id="752008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.24" lat="1.54"/>
+    <node id="752009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.26" lat="1.58"/>
+    <node id="752010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.24" lat="1.58"/>
+    <node id="752011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.22" lat="1.54"/>
+
+    <way id="752800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="752000"/>
+        <nd ref="752001"/>
+        <nd ref="752002"/>
+        <nd ref="752003"/>
+        <nd ref="752000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="752"/>
+    </way>
+    <way id="752801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="752004"/>
+        <nd ref="752005"/>
+        <nd ref="752006"/>
+        <nd ref="752007"/>
+        <nd ref="752004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="752"/>
+    </way>
+    <way id="752802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="752008"/>
+        <nd ref="752009"/>
+        <nd ref="752010"/>
+        <nd ref="752011"/>
+        <nd ref="752008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="752"/>
+    </way>
+    <relation id="752900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="752800" role="outer"/>
+        <member type="way" ref="752801" role="inner"/>
+        <member type="way" ref="752802" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="752"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/data.osm.pbf
new file mode 100644
index 00000000..72571673
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/nodes.wkt
new file mode 100644
index 00000000..42c6b81e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/nodes.wkt
@@ -0,0 +1,12 @@
+752000 POINT(7.21 1.51)
+752001 POINT(7.29 1.51)
+752002 POINT(7.29 1.59)
+752003 POINT(7.21 1.59)
+752004 POINT(7.25 1.56)
+752005 POINT(7.27 1.56)
+752006 POINT(7.25 1.52)
+752007 POINT(7.23 1.52)
+752008 POINT(7.24 1.54)
+752009 POINT(7.26 1.58)
+752010 POINT(7.24 1.58)
+752011 POINT(7.22 1.54)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/test.json
new file mode 100644
index 00000000..05c36ed4
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 752,
+    "description": "Touching inner without common nodes.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 752900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fix": [
+            {
+                "from_id": 752900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.21 1.51,7.29 1.51,7.29 1.59,7.21 1.59,7.21 1.51),(7.25 1.56,7.27 1.56,7.25 1.52,7.23 1.52,7.24 1.54,7.22 1.54,7.24 1.58,7.26 1.58,7.25 1.56)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "752"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/ways.wkt
new file mode 100644
index 00000000..8636c307
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/752/ways.wkt
@@ -0,0 +1,3 @@
+752800 LINESTRING(7.21 1.51,7.29 1.51,7.29 1.59,7.21 1.59,7.21 1.51)
+752801 LINESTRING(7.25 1.56,7.27 1.56,7.25 1.52,7.23 1.52,7.25 1.56)
+752802 LINESTRING(7.24 1.54,7.26 1.58,7.24 1.58,7.22 1.54,7.24 1.54)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/data.osm
new file mode 100644
index 00000000..10bbd4e9
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/data.osm
@@ -0,0 +1,55 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="753000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.51"/>
+    <node id="753001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.39" lat="1.51"/>
+    <node id="753002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.39" lat="1.59"/>
+    <node id="753003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.31" lat="1.59"/>
+
+    <node id="753004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.35" lat="1.56"/>
+    <node id="753005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.37" lat="1.56"/>
+    <node id="753006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.35" lat="1.52"/>
+    <node id="753007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.52"/>
+
+    <node id="753008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.34" lat="1.54"/>
+    <node id="753009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.36" lat="1.58"/>
+    <node id="753010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.34" lat="1.58"/>
+    <node id="753011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.54"/>
+
+    <way id="753800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="753000"/>
+        <nd ref="753001"/>
+        <nd ref="753002"/>
+        <nd ref="753003"/>
+        <nd ref="753000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="753"/>
+    </way>
+    <way id="753801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="753004"/>
+        <nd ref="753005"/>
+        <nd ref="753006"/>
+        <nd ref="753007"/>
+        <nd ref="753004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="753"/>
+    </way>
+    <way id="753802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="753008"/>
+        <nd ref="753004"/>
+        <nd ref="753009"/>
+        <nd ref="753010"/>
+        <nd ref="753011"/>
+        <nd ref="753008"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="753"/>
+    </way>
+    <relation id="753900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="753800" role="outer"/>
+        <member type="way" ref="753801" role="inner"/>
+        <member type="way" ref="753802" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="753"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/data.osm.pbf
new file mode 100644
index 00000000..262d3f42
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/nodes.wkt
new file mode 100644
index 00000000..0bdc399c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/nodes.wkt
@@ -0,0 +1,12 @@
+753000 POINT(7.31 1.51)
+753001 POINT(7.39 1.51)
+753002 POINT(7.39 1.59)
+753003 POINT(7.31 1.59)
+753004 POINT(7.35 1.56)
+753005 POINT(7.37 1.56)
+753006 POINT(7.35 1.52)
+753007 POINT(7.33 1.52)
+753008 POINT(7.34 1.54)
+753009 POINT(7.36 1.58)
+753010 POINT(7.34 1.58)
+753011 POINT(7.32 1.54)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/test.json
new file mode 100644
index 00000000..9fe57f13
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 753,
+    "description": "Touching inner with one common node missing.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 753900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fix": [
+            {
+                "from_id": 753900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.31 1.51,7.39 1.51,7.39 1.59,7.31 1.59,7.31 1.51),(7.35 1.56,7.37 1.56,7.35 1.52,7.33 1.52,7.34 1.54,7.32 1.54,7.34 1.58,7.36 1.58,7.35 1.56)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "753"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/ways.wkt
new file mode 100644
index 00000000..f20fe1a7
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/753/ways.wkt
@@ -0,0 +1,3 @@
+753800 LINESTRING(7.31 1.51,7.39 1.51,7.39 1.59,7.31 1.59,7.31 1.51)
+753801 LINESTRING(7.35 1.56,7.37 1.56,7.35 1.52,7.33 1.52,7.35 1.56)
+753802 LINESTRING(7.34 1.54,7.35 1.56,7.36 1.58,7.34 1.58,7.32 1.54,7.34 1.54)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/data.osm
new file mode 100644
index 00000000..e71df500
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/data.osm
@@ -0,0 +1,39 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="754000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.47" lat="1.51"/>
+    <node id="754001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.51"/>
+    <node id="754002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.57"/>
+    <node id="754003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.47" lat="1.57"/>
+
+    <node id="754004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.45" lat="1.56"/>
+    <node id="754005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.47" lat="1.54"/>
+    <node id="754006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.45" lat="1.52"/>
+    <node id="754007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.54"/>
+
+    <way id="754800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="754000"/>
+        <nd ref="754001"/>
+        <nd ref="754002"/>
+        <nd ref="754003"/>
+        <nd ref="754000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="754"/>
+    </way>
+    <way id="754801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="754004"/>
+        <nd ref="754005"/>
+        <nd ref="754006"/>
+        <nd ref="754007"/>
+        <nd ref="754004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="754"/>
+    </way>
+    <relation id="754900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="754800" role="outer"/>
+        <member type="way" ref="754801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="754"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/data.osm.pbf
new file mode 100644
index 00000000..abfd09b5
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/nodes.wkt
new file mode 100644
index 00000000..c792a38f
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/nodes.wkt
@@ -0,0 +1,8 @@
+754000 POINT(7.47 1.51)
+754001 POINT(7.41 1.51)
+754002 POINT(7.41 1.57)
+754003 POINT(7.47 1.57)
+754004 POINT(7.45 1.56)
+754005 POINT(7.47 1.54)
+754006 POINT(7.45 1.52)
+754007 POINT(7.43 1.54)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/test.json
new file mode 100644
index 00000000..1af777aa
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 754,
+    "description": "Inner ring touching outer, but not in node.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 754900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fix": [
+            {
+                "from_id": 754900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.47 1.51,7.41 1.51,7.41 1.57,7.47 1.57,7.47 1.54,7.47 1.51),(7.45 1.56,7.47 1.54,7.45 1.52,7.43 1.54,7.45 1.56)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "754"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/ways.wkt
new file mode 100644
index 00000000..4d84cdfa
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/754/ways.wkt
@@ -0,0 +1,2 @@
+754800 LINESTRING(7.47 1.51,7.41 1.51,7.41 1.57,7.47 1.57,7.47 1.51)
+754801 LINESTRING(7.45 1.56,7.47 1.54,7.45 1.52,7.43 1.54,7.45 1.56)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/data.osm
new file mode 100644
index 00000000..5a4fce64
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/data.osm
@@ -0,0 +1,40 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="755000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.57" lat="1.51"/>
+    <node id="755001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.51" lat="1.51"/>
+    <node id="755002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.51" lat="1.57"/>
+    <node id="755003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.57" lat="1.57"/>
+
+    <node id="755004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.56"/>
+    <node id="755005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.57" lat="1.54"/>
+    <node id="755006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.52"/>
+    <node id="755007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.53" lat="1.54"/>
+
+    <way id="755800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="755000"/>
+        <nd ref="755001"/>
+        <nd ref="755002"/>
+        <nd ref="755003"/>
+        <nd ref="755005"/>
+        <nd ref="755000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="755"/>
+    </way>
+    <way id="755801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="755004"/>
+        <nd ref="755005"/>
+        <nd ref="755006"/>
+        <nd ref="755007"/>
+        <nd ref="755004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="755"/>
+    </way>
+    <relation id="755900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="755800" role="outer"/>
+        <member type="way" ref="755801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="755"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/data.osm.pbf
new file mode 100644
index 00000000..4453f240
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/nodes.wkt
new file mode 100644
index 00000000..3c271c18
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/nodes.wkt
@@ -0,0 +1,8 @@
+755000 POINT(7.57 1.51)
+755001 POINT(7.51 1.51)
+755002 POINT(7.51 1.57)
+755003 POINT(7.57 1.57)
+755004 POINT(7.55 1.56)
+755005 POINT(7.57 1.54)
+755006 POINT(7.55 1.52)
+755007 POINT(7.53 1.54)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/test.json
new file mode 100644
index 00000000..2eb3d452
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 755,
+    "description": "Inner ring touching outer in node.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 755900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.57 1.51,7.51 1.51,7.51 1.57,7.57 1.57,7.57 1.54,7.57 1.51),(7.55 1.56,7.57 1.54,7.55 1.52,7.53 1.54,7.55 1.56)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "755"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/ways.wkt
new file mode 100644
index 00000000..0ca2e3e0
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/755/ways.wkt
@@ -0,0 +1,2 @@
+755800 LINESTRING(7.57 1.51,7.51 1.51,7.51 1.57,7.57 1.57,7.57 1.54,7.57 1.51)
+755801 LINESTRING(7.55 1.56,7.57 1.54,7.55 1.52,7.53 1.54,7.55 1.56)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/data.osm
new file mode 100644
index 00000000..dd025b34
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/data.osm
@@ -0,0 +1,39 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="756000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.67" lat="1.51"/>
+    <node id="756001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.61" lat="1.51"/>
+    <node id="756002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.61" lat="1.57"/>
+    <node id="756003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.67" lat="1.57"/>
+
+    <node id="756004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.55"/>
+    <node id="756005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.67" lat="1.55"/>
+    <node id="756006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.67" lat="1.53"/>
+    <node id="756007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.53"/>
+
+    <way id="756800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="756000"/>
+        <nd ref="756001"/>
+        <nd ref="756002"/>
+        <nd ref="756003"/>
+        <nd ref="756000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="756"/>
+    </way>
+    <way id="756801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="756004"/>
+        <nd ref="756005"/>
+        <nd ref="756006"/>
+        <nd ref="756007"/>
+        <nd ref="756004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="756"/>
+    </way>
+    <relation id="756900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="756800" role="outer"/>
+        <member type="way" ref="756801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="756"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/data.osm.pbf
new file mode 100644
index 00000000..9ef03b1c
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/nodes.wkt
new file mode 100644
index 00000000..07ee982e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/nodes.wkt
@@ -0,0 +1,8 @@
+756000 POINT(7.67 1.51)
+756001 POINT(7.61 1.51)
+756002 POINT(7.61 1.57)
+756003 POINT(7.67 1.57)
+756004 POINT(7.65 1.55)
+756005 POINT(7.67 1.55)
+756006 POINT(7.67 1.53)
+756007 POINT(7.65 1.53)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/test.json
new file mode 100644
index 00000000..796f3334
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 756,
+    "description": "Inner ring touches outer ring in line, no common nodes.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 756900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fix": [
+            {
+                "from_id": 756900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.67 1.51,7.61 1.51,7.61 1.57,7.67 1.57,7.67 1.55,7.65 1.55,7.65 1.53,7.67 1.53,7.67 1.51)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "756"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/ways.wkt
new file mode 100644
index 00000000..f412563b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/756/ways.wkt
@@ -0,0 +1,2 @@
+756800 LINESTRING(7.67 1.51,7.61 1.51,7.61 1.57,7.67 1.57,7.67 1.51)
+756801 LINESTRING(7.65 1.55,7.67 1.55,7.67 1.53,7.65 1.53,7.65 1.55)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/data.osm
new file mode 100644
index 00000000..49991cab
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/data.osm
@@ -0,0 +1,41 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="757000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.77" lat="1.51"/>
+    <node id="757001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.71" lat="1.51"/>
+    <node id="757002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.71" lat="1.57"/>
+    <node id="757003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.77" lat="1.57"/>
+
+    <node id="757004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.75" lat="1.55"/>
+    <node id="757005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.77" lat="1.55"/>
+    <node id="757006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.77" lat="1.53"/>
+    <node id="757007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.75" lat="1.53"/>
+
+    <way id="757800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="757000"/>
+        <nd ref="757001"/>
+        <nd ref="757002"/>
+        <nd ref="757003"/>
+        <nd ref="757005"/>
+        <nd ref="757006"/>
+        <nd ref="757000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="757"/>
+    </way>
+    <way id="757801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="757004"/>
+        <nd ref="757005"/>
+        <nd ref="757006"/>
+        <nd ref="757007"/>
+        <nd ref="757004"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="757"/>
+    </way>
+    <relation id="757900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="757800" role="outer"/>
+        <member type="way" ref="757801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="757"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/data.osm.pbf
new file mode 100644
index 00000000..ad75db8e
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/nodes.wkt
new file mode 100644
index 00000000..0bb4b144
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/nodes.wkt
@@ -0,0 +1,8 @@
+757000 POINT(7.77 1.51)
+757001 POINT(7.71 1.51)
+757002 POINT(7.71 1.57)
+757003 POINT(7.77 1.57)
+757004 POINT(7.75 1.55)
+757005 POINT(7.77 1.55)
+757006 POINT(7.77 1.53)
+757007 POINT(7.75 1.53)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/result
new file mode 100644
index 00000000..9977a283
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/result
@@ -0,0 +1 @@
+invalid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/test.json
new file mode 100644
index 00000000..e947077a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/test.json
@@ -0,0 +1,25 @@
+{
+    "test_id": 757,
+    "description": "Inner ring touches outer ring in line using common nodes.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 757900,
+                "from_type": "relation",
+                "wkt": "INVALID"
+            }
+        ],
+        "fix": [
+            {
+                "from_id": 757900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.77 1.51,7.71 1.51,7.71 1.57,7.77 1.57,7.77 1.55,7.75 1.55,7.75 1.53,7.77 1.53,7.77 1.51)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "757"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/ways.wkt
new file mode 100644
index 00000000..608a1e23
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/757/ways.wkt
@@ -0,0 +1,2 @@
+757800 LINESTRING(7.77 1.51,7.71 1.51,7.71 1.57,7.77 1.57,7.77 1.55,7.77 1.53,7.77 1.51)
+757801 LINESTRING(7.75 1.55,7.77 1.55,7.77 1.53,7.75 1.53,7.75 1.55)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/data.osm
new file mode 100644
index 00000000..be2f49e1
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/data.osm
@@ -0,0 +1,40 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="758000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.81" lat="1.53"/>
+    <node id="758001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.81" lat="1.57"/>
+    <node id="758002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.84" lat="1.59"/>
+    <node id="758003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.86" lat="1.55"/>
+    <node id="758004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.84" lat="1.51"/>
+
+    <node id="758005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.84" lat="1.53"/>
+    <node id="758006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.82" lat="1.55"/>
+    <node id="758007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.84" lat="1.57"/>
+
+    <way id="758800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="758000"/>
+        <nd ref="758001"/>
+        <nd ref="758002"/>
+        <nd ref="758003"/>
+        <nd ref="758004"/>
+        <nd ref="758000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="758"/>
+    </way>
+    <way id="758801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="758003"/>
+        <nd ref="758005"/>
+        <nd ref="758006"/>
+        <nd ref="758007"/>
+        <nd ref="758003"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="758"/>
+    </way>
+    <relation id="758900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="758800" role="outer"/>
+        <member type="way" ref="758801" role="inner"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="758"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/data.osm.pbf
new file mode 100644
index 00000000..22505bba
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/nodes.wkt
new file mode 100644
index 00000000..683a9cc6
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/nodes.wkt
@@ -0,0 +1,8 @@
+758000 POINT(7.81 1.53)
+758001 POINT(7.81 1.57)
+758002 POINT(7.84 1.59)
+758003 POINT(7.86 1.55)
+758004 POINT(7.84 1.51)
+758005 POINT(7.84 1.53)
+758006 POINT(7.82 1.55)
+758007 POINT(7.84 1.57)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/test.json
new file mode 100644
index 00000000..48eb7ae8
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 758,
+    "description": "Inner touching outer in single node.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 758900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.81 1.53,7.81 1.57,7.84 1.59,7.86 1.55,7.84 1.51,7.81 1.53),(7.86 1.55,7.84 1.53,7.82 1.55,7.84 1.57,7.86 1.55)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "758"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/ways.wkt
new file mode 100644
index 00000000..0c7fc4e7
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/758/ways.wkt
@@ -0,0 +1,2 @@
+758800 LINESTRING(7.81 1.53,7.81 1.57,7.84 1.59,7.86 1.55,7.84 1.51,7.81 1.53)
+758801 LINESTRING(7.86 1.55,7.84 1.53,7.82 1.55,7.84 1.57,7.86 1.55)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/data.osm
new file mode 100644
index 00000000..fd5728e0
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/data.osm
@@ -0,0 +1,33 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="759000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.91" lat="1.53"/>
+    <node id="759001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.91" lat="1.57"/>
+    <node id="759002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.94" lat="1.59"/>
+    <node id="759003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.96" lat="1.55"/>
+    <node id="759004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.94" lat="1.51"/>
+    <node id="759005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.94" lat="1.53"/>
+    <node id="759006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.92" lat="1.55"/>
+    <node id="759007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.94" lat="1.57"/>
+
+    <way id="759800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="759000"/>
+        <nd ref="759001"/>
+        <nd ref="759002"/>
+        <nd ref="759003"/>
+        <nd ref="759007"/>
+        <nd ref="759006"/>
+        <nd ref="759005"/>
+        <nd ref="759003"/>
+        <nd ref="759004"/>
+        <nd ref="759000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="759"/>
+    </way>
+    <relation id="759900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="759800" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="759"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/data.osm.pbf
new file mode 100644
index 00000000..11835521
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/nodes.wkt
new file mode 100644
index 00000000..d2fed63b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/nodes.wkt
@@ -0,0 +1,8 @@
+759000 POINT(7.91 1.53)
+759001 POINT(7.91 1.57)
+759002 POINT(7.94 1.59)
+759003 POINT(7.96 1.55)
+759004 POINT(7.94 1.51)
+759005 POINT(7.94 1.53)
+759006 POINT(7.92 1.55)
+759007 POINT(7.94 1.57)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/test.json
new file mode 100644
index 00000000..0cad87f3
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 759,
+    "description": "Outer going back on itself in single node.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 759900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.91 1.53,7.91 1.57,7.94 1.59,7.96 1.55,7.94 1.51,7.91 1.53),(7.96 1.55,7.94 1.53,7.92 1.55,7.94 1.57,7.96 1.55)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "759"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/ways.wkt
new file mode 100644
index 00000000..960c4949
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/759/ways.wkt
@@ -0,0 +1 @@
+759800 LINESTRING(7.91 1.53,7.91 1.57,7.94 1.59,7.96 1.55,7.94 1.57,7.92 1.55,7.94 1.53,7.96 1.55,7.94 1.51,7.91 1.53)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/data.osm
new file mode 100644
index 00000000..565ce86f
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/data.osm
@@ -0,0 +1,37 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="760000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.67"/>
+    <node id="760001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.07" lat="1.67"/>
+    <node id="760002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.07" lat="1.64"/>
+    <node id="760003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.64"/>
+    <node id="760004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.65"/>
+    <node id="760005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.65"/>
+    <node id="760006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.03" lat="1.63"/>
+    <node id="760007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.05" lat="1.63"/>
+    <node id="760008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.07" lat="1.61"/>
+    <node id="760009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.01" lat="1.61"/>
+    <way id="760800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="760000"/>
+        <nd ref="760001"/>
+        <nd ref="760002"/>
+        <nd ref="760003"/>
+        <nd ref="760004"/>
+        <nd ref="760005"/>
+        <nd ref="760006"/>
+        <nd ref="760007"/>
+        <nd ref="760003"/>
+        <nd ref="760002"/>
+        <nd ref="760008"/>
+        <nd ref="760009"/>
+        <nd ref="760000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="760"/>
+    </way>
+    <relation id="760900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="760800" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="760"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/data.osm.pbf
new file mode 100644
index 00000000..150e8aa2
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/nodes.wkt
new file mode 100644
index 00000000..b63b8807
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/nodes.wkt
@@ -0,0 +1,10 @@
+760000 POINT(7.01 1.67)
+760001 POINT(7.07 1.67)
+760002 POINT(7.07 1.64)
+760003 POINT(7.05 1.64)
+760004 POINT(7.05 1.65)
+760005 POINT(7.03 1.65)
+760006 POINT(7.03 1.63)
+760007 POINT(7.05 1.63)
+760008 POINT(7.07 1.61)
+760009 POINT(7.01 1.61)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/test.json
new file mode 100644
index 00000000..2e24fa79
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 760,
+    "description": "Faking inner ring with outer going back on itself (with relation).",
+    "areas": {
+        "default": [
+            {
+                "from_id": 760900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.01 1.67,7.07 1.67,7.07 1.61,7.01 1.61,7.01 1.67),(7.05 1.65,7.03 1.65,7.03 1.63,7.05 1.63,7.05 1.65)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "760"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/ways.wkt
new file mode 100644
index 00000000..32add34a
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/760/ways.wkt
@@ -0,0 +1 @@
+760800 LINESTRING(7.01 1.67,7.07 1.67,7.07 1.64,7.05 1.64,7.05 1.65,7.03 1.65,7.03 1.63,7.05 1.63,7.05 1.64,7.07 1.64,7.07 1.61,7.01 1.61,7.01 1.67)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/data.osm
new file mode 100644
index 00000000..a63ce664
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/data.osm
@@ -0,0 +1,31 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="761000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.67"/>
+    <node id="761001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.17" lat="1.67"/>
+    <node id="761002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.17" lat="1.64"/>
+    <node id="761003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.64"/>
+    <node id="761004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.65"/>
+    <node id="761005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.13" lat="1.65"/>
+    <node id="761006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.13" lat="1.63"/>
+    <node id="761007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.15" lat="1.63"/>
+    <node id="761008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.17" lat="1.61"/>
+    <node id="761009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.11" lat="1.61"/>
+    <way id="761800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="761000"/>
+        <nd ref="761001"/>
+        <nd ref="761002"/>
+        <nd ref="761003"/>
+        <nd ref="761004"/>
+        <nd ref="761005"/>
+        <nd ref="761006"/>
+        <nd ref="761007"/>
+        <nd ref="761003"/>
+        <nd ref="761002"/>
+        <nd ref="761008"/>
+        <nd ref="761009"/>
+        <nd ref="761000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="761"/>
+        <tag k="area" v="yes"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/data.osm.pbf
new file mode 100644
index 00000000..798a7292
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/nodes.wkt
new file mode 100644
index 00000000..3c0e6a82
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/nodes.wkt
@@ -0,0 +1,10 @@
+761000 POINT(7.11 1.67)
+761001 POINT(7.17 1.67)
+761002 POINT(7.17 1.64)
+761003 POINT(7.15 1.64)
+761004 POINT(7.15 1.65)
+761005 POINT(7.13 1.65)
+761006 POINT(7.13 1.63)
+761007 POINT(7.15 1.63)
+761008 POINT(7.17 1.61)
+761009 POINT(7.11 1.61)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/test.json
new file mode 100644
index 00000000..f65cb158
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 761,
+    "description": "Faking inner ring with outer going back on itself (with way).",
+    "areas": {
+        "default": [
+            {
+                "from_id": 761800,
+                "from_type": "way",
+                "wkt": "MULTIPOLYGON(((7.11 1.67,7.17 1.67,7.17 1.61,7.11 1.61,7.11 1.67),(7.15 1.65,7.13 1.65,7.13 1.63,7.15 1.63,7.15 1.65)))",
+                "tags": {
+                    "test:section": "mp-geom",
+                    "test:id": "761",
+                    "area": "yes"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/ways.wkt
new file mode 100644
index 00000000..e730516b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/761/ways.wkt
@@ -0,0 +1 @@
+761800 LINESTRING(7.11 1.67,7.17 1.67,7.17 1.64,7.15 1.64,7.15 1.65,7.13 1.65,7.13 1.63,7.15 1.63,7.15 1.64,7.17 1.64,7.17 1.61,7.11 1.61,7.11 1.67)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/data.osm
new file mode 100644
index 00000000..61f7474b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/data.osm
@@ -0,0 +1,49 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="762000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.61"/>
+    <node id="762001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.27" lat="1.61"/>
+    <node id="762002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.27" lat="1.64"/>
+    <node id="762003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.27" lat="1.67"/>
+    <node id="762004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.67"/>
+    <node id="762005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.21" lat="1.64"/>
+    <node id="762006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.23" lat="1.65"/>
+    <node id="762007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.25" lat="1.65"/>
+    <node id="762008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.25" lat="1.64"/>
+    <node id="762009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.25" lat="1.63"/>
+    <node id="762010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.23" lat="1.63"/>
+    <node id="762011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.23" lat="1.64"/>
+    <way id="762800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="762005"/>
+        <nd ref="762004"/>
+        <nd ref="762003"/>
+        <nd ref="762002"/>
+        <nd ref="762008"/>
+        <nd ref="762007"/>
+        <nd ref="762006"/>
+        <nd ref="762011"/>
+        <nd ref="762005"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="762"/>
+    </way>
+    <way id="762801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="762000"/>
+        <nd ref="762001"/>
+        <nd ref="762002"/>
+        <nd ref="762008"/>
+        <nd ref="762009"/>
+        <nd ref="762010"/>
+        <nd ref="762011"/>
+        <nd ref="762005"/>
+        <nd ref="762000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="762"/>
+    </way>
+    <relation id="762900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="762800" role="outer"/>
+        <member type="way" ref="762801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="762"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/data.osm.pbf
new file mode 100644
index 00000000..38a3d918
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/nodes.wkt
new file mode 100644
index 00000000..225fe122
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/nodes.wkt
@@ -0,0 +1,12 @@
+762000 POINT(7.21 1.61)
+762001 POINT(7.27 1.61)
+762002 POINT(7.27 1.64)
+762003 POINT(7.27 1.67)
+762004 POINT(7.21 1.67)
+762005 POINT(7.21 1.64)
+762006 POINT(7.23 1.65)
+762007 POINT(7.25 1.65)
+762008 POINT(7.25 1.64)
+762009 POINT(7.25 1.63)
+762010 POINT(7.23 1.63)
+762011 POINT(7.23 1.64)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/test.json
new file mode 100644
index 00000000..772a7e4c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 762,
+    "description": "Touching outer rings.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 762900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.21 1.67,7.27 1.67,7.27 1.61,7.21 1.61,7.21 1.67),(7.25 1.65,7.23 1.65,7.23 1.63,7.25 1.63,7.25 1.65)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "762"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/ways.wkt
new file mode 100644
index 00000000..905a056c
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/762/ways.wkt
@@ -0,0 +1,2 @@
+762800 LINESTRING(7.21 1.64,7.21 1.67,7.27 1.67,7.27 1.64,7.25 1.64,7.25 1.65,7.23 1.65,7.23 1.64,7.21 1.64)
+762801 LINESTRING(7.21 1.61,7.27 1.61,7.27 1.64,7.25 1.64,7.25 1.63,7.23 1.63,7.23 1.64,7.21 1.64,7.21 1.61)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/data.osm
new file mode 100644
index 00000000..b93c6331
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/data.osm
@@ -0,0 +1,83 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="763000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.35" lat="1.65"/>
+
+    <node id="763001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.64"/>
+    <node id="763002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.63"/>
+    <node id="763003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.62"/>
+    <node id="763004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.62"/>
+    <node id="763005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.34" lat="1.63"/>
+
+    <node id="763006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.36" lat="1.63"/>
+    <node id="763007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.37" lat="1.62"/>
+    <node id="763008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.38" lat="1.62"/>
+    <node id="763009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.38" lat="1.63"/>
+    <node id="763010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.37" lat="1.64"/>
+
+    <node id="763011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.66"/>
+    <node id="763012" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.67"/>
+    <node id="763013" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.32" lat="1.68"/>
+    <node id="763014" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.33" lat="1.68"/>
+    <node id="763015" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.34" lat="1.67"/>
+
+    <node id="763016" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.36" lat="1.67"/>
+    <node id="763017" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.37" lat="1.68"/>
+    <node id="763018" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.38" lat="1.68"/>
+    <node id="763019" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.38" lat="1.67"/>
+    <node id="763020" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.37" lat="1.66"/>
+
+    <way id="763800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="763000"/>
+        <nd ref="763001"/>
+        <nd ref="763002"/>
+        <nd ref="763003"/>
+        <nd ref="763004"/>
+        <nd ref="763005"/>
+        <nd ref="763000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="763"/>
+    </way>
+    <way id="763801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="763000"/>
+        <nd ref="763006"/>
+        <nd ref="763007"/>
+        <nd ref="763008"/>
+        <nd ref="763009"/>
+        <nd ref="763010"/>
+        <nd ref="763000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="763"/>
+    </way>
+    <way id="763802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="763000"/>
+        <nd ref="763011"/>
+        <nd ref="763012"/>
+        <nd ref="763013"/>
+        <nd ref="763014"/>
+        <nd ref="763015"/>
+        <nd ref="763000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="763"/>
+    </way>
+    <way id="763803" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="763000"/>
+        <nd ref="763016"/>
+        <nd ref="763017"/>
+        <nd ref="763018"/>
+        <nd ref="763019"/>
+        <nd ref="763020"/>
+        <nd ref="763000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="763"/>
+    </way>
+    <relation id="763900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="763800" role="outer"/>
+        <member type="way" ref="763801" role="outer"/>
+        <member type="way" ref="763802" role="outer"/>
+        <member type="way" ref="763803" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="763"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/data.osm.pbf
new file mode 100644
index 00000000..43d9cf82
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/nodes.wkt
new file mode 100644
index 00000000..14936d3e
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/nodes.wkt
@@ -0,0 +1,21 @@
+763000 POINT(7.35 1.65)
+763001 POINT(7.33 1.64)
+763002 POINT(7.32 1.63)
+763003 POINT(7.32 1.62)
+763004 POINT(7.33 1.62)
+763005 POINT(7.34 1.63)
+763006 POINT(7.36 1.63)
+763007 POINT(7.37 1.62)
+763008 POINT(7.38 1.62)
+763009 POINT(7.38 1.63)
+763010 POINT(7.37 1.64)
+763011 POINT(7.33 1.66)
+763012 POINT(7.32 1.67)
+763013 POINT(7.32 1.68)
+763014 POINT(7.33 1.68)
+763015 POINT(7.34 1.67)
+763016 POINT(7.36 1.67)
+763017 POINT(7.37 1.68)
+763018 POINT(7.38 1.68)
+763019 POINT(7.38 1.67)
+763020 POINT(7.37 1.66)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/test.json
new file mode 100644
index 00000000..5f6e2713
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 763,
+    "description": "Valid multipolygon with four outer rings touching in a single point.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 763900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.35 1.65,7.33 1.64,7.32 1.63,7.32 1.62,7.33 1.62,7.34 1.63,7.35 1.65)),((7.35 1.65,7.36 1.63,7.37 1.62,7.38 1.62,7.38 1.63,7.37 1.64,7.35 1.65)),((7.35 1.65,7.33 1.66,7.32 1.67,7.32 1.68,7.33 1.68,7.34 1.67,7.35 1.65)),((7.35 1.65,7.36 1.67,7.37 1.68,7.38 1.68,7.38 1.67,7.37 1.66,7.35 1.65)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "763"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/ways.wkt
new file mode 100644
index 00000000..22329855
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/763/ways.wkt
@@ -0,0 +1,4 @@
+763800 LINESTRING(7.35 1.65,7.33 1.64,7.32 1.63,7.32 1.62,7.33 1.62,7.34 1.63,7.35 1.65)
+763801 LINESTRING(7.35 1.65,7.36 1.63,7.37 1.62,7.38 1.62,7.38 1.63,7.37 1.64,7.35 1.65)
+763802 LINESTRING(7.35 1.65,7.33 1.66,7.32 1.67,7.32 1.68,7.33 1.68,7.34 1.67,7.35 1.65)
+763803 LINESTRING(7.35 1.65,7.36 1.67,7.37 1.68,7.38 1.68,7.38 1.67,7.37 1.66,7.35 1.65)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/data.osm
new file mode 100644
index 00000000..3a4e507d
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/data.osm
@@ -0,0 +1,98 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="764000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.45" lat="1.65"/>
+
+    <node id="764001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.64"/>
+    <node id="764002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.63"/>
+    <node id="764003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.62"/>
+    <node id="764004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.62"/>
+    <node id="764005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.44" lat="1.63"/>
+
+    <node id="764006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.46" lat="1.63"/>
+    <node id="764007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.47" lat="1.62"/>
+    <node id="764008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.48" lat="1.62"/>
+    <node id="764009" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.48" lat="1.63"/>
+    <node id="764010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.47" lat="1.64"/>
+
+    <node id="764011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.66"/>
+    <node id="764012" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.67"/>
+    <node id="764013" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.42" lat="1.68"/>
+    <node id="764014" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.43" lat="1.68"/>
+    <node id="764015" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.44" lat="1.67"/>
+
+    <node id="764016" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.46" lat="1.67"/>
+    <node id="764017" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.47" lat="1.68"/>
+    <node id="764018" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.48" lat="1.68"/>
+    <node id="764019" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.48" lat="1.67"/>
+    <node id="764020" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.47" lat="1.66"/>
+
+    <node id="764030" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.61"/>
+    <node id="764031" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.41" lat="1.69"/>
+    <node id="764032" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.49" lat="1.69"/>
+    <node id="764033" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.49" lat="1.61"/>
+
+    <way id="764800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="764000"/>
+        <nd ref="764001"/>
+        <nd ref="764002"/>
+        <nd ref="764003"/>
+        <nd ref="764004"/>
+        <nd ref="764005"/>
+        <nd ref="764000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="764"/>
+    </way>
+    <way id="764801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="764000"/>
+        <nd ref="764006"/>
+        <nd ref="764007"/>
+        <nd ref="764008"/>
+        <nd ref="764009"/>
+        <nd ref="764010"/>
+        <nd ref="764000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="764"/>
+    </way>
+    <way id="764802" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="764000"/>
+        <nd ref="764011"/>
+        <nd ref="764012"/>
+        <nd ref="764013"/>
+        <nd ref="764014"/>
+        <nd ref="764015"/>
+        <nd ref="764000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="764"/>
+    </way>
+    <way id="764803" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="764000"/>
+        <nd ref="764016"/>
+        <nd ref="764017"/>
+        <nd ref="764018"/>
+        <nd ref="764019"/>
+        <nd ref="764020"/>
+        <nd ref="764000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="764"/>
+    </way>
+    <way id="764804" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="764030"/>
+        <nd ref="764031"/>
+        <nd ref="764032"/>
+        <nd ref="764033"/>
+        <nd ref="764030"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="764"/>
+    </way>
+    <relation id="764900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="764800" role="inner"/>
+        <member type="way" ref="764801" role="inner"/>
+        <member type="way" ref="764802" role="inner"/>
+        <member type="way" ref="764803" role="inner"/>
+        <member type="way" ref="764804" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="764"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/data.osm.pbf
new file mode 100644
index 00000000..36a25ca5
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/nodes.wkt
new file mode 100644
index 00000000..309aa4c4
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/nodes.wkt
@@ -0,0 +1,25 @@
+764000 POINT(7.45 1.65)
+764001 POINT(7.43 1.64)
+764002 POINT(7.42 1.63)
+764003 POINT(7.42 1.62)
+764004 POINT(7.43 1.62)
+764005 POINT(7.44 1.63)
+764006 POINT(7.46 1.63)
+764007 POINT(7.47 1.62)
+764008 POINT(7.48 1.62)
+764009 POINT(7.48 1.63)
+764010 POINT(7.47 1.64)
+764011 POINT(7.43 1.66)
+764012 POINT(7.42 1.67)
+764013 POINT(7.42 1.68)
+764014 POINT(7.43 1.68)
+764015 POINT(7.44 1.67)
+764016 POINT(7.46 1.67)
+764017 POINT(7.47 1.68)
+764018 POINT(7.48 1.68)
+764019 POINT(7.48 1.67)
+764020 POINT(7.47 1.66)
+764030 POINT(7.41 1.61)
+764031 POINT(7.41 1.69)
+764032 POINT(7.49 1.69)
+764033 POINT(7.49 1.61)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/test.json
new file mode 100644
index 00000000..157a22fd
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 764,
+    "description": "Valid multipolygon with one outer ring and four inner rings touching in a single point.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 764900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.41 1.61,7.41 1.69,7.49 1.69,7.49 1.61,7.41 1.61),(7.45 1.65,7.43 1.64,7.42 1.63,7.42 1.62,7.43 1.62,7.44 1.63,7.45 1.65),(7.45 1.65,7.46 1.63,7.47 1.62,7.48 1.62,7.48 1.63,7.47 1.64,7.45 1.65),(7.45 1.65,7.43 1.66,7.42 1.67,7.42 1.68,7.43 1.68,7.44 1.67,7.45 1.65),(7.45 1.65,7.46 1.67,7.47 1.68,7.48 1.68,7.48 1.67,7.47 1.66,7.45 1.65)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "764"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/ways.wkt
new file mode 100644
index 00000000..d51e3896
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/764/ways.wkt
@@ -0,0 +1,5 @@
+764800 LINESTRING(7.45 1.65,7.43 1.64,7.42 1.63,7.42 1.62,7.43 1.62,7.44 1.63,7.45 1.65)
+764801 LINESTRING(7.45 1.65,7.46 1.63,7.47 1.62,7.48 1.62,7.48 1.63,7.47 1.64,7.45 1.65)
+764802 LINESTRING(7.45 1.65,7.43 1.66,7.42 1.67,7.42 1.68,7.43 1.68,7.44 1.67,7.45 1.65)
+764803 LINESTRING(7.45 1.65,7.46 1.67,7.47 1.68,7.48 1.68,7.48 1.67,7.47 1.66,7.45 1.65)
+764804 LINESTRING(7.41 1.61,7.41 1.69,7.49 1.69,7.49 1.61,7.41 1.61)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/data.osm
new file mode 100644
index 00000000..03a0d1d7
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/data.osm
@@ -0,0 +1,35 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="765000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.57" lat="1.66"/>
+    <node id="765001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.68"/>
+    <node id="765002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.53" lat="1.66"/>
+    <node id="765003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.64"/>
+    <node id="765004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.55" lat="1.63"/>
+    <node id="765005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.58" lat="1.63"/>
+    <node id="765006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.58" lat="1.62"/>
+    <node id="765007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.52" lat="1.62"/>
+    <node id="765008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.52" lat="1.63"/>
+    <way id="765800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="765000"/>
+        <nd ref="765001"/>
+        <nd ref="765002"/>
+        <nd ref="765003"/>
+        <nd ref="765004"/>
+        <nd ref="765005"/>
+        <nd ref="765006"/>
+        <nd ref="765007"/>
+        <nd ref="765008"/>
+        <nd ref="765004"/>
+        <nd ref="765003"/>
+        <nd ref="765000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="765"/>
+    </way>
+    <relation id="765900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="765800" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="765"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/data.osm.pbf
new file mode 100644
index 00000000..c18d811a
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/nodes.wkt
new file mode 100644
index 00000000..c71e8965
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/nodes.wkt
@@ -0,0 +1,9 @@
+765000 POINT(7.57 1.66)
+765001 POINT(7.55 1.68)
+765002 POINT(7.53 1.66)
+765003 POINT(7.55 1.64)
+765004 POINT(7.55 1.63)
+765005 POINT(7.58 1.63)
+765006 POINT(7.58 1.62)
+765007 POINT(7.52 1.62)
+765008 POINT(7.52 1.63)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/test.json
new file mode 100644
index 00000000..ba2b1979
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 765,
+    "description": "Multipolygon with one outer ring that should be split into two components.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 765900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.57 1.66,7.55 1.68,7.53 1.66,7.55 1.64,7.57 1.66)),((7.55 1.63,7.58 1.63,7.58 1.62,7.52 1.62,7.52 1.63,7.55 1.63)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "765"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/ways.wkt
new file mode 100644
index 00000000..7776dc21
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/765/ways.wkt
@@ -0,0 +1 @@
+765800 LINESTRING(7.57 1.66,7.55 1.68,7.53 1.66,7.55 1.64,7.55 1.63,7.58 1.63,7.58 1.62,7.52 1.62,7.52 1.63,7.55 1.63,7.55 1.64,7.57 1.66)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/data.osm
new file mode 100644
index 00000000..0ff0d9cd
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/data.osm
@@ -0,0 +1,52 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="766000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.67" lat="1.66"/>
+    <node id="766001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.68"/>
+    <node id="766002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.63" lat="1.66"/>
+    <node id="766003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.64"/>
+    <node id="766004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.65" lat="1.63"/>
+    <node id="766005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.68" lat="1.63"/>
+    <node id="766006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.68" lat="1.62"/>
+    <node id="766007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.62" lat="1.62"/>
+    <node id="766008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.62" lat="1.63"/>
+
+    <node id="766010" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.61" lat="1.61"/>
+    <node id="766011" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.61" lat="1.69"/>
+    <node id="766012" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.69" lat="1.69"/>
+    <node id="766013" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.69" lat="1.61"/>
+
+    <way id="766800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="766000"/>
+        <nd ref="766001"/>
+        <nd ref="766002"/>
+        <nd ref="766003"/>
+        <nd ref="766004"/>
+        <nd ref="766005"/>
+        <nd ref="766006"/>
+        <nd ref="766007"/>
+        <nd ref="766008"/>
+        <nd ref="766004"/>
+        <nd ref="766003"/>
+        <nd ref="766000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="766"/>
+    </way>
+    <way id="766801" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="766010"/>
+        <nd ref="766011"/>
+        <nd ref="766012"/>
+        <nd ref="766013"/>
+        <nd ref="766010"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="766"/>
+    </way>
+
+    <relation id="766900" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <member type="way" ref="766800" role="inner"/>
+        <member type="way" ref="766801" role="outer"/>
+        <tag k="type" v="multipolygon"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="766"/>
+        <tag k="landuse" v="forest"/>
+    </relation>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/data.osm.pbf
new file mode 100644
index 00000000..cd187340
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/nodes.wkt
new file mode 100644
index 00000000..6231430f
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/nodes.wkt
@@ -0,0 +1,13 @@
+766000 POINT(7.67 1.66)
+766001 POINT(7.65 1.68)
+766002 POINT(7.63 1.66)
+766003 POINT(7.65 1.64)
+766004 POINT(7.65 1.63)
+766005 POINT(7.68 1.63)
+766006 POINT(7.68 1.62)
+766007 POINT(7.62 1.62)
+766008 POINT(7.62 1.63)
+766010 POINT(7.61 1.61)
+766011 POINT(7.61 1.69)
+766012 POINT(7.69 1.69)
+766013 POINT(7.69 1.61)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/result b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/result
new file mode 100644
index 00000000..1e2466df
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/result
@@ -0,0 +1 @@
+valid
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/test.json b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/test.json
new file mode 100644
index 00000000..feb62a1b
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/test.json
@@ -0,0 +1,18 @@
+{
+    "test_id": 766,
+    "description": "Multipolygon with one outer and inner ring that should be split into two components.",
+    "areas": {
+        "default": [
+            {
+                "from_id": 766900,
+                "from_type": "relation",
+                "wkt": "MULTIPOLYGON(((7.61 1.61,7.61 1.69,7.69 1.69,7.69 1.61,7.61 1.61),(7.67 1.66,7.65 1.68,7.63 1.66,7.65 1.64,7.67 1.66),(7.65 1.63,7.68 1.63,7.68 1.62,7.62 1.62,7.62 1.63,7.65 1.63)))",
+                "tags": {
+                    "landuse": "forest",
+                    "test:section": "mp-geom",
+                    "test:id": "766"
+                }
+            }
+        ]
+    }
+}
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/ways.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/ways.wkt
new file mode 100644
index 00000000..d281a556
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/766/ways.wkt
@@ -0,0 +1,2 @@
+766800 LINESTRING(7.67 1.66,7.65 1.68,7.63 1.66,7.65 1.64,7.65 1.63,7.68 1.63,7.68 1.62,7.62 1.62,7.62 1.63,7.65 1.63,7.65 1.64,7.67 1.66)
+766801 LINESTRING(7.61 1.61,7.61 1.69,7.69 1.69,7.69 1.61,7.61 1.61)
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/767/data.osm b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/767/data.osm
new file mode 100644
index 00000000..1eb82bba
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/767/data.osm
@@ -0,0 +1,29 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="testdata" upload="false">
+    <node id="767000" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.77" lat="1.66"/>
+    <node id="767001" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.75" lat="1.68"/>
+    <node id="767002" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.73" lat="1.66"/>
+    <node id="767003" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.75" lat="1.64"/>
+    <node id="767004" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.75" lat="1.63"/>
+    <node id="767005" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.78" lat="1.63"/>
+    <node id="767006" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.78" lat="1.62"/>
+    <node id="767007" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.72" lat="1.62"/>
+    <node id="767008" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1" lon="7.72" lat="1.63"/>
+    <way id="767800" version="1" timestamp="2014-01-01T00:00:00Z" uid="1" user="test" changeset="1">
+        <nd ref="767000"/>
+        <nd ref="767001"/>
+        <nd ref="767002"/>
+        <nd ref="767003"/>
+        <nd ref="767004"/>
+        <nd ref="767005"/>
+        <nd ref="767006"/>
+        <nd ref="767007"/>
+        <nd ref="767008"/>
+        <nd ref="767004"/>
+        <nd ref="767003"/>
+        <nd ref="767000"/>
+        <tag k="test:section" v="mp-geom"/>
+        <tag k="test:id" v="767"/>
+        <tag k="area" v="yes"/>
+    </way>
+</osm>
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/767/data.osm.pbf b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/767/data.osm.pbf
new file mode 100644
index 00000000..292a9ce5
Binary files /dev/null and b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/767/data.osm.pbf differ
diff --git a/baremaps-core/src/test/resources/osm-testdata/grid/data/7/767/nodes.wkt b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/767/nodes.wkt
new file mode 100644
index 00000000..9c77f609
--- /dev/null
+++ b/baremaps-core/src/test/resources/osm-testdata/grid/data/7/767/nodes.wkt
@@ -0,0 +1,9 @@
+767000 POINT(7.77 1.66)
... 31901 lines suppressed ...