Track expression dependencies (#2113)
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <mbgl/style/conversion/constant.hpp>
|
||||
#include <mbgl/style/conversion/property_value.hpp>
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
#include <mbgl/util/logging.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
@@ -52,33 +53,37 @@ TEST(StyleConversion, Function) {
|
||||
ASSERT_EQ("function base must be a number", error.message);
|
||||
}
|
||||
|
||||
TEST(StyleConversion, CompositeFunctionExpression) {
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
void parseCheck(const std::string& json, std::string expectedError = {}) {
|
||||
using namespace std::string_literals;
|
||||
SCOPED_TRACE("Expression: "s + json);
|
||||
|
||||
Error error;
|
||||
const auto expr = convertJSON<PropertyValue<T>>(json, error, true, false);
|
||||
if (expectedError.empty()) {
|
||||
ASSERT_TRUE(expr);
|
||||
} else {
|
||||
ASSERT_FALSE(expr);
|
||||
ASSERT_EQ(expectedError, error.message);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
auto parseFunction = [&](const std::string& json) {
|
||||
return convertJSON<PropertyValue<float>>(json, error, true, false);
|
||||
};
|
||||
|
||||
auto fn1 = parseFunction(R"(["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10])");
|
||||
ASSERT_TRUE(fn1);
|
||||
|
||||
auto fn2 = parseFunction(
|
||||
R"(["coalesce", ["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10], 0])");
|
||||
ASSERT_TRUE(fn2);
|
||||
|
||||
auto fn3 = parseFunction(
|
||||
TEST(StyleConversion, CompositeFunctionExpression) {
|
||||
parseCheck<float>(R"(["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10])");
|
||||
parseCheck<float>(R"(["coalesce", ["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10], 0])");
|
||||
parseCheck<float>(
|
||||
R"(["let", "a", 0, ["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10] ])");
|
||||
ASSERT_TRUE(fn3);
|
||||
|
||||
auto fn4 = parseFunction(
|
||||
parseCheck<float>(
|
||||
R"(["coalesce", ["let", "a", 0, ["interpolate", ["linear"], ["zoom"], 0, ["number", ["get", "x"]], 10, 10]], 0])");
|
||||
ASSERT_TRUE(fn4);
|
||||
|
||||
auto fn5 = parseFunction(
|
||||
R"(["coalesce", ["interpolate", ["linear"], ["number", ["get", "x"]], 0, ["zoom"], 10, 10], 0])");
|
||||
ASSERT_FALSE(fn5);
|
||||
ASSERT_EQ(R"("zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.)",
|
||||
error.message);
|
||||
parseCheck<float>(
|
||||
R"(["coalesce", ["interpolate", ["linear"], ["number", ["get", "x"]], 0, ["zoom"], 10, 10], 0])",
|
||||
R"("zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.)");
|
||||
parseCheck<float>(R"(["number", ["get", "x", ["literal", {"x": 0}]]])");
|
||||
parseCheck<bool>(R"(["has", "x", ["literal", {"x": 0}]])");
|
||||
parseCheck<bool>(R"(["has", "x", ["properties"]])");
|
||||
}
|
||||
|
||||
TEST(StyleConversion, TokenStrings) {
|
||||
|
||||
79
test/style/expression/dependency.test.cpp
Normal file
79
test/style/expression/dependency.test.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
#include <mbgl/style/expression/format_section_override.hpp>
|
||||
#include <mbgl/style/layers/custom_layer_impl.hpp>
|
||||
#include <mbgl/test/util.hpp>
|
||||
|
||||
using namespace mbgl;
|
||||
using namespace mbgl::style;
|
||||
using namespace mbgl::style::expression;
|
||||
using namespace mbgl::style::expression::dsl;
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
namespace std {
|
||||
using ::mbgl::operator<<;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
auto createOverride(expression::type::Type exprType,
|
||||
PossiblyEvaluatedPropertyValue<T> propValue,
|
||||
std::string propName) {
|
||||
return std::make_unique<FormatSectionOverride<T>>(std::move(exprType), std::move(propValue), std::move(propName));
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Get) {
|
||||
EXPECT_EQ(Dependency::Feature, number(get("property"))->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Id) {
|
||||
EXPECT_EQ(Dependency::Feature, id()->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Zoom) {
|
||||
EXPECT_EQ(Dependency::Zoom, zoom()->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Convert) {
|
||||
EXPECT_EQ(Dependency::Feature, toColor(string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, toString(number(string(get("color"))))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, boolean(string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, toFormatted(toColor(string(get("color"))))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature | Dependency::Image, toImage(string(get("color")))->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Compare) {
|
||||
EXPECT_EQ(Dependency::Feature, eq(string(get("color")), string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, lt(string(get("color")), string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, gt(string(get("color")), string(get("color")))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, eq(string(get("color")), string(get("color")))->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Interpolate) {
|
||||
EXPECT_EQ(Dependency::Feature, step(number(id()), literal(0.0), 0.0, literal(0.0))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, step(literal(0.0), number(id()), 0.0, literal(0.0))->dependencies);
|
||||
EXPECT_EQ(Dependency::Feature, step(literal(0.0), literal(0.0), 0.0, number(id()))->dependencies);
|
||||
|
||||
interpolate(linear(), number(id()), 0.0, literal(0.0), 0.0, literal(0.0), 0.0, literal(0.0));
|
||||
interpolate(linear(), literal(0.0), 0.0, number(id()), 0.0, literal(0.0), 0.0, literal(0.0));
|
||||
interpolate(linear(), literal(0.0), 0.0, literal(0.0), 0.0, number(id()), 0.0, literal(0.0));
|
||||
interpolate(linear(), literal(0.0), 0.0, literal(0.0), 0.0, literal(0.0), 0.0, number(id()));
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Image) {
|
||||
EXPECT_EQ(Dependency::Image, image(literal("airport-11"))->dependencies);
|
||||
EXPECT_EQ(Dependency::Image | Dependency::Feature, image(get(literal("image_name"s)))->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, Distance) {
|
||||
const std::string pointGeoSource = R"({
|
||||
"type": "Point",
|
||||
"coordinates":[24.938492774963375,60.16980226227959]})";
|
||||
const auto exprStr = R"(["distance", )" + pointGeoSource + R"( ])";
|
||||
const auto expression = createExpression(exprStr.c_str());
|
||||
EXPECT_EQ(Dependency::Feature, expression->dependencies);
|
||||
}
|
||||
|
||||
TEST(ExpressionDependencies, CustomLayer) {
|
||||
auto impl = makeMutable<CustomLayer::Impl>("", nullptr);
|
||||
EXPECT_EQ(Dependency::None, CustomLayerProperties{std::move(impl)}.getDependencies());
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
#include <mbgl/style/rapidjson_conversion.hpp>
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
#include <mbgl/style/expression/is_expression.hpp>
|
||||
#include <mbgl/test/util.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/style/conversion_impl.hpp>
|
||||
#include <mbgl/util/rapidjson.hpp>
|
||||
#include <mbgl/style/rapidjson_conversion.hpp>
|
||||
#include <mbgl/style/expression/is_expression.hpp>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
|
||||
@@ -81,6 +82,10 @@ TEST_P(ExpressionEqualityTest, ExpressionEquality) {
|
||||
|
||||
EXPECT_TRUE(*expression_a1 == *expression_a2);
|
||||
EXPECT_TRUE(*expression_a1 != *expression_b);
|
||||
|
||||
// Exercise the type-not-equal branches
|
||||
using namespace expression;
|
||||
EXPECT_FALSE(*expression_b == *((expression_b->getKind() == Kind::Literal) ? dsl::id() : dsl::literal(0.0)));
|
||||
}
|
||||
|
||||
static void populateNames(std::vector<std::string>& names) {
|
||||
@@ -127,6 +132,7 @@ static void populateNames(std::vector<std::string>& names) {
|
||||
INSTANTIATE_TEST_SUITE_P(Expression, ExpressionEqualityTest, ::testing::ValuesIn([] {
|
||||
std::vector<std::string> names;
|
||||
populateNames(names);
|
||||
std::sort(names.begin(), names.end());
|
||||
EXPECT_GT(names.size(), 0u);
|
||||
return names;
|
||||
}()));
|
||||
|
||||
@@ -192,15 +192,44 @@ TEST(Filter, NotHas) {
|
||||
}
|
||||
|
||||
TEST(Filter, ID) {
|
||||
FeatureIdentifier id1{uint64_t{1234}};
|
||||
const FeatureIdentifier id1{uint64_t{1234}};
|
||||
ASSERT_TRUE(filter("[\"==\", \"$id\", 1234]", {{}}, id1));
|
||||
ASSERT_FALSE(filter("[\"==\", \"$id\", \"1234\"]", {{}}, id1));
|
||||
ASSERT_FALSE(filter("[\"==\", \"$id\", 1234]", {{"id", uint64_t(1234)}}));
|
||||
ASSERT_FALSE(filter("[\"==\", \"$id\", \"1234\"]", {{"id", uint64_t(1234)}}));
|
||||
|
||||
FeatureIdentifier id2{std::string{"1"}};
|
||||
ASSERT_FALSE(filter("[\"<\", \"$id\", 0]", {{}}, id1));
|
||||
ASSERT_FALSE(filter("[\"<\", \"$id\", 1234]", {{}}, id1));
|
||||
ASSERT_TRUE(filter("[\"<=\", \"$id\", 1234]", {{}}, id1));
|
||||
ASSERT_FALSE(filter("[\"<\", \"$id\", 123]", {{}}, id1));
|
||||
ASSERT_FALSE(filter("[\"<=\", \"$id\", 123]", {{}}, id1));
|
||||
ASSERT_TRUE(filter("[\">\", \"$id\", 0]", {{}}, id1));
|
||||
ASSERT_TRUE(filter("[\">\", \"$id\", 123]", {{}}, id1));
|
||||
ASSERT_TRUE(filter("[\">=\", \"$id\", 123]", {{}}, id1));
|
||||
ASSERT_FALSE(filter("[\">\", \"$id\", 1234]", {{}}, id1));
|
||||
ASSERT_TRUE(filter("[\">=\", \"$id\", 1234]", {{}}, id1));
|
||||
|
||||
ASSERT_FALSE(filter("[\">\", \"$id\", \"1\"]", {{}}, id1));
|
||||
ASSERT_FALSE(filter("[\"<\", \"$id\", \"1\"]", {{}}, id1));
|
||||
ASSERT_FALSE(filter("[\">=\", \"$id\", \"1\"]", {{}}, id1));
|
||||
ASSERT_FALSE(filter("[\"<=\", \"$id\", \"1\"]", {{}}, id1));
|
||||
|
||||
const FeatureIdentifier id2{std::string{"1"}};
|
||||
ASSERT_FALSE(filter("[\"<\", \"$id\", \"0\"]", {{}}, id2));
|
||||
ASSERT_TRUE(filter("[\"<\", \"$id\", \"1234\"]", {{}}, id2));
|
||||
ASSERT_TRUE(filter("[\"<=\", \"$id\", \"1234\"]", {{}}, id2));
|
||||
ASSERT_FALSE(filter("[\"<\", \"$id\", \"012\"]", {{}}, id2));
|
||||
ASSERT_FALSE(filter("[\"<=\", \"$id\", \"012\"]", {{}}, id2));
|
||||
ASSERT_TRUE(filter("[\">\", \"$id\", \"0\"]", {{}}, id2));
|
||||
ASSERT_FALSE(filter("[\">\", \"$id\", \"234\"]", {{}}, id2));
|
||||
ASSERT_TRUE(filter("[\">=\", \"$id\", \"012\"]", {{}}, id2));
|
||||
ASSERT_FALSE(filter("[\">\", \"$id\", \"1234\"]", {{}}, id2));
|
||||
ASSERT_FALSE(filter("[\">=\", \"$id\", \"1234\"]", {{}}, id2));
|
||||
|
||||
ASSERT_FALSE(filter("[\"==\", \"$id\", 1234]", {{"id", uint64_t(1234)}}));
|
||||
ASSERT_FALSE(filter("[\">\", \"$id\", 1]", {{}}, id2));
|
||||
ASSERT_FALSE(filter("[\"<\", \"$id\", 1]", {{}}, id2));
|
||||
ASSERT_FALSE(filter("[\">=\", \"$id\", 1]", {{}}, id2));
|
||||
ASSERT_FALSE(filter("[\"<=\", \"$id\", 1]", {{}}, id2));
|
||||
}
|
||||
|
||||
TEST(Filter, Expression) {
|
||||
@@ -214,15 +243,80 @@ TEST(Filter, PropertyExpression) {
|
||||
}
|
||||
|
||||
TEST(Filter, LegacyProperty) {
|
||||
// <
|
||||
|
||||
ASSERT_TRUE(filter("[\"<\", \"two\", 2]", {{"two", int64_t(1)}}));
|
||||
ASSERT_FALSE(filter("[\"<\", \"two\", \"2\"]", {{"two", int64_t(1)}}));
|
||||
ASSERT_FALSE(filter("[\"<\", \"two\", 2]", {{"two", std::string("1")}}));
|
||||
ASSERT_TRUE(filter("[\"<\", \"two\", \"2\"]", {{"two", std::string("1")}}));
|
||||
|
||||
ASSERT_FALSE(filter("[\"<\", \"two\", 2]", {{"two", int64_t(2)}}));
|
||||
ASSERT_FALSE(filter("[\"<\", \"two\", \"2\"]", {{"two", int64_t(2)}}));
|
||||
ASSERT_FALSE(filter("[\"<\", \"two\", 2]", {{"two", std::string("2")}}));
|
||||
ASSERT_FALSE(filter("[\"<\", \"two\", \"2\"]", {{"two", std::string("2")}}));
|
||||
|
||||
// <=
|
||||
|
||||
ASSERT_TRUE(filter("[\"<=\", \"two\", 2]", {{"two", int64_t(1)}}));
|
||||
ASSERT_FALSE(filter("[\"<=\", \"two\", \"2\"]", {{"two", int64_t(1)}}));
|
||||
ASSERT_FALSE(filter("[\"<=\", \"two\", 2]", {{"two", std::string("1")}}));
|
||||
ASSERT_TRUE(filter("[\"<=\", \"two\", \"2\"]", {{"two", std::string("1")}}));
|
||||
|
||||
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_FALSE(filter("[\"<=\", \"two\", 2]", {{"two", std::string("2")}}));
|
||||
ASSERT_TRUE(filter("[\"<=\", \"two\", \"2\"]", {{"two", std::string("2")}}));
|
||||
ASSERT_FALSE(filter("[\"<\", \"two\", \"1\"]", {{"two", std::string("2")}}));
|
||||
|
||||
ASSERT_FALSE(filter("[\"<=\", \"two\", 2]", {{"two", int64_t(3)}}));
|
||||
ASSERT_FALSE(filter("[\"<=\", \"two\", \"2\"]", {{"two", int64_t(3)}}));
|
||||
ASSERT_FALSE(filter("[\"<=\", \"two\", 2]", {{"two", std::string("3")}}));
|
||||
ASSERT_FALSE(filter("[\"<=\", \"two\", \"2\"]", {{"two", std::string("3")}}));
|
||||
|
||||
// >
|
||||
|
||||
ASSERT_FALSE(filter("[\">\", \"two\", 2]", {{"two", int64_t(2)}}));
|
||||
ASSERT_FALSE(filter("[\">\", \"two\", \"2\"]", {{"two", int64_t(2)}}));
|
||||
ASSERT_FALSE(filter("[\">\", \"two\", 2]", {{"two", std::string("2")}}));
|
||||
ASSERT_FALSE(filter("[\">\", \"two\", \"2\"]", {{"two", std::string("2")}}));
|
||||
|
||||
ASSERT_TRUE(filter("[\">\", \"two\", 2]", {{"two", int64_t(3)}}));
|
||||
ASSERT_FALSE(filter("[\">\", \"two\", \"2\"]", {{"two", int64_t(3)}}));
|
||||
ASSERT_FALSE(filter("[\">\", \"two\", 2]", {{"two", std::string("3")}}));
|
||||
ASSERT_TRUE(filter("[\">\", \"two\", \"2\"]", {{"two", std::string("3")}}));
|
||||
|
||||
// >=
|
||||
|
||||
ASSERT_FALSE(filter("[\">=\", \"two\", 2]", {{"two", int64_t(1)}}));
|
||||
ASSERT_FALSE(filter("[\">=\", \"two\", \"2\"]", {{"two", int64_t(1)}}));
|
||||
ASSERT_FALSE(filter("[\">=\", \"two\", 2]", {{"two", std::string("1")}}));
|
||||
ASSERT_FALSE(filter("[\">=\", \"two\", \"2\"]", {{"two", std::string("1")}}));
|
||||
|
||||
ASSERT_TRUE(filter("[\">=\", \"two\", 2]", {{"two", int64_t(2)}}));
|
||||
ASSERT_FALSE(filter("[\">=\", \"two\", \"2\"]", {{"two", int64_t(2)}}));
|
||||
ASSERT_FALSE(filter("[\">=\", \"two\", 2]", {{"two", std::string("2")}}));
|
||||
ASSERT_TRUE(filter("[\">=\", \"two\", \"2\"]", {{"two", std::string("2")}}));
|
||||
|
||||
ASSERT_TRUE(filter("[\">=\", \"two\", 2]", {{"two", int64_t(3)}}));
|
||||
ASSERT_FALSE(filter("[\">=\", \"two\", \"2\"]", {{"two", int64_t(3)}}));
|
||||
ASSERT_FALSE(filter("[\">=\", \"two\", 2]", {{"two", std::string("3")}}));
|
||||
ASSERT_TRUE(filter("[\">=\", \"two\", \"2\"]", {{"two", std::string("3")}}));
|
||||
|
||||
//
|
||||
|
||||
ASSERT_TRUE(filter("[\"==\", \"two\", 4]", {{"two", int64_t(4)}}));
|
||||
ASSERT_FALSE(filter("[\"==\", \"two\", 4]", {{"two", std::string("4")}}));
|
||||
ASSERT_FALSE(filter("[\"==\", \"two\", \"4\"]", {{"two", int64_t(4)}}));
|
||||
ASSERT_TRUE(filter("[\"==\", \"two\", \"4\"]", {{"two", std::string("4")}}));
|
||||
|
||||
ASSERT_FALSE(filter("[\"==\", \"two\", 4]", {{"two", int64_t(2)}}));
|
||||
ASSERT_FALSE(filter("[\"==\", \"two\", 4]", {{"two", std::string("2")}}));
|
||||
ASSERT_FALSE(filter("[\"==\", \"two\", \"4\"]", {{"two", int64_t(2)}}));
|
||||
ASSERT_FALSE(filter("[\"==\", \"two\", \"4\"]", {{"two", std::string("2")}}));
|
||||
|
||||
ASSERT_FALSE(filter("[\"==\", \"one\", true]", {{"two", true}}));
|
||||
ASSERT_FALSE(filter("[\"==\", \"one\", false]", {{"two", true}}));
|
||||
ASSERT_TRUE(filter("[\"==\", \"two\", true]", {{"two", true}}));
|
||||
ASSERT_FALSE(filter("[\"==\", \"two\", false]", {{"two", true}}));
|
||||
}
|
||||
|
||||
TEST(Filter, Serialize) {
|
||||
@@ -254,6 +348,28 @@ TEST(Filter, ZoomExpressionNested) {
|
||||
R"(["==", ["get", "two"], ["+", ["zoom"], 1]])", {{"two", int64_t(2)}}, {}, FeatureType::Point, {}, 2.0f));
|
||||
}
|
||||
|
||||
TEST(Filter, GeomType) {
|
||||
ASSERT_TRUE(filter(R"(["==", ["geometry-type"], "Point"])", {{}}, {}, FeatureType::Point, {}, 2.0f));
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "LineString"])", {{}}, {}, FeatureType::Point, {}, 2.0f));
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "Polygon"])", {{}}, {}, FeatureType::Point, {}, 2.0f));
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "Unknown"])", {{}}, {}, FeatureType::Point, {}, 2.0f));
|
||||
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "Point"])", {{}}, {}, FeatureType::LineString, {}, 2.0f));
|
||||
ASSERT_TRUE(filter(R"(["==", ["geometry-type"], "LineString"])", {{}}, {}, FeatureType::LineString, {}, 2.0f));
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "Polygon"])", {{}}, {}, FeatureType::LineString, {}, 2.0f));
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "Unknown"])", {{}}, {}, FeatureType::LineString, {}, 2.0f));
|
||||
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "Point"])", {{}}, {}, FeatureType::Polygon, {}, 2.0f));
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "LineString"])", {{}}, {}, FeatureType::Polygon, {}, 2.0f));
|
||||
ASSERT_TRUE(filter(R"(["==", ["geometry-type"], "Polygon"])", {{}}, {}, FeatureType::Polygon, {}, 2.0f));
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "Unknown"])", {{}}, {}, FeatureType::Polygon, {}, 2.0f));
|
||||
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "Point"])", {{}}, {}, FeatureType::Unknown, {}, 2.0f));
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "LineString"])", {{}}, {}, FeatureType::Unknown, {}, 2.0f));
|
||||
ASSERT_FALSE(filter(R"(["==", ["geometry-type"], "Polygon"])", {{}}, {}, FeatureType::Unknown, {}, 2.0f));
|
||||
ASSERT_TRUE(filter(R"(["==", ["geometry-type"], "Unknown"])", {{}}, {}, FeatureType::Unknown, {}, 2.0f));
|
||||
}
|
||||
|
||||
TEST(Filter, Internal) {
|
||||
filter(R"(["filter-==","class","snow"])");
|
||||
}
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
#include <mbgl/test/util.hpp>
|
||||
#include <mbgl/test/stub_geometry_tile_feature.hpp>
|
||||
|
||||
#include <mbgl/style/property_expression.hpp>
|
||||
#include <mbgl/renderer/property_evaluator.hpp>
|
||||
#include <mbgl/renderer/property_evaluation_parameters.hpp>
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
#include <mbgl/style/expression/find_zoom_curve.hpp>
|
||||
#include <mbgl/style/expression/format_section_override.hpp>
|
||||
|
||||
#include <mbgl/style/property_expression.hpp>
|
||||
#include <mbgl/test/stub_geometry_tile_feature.hpp>
|
||||
#include <mbgl/test/util.hpp>
|
||||
#include <mbgl/util/geojson.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
|
||||
@@ -19,6 +18,10 @@ using namespace mbgl::style::expression::dsl;
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
namespace std {
|
||||
using ::mbgl::operator<<;
|
||||
}
|
||||
|
||||
static const StubGeometryTileFeature oneInteger{PropertyMap{{"property", uint64_t(1)}}};
|
||||
|
||||
static const StubGeometryTileFeature oneDouble{PropertyMap{{"property", 1.0}}};
|
||||
@@ -52,19 +55,26 @@ TEST(PropertyExpression, Constant) {
|
||||
EXPECT_EQ(2.0f, evaluate(PropertyValue<float>(2.0f), 22));
|
||||
EXPECT_EQ(3.8f, evaluate(PropertyValue<float>(3.8f), 22));
|
||||
EXPECT_EQ(22.0f, evaluate(PropertyValue<float>(22.0f), 22));
|
||||
|
||||
EXPECT_EQ(Dependency::None, PropertyValue<float>(2.0f).getDependencies());
|
||||
}
|
||||
|
||||
TEST(PropertyExpression, Expression) {
|
||||
PropertyExpression<float> expression(interpolate(linear(), zoom(), 0.0, literal(0.0), 1.0, literal(1.0)));
|
||||
EXPECT_EQ(0.0, evaluate(expression, 0.0));
|
||||
EXPECT_EQ(0.5, evaluate(expression, 0.5));
|
||||
EXPECT_EQ(Dependency::Zoom, expression.getDependencies());
|
||||
}
|
||||
|
||||
TEST(PropertyExpression, Defaults) {
|
||||
EXPECT_EQ(1.0f, PropertyExpression<float>(number(get("property")), 0.0f).evaluate(oneInteger, 2.0f));
|
||||
EXPECT_EQ(1.0f, PropertyExpression<float>(number(get("property")), 0.0f).evaluate(oneDouble, 2.0f));
|
||||
EXPECT_EQ(0.0f, PropertyExpression<float>(number(get("property")), 0.0f).evaluate(oneString, 2.0f));
|
||||
EXPECT_EQ(2.0f, PropertyExpression<float>(number(get("property"))).evaluate(oneString, 2.0f));
|
||||
const PropertyExpression<float> noDefault(number(get("property")));
|
||||
const PropertyExpression<float> withDefault(number(get("property")), 0.0f);
|
||||
EXPECT_EQ(1.0f, withDefault.evaluate(oneInteger, 2.0f));
|
||||
EXPECT_EQ(1.0f, withDefault.evaluate(oneDouble, 2.0f));
|
||||
EXPECT_EQ(0.0f, withDefault.evaluate(oneString, 2.0f));
|
||||
EXPECT_EQ(2.0f, noDefault.evaluate(oneString, 2.0f));
|
||||
|
||||
EXPECT_EQ(Dependency::Feature, noDefault.getDependencies());
|
||||
}
|
||||
|
||||
TEST(PropertyExpression, ZoomInterpolation) {
|
||||
@@ -166,6 +176,8 @@ TEST(PropertyExpression, FormatSectionOverride) {
|
||||
PossiblyEvaluatedPropertyValue<Color> constantValueGreen(Color::green());
|
||||
PossiblyEvaluatedPropertyValue<Color> ddsValueRed(toColor(string(get("color"))));
|
||||
|
||||
EXPECT_EQ(Dependency::Feature, ddsValueRed.getDependencies());
|
||||
|
||||
// Evaluation test
|
||||
{
|
||||
auto override1 = createOverride(expression::type::Color, constantValueGreen, "text-color");
|
||||
@@ -174,6 +186,9 @@ TEST(PropertyExpression, FormatSectionOverride) {
|
||||
EXPECT_EQ(Color::green(), propExpr.evaluate(oneDouble, Color()));
|
||||
EXPECT_EQ(Color::blue(), propExpr.evaluate(ctx));
|
||||
|
||||
/// Override implies a feature dependency (See `::isFeatureConstant`)
|
||||
EXPECT_EQ(Dependency::Override | Dependency::Feature, propExpr.getDependencies());
|
||||
|
||||
auto override2 = createOverride(expression::type::Color, ddsValueRed, "text-color");
|
||||
PropertyExpression<Color> propExprDDS(std::move(override2));
|
||||
EXPECT_EQ(Color::red(), propExprDDS.evaluate(oneColor, Color()));
|
||||
@@ -203,6 +218,8 @@ TEST(PropertyExpression, ImageExpression) {
|
||||
EXPECT_FALSE(evaluatedImage.isAvailable());
|
||||
EXPECT_EQ(evaluatedImage.id(), "airport-11"s);
|
||||
|
||||
EXPECT_EQ(Dependency::Image, propExpr.getDependencies());
|
||||
|
||||
PropertyExpression<expression::Image> ddPropExpr(image(get(literal("image_name"s))));
|
||||
evaluatedImage = ddPropExpr.evaluate(oneImage, emptySet, expression::Image());
|
||||
EXPECT_FALSE(evaluatedImage.isAvailable());
|
||||
@@ -220,11 +237,15 @@ TEST(PropertyExpression, ImageExpression) {
|
||||
EXPECT_TRUE(evaluatedImage.isAvailable());
|
||||
EXPECT_EQ(evaluatedImage.id(), "airport-11"s);
|
||||
|
||||
EXPECT_EQ(Dependency::Image, propExpr.getDependencies());
|
||||
|
||||
PropertyExpression<expression::Image> ddPropExpr(image(get(literal("image_name"s))));
|
||||
evaluatedImage = ddPropExpr.evaluate(oneImage, availableImages, expression::Image());
|
||||
EXPECT_TRUE(evaluatedImage.isAvailable());
|
||||
EXPECT_EQ(evaluatedImage.id(), "maki-11"s);
|
||||
|
||||
EXPECT_EQ(Dependency::Image | Dependency::Feature, ddPropExpr.getDependencies());
|
||||
|
||||
evaluatedImage = ddPropExpr.evaluate(emptyTileFeature, availableImages, expression::Image());
|
||||
EXPECT_FALSE(evaluatedImage.isAvailable());
|
||||
EXPECT_EQ(evaluatedImage.id(), ""s);
|
||||
@@ -240,6 +261,8 @@ TEST(PropertyExpression, ImageExpression) {
|
||||
evaluatedImage = propExpr.evaluate(18.0, emptyTileFeature, availableImages, expression::Image());
|
||||
EXPECT_TRUE(evaluatedImage.isAvailable());
|
||||
EXPECT_EQ(evaluatedImage.id(), "bicycle-15"s);
|
||||
|
||||
EXPECT_EQ(Dependency::Image | Dependency::Zoom, propExpr.getDependencies());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,6 +310,8 @@ TEST(PropertyExpression, WithinExpression) {
|
||||
ASSERT_TRUE(expression);
|
||||
PropertyExpression<bool> propExpr(std::move(expression));
|
||||
|
||||
EXPECT_EQ(Dependency::Feature, propExpr.getDependencies());
|
||||
|
||||
// evaluation test with valid geojson source but FeatureType is not Point/LineString
|
||||
// (currently only support FeatureType::Point and FeatureType::LineString)
|
||||
{
|
||||
@@ -536,6 +561,8 @@ TEST(PropertyExpression, DistanceExpression) {
|
||||
ASSERT_TRUE(expression);
|
||||
PropertyExpression<double> propExpr(std::move(expression));
|
||||
|
||||
EXPECT_EQ(Dependency::Feature, propExpr.getDependencies());
|
||||
|
||||
auto evaluatedResult = propExpr.evaluate(EvaluationContext(&pointFeature).withCanonicalTileID(&canonicalTileID),
|
||||
invalidResult);
|
||||
EXPECT_NEAR(491.307, evaluatedResult, 0.01);
|
||||
|
||||
@@ -82,14 +82,12 @@ TEST(Style, DuplicateSource) {
|
||||
TEST(Style, RemoveSourceInUse) {
|
||||
util::RunLoop loop;
|
||||
|
||||
auto log = new FixtureLogObserver();
|
||||
Log::setObserver(std::unique_ptr<Log::Observer>(log));
|
||||
FixtureLog log;
|
||||
|
||||
auto fileSource = std::make_shared<StubFileSource>();
|
||||
Style::Impl style{fileSource, 1.0};
|
||||
|
||||
style.loadJSON(util::read_file("test/fixtures/resources/style-unused-sources.json"));
|
||||
|
||||
style.addSource(std::make_unique<VectorSource>("sourceId", "mptiler://tiles/contours"));
|
||||
style.addLayer(std::make_unique<LineLayer>("layerId", "sourceId"));
|
||||
|
||||
@@ -109,7 +107,7 @@ TEST(Style, RemoveSourceInUse) {
|
||||
Sleep(1000);
|
||||
#endif
|
||||
|
||||
EXPECT_EQ(log->count(logMessage), 1u);
|
||||
EXPECT_EQ(log.count(logMessage), 1u);
|
||||
}
|
||||
|
||||
TEST(Style, SourceImplsOrder) {
|
||||
|
||||
@@ -353,7 +353,7 @@ void testHasOverrides(LayoutType& layout) {
|
||||
|
||||
// Expression, overridden text-color.
|
||||
FormatExpressionSection section(literal(""));
|
||||
section.setTextSectionOptions(std::nullopt, std::nullopt, toColor(literal("red")));
|
||||
section.setTextSectionOptions({}, {}, toColor(literal("red")));
|
||||
auto formatExprOverride = std::make_unique<FormatExpression>(std::vector<FormatExpressionSection>{section});
|
||||
PropertyExpression<Formatted> propExprOverride(std::move(formatExprOverride));
|
||||
layout.template get<TextField>() = PropertyValueType<Formatted>(std::move(propExprOverride));
|
||||
@@ -362,7 +362,7 @@ void testHasOverrides(LayoutType& layout) {
|
||||
// Nested expressions, overridden text-color.
|
||||
auto formattedExpr1 = format("first paragraph");
|
||||
FormatExpressionSection secondParagraph(literal("second paragraph"));
|
||||
secondParagraph.setTextSectionOptions(std::nullopt, std::nullopt, toColor(literal("blue")));
|
||||
secondParagraph.setTextSectionOptions({}, {}, toColor(literal("blue")));
|
||||
std::vector<FormatExpressionSection> sections{{std::move(secondParagraph)}};
|
||||
auto formattedExpr2 = std::make_unique<FormatExpression>(std::move(sections));
|
||||
std::unordered_map<std::string, std::shared_ptr<Expression>> branches{{"1st", std::move(formattedExpr1)},
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <mbgl/test/util.hpp>
|
||||
#include <mbgl/test/fixture_log_observer.hpp>
|
||||
|
||||
#include <mbgl/style/expression/dsl.hpp>
|
||||
#include <mbgl/style/parser.hpp>
|
||||
#include <mbgl/util/io.hpp>
|
||||
#include <mbgl/util/enum.hpp>
|
||||
@@ -32,18 +33,18 @@ class StyleParserTest : public ::testing::TestWithParam<std::string> {};
|
||||
TEST_P(StyleParserTest, ParseStyle) {
|
||||
const std::string base = std::string("test/fixtures/style_parser/") + GetParam();
|
||||
|
||||
using namespace std::string_literals;
|
||||
SCOPED_TRACE("Loading: "s + base);
|
||||
|
||||
FixtureLog log;
|
||||
|
||||
rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> infoDoc;
|
||||
infoDoc.Parse<0>(util::read_file(base + ".info.json").c_str());
|
||||
ASSERT_FALSE(infoDoc.HasParseError());
|
||||
ASSERT_TRUE(infoDoc.IsObject());
|
||||
|
||||
auto observer = new FixtureLogObserver();
|
||||
Log::setObserver(std::unique_ptr<Log::Observer>(observer));
|
||||
|
||||
style::Parser parser;
|
||||
auto error = parser.parse(util::read_file(base + ".style.json"));
|
||||
|
||||
if (error) {
|
||||
if (auto error = parser.parse(util::read_file(base + ".style.json"))) {
|
||||
Log::Error(Event::ParseStyle, "Failed to parse style: " + util::toString(error));
|
||||
}
|
||||
|
||||
@@ -71,11 +72,14 @@ TEST_P(StyleParserTest, ParseStyle) {
|
||||
Sleep(10);
|
||||
#endif
|
||||
|
||||
EXPECT_EQ(count, observer->count(message)) << "Message: " << message << std::endl;
|
||||
SCOPED_TRACE("Checking: "s + message.msg);
|
||||
|
||||
const auto observedCount = log.count(message);
|
||||
EXPECT_EQ(count, observedCount) << "Message: " << message << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
const auto& unchecked = observer->unchecked();
|
||||
const auto& unchecked = log.unchecked();
|
||||
if (unchecked.size()) {
|
||||
std::cerr << "Unchecked Log Messages (" << base << "/" << name << "): " << std::endl << unchecked;
|
||||
}
|
||||
@@ -292,3 +296,21 @@ TEST(StyleParser, FontStacksGetExpression) {
|
||||
auto result = parser.fontStacks();
|
||||
ASSERT_EQ(0u, result.size());
|
||||
}
|
||||
|
||||
TEST(StyleParser, ZoomCurve) {
|
||||
using namespace mbgl::style;
|
||||
using namespace mbgl::style::expression;
|
||||
using namespace mbgl::style::expression::dsl;
|
||||
|
||||
const auto zoomInterp = []() {
|
||||
return interpolate(linear(), zoom(), 0.0, literal(0.0), 0.0, literal(0.0));
|
||||
};
|
||||
|
||||
auto expr1 = interpolate(linear(), literal(0.0), 0.0, zoomInterp(), 0.0, zoomInterp());
|
||||
ASSERT_TRUE(expr1);
|
||||
ASSERT_TRUE(findZoomCurveChecked(*expr1).is<std::nullptr_t>());
|
||||
|
||||
auto expr2 = interpolate(linear(), zoom(), 0.0, literal(0.0), 0.0, zoomInterp());
|
||||
ASSERT_TRUE(expr2);
|
||||
ASSERT_TRUE(findZoomCurveChecked(*expr2).is<std::nullptr_t>());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user