diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/api/query.test.cpp | 15 | ||||
-rw-r--r-- | test/fixtures/offline_database/satellite_test.db | bin | 0 -> 114688 bytes | |||
-rw-r--r-- | test/gl/bucket.test.cpp | 3 | ||||
-rw-r--r-- | test/renderer/group_by_layout.test.cpp | 5 | ||||
-rw-r--r-- | test/storage/offline_database.test.cpp | 81 | ||||
-rw-r--r-- | test/storage/sqlite.test.cpp | 47 | ||||
-rw-r--r-- | test/style/conversion/stringify.test.cpp | 9 | ||||
-rw-r--r-- | test/style/conversion/tileset.test.cpp | 2 | ||||
-rw-r--r-- | test/style/expression/expression.test.cpp | 8 | ||||
-rw-r--r-- | test/style/filter.test.cpp | 65 | ||||
-rw-r--r-- | test/style/style_layer.test.cpp | 2 | ||||
-rw-r--r-- | test/text/cross_tile_symbol_index.test.cpp | 24 | ||||
-rw-r--r-- | test/util/tile_cover.test.cpp | 232 | ||||
-rw-r--r-- | test/util/tile_range.test.cpp | 8 | ||||
-rw-r--r-- | test/util/token.test.cpp | 3 |
15 files changed, 416 insertions, 88 deletions
diff --git a/test/api/query.test.cpp b/test/api/query.test.cpp index c67ff9064c..ffab52692b 100644 --- a/test/api/query.test.cpp +++ b/test/api/query.test.cpp @@ -13,6 +13,7 @@ using namespace mbgl; using namespace mbgl::style; +using namespace mbgl::style::expression; namespace { @@ -67,18 +68,19 @@ TEST(Query, QueryRenderedFeaturesFilterLayer) { TEST(Query, QueryRenderedFeaturesFilter) { QueryTest test; + ParsingContext context; auto zz = test.map.pixelForLatLng({ 0, 0 }); - const EqualsFilter eqFilter = { "key1", std::string("value1") }; + const Filter eqFilter(createCompoundExpression("filter-==", createLiteral("key1"), createLiteral("value1"), context)); auto features1 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{}, { eqFilter }}); EXPECT_EQ(features1.size(), 1u); - const IdentifierNotEqualsFilter idNotEqFilter = { std::string("feature1") }; + const Filter idNotEqFilter(createCompoundExpression("!", std::move(*createCompoundExpression("filter-id-==", createLiteral("feature1"), context)), context)); auto features2 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{{ "layer4" }}, { idNotEqFilter }}); EXPECT_EQ(features2.size(), 0u); - const GreaterThanFilter gtFilter = { "key2", 1.0 }; + const Filter gtFilter(createCompoundExpression("filter->", createLiteral("key2"), createLiteral(1.0), context)); auto features3 = test.frontend.getRenderer()->queryRenderedFeatures(zz, {{ }, { gtFilter }}); EXPECT_EQ(features3.size(), 1u); } @@ -108,16 +110,17 @@ TEST(Query, QuerySourceFeaturesOptionValidation) { TEST(Query, QuerySourceFeaturesFilter) { QueryTest test; + ParsingContext context; - const EqualsFilter eqFilter = { "key1", std::string("value1") }; + const Filter eqFilter(createCompoundExpression("filter-==", createLiteral("key1"), createLiteral("value1"), context)); auto features1 = test.frontend.getRenderer()->querySourceFeatures("source4", {{}, { eqFilter }}); EXPECT_EQ(features1.size(), 1u); - const IdentifierNotEqualsFilter idNotEqFilter = { std::string("feature1") }; + const Filter idNotEqFilter(createCompoundExpression("!", std::move(*createCompoundExpression("filter-id-==", createLiteral("feature1"), context)), context)); auto features2 = test.frontend.getRenderer()->querySourceFeatures("source4", {{}, { idNotEqFilter }}); EXPECT_EQ(features2.size(), 0u); - const GreaterThanFilter gtFilter = { "key2", 1.0 }; + const Filter gtFilter(createCompoundExpression("filter->", createLiteral("key2"), createLiteral(1.0), context)); auto features3 = test.frontend.getRenderer()->querySourceFeatures("source4", {{}, { gtFilter }}); EXPECT_EQ(features3.size(), 1u); } diff --git a/test/fixtures/offline_database/satellite_test.db b/test/fixtures/offline_database/satellite_test.db Binary files differnew file mode 100644 index 0000000000..95dd8617ff --- /dev/null +++ b/test/fixtures/offline_database/satellite_test.db diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp index 8393fd130d..9b28b2e01a 100644 --- a/test/gl/bucket.test.cpp +++ b/test/gl/bucket.test.cpp @@ -110,10 +110,11 @@ TEST(Buckets, SymbolBucket) { bool sdfIcons = false; bool iconsNeedLinear = false; bool sortFeaturesByY = false; + std::string bucketLeaderID = "test"; std::vector<SymbolInstance> symbolInstances; gl::Context context; - SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(symbolInstances) }; + SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances) }; ASSERT_FALSE(bucket.hasIconData()); ASSERT_FALSE(bucket.hasTextData()); ASSERT_FALSE(bucket.hasCollisionBoxData()); diff --git a/test/renderer/group_by_layout.test.cpp b/test/renderer/group_by_layout.test.cpp index 958f1bdf24..6cf17e2279 100644 --- a/test/renderer/group_by_layout.test.cpp +++ b/test/renderer/group_by_layout.test.cpp @@ -5,9 +5,11 @@ #include <mbgl/style/layers/background_layer.hpp> #include <mbgl/style/layers/circle_layer.hpp> #include <mbgl/style/layers/line_layer.hpp> +#include <mbgl/style/expression/compound_expression.hpp> using namespace mbgl; using namespace mbgl::style; +using namespace mbgl::style::expression; static std::vector<std::unique_ptr<RenderLayer>> toRenderLayers(const std::vector<std::unique_ptr<Layer>>& layers) { std::vector<std::unique_ptr<RenderLayer>> result; @@ -39,7 +41,8 @@ TEST(GroupByLayout, UnrelatedFilter) { std::vector<std::unique_ptr<Layer>> layers; layers.push_back(std::make_unique<LineLayer>("a", "source")); layers.push_back(std::make_unique<LineLayer>("b", "source")); - layers[0]->as<LineLayer>()->setFilter(EqualsFilter()); + ParsingContext context; + layers[0]->as<LineLayer>()->setFilter(Filter(createCompoundExpression("filter-has-id", context))); auto result = groupByLayout(toRenderLayers(layers)); ASSERT_EQ(2u, result.size()); } diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index 94daf59c02..656231eebe 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -38,6 +38,10 @@ void writeFile(const char* name, const std::string& data) { mbgl::util::write_file(name, data); } +void copyFile(const char* orig, const char* dest) { + mbgl::util::write_file(dest, mbgl::util::read_file(orig)); +} + } // namespace TEST(OfflineDatabase, TEST_REQUIRES_WRITE(Create)) { @@ -62,7 +66,7 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(SchemaVersion)) { std::string path("test/fixtures/offline_database/offline.db"); { - mapbox::sqlite::Database db(path, mapbox::sqlite::Create | mapbox::sqlite::ReadWrite); + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::Create | mapbox::sqlite::ReadWrite); db.exec("PRAGMA user_version = 1"); } @@ -143,6 +147,36 @@ TEST(OfflineDatabase, PutResource) { EXPECT_EQ("second", *updateGetResult->data); } +TEST(OfflineDatabase, TEST_REQUIRES_WRITE(GetResourceFromOfflineRegion)) { + using namespace mbgl; + + createDir("test/fixtures/offline_database"); + deleteFile("test/fixtures/offline_database/satellite.db"); + copyFile("test/fixtures/offline_database/satellite_test.db", "test/fixtures/offline_database/satellite.db"); + + OfflineDatabase db("test/fixtures/offline_database/satellite.db", mapbox::sqlite::ReadOnly); + + Resource resource = Resource::style("mapbox://styles/mapbox/satellite-v9"); + ASSERT_TRUE(db.get(resource)); +} + +TEST(OfflineDatabase, PutAndGetResource) { + using namespace mbgl; + + OfflineDatabase db(":memory:"); + + Response response1; + response1.data = std::make_shared<std::string>("foobar"); + + Resource resource = Resource::style("mapbox://example.com/style"); + + db.put(resource, response1); + + auto response2 = db.get(resource); + + ASSERT_EQ(*response1.data, *(*response2).data); +} + TEST(OfflineDatabase, PutTile) { using namespace mbgl; @@ -565,40 +599,45 @@ TEST(OfflineDatabase, OfflineMapboxTileCount) { } static int databasePageCount(const std::string& path) { - mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly); - mapbox::sqlite::Statement stmt = db.prepare("pragma page_count"); - stmt.run(); - return stmt.get<int>(0); + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{ db, "pragma page_count" }; + mapbox::sqlite::Query query{ stmt }; + query.run(); + return query.get<int>(0); } static int databaseUserVersion(const std::string& path) { - mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly); - mapbox::sqlite::Statement stmt = db.prepare("pragma user_version"); - stmt.run(); - return stmt.get<int>(0); + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{ db, "pragma user_version" }; + mapbox::sqlite::Query query{ stmt }; + query.run(); + return query.get<int>(0); } static std::string databaseJournalMode(const std::string& path) { - mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly); - mapbox::sqlite::Statement stmt = db.prepare("pragma journal_mode"); - stmt.run(); - return stmt.get<std::string>(0); + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{ db, "pragma journal_mode" }; + mapbox::sqlite::Query query{ stmt }; + query.run(); + return query.get<std::string>(0); } static int databaseSyncMode(const std::string& path) { - mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly); - mapbox::sqlite::Statement stmt = db.prepare("pragma synchronous"); - stmt.run(); - return stmt.get<int>(0); + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{ db, "pragma synchronous" }; + mapbox::sqlite::Query query{ stmt }; + query.run(); + return query.get<int>(0); } static std::vector<std::string> databaseTableColumns(const std::string& path, const std::string& name) { - mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); const auto sql = std::string("pragma table_info(") + name + ")"; - mapbox::sqlite::Statement stmt = db.prepare(sql.c_str()); + mapbox::sqlite::Statement stmt{ db, sql.c_str() }; + mapbox::sqlite::Query query{ stmt }; std::vector<std::string> columns; - while (stmt.run()) { - columns.push_back(stmt.get<std::string>(1)); + while (query.run()) { + columns.push_back(query.get<std::string>(1)); } return columns; } diff --git a/test/storage/sqlite.test.cpp b/test/storage/sqlite.test.cpp index 36715a2fd0..553736a0b1 100644 --- a/test/storage/sqlite.test.cpp +++ b/test/storage/sqlite.test.cpp @@ -6,33 +6,32 @@ TEST(SQLite, Statement) { using namespace mbgl; - mapbox::sqlite::Database db(":memory:", mapbox::sqlite::Create | mapbox::sqlite::ReadWrite); + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(":memory:", mapbox::sqlite::Create | mapbox::sqlite::ReadWrite); db.exec("CREATE TABLE test (id INTEGER);"); - mapbox::sqlite::Statement stmt1 = db.prepare("INSERT INTO test (id) VALUES (?1);"); - ASSERT_EQ(stmt1.lastInsertRowId(), 0); - ASSERT_EQ(stmt1.changes(), 0u); - stmt1.bind(1, 10); - stmt1.run(); - ASSERT_EQ(stmt1.lastInsertRowId(), 1); - ASSERT_EQ(stmt1.changes(), 1u); + mapbox::sqlite::Statement stmt1{ db, "INSERT INTO test (id) VALUES (?1);" }; + mapbox::sqlite::Query query1{ stmt1 }; + ASSERT_EQ(query1.lastInsertRowId(), 0); + ASSERT_EQ(query1.changes(), 0u); + query1.bind(1, 10); + query1.run(); + ASSERT_EQ(query1.lastInsertRowId(), 1); + ASSERT_EQ(query1.changes(), 1u); - mapbox::sqlite::Statement stmt2 = db.prepare("INSERT INTO test (id) VALUES (?1);"); - ASSERT_EQ(stmt2.lastInsertRowId(), 0); - ASSERT_EQ(stmt2.changes(), 0u); - stmt2.bind(1, 20); - stmt2.run(); - ASSERT_EQ(stmt2.lastInsertRowId(), 2); - ASSERT_EQ(stmt2.changes(), 1u); + mapbox::sqlite::Statement stmt2{ db, "INSERT INTO test (id) VALUES (?1);" }; + mapbox::sqlite::Query query2{ stmt2 }; + ASSERT_EQ(query2.lastInsertRowId(), 0); + ASSERT_EQ(query2.changes(), 0u); + query2.bind(1, 20); + query2.run(); + ASSERT_EQ(query2.lastInsertRowId(), 2); + ASSERT_EQ(query2.changes(), 1u); } -TEST(SQLite, TEST_REQUIRES_WRITE(CantOpenException)) { - try { - // Should throw a CANTOPEN when the database doesn't exist, - // make sure all the backends behave the same way. - mapbox::sqlite::Database("test/fixtures/offline_database/foobar123.db", mapbox::sqlite::ReadOnly); - FAIL(); - } catch (mapbox::sqlite::Exception& ex) { - ASSERT_EQ(ex.code, mapbox::sqlite::Exception::Code::CANTOPEN); - } +TEST(SQLite, TEST_REQUIRES_WRITE(TryOpen)) { + // Should return a CANTOPEN exception when the database doesn't exist, + // make sure all the backends behave the same way. + auto result = mapbox::sqlite::Database::tryOpen("test/fixtures/offline_database/foobar123.db", mapbox::sqlite::ReadOnly); + ASSERT_TRUE(result.is<mapbox::sqlite::Exception>()); + ASSERT_EQ(result.get<mapbox::sqlite::Exception>().code, mapbox::sqlite::ResultCode::CantOpen); } diff --git a/test/style/conversion/stringify.test.cpp b/test/style/conversion/stringify.test.cpp index 136f276aaf..c3faf1f838 100644 --- a/test/style/conversion/stringify.test.cpp +++ b/test/style/conversion/stringify.test.cpp @@ -1,5 +1,6 @@ #include <mbgl/test/util.hpp> +#include <mbgl/style/expression/literal.hpp> #include <mbgl/style/conversion/stringify.hpp> #include <mbgl/style/types.hpp> #include <mbgl/style/layers/symbol_layer_properties.hpp> @@ -75,8 +76,12 @@ TEST(Stringify, Value) { } TEST(Stringify, Filter) { - ASSERT_EQ(stringify(NullFilter()), "null"); - ASSERT_EQ(stringify(EqualsFilter { "a", 1.0 }), "[\"==\",\"a\",1.0]"); + using namespace mbgl::style::expression; + + ASSERT_EQ(stringify(Filter()), "null"); + + ParsingContext context; + ASSERT_EQ(stringify(Filter(createCompoundExpression("filter-==", createLiteral("a"), createLiteral(1.0), context))), "[\"filter-==\",\"a\",1.0]"); } TEST(Stringify, CameraFunction) { diff --git a/test/style/conversion/tileset.test.cpp b/test/style/conversion/tileset.test.cpp index f10aa0e318..f405fb1361 100644 --- a/test/style/conversion/tileset.test.cpp +++ b/test/style/conversion/tileset.test.cpp @@ -66,7 +66,7 @@ TEST(Tileset, BoundsAreClamped) { Error error; mbgl::optional<Tileset> converted = convertJSON<Tileset>(R"JSON({ "tiles": ["http://mytiles"], - "bounds": [-181.0000005,-90,180.00000000000006,90] + "bounds": [-181.0000005,-90.000000006,180.00000000000006,91] })JSON", error); EXPECT_TRUE((bool) converted); EXPECT_EQ(converted->bounds, LatLngBounds::hull({90, -180}, {-90, 180})); diff --git a/test/style/expression/expression.test.cpp b/test/style/expression/expression.test.cpp index fe5c261be1..709624a50f 100644 --- a/test/style/expression/expression.test.cpp +++ b/test/style/expression/expression.test.cpp @@ -24,11 +24,15 @@ TEST(Expression, IsExpression) { spec["expression_name"].IsObject() && spec["expression_name"].HasMember("values") && spec["expression_name"]["values"].IsObject()); - + const auto& allExpressions = spec["expression_name"]["values"]; - + for(auto& entry : allExpressions.GetObject()) { const std::string name { entry.name.GetString(), entry.name.GetStringLength() }; + if (name == "collator" || name == "line-progress" || name == "resolved-locale" || name == "feature-state") { + // Not yet implemented + continue; + } JSDocument document; document.Parse<0>(R"([")" + name + R"("])"); diff --git a/test/style/filter.test.cpp b/test/style/filter.test.cpp index 49edcaef45..c59a73eab1 100644 --- a/test/style/filter.test.cpp +++ b/test/style/filter.test.cpp @@ -4,7 +4,6 @@ #include <mbgl/test/stub_geometry_tile_feature.hpp> #include <mbgl/style/filter.hpp> -#include <mbgl/style/filter_evaluator.hpp> #include <mbgl/style/conversion/json.hpp> #include <mbgl/style/conversion/filter.hpp> @@ -28,6 +27,24 @@ bool filter(const char * json, return (*filter)(context); } +void invalidFilter(const char * json) { + conversion::Error error; + optional<Filter> filter = conversion::convertJSON<Filter>(json, error); + EXPECT_FALSE(bool(filter)); + EXPECT_NE(error.message, ""); +} + +TEST(Filter, EqualsNull) { + auto f = R"(["==", "foo", null])"; + ASSERT_TRUE(filter(f, {{ "foo", mapbox::geometry::null_value }})); + + ASSERT_FALSE(filter(f, {{ "foo", int64_t(0) }})); + ASSERT_FALSE(filter(f, {{ "foo", int64_t(1) }})); + ASSERT_FALSE(filter(f, {{ "foo", std::string("0") }})); + ASSERT_FALSE(filter(f, {{ "foo", true }})); + ASSERT_FALSE(filter(f, {{ "foo", false }})); + ASSERT_FALSE(filter(f, {{ }})); +} TEST(Filter, EqualsString) { auto f = R"(["==", "foo", "bar"])"; ASSERT_TRUE(filter(f, {{ "foo", std::string("bar") }})); @@ -53,6 +70,12 @@ TEST(Filter, EqualsType) { auto f = R"(["==", "$type", "LineString"])"; ASSERT_FALSE(filter(f, {{}}, {}, FeatureType::Point, {})); ASSERT_TRUE(filter(f, {{}}, {}, FeatureType::LineString, {})); + ASSERT_FALSE(filter(f, {{}}, {}, FeatureType::Point, {})); + + invalidFilter("[\"==\", \"$type\"]"); + invalidFilter("[\"==\", \"$type\", null]"); + invalidFilter("[\"==\", \"$type\", \"foo\", 1]"); + invalidFilter("[\"==\", \"$type\", \"foo\", \"Point\"]"); } TEST(Filter, InType) { @@ -62,6 +85,14 @@ TEST(Filter, InType) { ASSERT_TRUE(filter(f, {{}}, {}, FeatureType::Polygon)); } +TEST(Filter, InID) { + auto f = R"(["in", "$id", "123", "1234", 1234])"; + ASSERT_FALSE(filter(f)); + ASSERT_TRUE(filter(f, {{}}, { uint64_t(1234) })); + ASSERT_TRUE(filter(f, {{}}, { std::string("1234") })); + ASSERT_FALSE(filter(f, {{}}, { std::string("4321") })); +} + TEST(Filter, Any) { ASSERT_FALSE(filter("[\"any\"]")); ASSERT_TRUE(filter("[\"any\", [\"==\", \"foo\", 1]]", {{ std::string("foo"), int64_t(1) }})); @@ -69,6 +100,13 @@ TEST(Filter, Any) { ASSERT_TRUE(filter("[\"any\", [\"==\", \"foo\", 0], [\"==\", \"foo\", 1]]", {{ std::string("foo"), int64_t(1) }})); } +TEST(Filter, AnyExpression) { + ASSERT_FALSE(filter("[\"any\"]")); + ASSERT_TRUE(filter("[\"any\", [\"==\", [\"get\", \"foo\"], 1]]", {{ std::string("foo"), int64_t(1) }})); + ASSERT_FALSE(filter("[\"any\", [\"==\", [\"get\", \"foo\"], 0]]", {{ std::string("foo"), int64_t(1) }})); + ASSERT_TRUE(filter("[\"any\", [\"==\", [\"get\", \"foo\"], 0], [\"==\", [\"get\", \"foo\"], 1]]", {{ std::string("foo"), int64_t(1) }})); +} + TEST(Filter, All) { ASSERT_TRUE(filter("[\"all\"]", {{}})); ASSERT_TRUE(filter("[\"all\", [\"==\", \"foo\", 1]]", {{ std::string("foo"), int64_t(1) }})); @@ -76,6 +114,12 @@ TEST(Filter, All) { ASSERT_FALSE(filter("[\"all\", [\"==\", \"foo\", 0], [\"==\", \"foo\", 1]]", {{ std::string("foo"), int64_t(1) }})); } +TEST(Filter, AllExpression) { + ASSERT_TRUE(filter("[\"all\", [\"==\", [\"get\", \"foo\"], 1]]", {{ std::string("foo"), int64_t(1) }})); + ASSERT_FALSE(filter("[\"all\", [\"==\", [\"get\", \"foo\"], 0]]", {{ std::string("foo"), int64_t(1) }})); + ASSERT_FALSE(filter("[\"all\", [\"==\", [\"get\", \"foo\"], 0], [\"==\", [\"get\", \"foo\"], 1]]", {{ std::string("foo"), int64_t(1) }})); +} + TEST(Filter, None) { ASSERT_TRUE(filter("[\"none\"]")); ASSERT_FALSE(filter("[\"none\", [\"==\", \"foo\", 1]]", {{ std::string("foo"), int64_t(1) }})); @@ -88,6 +132,7 @@ TEST(Filter, Has) { ASSERT_TRUE(filter("[\"has\", \"foo\"]", {{ std::string("foo"), int64_t(0) }})); ASSERT_TRUE(filter("[\"has\", \"foo\"]", {{ std::string("foo"), false }})); ASSERT_FALSE(filter("[\"has\", \"foo\"]")); + ASSERT_FALSE(filter("[\"has\", \"$id\"]")); } TEST(Filter, NotHas) { @@ -101,7 +146,11 @@ TEST(Filter, ID) { FeatureIdentifier id1 { uint64_t{ 1234 } }; ASSERT_TRUE(filter("[\"==\", \"$id\", 1234]", {{}}, id1)); ASSERT_FALSE(filter("[\"==\", \"$id\", \"1234\"]", {{}}, id1)); - + + FeatureIdentifier id2 { std::string{ "1" } }; + ASSERT_FALSE(filter("[\"<\", \"$id\", \"0\"]", {{}}, id2)); + ASSERT_TRUE(filter("[\"<\", \"$id\", \"1234\"]", {{}}, id2)); + ASSERT_FALSE(filter("[\"==\", \"$id\", 1234]", {{ "id", uint64_t(1234) }})); } @@ -115,6 +164,18 @@ TEST(Filter, PropertyExpression) { ASSERT_FALSE(filter("[\"==\", [\"get\", \"two\"], 4]", {{"two", int64_t(2)}})); } +TEST(Filter, LegacyProperty) { + ASSERT_TRUE(filter("[\"<=\", \"two\", 2]", {{"two", int64_t(2)}})); + ASSERT_FALSE(filter("[\"==\", \"two\", 4]", {{"two", int64_t(2)}})); + + ASSERT_FALSE(filter("[\"<=\", \"two\", \"2\"]", {{"two", int64_t(2)}})); + ASSERT_FALSE(filter("[\"==\", \"bool\", false]", {{"two", true}})); + + ASSERT_TRUE(filter("[\"<=\", \"two\", \"2\"]", {{"two", std::string("2")}})); + ASSERT_FALSE(filter("[\"<\", \"two\", \"1\"]", {{"two", std::string("2")}})); + ASSERT_FALSE(filter("[\"==\", \"two\", 4]", {{"two", std::string("2")}})); +} + TEST(Filter, ZoomExpressionNested) { ASSERT_TRUE(filter(R"(["==", ["get", "two"], ["zoom"]])", {{"two", int64_t(2)}}, {}, FeatureType::Point, {}, 2.0f)); ASSERT_FALSE(filter(R"(["==", ["get", "two"], ["+", ["zoom"], 1]])", {{"two", int64_t(2)}}, {}, FeatureType::Point, {}, 2.0f)); diff --git a/test/style/style_layer.test.cpp b/test/style/style_layer.test.cpp index 77acca2868..624ed088c3 100644 --- a/test/style/style_layer.test.cpp +++ b/test/style/style_layer.test.cpp @@ -211,7 +211,7 @@ TEST(Layer, Observer) { EXPECT_EQ(layer.get(), &layer_); filterChanged = true; }; - layer->setFilter(NullFilter()); + layer->setFilter(Filter()); EXPECT_TRUE(filterChanged); // Notifies observer on visibility change. diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp index 794c2b59a1..5d255a6105 100644 --- a/test/text/cross_tile_symbol_index.test.cpp +++ b/test/text/cross_tile_symbol_index.test.cpp @@ -25,12 +25,13 @@ TEST(CrossTileSymbolLayerIndex, addBucket) { bool sdfIcons = false; bool iconsNeedLinear = false; bool sortFeaturesByY = false; + std::string bucketLeaderID = "test"; OverscaledTileID mainID(6, 0, 6, 8, 8); std::vector<SymbolInstance> mainInstances; mainInstances.push_back(makeSymbolInstance(1000, 1000, u"Detroit")); mainInstances.push_back(makeSymbolInstance(2000, 2000, u"Toronto")); - SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(mainInstances) }; + SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) }; mainBucket.bucketInstanceId = ++maxBucketInstanceId; index.addBucket(mainID, mainBucket, maxCrossTileID); @@ -45,7 +46,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) { childInstances.push_back(makeSymbolInstance(2000, 2000, u"Windsor")); childInstances.push_back(makeSymbolInstance(3000, 3000, u"Toronto")); childInstances.push_back(makeSymbolInstance(4001, 4001, u"Toronto")); - SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(childInstances) }; + SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) }; childBucket.bucketInstanceId = ++maxBucketInstanceId; index.addBucket(childID, childBucket, maxCrossTileID); @@ -61,7 +62,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) { OverscaledTileID parentID(5, 0, 5, 4, 4); std::vector<SymbolInstance> parentInstances; parentInstances.push_back(makeSymbolInstance(500, 500, u"Detroit")); - SymbolBucket parentBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(parentInstances) }; + SymbolBucket parentBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(parentInstances) }; parentBucket.bucketInstanceId = ++maxBucketInstanceId; index.addBucket(parentID, parentBucket, maxCrossTileID); @@ -77,7 +78,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) { std::vector<SymbolInstance> grandchildInstances; grandchildInstances.push_back(makeSymbolInstance(4000, 4000, u"Detroit")); grandchildInstances.push_back(makeSymbolInstance(4000, 4000, u"Windsor")); - SymbolBucket grandchildBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(grandchildInstances) }; + SymbolBucket grandchildBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(grandchildInstances) }; grandchildBucket.bucketInstanceId = ++maxBucketInstanceId; index.addBucket(grandchildID, grandchildBucket, maxCrossTileID); @@ -98,17 +99,18 @@ TEST(CrossTileSymbolLayerIndex, resetIDs) { bool sdfIcons = false; bool iconsNeedLinear = false; bool sortFeaturesByY = false; + std::string bucketLeaderID = "test"; OverscaledTileID mainID(6, 0, 6, 8, 8); std::vector<SymbolInstance> mainInstances; mainInstances.push_back(makeSymbolInstance(1000, 1000, u"Detroit")); - SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(mainInstances) }; + SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) }; mainBucket.bucketInstanceId = ++maxBucketInstanceId; OverscaledTileID childID(7, 0, 7, 16, 16); std::vector<SymbolInstance> childInstances; childInstances.push_back(makeSymbolInstance(2000, 2000, u"Detroit")); - SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(childInstances) }; + SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) }; childBucket.bucketInstanceId = ++maxBucketInstanceId; // assigns a new id @@ -137,12 +139,13 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) { bool sdfIcons = false; bool iconsNeedLinear = false; bool sortFeaturesByY = false; + std::string bucketLeaderID = "test"; OverscaledTileID mainID(6, 0, 6, 8, 8); std::vector<SymbolInstance> mainInstances; mainInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A mainInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B - SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(mainInstances) }; + SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) }; mainBucket.bucketInstanceId = ++maxBucketInstanceId; OverscaledTileID childID(7, 0, 7, 16, 16); @@ -150,7 +153,7 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) { childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // A' childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // B' childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // C' - SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(childInstances) }; + SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) }; childBucket.bucketInstanceId = ++maxBucketInstanceId; // assigns new ids @@ -174,19 +177,20 @@ TEST(CrossTileSymbolLayerIndex, bucketReplacement) { bool sdfIcons = false; bool iconsNeedLinear = false; bool sortFeaturesByY = false; + std::string bucketLeaderID = "test"; OverscaledTileID tileID(6, 0, 6, 8, 8); std::vector<SymbolInstance> firstInstances; firstInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A firstInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B - SymbolBucket firstBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(firstInstances) }; + SymbolBucket firstBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(firstInstances) }; firstBucket.bucketInstanceId = ++maxBucketInstanceId; std::vector<SymbolInstance> secondInstances; secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A' secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B' secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // C' - SymbolBucket secondBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(secondInstances) }; + SymbolBucket secondBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(secondInstances) }; secondBucket.bucketInstanceId = ++maxBucketInstanceId; // assigns new ids diff --git a/test/util/tile_cover.test.cpp b/test/util/tile_cover.test.cpp index 933c18b5ea..7defa761af 100644 --- a/test/util/tile_cover.test.cpp +++ b/test/util/tile_cover.test.cpp @@ -2,6 +2,8 @@ #include <mbgl/util/geo.hpp> #include <mbgl/map/transform.hpp> +#include <algorithm> + #include <gtest/gtest.h> using namespace mbgl; @@ -22,8 +24,8 @@ TEST(TileCover, Antarctic) { TEST(TileCover, WorldZ0) { EXPECT_EQ((std::vector<UnwrappedTileID>{ - { 0, 0, 0 }, - }), + { 0, 0, 0 }, + }), util::tileCover(LatLngBounds::world(), 0)); } @@ -37,15 +39,15 @@ TEST(TileCover, Pitch) { transform.setPitch(40.0 * M_PI / 180.0); EXPECT_EQ((std::vector<UnwrappedTileID>{ - { 2, 1, 2 }, { 2, 1, 1 }, { 2, 2, 2 }, { 2, 2, 1 }, { 2, 3, 2 } - }), + { 2, 1, 2 }, { 2, 1, 1 }, { 2, 2, 2 }, { 2, 2, 1 }, { 2, 3, 2 } + }), util::tileCover(transform.getState(), 2)); } TEST(TileCover, WorldZ1) { EXPECT_EQ((std::vector<UnwrappedTileID>{ - { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 }, - }), + { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 }, + }), util::tileCover(LatLngBounds::world(), 1)); } @@ -59,21 +61,44 @@ TEST(TileCover, SingletonZ1) { util::tileCover(LatLngBounds::singleton({ 0, 0 }), 1)); } +TEST(TileCoverStream, Arctic) { + auto bounds = LatLngBounds::hull({ 84, -180 }, { 70, 180 }); + auto zoom = 3; + util::TileCover tc(bounds, zoom); + auto results = util::tileCover(bounds, zoom); + std::vector<UnwrappedTileID> t; + while(tc.hasNext()) { + t.push_back(*tc.next()); + }; + EXPECT_EQ(t.size(), results.size()); +} + +TEST(TileCoverStream, WorldZ1) { + auto zoom = 1; + util::TileCover tc(LatLngBounds::world(), zoom); + std::vector<UnwrappedTileID> t; + while(tc.hasNext()) { + t.push_back(*tc.next()); + }; + EXPECT_EQ((std::vector<UnwrappedTileID>{ + { 1, 0, 0 }, { 1, 1, 0 }, { 1, 0, 1 }, { 1, 1, 1 }, + }), t); +} + static const LatLngBounds sanFrancisco = LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 }); TEST(TileCover, SanFranciscoZ0) { EXPECT_EQ((std::vector<UnwrappedTileID>{ - { 0, 0, 0 }, - }), + { 0, 0, 0 }, + }), util::tileCover(sanFrancisco, 0)); } TEST(TileCover, SanFranciscoZ10) { EXPECT_EQ((std::vector<UnwrappedTileID>{ - { 10, 163, 395 }, { 10, 163, 396 }, { 10, 164, 395 }, { 10, 164, 396 }, - - }), + { 10, 163, 395 }, { 10, 163, 396 }, { 10, 164, 395 }, { 10, 164, 396 }, + }), util::tileCover(sanFrancisco, 10)); } @@ -85,11 +110,192 @@ TEST(TileCover, SanFranciscoZ0Wrapped) { util::tileCover(sanFranciscoWrapped, 0)); } +TEST(TileCover, GeomPoint) { + auto point = Point<double>{ -122.5744, 37.6609 }; + + EXPECT_EQ((std::vector<UnwrappedTileID>{ {2 ,0 ,1 } }), + util::tileCover(point, 2)); +} + +TEST(TileCover, GeomMultiPoint) { + auto points = MultiPoint<double>{ { -122.5, 37.76 }, { -122.4, 37.76} }; + + EXPECT_EQ((std::vector<UnwrappedTileID>{ + {20, 167480, 405351}, {20, 167772, 405351} }), + util::tileCover(points, 20)); +} + +TEST(TileCover, GeomLineZ10) { + auto lineCover = util::tileCover(LineString<double>{ + {-121.49368286132812,38.57903714667459}, + {-122.4422836303711,37.773157169570695} + }, 10); + EXPECT_EQ((std::vector<UnwrappedTileID>{ + { 10, 166, 392}, {10, 165, 393}, {10, 166, 393}, + {10, 164, 394}, {10, 165, 394}, {10,163,395}, {10, 164, 395} + }),lineCover); + +} + +TEST(TileCover, WrappedGeomLineZ10) { + auto lineCover = util::tileCover(LineString<double>{ + {-179.93342914581299,38.892101707724315}, + {-180.02394485473633,38.89203490311832} + }, 10); + EXPECT_EQ((std::vector<UnwrappedTileID>{ { 10, -1, 391 }, { 10, 0, 391 } }), + lineCover); + + lineCover = util::tileCover(LineString<double>{ + {179.93342914581299,38.892101707724315}, + {180.02394485473633,38.89203490311832} + }, 10); + EXPECT_EQ((std::vector<UnwrappedTileID>{ { 10, 1023, 391 }, { 10, 1024, 391 } }), + lineCover); +} + +TEST(TileCover, GeomMultiLineString) { + auto geom = MultiLineString<double>{ + { { -122.5, 37.76 }, { -122.4, 37.76} }, + { { -122.5, 37.72 }, { -122.4, 37.72} } }; + + EXPECT_EQ((std::vector<UnwrappedTileID>{ + {14, 2616, 6333}, {14, 2617, 6333}, {14, 2618, 6333}, + {14, 2619, 6333}, {14, 2620, 6333}, {14, 2621, 6333}, + {14, 2616, 6335}, {14, 2617, 6335}, {14, 2618, 6335}, + {14, 2619, 6335}, {14, 2620, 6335}, {14, 2621, 6335}}), + util::tileCover(geom, 14)); +} + +TEST(TileCover, GeomPolygon) { + auto polygon = Polygon<double>{ + { + {5.09765625,53.067626642387374}, + {2.373046875,43.389081939117496}, + {-4.74609375,48.45835188280866}, + {-1.494140625,37.09023980307208}, + {22.587890625,36.24427318493909}, + {31.640625,46.13417004624326}, + {17.841796875,54.7246201949245}, + {5.09765625,53.067626642387374}, + },{ + {19.6875,49.66762782262194}, + {22.8515625,43.51668853502906}, + {13.623046875,45.089035564831036}, + {16.34765625,39.095962936305476}, + {5.185546875,41.244772343082076}, + {8.701171874999998,50.233151832472245}, + {19.6875,49.66762782262194} + } + }; + + auto results = util::tileCover(polygon, 8); + + EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 134, 87}), results.end()); + EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 139, 87}), results.end()); + // Should have a hole + EXPECT_EQ(std::find(results.begin(), results.end(), UnwrappedTileID{8, 136, 87}), results.end()); +} + +TEST(TileCover, GeomMultiPolygon) { + auto multiPolygon = MultiPolygon<double>{ + {{ + {5.09765625,53.067626642387374}, + {2.373046875,43.389081939117496}, + {-4.74609375,48.45835188280866}, + {-1.494140625,37.09023980307208}, + {22.587890625,36.24427318493909}, + {31.640625,46.13417004624326}, + {17.841796875,54.7246201949245}, + {5.09765625,53.067626642387374}, + }},{{ + {59.150390625,45.460130637921004}, + {65.126953125,41.11246878918088}, + {69.169921875,47.45780853075031}, + {63.896484375,50.064191736659104}, + {59.150390625,45.460130637921004} + }} + }; + auto results = util::tileCover(multiPolygon, 8); + + EXPECT_EQ(424u, results.size()); + EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 139, 87}), results.end()); + EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 136, 87}), results.end()); + EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 174, 94}), results.end()); +} + +TEST(TileCover, GeomSanFranciscoPoly) { + auto sanFranciscoGeom = Polygon<double>{ + { + {-122.5143814086914,37.779127216982424}, + {-122.50811576843262,37.72721239056709}, + {-122.50313758850099,37.70820178063929}, + {-122.3938751220703,37.707454835665274}, + {-122.37567901611328,37.70663997801684}, + {-122.36297607421874,37.71343018466285}, + {-122.354736328125,37.727280276860036}, + {-122.36469268798828,37.73868429065797}, + {-122.38014221191408,37.75442980295571}, + {-122.38391876220702,37.78753873820529}, + {-122.35919952392578,37.8065289741725}, + {-122.35679626464844,37.820632846207864}, + {-122.3712158203125,37.835276322922695}, + {-122.3818588256836,37.82958198283902}, + {-122.37190246582031,37.80788523279169}, + {-122.38735198974608,37.791337175930686}, + {-122.40966796874999,37.812767557570204}, + {-122.46425628662108,37.807071480609274}, + {-122.46803283691405,37.810326435534755}, + {-122.47901916503906,37.81168262440736}, + {-122.48966217041016,37.78916666399649}, + {-122.50579833984375,37.78781006166096}, + {-122.5143814086914,37.779127216982424} + } + }; + + EXPECT_EQ((std::vector<UnwrappedTileID>{ + { 12, 654, 1582 }, { 12, 655, 1582 }, + { 12, 654, 1583 }, { 12, 655, 1583 }, + { 12, 654, 1584 }, { 12, 655, 1584 } + }), util::tileCover(sanFranciscoGeom, 12)); +} + +TEST(TileCover, GeomInvalid) { + auto point = Point<double>{ -122.5744, 97.6609 }; + EXPECT_THROW(util::tileCover(point, 2), std::domain_error); + + auto badPoly = Polygon<double> { { {1.0, 35.0} } }; + EXPECT_EQ((std::vector<UnwrappedTileID>{ }), util::tileCover(badPoly, 16)); + + //Should handle open polygons. + badPoly = Polygon<double> { { {1.0, 34.2}, {1.0, 34.4}, {0.5, 34.3} } }; + EXPECT_EQ((std::vector<UnwrappedTileID>{ + { 10, 513, 407 }, { 10, 514, 407}, + { 10, 513, 408 }, { 10, 514, 408} + }), util::tileCover(badPoly, 10)); +} + + +TEST(TileCount, World) { + EXPECT_EQ(1u, util::tileCount(LatLngBounds::world(), 0)); + EXPECT_EQ(4u, util::tileCount(LatLngBounds::world(), 1)); +} + TEST(TileCount, SanFranciscoZ10) { - EXPECT_EQ(4u, util::tileCount(sanFrancisco, 10, util::tileSize)); + EXPECT_EQ(4u, util::tileCount(sanFrancisco, 10)); +} + +TEST(TileCount, SanFranciscoWrappedZ10) { + EXPECT_EQ(4u, util::tileCount(sanFranciscoWrapped, 10)); } TEST(TileCount, SanFranciscoZ22) { - EXPECT_EQ(7254450u, util::tileCount(sanFrancisco, 22, util::tileSize)); + EXPECT_EQ(7254450u, util::tileCount(sanFrancisco, 22)); } +TEST(TileCount, BoundsCrossingAntimeridian) { + auto crossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830}); + + EXPECT_EQ(1u, util::tileCount(crossingBounds, 0)); + EXPECT_EQ(4u, util::tileCount(crossingBounds, 3)); + EXPECT_EQ(8u, util::tileCount(crossingBounds, 4)); +} diff --git a/test/util/tile_range.test.cpp b/test/util/tile_range.test.cpp index c4c37c74d7..83ac5096a5 100644 --- a/test/util/tile_range.test.cpp +++ b/test/util/tile_range.test.cpp @@ -52,14 +52,14 @@ TEST(TileRange, ContainsWrappedBounds) { TEST(TileRange, ContainsBoundsCrossingAntimeridian) { { - auto cossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830}); - auto range = util::TileRange::fromLatLngBounds(cossingBounds, 1); + auto crossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830}); + auto range = util::TileRange::fromLatLngBounds(crossingBounds, 1); EXPECT_TRUE(range.contains(CanonicalTileID(1, 1, 1))); EXPECT_TRUE(range.contains(CanonicalTileID(1, 0, 0))); } { - auto cossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830}); - auto range = util::TileRange::fromLatLngBounds(cossingBounds, 6); + auto crossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830}); + auto range = util::TileRange::fromLatLngBounds(crossingBounds, 6); EXPECT_FALSE(range.contains(CanonicalTileID(6, 55, 34))); EXPECT_FALSE(range.contains(CanonicalTileID(6, 5, 28))); EXPECT_TRUE(range.contains(CanonicalTileID(6, 63, 28))); diff --git a/test/util/token.test.cpp b/test/util/token.test.cpp index a2885dc8dd..d0cf1e31cf 100644 --- a/test/util/token.test.cpp +++ b/test/util/token.test.cpp @@ -47,4 +47,7 @@ TEST(Token, replaceTokens) { if (token == "HØYDE") return "150"; return ""; })); + EXPECT_EQ("{unknown}", mbgl::util::replaceTokens("{unknown}", [](const std::string&) -> optional<std::string> { + return {}; + })); } |