diff options
author | Konstantin Käfer <mail@kkaefer.com> | 2016-05-10 11:48:22 +0200 |
---|---|---|
committer | Konstantin Käfer <mail@kkaefer.com> | 2016-05-10 14:50:56 +0200 |
commit | 7332ae00735a7cb1a0a4528d48e5956aa593b8b8 (patch) | |
tree | 5d680f5388c2019834975a22cd941d0cefb59a31 /test/algorithm | |
parent | ec70125e41e4e9db5f1d0941c0129d80f5792896 (diff) | |
download | qtlocation-mapboxgl-7332ae00735a7cb1a0a4528d48e5956aa593b8b8.tar.gz |
[core] retain tiles differently and remove old TileID class
Diffstat (limited to 'test/algorithm')
-rw-r--r-- | test/algorithm/mock.hpp | 60 | ||||
-rw-r--r-- | test/algorithm/update_renderables.cpp | 367 |
2 files changed, 427 insertions, 0 deletions
diff --git a/test/algorithm/mock.hpp b/test/algorithm/mock.hpp new file mode 100644 index 0000000000..89f51b15b8 --- /dev/null +++ b/test/algorithm/mock.hpp @@ -0,0 +1,60 @@ +#ifndef MBGL_TEST_MOCK +#define MBGL_TEST_MOCK + +#include <cstdint> +#include <string> +#include <memory> +#include <set> +#include <map> + +#include <mbgl/tile/tile_id.hpp> + +struct MockSourceInfo { + uint8_t maxZoom = 16; + uint8_t minZoom = 0; +}; + +struct MockTileData; + +struct MockRenderable { + MockRenderable(mbgl::UnwrappedTileID id_, MockTileData& data_) : id(id_), data(data_) {} + + const mbgl::UnwrappedTileID id; + MockTileData& data; + + bool operator==(const MockRenderable& rhs) const { + return &data == &rhs.data; + } +}; + +::std::ostream& operator<<(::std::ostream& os, const MockRenderable&) { + return os << "Renderable{}"; +} + +struct MockSource { + MockSourceInfo info; + std::map<mbgl::OverscaledTileID, std::unique_ptr<MockTileData>> dataTiles; + std::set<mbgl::UnwrappedTileID> idealTiles; + std::map<mbgl::UnwrappedTileID, MockRenderable> renderables; + + // Test API + inline MockTileData* createTileData(const mbgl::OverscaledTileID& tileID); +}; + +struct MockBucket {}; + + +struct MockTileData { + bool isReady() { + return ready; + } + + bool ready = false; +}; + +MockTileData* MockSource::createTileData(const mbgl::OverscaledTileID& tileID) { + // Replace the existing MockTileData object, if any. + return (dataTiles[tileID] = std::make_unique<MockTileData>()).get(); +} + +#endif diff --git a/test/algorithm/update_renderables.cpp b/test/algorithm/update_renderables.cpp new file mode 100644 index 0000000000..860381bdfa --- /dev/null +++ b/test/algorithm/update_renderables.cpp @@ -0,0 +1,367 @@ +#include <mbgl/test/util.hpp> +#include "mock.hpp" + +#include <mbgl/algorithm/update_renderables_impl.hpp> + +using namespace mbgl; + +TEST(UpdateRenderables, SingleTile) { + MockSource source; + source.idealTiles.emplace(UnwrappedTileID{ 1, 1, 1 }); + + // Make sure that we're getting the tile back. + auto tile_1_1_1 = source.createTileData(OverscaledTileID{ 1, 1, 1 }); + tile_1_1_1->ready = true; + + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } }, + }), + source.renderables); + + // Check a repeated render with the same data. + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } }, + }), + source.renderables); + + // Insert a tile we don't have data for. + source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 1 }); + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } }, + }), + source.renderables); + + // Now insert the missing tile and check that we're rendering it. + auto tile_1_0_1 = source.createTileData(OverscaledTileID{ 1, 0, 1 }); + tile_1_0_1->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } }, + { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } }, + }), + source.renderables); + + // Insert another tile, and another bucket that has a different name and check that we're not + // using it. + source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 }); + auto tile_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, 0 }); + + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } }, + { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } }, + }), + source.renderables); + + // Then, add the bucket and check that it's getting used. + tile_1_0_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 0, 0 }, MockRenderable{ { 1, 0, 0 }, *tile_1_0_0 } }, + { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } }, + { { 1, 1, 1 }, MockRenderable{ { 1, 1, 1 }, *tile_1_1_1 } }, + }), + source.renderables); +} + +TEST(UpdateRenderables, UseParentTile) { + MockSource source; + source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 1 }); + source.idealTiles.emplace(UnwrappedTileID{ 1, 1, 0 }); + source.idealTiles.emplace(UnwrappedTileID{ 1, 1, 1 }); + + // Make sure that we're getting the tile back. + auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 }); + tile_0_0_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } }, + }), + source.renderables); +} + +TEST(UpdateRenderables, DontUseWrongParentTile) { + MockSource source; + source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 }); + + auto tile_1_1_0 = source.createTileData(OverscaledTileID{ 1, 1, 0 }); + tile_1_1_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 2); + EXPECT_EQ(decltype(source.renderables)({}), source.renderables); + + // Add a new child tile and check that it is now used. + source.idealTiles.emplace(UnwrappedTileID{ 2, 2, 0 }); + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 2); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 1, 0 }, MockRenderable{ { 1, 1, 0 }, *tile_1_1_0 } }, + }), + source.renderables); +} + +TEST(UpdateRenderables, UseParentTileWhenChildNotReady) { + MockSource source; + source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 1 }); + + auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 }); + tile_0_0_0->ready = true; + + auto tile_1_0_1 = source.createTileData(OverscaledTileID{ 1, 0, 1 }); + // Don't create bucket. + + // Make sure that it renders the parent tile. + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } }, + }), + source.renderables); + + // Now insert the bucket and make sure we're now using the matching tile + tile_1_0_1->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } }, + }), + source.renderables); +} + +TEST(UpdateRenderables, UseOverlappingParentTile) { + MockSource source; + source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 }); + source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 1 }); + + auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 }); + tile_0_0_0->ready = true; + + auto tile_1_0_1 = source.createTileData(OverscaledTileID{ 1, 0, 1 }); + tile_1_0_1->ready = true; + + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } }, + { { 1, 0, 1 }, MockRenderable{ { 1, 0, 1 }, *tile_1_0_1 } }, + }), + source.renderables); +} + +TEST(UpdateRenderables, UseChildTiles) { + MockSource source; + source.idealTiles.emplace(UnwrappedTileID{ 0, 0, 0 }); + + auto tile_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, 0 }); + tile_1_0_0->ready = true; + auto tile_1_1_0 = source.createTileData(OverscaledTileID{ 1, 1, 0 }); + tile_1_1_0->ready = true; + + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 0); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 0, 0 }, MockRenderable{ { 1, 0, 0 }, *tile_1_0_0 } }, + { { 1, 1, 0 }, MockRenderable{ { 1, 1, 0 }, *tile_1_1_0 } }, + }), + source.renderables); +} + +TEST(UpdateRenderables, PreferChildTiles) { + MockSource source; + source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 }); + + auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 }); + tile_0_0_0->ready = true; + auto tile_2_0_0 = source.createTileData(OverscaledTileID{ 2, 0, 0 }); + tile_2_0_0->ready = true; + + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } }, + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } }, + }), + source.renderables); + + // Now add more children to cover the ideal tile fully, until it is covered fully, and verify + // that the parent doesn't get rendered. + auto tile_2_0_1 = source.createTileData(OverscaledTileID{ 2, 0, 1 }); + tile_2_0_1->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } }, + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } }, + { { 2, 0, 1 }, MockRenderable{ { 2, 0, 1 }, *tile_2_0_1 } }, + }), + source.renderables); + + auto tile_2_1_0 = source.createTileData(OverscaledTileID{ 2, 1, 0 }); + tile_2_1_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } }, + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } }, + { { 2, 0, 1 }, MockRenderable{ { 2, 0, 1 }, *tile_2_0_1 } }, + { { 2, 1, 0 }, MockRenderable{ { 2, 1, 0 }, *tile_2_1_0 } }, + }), + source.renderables); + + // Adding the last child tile covers 1/0/0 fully, so we don't need 0/0/0 anymore. + auto tile_2_1_1 = source.createTileData(OverscaledTileID{ 2, 1, 1 }); + tile_2_1_1->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } }, + { { 2, 0, 1 }, MockRenderable{ { 2, 0, 1 }, *tile_2_0_1 } }, + { { 2, 1, 0 }, MockRenderable{ { 2, 1, 0 }, *tile_2_1_0 } }, + { { 2, 1, 1 }, MockRenderable{ { 2, 1, 1 }, *tile_2_1_1 } }, + }), + source.renderables); +} + +TEST(UpdateRenderables, UseParentAndChildTiles) { + MockSource source; + source.idealTiles.emplace(UnwrappedTileID{ 1, 0, 0 }); + + auto tile_0_0_0 = source.createTileData(OverscaledTileID{ 0, 0, 0 }); + tile_0_0_0->ready = true; + auto tile_2_0_0 = source.createTileData(OverscaledTileID{ 2, 0, 0 }); + tile_2_0_0->ready = true; + + // Check that it uses the child tile, but not the parent tile. + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } }, + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_0_0 } }, + }), + source.renderables); + + // Then, remove the child tile and check that it now uses the parent tile. + source.dataTiles.erase(OverscaledTileID{ 2, 0, 0 }); + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 1); + EXPECT_EQ(decltype(source.renderables)({ + { { 0, 0, 0 }, MockRenderable{ { 0, 0, 0 }, *tile_0_0_0 } }, + }), + source.renderables); +} + +TEST(UpdateRenderables, DontUseTilesLowerThanMinzoom) { + MockSource source; + source.info.minZoom = 2; + source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 }); + + auto tile_1_0_0 = source.createTileData(OverscaledTileID{ 1, 0, 0 }); + tile_1_0_0->ready = true; + + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 2); + EXPECT_EQ(decltype(source.renderables)({}), source.renderables); +} + +TEST(UpdateRenderables, UseOverzoomedTileAfterMaxzoom) { + MockSource source; + source.info.maxZoom = 2; + source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 }); + + // Add a child tile (that should never occur in practice) and make sure it's not selected. + auto tile_3_3_0_0 = source.createTileData(OverscaledTileID{ 3, 0, 0 }); + tile_3_3_0_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 2); + EXPECT_EQ(decltype(source.renderables)({}), source.renderables); + + // Only add a non-overzoomed ("parent") tile at first. + auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, { 2, 0, 0 } }); + tile_2_2_0_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 3); + EXPECT_EQ(decltype(source.renderables)({ + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_2_0_0 } }, + }), + source.renderables); + + // Then add the overzoomed tile matching the zoom level we're rendering. + auto tile_3_2_0_0 = source.createTileData(OverscaledTileID{ 3, { 2, 0, 0 } }); + tile_3_2_0_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 3); + EXPECT_EQ(decltype(source.renderables)({ + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_3_2_0_0 } }, + }), + source.renderables); + + // Check that it's switching back to the tile that has the matching overzoom value. + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 2); + EXPECT_EQ(decltype(source.renderables)({ + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_2_0_0 } }, + }), + source.renderables); + + // Now remove the best match. + source.dataTiles.erase(OverscaledTileID{ 2, { 2, 0, 0 } }); + tile_2_2_0_0 = nullptr; + + // Use the overzoomed tile even though it doesn't match the zoom level. + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 2); + EXPECT_EQ(decltype(source.renderables)({ + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_3_2_0_0 } }, + }), + source.renderables); +} + +TEST(UpdateRenderables, AscendToNonOverzoomedTiles) { + MockSource source; + source.info.maxZoom = 2; + source.idealTiles.emplace(UnwrappedTileID{ 2, 0, 0 }); + + // Add a matching overzoomed tile and make sure it gets selected. + auto tile_3_2_0_0 = source.createTileData(OverscaledTileID{ 3, { 2, 0, 0 } }); + tile_3_2_0_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 3); + EXPECT_EQ(decltype(source.renderables)({ + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_3_2_0_0 } }, + }), + source.renderables); + + // Then, swap it with a non-overzoomed tile. + source.dataTiles.erase(OverscaledTileID{ 3, { 2, 0, 0 } }); + tile_3_2_0_0 = nullptr; + auto tile_2_2_0_0 = source.createTileData(OverscaledTileID{ 2, { 2, 0, 0 } }); + tile_2_2_0_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 3); + EXPECT_EQ(decltype(source.renderables)({ + { { 2, 0, 0 }, MockRenderable{ { 2, 0, 0 }, *tile_2_2_0_0 } }, + }), + source.renderables); + + // Then, swap it with a parent tile. + source.dataTiles.erase(OverscaledTileID{ 2, { 2, 0, 0 } }); + tile_2_2_0_0 = nullptr; + auto tile_1_1_0_0 = source.createTileData(OverscaledTileID{ 1, { 1, 0, 0 } }); + tile_1_1_0_0->ready = true; + source.renderables = algorithm::updateRenderables<MockRenderable>( + source.dataTiles, source.idealTiles, source.info, 3); + EXPECT_EQ(decltype(source.renderables)({ + { { 1, 0, 0 }, MockRenderable{ { 1, 0, 0 }, *tile_1_1_0_0 } }, + }), + source.renderables); +} |