Result<Function<T>> operator()(const V& value) const { if (!isObject(value)) { return Error { "function must be an object" }; } auto stopsValue = objectMember(value, "stops"); if (!stopsValue) { return Error { "function value must specify stops" }; } if (!isArray(*stopsValue)) { return Error { "function stops must be an array" }; } if (arrayLength(*stopsValue) == 0) { return Error { "function must have at least one stop" }; } std::vector<std::pair<float, T>> stops; for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { const auto& stopValue = arrayMember(*stopsValue, i); if (!isArray(stopValue)) { return Error { "function stop must be an array" }; } if (arrayLength(stopValue) != 2) { return Error { "function stop must have two elements" }; } optional<float> z = toNumber(arrayMember(stopValue, 0)); if (!z) { return Error { "function stop zoom level must be a number" }; } Result<T> v = convert<T>(arrayMember(stopValue, 1)); if (!v) { return v.error(); } stops.emplace_back(*z, *v); } auto baseValue = objectMember(value, "base"); if (!baseValue) { return Function<T>(stops, 1.0f); } optional<float> base = toNumber(*baseValue); if (!base) { return Error { "function base must be a number"}; } return Function<T>(stops, *base); }
/** * @test Verify structure field deployments ('SomeIpStructEnum...') */ TEST_F(DeploymentTest, StructEnumFieldDeployment) { CommonAPI::CallStatus callStatus; { v1_0::commonapi::someip::deploymenttest::TestInterface::tStruct_field_depls outv; v1_0::commonapi::someip::deploymenttest::TestInterface::tStruct_field structMember; std::vector<uint8_t> a(8); std::iota (std::begin(a), std::end(a), 0); structMember.setUint8Member(a); outv.setStructMember(structMember); v1_0::commonapi::someip::deploymenttest::TestInterface::tEnum enumMember; // this enum value is too large to fit. It will be truncated during transfer. enumMember = v1_0::commonapi::someip::deploymenttest::TestInterface::tEnum::V3; outv.setEnumMember(enumMember); uint16_t intMember; intMember = 3; outv.setIntMember(intMember); v1_0::commonapi::someip::deploymenttest::TestInterface::tUnion_field unionMember; std::string str = "str"; unionMember = str; outv.setUnionMember(unionMember); std::vector<int8_t> arrayMember(8); std::iota (std::begin(arrayMember), std::end(arrayMember), 0); outv.setArrayMember(arrayMember); v1_0::commonapi::someip::deploymenttest::TestInterface::tStruct_field_depls inv; testProxy_->getAStruct_field_deplsAttribute().setValue(outv, callStatus, inv); ASSERT_EQ(callStatus, CommonAPI::CallStatus::SUCCESS); ASSERT_EQ(inv.getEnumMember(), 232); // 232 is the 8-bit truncated value of V3 = 1000 } }
/** * @test Verify structure field deployments ('SomeIpStructInt...') * Disabled until the bit length deployments are working again. */ TEST_F(DeploymentTest, DISABLED_StructIntFieldDeployment) { CommonAPI::CallStatus callStatus; { v1_0::commonapi::someip::deploymenttest::TestInterface::tStruct_field_depls outv; v1_0::commonapi::someip::deploymenttest::TestInterface::tStruct_field structMember; std::vector<uint8_t> a(8); std::iota (std::begin(a), std::end(a), 0); structMember.setUint8Member(a); outv.setStructMember(structMember); v1_0::commonapi::someip::deploymenttest::TestInterface::tEnum enumMember; enumMember = v1_0::commonapi::someip::deploymenttest::TestInterface::tEnum::V1; outv.setEnumMember(enumMember); uint16_t intMember; intMember = 4; // this value will be truncated during transfer. outv.setIntMember(intMember); v1_0::commonapi::someip::deploymenttest::TestInterface::tUnion_field unionMember; std::string str = "str"; unionMember = str; outv.setUnionMember(unionMember); std::vector<int8_t> arrayMember(8); std::iota (std::begin(arrayMember), std::end(arrayMember), 0); outv.setArrayMember(arrayMember); v1_0::commonapi::someip::deploymenttest::TestInterface::tStruct_field_depls inv; testProxy_->getAStruct_field_deplsAttribute().setValue(outv, callStatus, inv); ASSERT_EQ(callStatus, CommonAPI::CallStatus::SUCCESS); ASSERT_EQ(inv.getIntMember(), 0); } }
/** * @test Verify structure field deployments ('SomeIpStructUnion...') */ TEST_F(DeploymentTest, StructUnionFieldDeployment) { CommonAPI::CallStatus callStatus; { v1_0::commonapi::someip::deploymenttest::TestInterface::tStruct_field_depls outv; v1_0::commonapi::someip::deploymenttest::TestInterface::tStruct_field structMember; std::vector<uint8_t> a(8); std::iota (std::begin(a), std::end(a), 0); structMember.setUint8Member(a); outv.setStructMember(structMember); v1_0::commonapi::someip::deploymenttest::TestInterface::tEnum enumMember; enumMember = v1_0::commonapi::someip::deploymenttest::TestInterface::tEnum::V1; outv.setEnumMember(enumMember); uint16_t intMember; intMember = 3; outv.setIntMember(intMember); v1_0::commonapi::someip::deploymenttest::TestInterface::tUnion_field unionMember; // this value is too large, and the value should not be transmitted. std::string str(70000, 'a'); unionMember = str; outv.setUnionMember(unionMember); std::vector<int8_t> arrayMember(8); std::iota (std::begin(arrayMember), std::end(arrayMember), 0); outv.setArrayMember(arrayMember); v1_0::commonapi::someip::deploymenttest::TestInterface::tStruct_field_depls inv; testProxy_->getAStruct_field_deplsAttribute().setValue(outv, callStatus, inv); ASSERT_NE(callStatus, CommonAPI::CallStatus::SUCCESS); } }
optional<std::map<D, R>> convertStops(const V& value, Error& error) { auto stopsValue = objectMember(value, "stops"); if (!stopsValue) { error = { "function value must specify stops" }; return {}; } if (!isArray(*stopsValue)) { error = { "function stops must be an array" }; return {}; } if (arrayLength(*stopsValue) == 0) { error = { "function must have at least one stop" }; return {}; } std::map<D, R> stops; for (std::size_t i = 0; i < arrayLength(*stopsValue); ++i) { const auto& stopValue = arrayMember(*stopsValue, i); if (!isArray(stopValue)) { error = { "function stop must be an array" }; return {}; } if (arrayLength(stopValue) != 2) { error = { "function stop must have two elements" }; return {}; } optional<D> d = convert<D>(arrayMember(stopValue, 0), error); if (!d) { return {}; } optional<R> r = convert<R>(arrayMember(stopValue, 1), error); if (!r) { return {}; } stops.emplace(*d, *r); } return stops; }
Result<Tileset> operator()(const V& value) const { Tileset result; auto tiles = objectMember(value, "tiles"); if (!tiles) { return Error { "source must have tiles" }; } if (!isArray(*tiles)) { return Error { "source tiles must be an array" }; } for (std::size_t i = 0; i < arrayLength(*tiles); i++) { optional<std::string> urlTemplate = toString(arrayMember(*tiles, i)); if (!urlTemplate) { return Error { "source tiles member must be a string" }; } result.tiles.push_back(std::move(*urlTemplate)); } auto schemeValue = objectMember(value, "scheme"); if (schemeValue) { optional<std::string> scheme = toString(*schemeValue); if (scheme && *scheme == "tms") { result.scheme = Tileset::Scheme::TMS; } } auto minzoomValue = objectMember(value, "minzoom"); if (minzoomValue) { optional<float> minzoom = toNumber(*minzoomValue); if (!minzoom || *minzoom < 0 || *minzoom > std::numeric_limits<uint8_t>::max()) { return Error { "invalid minzoom" }; } result.zoomRange.min = *minzoom; } auto maxzoomValue = objectMember(value, "maxzoom"); if (maxzoomValue) { optional<float> maxzoom = toNumber(*maxzoomValue); if (!maxzoom || *maxzoom < 0 || *maxzoom > std::numeric_limits<uint8_t>::max()) { return Error { "invalid maxzoom" }; } result.zoomRange.max = *maxzoom; } auto attributionValue = objectMember(value, "attribution"); if (attributionValue) { optional<std::string> attribution = toString(*attributionValue); if (!attribution) { return Error { "source attribution must be a string" }; } result.attribution = std::move(*attribution); } return result; }
optional<Filter> operator()(const V& value, Error& error) const { if (!isArray(value)) { error = { "filter expression must be an array" }; return {}; } if (arrayLength(value) < 1) { error = { "filter expression must have at least 1 element" }; return {}; } optional<std::string> op = toString(arrayMember(value, 0)); if (!op) { error = { "filter operator must be a string" }; return {}; } if (*op == "==") { return convertEqualityFilter<EqualsFilter, TypeEqualsFilter, IdentifierEqualsFilter>(value, error); } else if (*op == "!=") { return convertEqualityFilter<NotEqualsFilter, TypeNotEqualsFilter, IdentifierNotEqualsFilter>(value, error); } else if (*op == ">") { return convertBinaryFilter<GreaterThanFilter>(value, error); } else if (*op == ">=") { return convertBinaryFilter<GreaterThanEqualsFilter>(value, error); } else if (*op == "<") { return convertBinaryFilter<LessThanFilter>(value, error); } else if (*op == "<=") { return convertBinaryFilter<LessThanEqualsFilter>(value, error); } else if (*op == "in") { return convertSetFilter<InFilter, TypeInFilter, IdentifierInFilter>(value, error); } else if (*op == "!in") { return convertSetFilter<NotInFilter, TypeNotInFilter, IdentifierNotInFilter>(value, error); } else if (*op == "all") { return convertCompoundFilter<AllFilter>(value, error); } else if (*op == "any") { return convertCompoundFilter<AnyFilter>(value, error); } else if (*op == "none") { return convertCompoundFilter<NoneFilter>(value, error); } else if (*op == "has") { return convertUnaryFilter<HasFilter, HasIdentifierFilter>(value, error); } else if (*op == "!has") { return convertUnaryFilter<NotHasFilter, NotHasIdentifierFilter>(value, error); } error = { R"(filter operator must be one of "==", "!=", ">", ">=", "<", "<=", "in", "!in", "all", "any", "none", "has", or "!has")" }; return {}; } private: optional<Value> normalizeValue(const optional<Value>& value, Error& error) const { if (!value) { error = { "filter expression value must be a boolean, number, or string" }; return {}; } else { return *value;
optional<std::array<float, N>> operator()(const Convertible& value, Error& error) const { if (!isArray(value) || arrayLength(value) != N) { error = { "value must be an array of " + util::toString(N) + " numbers" }; return {}; } std::array<float, N> result; for (size_t i = 0; i < N; i++) { optional<float> n = toNumber(arrayMember(value, i)); if (!n) { error = { "value must be an array of " + util::toString(N) + " numbers" }; return {}; } result[i] = *n; } return result; }
static optional<std::unique_ptr<Source>> convertImageSource(const std::string& id, const Convertible& value, Error& error) { auto urlValue = objectMember(value, "url"); if (!urlValue) { error = { "Image source must have a url value" }; return {}; } auto urlString = toString(*urlValue); if (!urlString) { error = { "Image url must be a URL string" }; return {}; } auto coordinatesValue = objectMember(value, "coordinates"); if (!coordinatesValue) { error = { "Image source must have a coordinates values" }; return {}; } if (!isArray(*coordinatesValue) || arrayLength(*coordinatesValue) != 4) { error = { "Image coordinates must be an array of four longitude latitude pairs" }; return {}; } std::array<LatLng, 4> coordinates; for (std::size_t i=0; i < 4; i++) { auto latLng = conversion::convert<LatLng>(arrayMember(*coordinatesValue,i), error); if (!latLng) { return {}; } coordinates[i] = *latLng; } auto result = std::make_unique<ImageSource>(id, coordinates); result->setURL(*urlString); return { std::move(result) }; }
optional<PropertyExpression<T>> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens) { auto expression = convertFunctionToExpression(expression::valueTypeToExpressionType<T>(), value, error, convertTokens); if (!expression) { return nullopt; } optional<T> defaultValue{}; auto defaultValueValue = objectMember(value, "default"); if (defaultValueValue) { defaultValue = convert<T>(*defaultValueValue, error); if (!defaultValue) { error.message = R"(wrong type for "default": )" + error.message; return nullopt; } } return PropertyExpression<T>(std::move(*expression), defaultValue); } template optional<PropertyExpression<AlignmentType>> convertFunctionToExpression<AlignmentType>(const Convertible&, Error&, bool); template optional<PropertyExpression<bool>> convertFunctionToExpression<bool>(const Convertible&, Error&, bool); template optional<PropertyExpression<CirclePitchScaleType>> convertFunctionToExpression<CirclePitchScaleType>(const Convertible&, Error&, bool); template optional<PropertyExpression<float>> convertFunctionToExpression<float>(const Convertible&, Error&, bool); template optional<PropertyExpression<HillshadeIlluminationAnchorType>> convertFunctionToExpression<HillshadeIlluminationAnchorType>(const Convertible&, Error&, bool); template optional<PropertyExpression<IconTextFitType>> convertFunctionToExpression<IconTextFitType>(const Convertible&, Error&, bool); template optional<PropertyExpression<LightAnchorType>> convertFunctionToExpression<LightAnchorType>(const Convertible&, Error&, bool); template optional<PropertyExpression<LineCapType>> convertFunctionToExpression<LineCapType>(const Convertible&, Error&, bool); template optional<PropertyExpression<LineJoinType>> convertFunctionToExpression<LineJoinType>(const Convertible&, Error&, bool); template optional<PropertyExpression<Color>> convertFunctionToExpression<Color>(const Convertible&, Error&, bool); template optional<PropertyExpression<Position>> convertFunctionToExpression<Position>(const Convertible&, Error&, bool); template optional<PropertyExpression<RasterResamplingType>> convertFunctionToExpression<RasterResamplingType>(const Convertible&, Error&, bool); template optional<PropertyExpression<std::array<float, 2>>> convertFunctionToExpression<std::array<float, 2>>(const Convertible&, Error&, bool); template optional<PropertyExpression<std::array<float, 4>>> convertFunctionToExpression<std::array<float, 4>>(const Convertible&, Error&, bool); template optional<PropertyExpression<std::string>> convertFunctionToExpression<std::string>(const Convertible&, Error&, bool); template optional<PropertyExpression<std::vector<float>>> convertFunctionToExpression<std::vector<float>>(const Convertible&, Error&, bool); template optional<PropertyExpression<std::vector<std::string>>> convertFunctionToExpression<std::vector<std::string>>(const Convertible&, Error&, bool); template optional<PropertyExpression<SymbolAnchorType>> convertFunctionToExpression<SymbolAnchorType>(const Convertible&, Error&, bool); template optional<PropertyExpression<SymbolPlacementType>> convertFunctionToExpression<SymbolPlacementType>(const Convertible&, Error&, bool); template optional<PropertyExpression<SymbolZOrderType>> convertFunctionToExpression<SymbolZOrderType>(const Convertible&, Error&, bool); template optional<PropertyExpression<TextJustifyType>> convertFunctionToExpression<TextJustifyType>(const Convertible&, Error&, bool); template optional<PropertyExpression<TextTransformType>> convertFunctionToExpression<TextTransformType>(const Convertible&, Error&, bool); template optional<PropertyExpression<TranslateAnchorType>> convertFunctionToExpression<TranslateAnchorType>(const Convertible&, Error&, bool); template optional<PropertyExpression<Formatted>> convertFunctionToExpression<Formatted>(const Convertible&, Error&, bool); // Ad-hoc Converters for double and int64_t. We should replace float with double wholesale, // and promote the int64_t Converter to general use (and it should check that the input is // an integer). template <> struct Converter<double> { optional<double> operator()(const Convertible& value, Error& error) const { auto converted = convert<float>(value, error); if (!converted) { return nullopt; } return *converted; } }; template <> struct Converter<int64_t> { optional<int64_t> operator()(const Convertible& value, Error& error) const { auto converted = convert<float>(value, error); if (!converted) { return nullopt; } return *converted; } }; enum class FunctionType { Interval, Exponential, Categorical, Identity, Invalid }; static bool interpolatable(type::Type type) { return type.match( [&] (const type::NumberType&) { return true; }, [&] (const type::ColorType&) { return true; }, [&] (const type::Array& array) { return array.N && array.itemType == type::Number; }, [&] (const auto&) { return false; } ); } static optional<std::unique_ptr<Expression>> convertLiteral(type::Type type, const Convertible& value, Error& error, bool convertTokens = false) { return type.match( [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> { auto result = convert<float>(value, error); if (!result) { return nullopt; } return literal(double(*result)); }, [&] (const type::BooleanType&) -> optional<std::unique_ptr<Expression>> { auto result = convert<bool>(value, error); if (!result) { return nullopt; } return literal(*result); }, [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> { auto result = convert<std::string>(value, error); if (!result) { return nullopt; } return convertTokens ? convertTokenStringToExpression(*result) : literal(*result); }, [&] (const type::ColorType&) -> optional<std::unique_ptr<Expression>> { auto result = convert<Color>(value, error); if (!result) { return nullopt; } return literal(*result); }, [&] (const type::Array& array) -> optional<std::unique_ptr<Expression>> { if (!isArray(value)) { error.message = "value must be an array"; return nullopt; } if (array.N && arrayLength(value) != *array.N) { error.message = "value must be an array of length " + util::toString(*array.N); return nullopt; } return array.itemType.match( [&] (const type::NumberType&) -> optional<std::unique_ptr<Expression>> { std::vector<expression::Value> result; result.reserve(arrayLength(value)); for (std::size_t i = 0; i < arrayLength(value); ++i) { optional<float> number = toNumber(arrayMember(value, i)); if (!number) { error.message = "value must be an array of numbers"; return nullopt; } result.push_back(double(*number)); } return literal(result); }, [&] (const type::StringType&) -> optional<std::unique_ptr<Expression>> { std::vector<expression::Value> result; result.reserve(arrayLength(value)); for (std::size_t i = 0; i < arrayLength(value); ++i) { optional<std::string> string = toString(arrayMember(value, i)); if (!string) { error.message = "value must be an array of strings"; return nullopt; } result.push_back(*string); } return literal(result); }, [&] (const auto&) -> optional<std::unique_ptr<Expression>> { assert(false); // No properties use this type. return nullopt; } ); },