#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace mln; using namespace mln::style; class GeoJSONTileTest { public: util::SimpleIdentity uniqueID; std::shared_ptr fileSource = std::make_shared(); TransformState transformState; util::RunLoop loop; AnnotationManager annotationManager{style}; std::shared_ptr imageManager = ImageManager::create(); std::shared_ptr glyphManager = std::make_shared(); gfx::DynamicTextureAtlasPtr dynamicTextureAtlas; Tileset tileset{{"https://example.com"}, {0, 22}, "none"}; TileParameters tileParameters; style::Style style; GeoJSONTileTest() : tileParameters{.pixelRatio = 1.0, .debugOptions = MapDebugOptions(), .transformState = transformState, .fileSource = fileSource, .mode = MapMode::Continuous, .annotationManager = annotationManager.makeWeakPtr(), .imageManager = imageManager, .glyphManager = glyphManager, .prefetchZoomDelta = 0, .threadPool = {Scheduler::GetBackground(), uniqueID}, .dynamicTextureAtlas = dynamicTextureAtlas}, style{fileSource, 1, tileParameters.threadPool} {} }; namespace { class FakeGeoJSONData : public GeoJSONData { public: FakeGeoJSONData(TileFeatures features_) : features(std::move(features_)) {} void getTile(const CanonicalTileID&, const std::function& fn, bool) final { assert(fn); fn(features); } Features getChildren(const std::uint32_t) final { return {}; } Features getLeaves(const std::uint32_t, const std::uint32_t, const std::uint32_t) final { return {}; } std::uint8_t getClusterExpansionZoom(std::uint32_t) final { return 0; } private: TileFeatures features; }; } // namespace TEST(GeoJSONTile, SynchronousUpdate) { GeoJSONTileTest test; CircleLayer layer("circle", "source"); mapbox::feature::feature_collection features; features.push_back(mapbox::feature::feature{mapbox::geometry::point(0, 0)}); auto data = std::make_shared(std::move(features)); TileParameters tileParameters = test.tileParameters; tileParameters.isUpdateSynchronous = true; GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", tileParameters, data); Immutable layerProperties = makeMutable( staticImmutableCast(layer.baseImpl)); std::vector> layers{layerProperties}; tile.setLayers(layers); ASSERT_TRUE(tile.isComplete()); ASSERT_TRUE(tile.isRenderable()); } TEST(GeoJSONTile, Issue7648) { GeoJSONTileTest test; CircleLayer layer("circle", "source"); mapbox::feature::feature_collection features; features.push_back(mapbox::feature::feature{mapbox::geometry::point(0, 0)}); auto data = std::make_shared(std::move(features)); GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, data); Immutable layerProperties = makeMutable( staticImmutableCast(layer.baseImpl)); StubTileObserver observer; observer.tileChanged = [&](const Tile&) { // Once present, the bucket should never "disappear", which would cause // flickering. ASSERT_TRUE(tile.layerPropertiesUpdated(layerProperties)); }; std::vector> layers{layerProperties}; tile.setLayers(layers); tile.setObserver(&observer); while (!tile.isComplete()) { test.loop.runOnce(); } tile.updateData(data, false, test.tileParameters.isUpdateSynchronous); while (!tile.isComplete()) { test.loop.runOnce(); } } // Tests that tiles remain renderable if they have been renderable and then had // an error sent to them, e.g. when revalidating/refreshing the request. TEST(GeoJSONTile, Issue9927) { GeoJSONTileTest test; CircleLayer layer("circle", "source"); mapbox::feature::feature_collection features; features.push_back(mapbox::feature::feature{mapbox::geometry::point(0, 0)}); auto data = std::make_shared(std::move(features)); GeoJSONTile tile(OverscaledTileID(0, 0, 0), "source", test.tileParameters, data); Immutable layerProperties = makeMutable( staticImmutableCast(layer.baseImpl)); std::vector> layers{layerProperties}; tile.setLayers(layers); while (!tile.isComplete()) { test.loop.runOnce(); } ASSERT_TRUE(tile.isRenderable()); ASSERT_TRUE(tile.layerPropertiesUpdated(layerProperties)); // Make sure that once we've had a renderable tile and then receive // erroneous data, we retain the previously rendered data and keep the tile // renderable. tile.setError(std::make_exception_ptr(std::runtime_error("Connection offline"))); ASSERT_TRUE(tile.isRenderable()); ASSERT_TRUE(tile.layerPropertiesUpdated(layerProperties)); // Then simulate a parsing failure and make sure that we keep it renderable // in this situation as well. We're using 3 as a correlationID since we've // done two three calls that increment this counter (as part of the // GeoJSONTile constructor, setLayers, and setPlacementConfig). tile.onError(std::make_exception_ptr(std::runtime_error("Parse error")), 3); ASSERT_TRUE(tile.isRenderable()); ASSERT_TRUE(tile.layerPropertiesUpdated(layerProperties)); }