Track expression dependencies (#2113)

This commit is contained in:
Tim Sylvester
2024-03-07 10:36:50 -08:00
committed by GitHub
parent 9614b566d8
commit 25678a4d99
105 changed files with 1082 additions and 339 deletions

View File

@@ -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) {

View 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());
}

View File

@@ -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;
}()));

View File

@@ -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"])");
}

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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)},

View File

@@ -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>());
}