#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace mbgl; using SourceType = mbgl::style::SourceType; class SourceTest { public: util::RunLoop loop; std::shared_ptr fileSource = std::make_shared(); StubStyleObserver styleObserver; StubRenderSourceObserver renderSourceObserver; Transform transform; TransformState transformState; Style style{fileSource, 1}; AnnotationManager annotationManager { style }; ImageManager imageManager; GlyphManager glyphManager; TileParameters tileParameters(MapMode mapMode = MapMode::Continuous) { return {1.0, MapDebugOptions(), transformState, fileSource, mapMode, annotationManager.makeWeakPtr(), imageManager, glyphManager, 0}; }; SourceTest() { // Squelch logging. Log::setObserver(std::make_unique()); transform.resize({ 512, 512 }); transform.jumpTo(CameraOptions().withCenter(LatLng()).withZoom(0.0)); transformState = transform.getState(); } void run() { loop.run(); } void end() { loop.stop(); } }; TEST(Source, LoadingFail) { SourceTest test; test.fileSource->sourceResponse = [&] (const Resource& resource) { EXPECT_EQ("url", resource.url); Response response; response.error = std::make_unique( Response::Error::Reason::Other, "Failed by the test case"); return response; }; test.styleObserver.sourceError = [&] (Source& source, std::exception_ptr error) { EXPECT_EQ("source", source.getID()); EXPECT_EQ("Failed by the test case", util::toString(error)); test.end(); }; VectorSource source("source", "url"); source.setObserver(&test.styleObserver); source.loadDescription(*test.fileSource); test.run(); } TEST(Source, LoadingCorrupt) { SourceTest test; test.fileSource->sourceResponse = [&] (const Resource& resource) { EXPECT_EQ("url", resource.url); Response response; response.data = std::make_unique("CORRUPTED"); return response; }; test.styleObserver.sourceError = [&] (Source& source, std::exception_ptr error) { EXPECT_EQ("source", source.getID()); EXPECT_EQ("Invalid value. at offset 0", util::toString(error)); test.end(); }; VectorSource source("source", "url"); source.setObserver(&test.styleObserver); source.loadDescription(*test.fileSource); test.run(); } TEST(Source, RasterTileEmpty) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.noContent = true; return response; }; RasterLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; RasterSource source("source", tileset, 512); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileChanged = [&] (RenderSource& source_, const OverscaledTileID&) { EXPECT_EQ("source", source_.baseImpl->id); test.end(); }; test.renderSourceObserver.tileError = [&] (RenderSource&, const OverscaledTileID&, std::exception_ptr) { FAIL() << "Should never be called"; }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, RasterDEMTileEmpty) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.noContent = true; return response; }; HillshadeLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; RasterDEMSource source("source", tileset, 512); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileChanged = [&] (RenderSource& source_, const OverscaledTileID&) { EXPECT_EQ("source", source_.baseImpl->id); test.end(); }; test.renderSourceObserver.tileError = [&] (RenderSource&, const OverscaledTileID&, std::exception_ptr) { FAIL() << "Should never be called"; }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, VectorTileEmpty) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.noContent = true; return response; }; LineLayer layer("id", "source"); layer.setSourceLayer("water"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; VectorSource source("source", tileset); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileChanged = [&] (RenderSource& source_, const OverscaledTileID&) { EXPECT_EQ("source", source_.baseImpl->id); test.end(); }; test.renderSourceObserver.tileError = [&] (RenderSource&, const OverscaledTileID&, std::exception_ptr) { FAIL() << "Should never be called"; }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, RasterTileFail) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.error = std::make_unique( Response::Error::Reason::Other, "Failed by the test case"); return response; }; RasterLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; RasterSource source("source", tileset, 512); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) { EXPECT_EQ(SourceType::Raster, source_.baseImpl->type); EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID); EXPECT_EQ("Failed by the test case", util::toString(error)); test.end(); }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, RasterDEMTileFail) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.error = std::make_unique( Response::Error::Reason::Other, "Failed by the test case"); return response; }; HillshadeLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; RasterDEMSource source("source", tileset, 512); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) { EXPECT_EQ(SourceType::RasterDEM, source_.baseImpl->type); EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID); EXPECT_EQ("Failed by the test case", util::toString(error)); test.end(); }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, VectorTileFail) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.error = std::make_unique( Response::Error::Reason::Other, "Failed by the test case"); return response; }; LineLayer layer("id", "source"); layer.setSourceLayer("water"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; VectorSource source("source", tileset); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) { EXPECT_EQ(SourceType::Vector, source_.baseImpl->type); EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID); EXPECT_EQ("Failed by the test case", util::toString(error)); test.end(); }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, RasterTileCorrupt) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.data = std::make_unique("CORRUPTED"); return response; }; RasterLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; RasterSource source("source", tileset, 512); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) { EXPECT_EQ(source_.baseImpl->type, SourceType::Raster); EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID); EXPECT_TRUE(bool(error)); // Not asserting on platform-specific error text. test.end(); }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, RasterDEMTileCorrupt) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.data = std::make_unique("CORRUPTED"); return response; }; HillshadeLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties };; Tileset tileset; tileset.tiles = { "tiles" }; RasterDEMSource source("source", tileset, 512); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) { EXPECT_EQ(source_.baseImpl->type, SourceType::RasterDEM); EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID); EXPECT_TRUE(bool(error)); // Not asserting on platform-specific error text. test.end(); }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, VectorTileCorrupt) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.data = std::make_unique("CORRUPTED"); return response; }; LineLayer layer("id", "source"); layer.setSourceLayer("water"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; VectorSource source("source", tileset); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileError = [&] (RenderSource& source_, const OverscaledTileID& tileID, std::exception_ptr error) { EXPECT_EQ(source_.baseImpl->type, SourceType::Vector); EXPECT_EQ(OverscaledTileID(0, 0, 0), tileID); EXPECT_EQ(util::toString(error), "unknown pbf field type exception"); test.end(); }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, RasterTileCancel) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { test.end(); return optional(); }; RasterLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; RasterSource source("source", tileset, 512); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileChanged = [&] (RenderSource&, const OverscaledTileID&) { FAIL() << "Should never be called"; }; test.renderSourceObserver.tileError = [&] (RenderSource&, const OverscaledTileID&, std::exception_ptr) { FAIL() << "Should never be called"; }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, RasterDEMTileCancel) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { test.end(); return optional(); }; HillshadeLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; RasterDEMSource source("source", tileset, 512); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileChanged = [&] (RenderSource&, const OverscaledTileID&) { FAIL() << "Should never be called"; }; test.renderSourceObserver.tileError = [&] (RenderSource&, const OverscaledTileID&, std::exception_ptr) { FAIL() << "Should never be called"; }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, VectorTileCancel) { SourceTest test; test.fileSource->tileResponse = [&] (const Resource&) { test.end(); return optional(); }; LineLayer layer("id", "source"); layer.setSourceLayer("water"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; Tileset tileset; tileset.tiles = { "tiles" }; VectorSource source("source", tileset); source.loadDescription(*test.fileSource); test.renderSourceObserver.tileChanged = [&] (RenderSource&, const OverscaledTileID&) { FAIL() << "Should never be called"; }; test.renderSourceObserver.tileError = [&] (RenderSource&, const OverscaledTileID&, std::exception_ptr) { FAIL() << "Should never be called"; }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, RasterTileAttribution) { SourceTest test; RasterLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; std::string mapboxOSM = ("© Mapbox " "©️ OpenStreetMap"); test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.noContent = true; return response; }; test.fileSource->sourceResponse = [&] (const Resource& resource) { EXPECT_EQ("url", resource.url); Response response; response.data = std::make_unique(R"TILEJSON({ "tilejson": "2.1.0", "attribution": ")TILEJSON" + mapboxOSM + R"TILEJSON(", "tiles": [ "tiles" ] })TILEJSON"); return response; }; test.styleObserver.sourceChanged = [&] (Source& source) { EXPECT_EQ(mapboxOSM, source.getAttribution()); EXPECT_FALSE(mapboxOSM.find("©️ OpenStreetMap") == std::string::npos); test.end(); }; RasterSource source("source", "url", 512); source.setObserver(&test.styleObserver); source.loadDescription(*test.fileSource); auto renderSource = RenderSource::create(source.baseImpl); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, RasterDEMTileAttribution) { SourceTest test; HillshadeLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; std::string mapbox = ("© Mapbox "); test.fileSource->tileResponse = [&] (const Resource&) { Response response; response.noContent = true; return response; }; test.fileSource->sourceResponse = [&] (const Resource& resource) { EXPECT_EQ("url", resource.url); Response response; response.data = std::make_unique(R"TILEJSON({ "tilejson": "2.1.0", "attribution": ")TILEJSON" + mapbox + R"TILEJSON(", "tiles": [ "tiles" ] })TILEJSON"); return response; }; test.styleObserver.sourceChanged = [&] (Source& source) { EXPECT_EQ(mapbox, source.getAttribution()); test.end(); }; RasterDEMSource source("source", "url", 512); source.setObserver(&test.styleObserver); source.loadDescription(*test.fileSource); auto renderSource = RenderSource::create(source.baseImpl); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.run(); } TEST(Source, GeoJSonSourceUrlUpdate) { SourceTest test; test.fileSource->sourceResponse = [&] (const Resource& resource) { EXPECT_EQ("url", resource.url); Response response; response.data = std::make_unique(R"({"geometry": {"type": "Point", "coordinates": [1.1, 1.1]}, "type": "Feature", "properties": {}})"); return response; }; test.styleObserver.sourceDescriptionChanged = [&] (Source&) { // Should be called (test will hang if it doesn't) test.end(); }; GeoJSONSource source("source"); source.setObserver(&test.styleObserver); // Load initial, so the source state will be loaded=true source.loadDescription(*test.fileSource); // Schedule an update test.loop.invoke([&] () { // Update the url source.setURL(std::string("http://source-url.ext")); }); test.run(); } TEST(Source, ImageSourceImageUpdate) { SourceTest test; test.fileSource->response = [&] (const Resource& resource) { EXPECT_EQ("http://url", resource.url); Response response; response.data = std::make_unique(util::read_file("test/fixtures/image/no_profile.png")); return response; }; test.styleObserver.sourceChanged = [&] (Source&) { // Should be called (test will hang if it doesn't) test.end(); }; std::array coords; ImageSource source("source", coords); source.setURL("http://url"); source.setObserver(&test.styleObserver); // Load initial, so the source state will be loaded=true source.loadDescription(*test.fileSource); PremultipliedImage rgba({ 1, 1 }); rgba.data[0] = 255; rgba.data[1] = 254; rgba.data[2] = 253; rgba.data[3] = 0; // Schedule an update test.loop.invoke([&] () { // Update the url source.setImage(std::move(rgba)); }); test.run(); } TEST(Source, CustomGeometrySourceSetTileData) { SourceTest test; CustomGeometrySource source("source", CustomGeometrySource::Options()); source.loadDescription(*test.fileSource); LineLayer layer("id", "source"); layer.setSourceLayer("water"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; test.renderSourceObserver.tileChanged = [&] (RenderSource& source_, const OverscaledTileID&) { EXPECT_EQ("source", source_.baseImpl->id); test.end(); }; test.renderSourceObserver.tileError = [&] (RenderSource&, const OverscaledTileID&, std::exception_ptr) { FAIL() << "Should never be called"; }; auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.loop.invoke([&] () { // Set Tile Data source.setTileData(CanonicalTileID(0, 0, 0), GeoJSON{ FeatureCollection{} }); }); test.run(); } namespace { class FakeTileSource; class FakeTile : public Tile { public: FakeTile(FakeTileSource& source_, const OverscaledTileID& tileID) : Tile(Tile::Kind::Geometry, tileID), source(source_) { renderable = true; } void setNecessity(TileNecessity necessity) override; void setUpdateParameters(const TileUpdateParameters&) override; bool layerPropertiesUpdated(const Immutable&) override { return true; } std::unique_ptr createRenderData() override { return nullptr; } private: FakeTileSource& source; }; class FakeTileSource : public RenderTileSetSource { public: MOCK_METHOD1(tileSetNecessity, void(TileNecessity)); MOCK_METHOD1(tileSetMinimumUpdateInterval, void(Duration)); explicit FakeTileSource(Immutable impl_) : RenderTileSetSource(std::move(impl_)) {} void updateInternal(const Tileset& tileset, const std::vector>& layers, const bool needsRendering, const bool needsRelayout, const TileParameters& parameters) override { tilePyramid.update(layers, needsRendering, needsRelayout, parameters, *baseImpl, util::tileSize, tileset.zoomRange, tileset.bounds, [&](const OverscaledTileID& tileID) { return std::make_unique(*this, tileID); }); } const optional& getTileset() const override { return static_cast(*baseImpl).tileset; } }; void FakeTile::setNecessity(TileNecessity necessity) { source.tileSetNecessity(necessity); } void FakeTile::setUpdateParameters(const TileUpdateParameters& params) { source.tileSetMinimumUpdateInterval(params.minimumUpdateInterval); } } // namespace TEST(Source, InvisibleSourcesTileNecessity) { SourceTest test; VectorSource initialized("source", Tileset{{"tiles"}}); initialized.loadDescription(*test.fileSource); FakeTileSource renderTilesetSource{initialized.baseImpl}; RenderSource* renderSource = &renderTilesetSource; LineLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers{layerProperties}; EXPECT_CALL(renderTilesetSource, tileSetNecessity(TileNecessity::Required)).Times(1); renderSource->update(initialized.baseImpl, layers, true, true, test.tileParameters()); // Necessity for invisible tiles must be set to `optional`. EXPECT_CALL(renderTilesetSource, tileSetNecessity(TileNecessity::Optional)).Times(1); renderSource->update(initialized.baseImpl, layers, false, false, test.tileParameters()); // Necessity is again `required` once tiles get back visible. EXPECT_CALL(renderTilesetSource, tileSetNecessity(TileNecessity::Required)).Times(1); renderSource->update(initialized.baseImpl, layers, true, false, test.tileParameters()); } TEST(Source, SourceMinimumUpdateInterval) { SourceTest test; VectorSource initialized("source", Tileset{{"tiles"}}); initialized.loadDescription(*test.fileSource); FakeTileSource renderTilesetSource{initialized.baseImpl}; RenderSource* renderSource = &renderTilesetSource; LineLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers{layerProperties}; Duration minimumTileUpdateInterval = initialized.getMinimumTileUpdateInterval(); auto baseImpl = initialized.baseImpl; EXPECT_EQ(Duration::zero(), minimumTileUpdateInterval); EXPECT_CALL(renderTilesetSource, tileSetMinimumUpdateInterval(minimumTileUpdateInterval)).Times(1); renderSource->update(baseImpl, layers, true, false, test.tileParameters()); initialized.setMinimumTileUpdateInterval(Seconds(1)); EXPECT_NE(baseImpl, initialized.baseImpl) << "Source impl was updated"; baseImpl = initialized.baseImpl; initialized.setMinimumTileUpdateInterval(Seconds(1)); // Set the same interval again. EXPECT_EQ(baseImpl, initialized.baseImpl) << "Source impl was not updated"; minimumTileUpdateInterval = initialized.getMinimumTileUpdateInterval(); EXPECT_EQ(Seconds(1), minimumTileUpdateInterval); EXPECT_CALL(renderTilesetSource, tileSetMinimumUpdateInterval(minimumTileUpdateInterval)).Times(1); renderSource->update(baseImpl, layers, true, false, test.tileParameters()); initialized.setMinimumTileUpdateInterval(Seconds(2)); minimumTileUpdateInterval = initialized.getMinimumTileUpdateInterval(); EXPECT_EQ(Seconds(2), minimumTileUpdateInterval); // No network activity for invisible tiles, and no reason to set the update interval. EXPECT_CALL(renderTilesetSource, tileSetMinimumUpdateInterval(minimumTileUpdateInterval)).Times(0); renderSource->update(initialized.baseImpl, layers, false, false, test.tileParameters()); // Tiles got visible, set the update interval now. EXPECT_CALL(renderTilesetSource, tileSetMinimumUpdateInterval(minimumTileUpdateInterval)).Times(1); renderSource->update(initialized.baseImpl, layers, true, false, test.tileParameters()); } TEST(Source, RenderTileSetSourceUpdate) { SourceTest test; class FakeRenderTileSetSource : public RenderTileSetSource { public: explicit FakeRenderTileSetSource(Immutable impl_) : RenderTileSetSource(std::move(impl_)) {} MOCK_METHOD0(mockedUpdateInternal, void()); void updateInternal(const Tileset&, const std::vector>&, const bool, const bool, const TileParameters&) override { mockedUpdateInternal(); } const optional& getTileset() const override { return static_cast(*baseImpl).tileset; } }; VectorSource initialized("source", Tileset{ {"tiles"} }); initialized.loadDescription(*test.fileSource); FakeRenderTileSetSource renderTilesetSource { initialized.baseImpl }; LineLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers { layerProperties }; // Check that `updateInternal()` is called even if the updated source has not yet loaded description. EXPECT_CALL(renderTilesetSource, mockedUpdateInternal()).Times(2); RenderSource* renderSource = &renderTilesetSource; renderSource->update(initialized.baseImpl, layers, true, true, test.tileParameters()); VectorSource uninitialized("source", "http://url"); renderSource->update(uninitialized.baseImpl, layers, true, true, test.tileParameters()); } TEST(Source, GeoJSONSourceTilesAfterDataReset) { SourceTest test; GeoJSONSource source("source"); auto geoJSONData = GeoJSONData::create(mapbox::geojson::parse( R"({"geometry": {"type": "Point", "coordinates": [1.1, 1.1]}, "type": "Feature", "properties": {}})")); source.setGeoJSONData(geoJSONData); RenderGeoJSONSource renderSource{staticImmutableCast(source.baseImpl)}; CircleLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers{layerProperties}; static_cast(renderSource).update(source.baseImpl, layers, true, true, test.tileParameters()); EXPECT_FALSE(renderSource.isLoaded()); // loaded == false, means that the source contains pending tiles. source.setGeoJSONData(nullptr); static_cast(renderSource).update(source.baseImpl, layers, true, true, test.tileParameters()); EXPECT_FALSE(renderSource.isLoaded()); // Tiles remain in continous mode. source.setGeoJSONData(geoJSONData); static_cast(renderSource).update(source.baseImpl, layers, true, true, test.tileParameters()); EXPECT_FALSE(renderSource.isLoaded()); source.setGeoJSONData(nullptr); static_cast(renderSource) .update(source.baseImpl, layers, true, true, test.tileParameters(MapMode::Static)); EXPECT_TRUE(renderSource.isLoaded()); // Tiles are reset in static mode. } TEST(Source, SetMaxParentOverscaleFactor) { SourceTest test; test.transform.jumpTo(CameraOptions().withCenter(LatLng()).withZoom(8.0)); test.transformState = test.transform.getState(); util::Timer timer; FixtureLog log; test.fileSource->tileResponse = [&](const Resource& res) { if (res.tileData->z == 5) { timer.start(Milliseconds(10), Duration::zero(), [&] { test.end(); }); } // No tiles above zoom level 5 should be requested. EXPECT_LE(5, int(res.tileData->z)); Response response; response.noContent = true; return response; }; RasterLayer layer("id", "source"); Immutable layerProperties = makeMutable(staticImmutableCast(layer.baseImpl)); std::vector> layers{layerProperties}; Tileset tileset; tileset.tiles = {"tiles"}; RasterSource source("source", tileset, 512); ASSERT_EQ(nullopt, source.getMaxOverscaleFactorForParentTiles()); source.setMaxOverscaleFactorForParentTiles(3); ASSERT_EQ(3, *source.getMaxOverscaleFactorForParentTiles()); source.loadDescription(*test.fileSource); auto renderSource = RenderSource::create(source.baseImpl); renderSource->setObserver(&test.renderSourceObserver); renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); test.renderSourceObserver.tileChanged = [&](RenderSource&, const OverscaledTileID&) { renderSource->update(source.baseImpl, layers, true, true, test.tileParameters()); }; test.run(); EXPECT_EQ( 1u, log.count( {EventSeverity::Warning, Event::Style, -1, "Parent tile overscale factor will cap prefetch delta to 3"})); EXPECT_EQ(0u, log.uncheckedCount()); }