diff options
author | Ivo van Dongen <ivovandongen@users.noreply.github.com> | 2016-08-23 14:57:55 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-08-23 14:57:55 +0200 |
commit | df3b44531e1c2a95edd2a035d3744f34ebb8d0e9 (patch) | |
tree | 2eb0ae3e4a3b793767643831cd8063aeab56075d | |
parent | 50da6e5e715f0356f430fba176dea13d15fe9d52 (diff) | |
download | qtlocation-mapboxgl-df3b44531e1c2a95edd2a035d3744f34ebb8d0e9.tar.gz |
[core] #6071 - extract GeoJSONOptions conversion from GeoJSONSource conversion
* [core] geojson_options - retain original error message
* [core] tests - initial style conversion stub methods
* [core] geojsonoptions conversion - initial unit tests
* [core] tests - fix forward reference issue
* [core] geojsonoptions conversion - unit tests
* [core] geojsonoptions conversion - renamed Holder to Value
-rw-r--r-- | cmake/core-files.cmake | 1 | ||||
-rw-r--r-- | cmake/test-files.cmake | 4 | ||||
-rw-r--r-- | include/mbgl/style/conversion/geojson_options.hpp | 78 | ||||
-rw-r--r-- | include/mbgl/style/conversion/source.hpp | 60 | ||||
-rw-r--r-- | test/src/mbgl/test/conversion_stubs.hpp | 111 | ||||
-rw-r--r-- | test/style/conversion/geojson_options.cpp | 68 |
6 files changed, 267 insertions, 55 deletions
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index d817909e33..e2795072bb 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -256,6 +256,7 @@ set(MBGL_CORE_FILES include/mbgl/style/conversion/filter.hpp include/mbgl/style/conversion/function.hpp include/mbgl/style/conversion/geojson.hpp + include/mbgl/style/conversion/geojson_options.hpp include/mbgl/style/conversion/layer.hpp include/mbgl/style/conversion/make_property_setters.hpp include/mbgl/style/conversion/property_setter.hpp diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake index d6c6215291..4736af6c56 100644 --- a/cmake/test-files.cmake +++ b/cmake/test-files.cmake @@ -42,6 +42,7 @@ set(MBGL_TEST_FILES test/src/main.cpp # src/mbgl/test + test/src/mbgl/test/conversion_stubs.hpp test/src/mbgl/test/fixture_log_observer.cpp test/src/mbgl/test/fixture_log_observer.hpp test/src/mbgl/test/stub_file_source.cpp @@ -72,6 +73,9 @@ set(MBGL_TEST_FILES test/style/style_parser.cpp test/style/tile_source.cpp test/style/variant.cpp + + # style conversion + test/style/conversion/geojson_options.cpp # text test/text/quads.cpp diff --git a/include/mbgl/style/conversion/geojson_options.hpp b/include/mbgl/style/conversion/geojson_options.hpp new file mode 100644 index 0000000000..880090b402 --- /dev/null +++ b/include/mbgl/style/conversion/geojson_options.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/sources/geojson_source.hpp> + +namespace mbgl { +namespace style { +namespace conversion { + +template <> +struct Converter<GeoJSONOptions> { + + template <class V> + Result<GeoJSONOptions> operator()(const V& value) const { + GeoJSONOptions options; + + const auto maxzoomValue = objectMember(value, "maxzoom"); + if (maxzoomValue) { + if (toNumber(*maxzoomValue)) { + options.maxzoom = static_cast<uint8_t>(*toNumber(*maxzoomValue)); + } else { + return Error{ "GeoJSON source maxzoom value must be a number" }; + } + } + + const auto bufferValue = objectMember(value, "buffer"); + if (bufferValue) { + if (toNumber(*bufferValue)) { + options.buffer = static_cast<uint16_t>(*toNumber(*bufferValue)); + } else { + return Error{ "GeoJSON source buffer value must be a number" }; + } + } + + const auto toleranceValue = objectMember(value, "tolerance"); + if (toleranceValue) { + if (toNumber(*toleranceValue)) { + options.tolerance = static_cast<double>(*toNumber(*toleranceValue)); + } else { + return Error{ "GeoJSON source tolerance value must be a number" }; + } + } + + const auto clusterValue = objectMember(value, "cluster"); + if (clusterValue) { + if (toBool(*clusterValue)) { + options.cluster = *toBool(*clusterValue); + } else { + return Error{ "GeoJSON source cluster value must be a boolean" }; + } + } + + const auto clusterMaxZoomValue = objectMember(value, "clusterMaxZoom"); + if (clusterMaxZoomValue) { + if (toNumber(*clusterMaxZoomValue)) { + options.clusterMaxZoom = static_cast<uint8_t>(*toNumber(*clusterMaxZoomValue)); + } else { + return Error{ "GeoJSON source clusterMaxZoom value must be a number" }; + } + } + + const auto clusterRadiusValue = objectMember(value, "clusterRadius"); + if (clusterRadiusValue) { + if (toNumber(*clusterRadiusValue)) { + options.clusterRadius = static_cast<double>(*toNumber(*clusterRadiusValue)); + } else { + return Error{ "GeoJSON source clusterRadius value must be a number" }; + } + } + + return { options }; + } + +}; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp index c4b2fe303f..6e1b4347c3 100644 --- a/include/mbgl/style/conversion/source.hpp +++ b/include/mbgl/style/conversion/source.hpp @@ -2,6 +2,7 @@ #include <mbgl/style/conversion.hpp> #include <mbgl/style/conversion/geojson.hpp> +#include <mbgl/style/conversion/geojson_options.hpp> #include <mbgl/style/conversion/tileset.hpp> #include <mbgl/style/source.hpp> #include <mbgl/style/sources/geojson_source.hpp> @@ -103,63 +104,12 @@ private: return Error{ "GeoJSON source must have a data value" }; } - GeoJSONOptions options; - - const auto maxzoomValue = objectMember(value, "maxzoom"); - if (maxzoomValue) { - if (toNumber(*maxzoomValue)) { - options.maxzoom = static_cast<uint8_t>(*toNumber(*maxzoomValue)); - } else { - return Error{ "GeoJSON source maxzoom value must be a number" }; - } - } - - const auto bufferValue = objectMember(value, "buffer"); - if (bufferValue) { - if (toNumber(*bufferValue)) { - options.buffer = static_cast<uint16_t>(*toNumber(*bufferValue)); - } else { - return Error{ "GeoJSON source buffer value must be a number" }; - } - } - - const auto toleranceValue = objectMember(value, "tolerance"); - if (toleranceValue) { - if (toNumber(*toleranceValue)) { - options.tolerance = static_cast<double>(*toNumber(*toleranceValue)); - } else { - return Error{ "GeoJSON source tolerance value must be a number" }; - } - } - - const auto clusterValue = objectMember(value, "cluster"); - if (clusterValue) { - if (toBool(*clusterValue)) { - options.cluster = *toBool(*clusterValue); - } else { - return Error{ "GeoJSON source cluster value must be a boolean" }; - } - } - - const auto clusterMaxZoomValue = objectMember(value, "clusterMaxZoom"); - if (clusterMaxZoomValue) { - if (toNumber(*clusterMaxZoomValue)) { - options.clusterMaxZoom = static_cast<uint8_t>(*toNumber(*clusterMaxZoomValue)); - } else { - return Error{ "GeoJSON source clusterMaxZoom value must be a number" }; - } - } - - const auto clusterRadiusValue = objectMember(value, "clusterRadius"); - if (clusterRadiusValue) { - if (toNumber(*clusterRadiusValue)) { - options.clusterRadius = static_cast<double>(*toNumber(*clusterRadiusValue)); - } else { - return Error{ "GeoJSON source clusterRadius value must be a number" }; - } + Result<GeoJSONOptions> options = convert<GeoJSONOptions>(value); + if (!options) { + return options.error(); } - auto result = std::make_unique<GeoJSONSource>(id, options); + auto result = std::make_unique<GeoJSONSource>(id, *options); if (isObject(*dataValue)) { Result<GeoJSON> geoJSON = convertGeoJSON(*dataValue); diff --git a/test/src/mbgl/test/conversion_stubs.hpp b/test/src/mbgl/test/conversion_stubs.hpp new file mode 100644 index 0000000000..60f110ea0d --- /dev/null +++ b/test/src/mbgl/test/conversion_stubs.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include <mbgl/style/conversion.hpp> +#include <mbgl/util/feature.hpp> +#include <mbgl/util/optional.hpp> +#include <mbgl/util/variant.hpp> + +#include <string> +#include <map> + +namespace mbgl { +namespace style { +namespace conversion { + +class Value; +using ValueMap = std::map<std::string, Value>; +using ValueVector = std::vector<Value>; +class Value : public mbgl::variant<std::string, float, bool, ValueMap, ValueVector> { + using variant::variant; +}; + +inline bool isUndefined(const Value&) { + //Variant is always intialized + return false; +} + +inline bool isArray(const Value& value) { + return value.is<ValueVector>(); +} + +inline std::size_t arrayLength(const Value& value) { + return value.get<ValueVector>().size(); +} + +inline Value arrayMember(const Value& value, std::size_t i) { + return value.get<ValueVector>()[i]; +} + +inline bool isObject(const Value& value) { + return value.is<ValueMap>(); +} + +inline optional<Value> objectMember(const Value& value, const char* key) { + auto map = value.get<ValueMap>(); + auto iter = map.find(key); + + if (iter != map.end()) { + return iter->second; + } else { + return {}; + } +} + +using EachMemberFn = std::function<optional<Error>(const std::string&, const Value&)>; + +optional<Error> eachMember(const Value& value, EachMemberFn&& fn) { + auto map = value.get<ValueMap>(); + auto iter = map.begin(); + + while (iter != map.end()) { + optional<Error> result = fn(iter->first, iter->second); + if (result) { + return result; + } + + ++iter; + } + + return {}; +} + +inline optional<bool> toBool(const Value& value) { + if (value.is<bool>()) { + return value.get<bool>(); + } else { + return {}; + } +} + +inline optional<float> toNumber(const Value& value) { + if (value.is<float>()) { + return value.get<float>(); + } else { + return {}; + } + return {}; +} + +inline optional<std::string> toString(const Value& value) { + if (value.is<std::string>()) { + return value.get<std::string>(); + } else { + return {}; + } +} + +inline optional<mbgl::Value> toValue(const Value& value) { + if (value.is<bool>()) { + return { value.get<bool>() }; + } else if (value.is<std::string>()) { + return { value.get<std::string>() }; + } else if (value.is<float>()) { + return { value.get<float>() }; + } else { + return {}; + } +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/test/style/conversion/geojson_options.cpp b/test/style/conversion/geojson_options.cpp new file mode 100644 index 0000000000..46a2aa950b --- /dev/null +++ b/test/style/conversion/geojson_options.cpp @@ -0,0 +1,68 @@ +#include <mbgl/test/util.hpp> + +#include <mbgl/style/conversion.hpp> +#include <mbgl/style/conversion/geojson_options.hpp> +#include <mbgl/test/conversion_stubs.hpp> + +#include <mbgl/platform/log.hpp> + +using namespace mbgl::style; +using namespace mbgl::style::conversion; + +TEST(GeoJSONOptions, Basic) { + ValueMap map; + Value raw(map); + Result<GeoJSONOptions> converted = convert<GeoJSONOptions>(raw); + ASSERT_TRUE((bool) converted); +} + +TEST(GeoJSONOptions, ErrorHandling) { + ValueMap map {{"maxzoom", "should not be a string"}}; + Value raw(map); + Result<GeoJSONOptions> converted = convert<GeoJSONOptions>(raw); + ASSERT_FALSE((bool) converted); +} + +TEST(GeoJSONOptions, RetainsDefaults) { + ValueMap map; + Value raw(map); + GeoJSONOptions converted = *convert<GeoJSONOptions>(raw); + GeoJSONOptions defaults; + + //GeoJSON-VT + ASSERT_EQ(converted.maxzoom, defaults.maxzoom); + ASSERT_EQ(converted.buffer, defaults.buffer); + ASSERT_EQ(converted.tolerance, defaults.tolerance); + + //Supercluster + ASSERT_EQ(converted.cluster, defaults.cluster); + ASSERT_EQ(converted.clusterRadius, defaults.clusterRadius); + ASSERT_EQ(converted.clusterMaxZoom, defaults.clusterMaxZoom); +} + + +TEST(GeoJSONOptions, FullConversion) { + ValueMap map { + //GeoJSON-VT + {"maxzoom", 1}, + {"buffer", 2}, + {"tolerance", 3}, + + //Supercluster + {"cluster", true}, + {"clusterRadius", 4}, + {"clusterMaxZoom", 5} + }; + Value raw(map); + GeoJSONOptions converted = *convert<GeoJSONOptions>(raw); + + //GeoJSON-VT + ASSERT_EQ(converted.maxzoom, 1); + ASSERT_EQ(converted.buffer, 2); + ASSERT_EQ(converted.tolerance, 3); + + //Supercluster + ASSERT_EQ(converted.cluster, true); + ASSERT_EQ(converted.clusterRadius, 4); + ASSERT_EQ(converted.clusterMaxZoom, 5); +} |