Commit 07406e64 authored by Wei Li's avatar Wei Li Committed by Commit Bot

Views: Check results of type conversions from strings

This CL changed the way how we handle conversion failures from strings.
Instead of using the default values, this CL returns 'false' to indicate
the conversion errors. This returned result is useful in case we need to
handle more complex type conversions such base::optional type.

Also, this CL simplify the type converter function definitions since we
only need to and from string conversions, not between arbitrary two
types.

BUG=938501

Change-Id: I1e6d8510c39a9a240161aa0b36c2141ab62ed0e8
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1606772
Commit-Queue: Wei Li <weili@chromium.org>
Reviewed-by: default avatarAllen Bauer <kylixrd@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659250}
parent 957a9770
......@@ -26,7 +26,7 @@ class ClassPropertyReadOnlyMetaData : public MemberMetaDataBase {
~ClassPropertyReadOnlyMetaData() override = default;
base::string16 GetValueAsString(void* obj) const override {
return Convert<TValue, base::string16>((static_cast<TClass*>(obj)->*Get)());
return ConvertToString<TValue>((static_cast<TClass*>(obj)->*Get)());
}
PropertyFlags GetPropertyFlags() const override {
......@@ -53,8 +53,9 @@ class ClassPropertyMetaData
~ClassPropertyMetaData() override = default;
void SetValueAsString(void* obj, const base::string16& new_value) override {
(static_cast<TClass*>(obj)->*Set)(Convert<base::string16, TValue>(
new_value, (static_cast<TClass*>(obj)->*Get)()));
TValue result;
if (ConvertFromString<TValue>(new_value, &result))
(static_cast<TClass*>(obj)->*Set)(result);
}
PropertyFlags GetPropertyFlags() const override {
......
......@@ -17,12 +17,6 @@ namespace metadata {
/***** String Conversions *****/
template <>
base::string16 ConvertToString<base::string16>(
const base::string16& source_value) {
return source_value;
}
template <>
base::string16 ConvertToString<int8_t>(int8_t source_value) {
return base::NumberToString16(source_value);
......@@ -85,110 +79,131 @@ base::string16 ConvertToString<gfx::Size>(const gfx::Size& source_value) {
}
template <>
int8_t ConvertFromString<int8_t>(const base::string16& source_value,
int8_t default_value) {
int32_t ret = 0;
return base::StringToInt(source_value, &ret) &&
base::IsValueInRangeForNumericType<int8_t>(ret)
? static_cast<int8_t>(ret)
: default_value;
base::string16 ConvertToString<base::string16>(
const base::string16& source_value) {
return source_value;
}
template <>
int16_t ConvertFromString<int16_t>(const base::string16& source_value,
int16_t default_value) {
bool ConvertFromString<int8_t>(const base::string16& source_value,
int8_t* dst_value) {
int32_t ret = 0;
return base::StringToInt(source_value, &ret) &&
base::IsValueInRangeForNumericType<int16_t>(ret)
? static_cast<int16_t>(ret)
: default_value;
if (base::StringToInt(source_value, &ret) &&
base::IsValueInRangeForNumericType<int8_t>(ret)) {
*dst_value = static_cast<int8_t>(ret);
return true;
}
return false;
}
template <>
int32_t ConvertFromString<int32_t>(const base::string16& source_value,
int32_t default_value) {
bool ConvertFromString<int16_t>(const base::string16& source_value,
int16_t* dst_value) {
int32_t ret = 0;
return base::StringToInt(source_value, &ret) ? static_cast<int32_t>(ret)
: default_value;
if (base::StringToInt(source_value, &ret) &&
base::IsValueInRangeForNumericType<int16_t>(ret)) {
*dst_value = static_cast<int16_t>(ret);
return true;
}
return false;
}
template <>
int64_t ConvertFromString<int64_t>(const base::string16& source_value,
int64_t default_value) {
int64_t ret = 0;
return base::StringToInt64(source_value, &ret) ? ret : default_value;
bool ConvertFromString<int32_t>(const base::string16& source_value,
int32_t* dst_value) {
return base::StringToInt(source_value, dst_value);
}
template <>
uint8_t ConvertFromString<uint8_t>(const base::string16& source_value,
uint8_t default_value) {
uint32_t ret = 0;
return base::StringToUint(source_value, &ret) &&
base::IsValueInRangeForNumericType<uint8_t>(ret)
? static_cast<uint8_t>(ret)
: default_value;
bool ConvertFromString<int64_t>(const base::string16& source_value,
int64_t* dst_value) {
return base::StringToInt64(source_value, dst_value);
}
template <>
uint16_t ConvertFromString<uint16_t>(const base::string16& source_value,
uint16_t default_value) {
bool ConvertFromString<uint8_t>(const base::string16& source_value,
uint8_t* dst_value) {
uint32_t ret = 0;
return base::StringToUint(source_value, &ret) &&
base::IsValueInRangeForNumericType<uint16_t>(ret)
? static_cast<uint16_t>(ret)
: default_value;
if (base::StringToUint(source_value, &ret) &&
base::IsValueInRangeForNumericType<uint8_t>(ret)) {
*dst_value = static_cast<uint8_t>(ret);
return true;
}
return false;
}
template <>
uint32_t ConvertFromString<uint32_t>(const base::string16& source_value,
uint32_t default_value) {
bool ConvertFromString<uint16_t>(const base::string16& source_value,
uint16_t* dst_value) {
uint32_t ret = 0;
return base::StringToUint(source_value, &ret) ? static_cast<uint32_t>(ret)
: default_value;
if (base::StringToUint(source_value, &ret) &&
base::IsValueInRangeForNumericType<uint16_t>(ret)) {
*dst_value = static_cast<uint16_t>(ret);
return true;
}
return false;
}
template <>
uint64_t ConvertFromString<uint64_t>(const base::string16& source_value,
uint64_t default_value) {
uint64_t ret = 0;
return base::StringToUint64(source_value, &ret) ? ret : default_value;
bool ConvertFromString<uint32_t>(const base::string16& source_value,
uint32_t* dst_value) {
return base::StringToUint(source_value, dst_value);
}
template <>
float ConvertFromString<float>(const base::string16& source_value,
float default_value) {
return static_cast<float>(
ConvertFromString<double>(source_value, default_value));
bool ConvertFromString<uint64_t>(const base::string16& source_value,
uint64_t* dst_value) {
return base::StringToUint64(source_value, dst_value);
}
template <>
double ConvertFromString<double>(const base::string16& source_value,
double default_value) {
double ret = 0;
return base::StringToDouble(base::UTF16ToUTF8(source_value), &ret)
? ret
: default_value;
bool ConvertFromString<float>(const base::string16& source_value,
float* dst_value) {
double temp;
if (ConvertFromString<double>(source_value, &temp)) {
*dst_value = static_cast<float>(temp);
return true;
}
return false;
}
template <>
bool ConvertFromString<double>(const base::string16& source_value,
double* dst_value) {
return base::StringToDouble(base::UTF16ToUTF8(source_value), dst_value);
}
template <>
bool ConvertFromString<bool>(const base::string16& source_value,
bool default_value) {
if (source_value == base::ASCIIToUTF16("false"))
bool* dst_value) {
if (source_value == base::ASCIIToUTF16("true") ||
source_value == base::ASCIIToUTF16("false")) {
*dst_value = source_value == base::ASCIIToUTF16("true");
return true;
}
return false;
return source_value == base::ASCIIToUTF16("true") || default_value;
}
template <>
gfx::Size ConvertFromString<gfx::Size>(const base::string16& source_value,
const gfx::Size& default_value) {
bool ConvertFromString<gfx::Size>(const base::string16& source_value,
gfx::Size* dst_value) {
const auto values =
base::SplitStringPiece(source_value, base::ASCIIToUTF16("{,}"),
base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
int width, height;
return (values.size() == 2) && base::StringToInt(values[0], &width) &&
base::StringToInt(values[1], &height)
? gfx::Size(width, height)
: default_value;
if ((values.size() == 2) && base::StringToInt(values[0], &width) &&
base::StringToInt(values[1], &height)) {
*dst_value = gfx::Size(width, height);
return true;
}
return false;
}
template <>
bool ConvertFromString<base::string16>(const base::string16& source_value,
base::string16* dst_value) {
*dst_value = source_value;
return true;
}
} // namespace metadata
......
......@@ -70,42 +70,27 @@ static const EnumStrings<T>& GetEnumStringsInstance();
} \
\
template <> \
T views::metadata::ConvertFromString<T>(const base::string16& source_value, \
T default_value) { \
bool views::metadata::ConvertFromString<T>( \
const base::string16& source_value, T* dst_value) { \
for (const auto& pair : GetEnumStringsInstance<T>().pairs) { \
if (source_value == pair.str_value) \
return pair.enum_value; \
if (source_value == pair.str_value) { \
*dst_value = pair.enum_value; \
return true; \
} \
return default_value; \
} \
return false; \
}
// TypeConverter Class --------------------------------------------------------
template <typename TSource, typename TTarget>
class TypeConverter {
public:
static TTarget Convert(ArgType<TSource>) = delete;
static TTarget Convert(ArgType<TSource>, ArgType<TTarget>) = delete;
private:
TypeConverter();
};
// Master Type Conversion Functions --------------------------------------------
template <typename TSource, typename TTarget>
TTarget Convert(ArgType<TSource> source_value) {
return TypeConverter<TSource, TTarget>::Convert(source_value);
}
// Type Conversion Template Function
// --------------------------------------------
template <typename TSource>
base::string16 ConvertToString(ArgType<TSource> source_value);
template <typename TSource, typename TTarget>
TTarget Convert(ArgType<TSource> source_value, ArgType<TTarget> default_value) {
return TypeConverter<TSource, TTarget>::Convert(source_value, default_value);
}
template <typename TTarget>
bool ConvertFromString(const base::string16& source_value, TTarget* dst_value);
// String Conversions ---------------------------------------------------------
template <typename TSource>
base::string16 ConvertToString(ArgType<TSource>) = delete;
template <>
VIEWS_EXPORT base::string16 ConvertToString<base::string16>(
const base::string16& source_value);
......@@ -147,97 +132,66 @@ template <>
VIEWS_EXPORT base::string16 ConvertToString<gfx::Size>(
const gfx::Size& source_value);
template <typename TSource>
class TypeConverter<TSource, base::string16> {
public:
static base::string16 Convert(ArgType<TSource> source_value) {
return ConvertToString<TSource>(source_value);
}
};
// A specialization used for string16 conversions. Since it simply passes
// the value, it is used for both converting to and from a string16 value.
template <>
class TypeConverter<base::string16, base::string16> {
public:
static base::string16 Convert(const base::string16& source_val) {
return ConvertToString<base::string16>(source_val);
}
static base::string16 Convert(const base::string16& source_val,
const base::string16& default_value) {
return ConvertToString<base::string16>(source_val);
}
};
template <typename TTarget>
TTarget ConvertFromString(const base::string16&, ArgType<TTarget>) = delete;
VIEWS_EXPORT base::string16 ConvertToString<base::string16>(
const base::string16& source_value);
template <>
VIEWS_EXPORT int8_t
ConvertFromString<int8_t>(const base::string16& source_value,
int8_t default_value);
VIEWS_EXPORT bool ConvertFromString<int8_t>(const base::string16& source_value,
int8_t* dst_value);
template <>
VIEWS_EXPORT int16_t
ConvertFromString<int16_t>(const base::string16& source_value,
int16_t default_value);
VIEWS_EXPORT bool ConvertFromString<int16_t>(const base::string16& source_value,
int16_t* dst_value);
template <>
VIEWS_EXPORT int32_t
ConvertFromString<int32_t>(const base::string16& source_value,
int32_t default_value);
VIEWS_EXPORT bool ConvertFromString<int32_t>(const base::string16& source_value,
int32_t* dst_value);
template <>
VIEWS_EXPORT int64_t
ConvertFromString<int64_t>(const base::string16& source_value,
int64_t default_value);
VIEWS_EXPORT bool ConvertFromString<int64_t>(const base::string16& source_value,
int64_t* dst_value);
template <>
VIEWS_EXPORT uint8_t
ConvertFromString<uint8_t>(const base::string16& source_value,
uint8_t default_value);
VIEWS_EXPORT bool ConvertFromString<uint8_t>(const base::string16& source_value,
uint8_t* dst_value);
template <>
VIEWS_EXPORT uint16_t
ConvertFromString<uint16_t>(const base::string16& source_value,
uint16_t default_value);
VIEWS_EXPORT bool ConvertFromString<uint16_t>(
const base::string16& source_value,
uint16_t* dst_value);
template <>
VIEWS_EXPORT uint32_t
ConvertFromString<uint32_t>(const base::string16& source_value,
uint32_t default_value);
VIEWS_EXPORT bool ConvertFromString<uint32_t>(
const base::string16& source_value,
uint32_t* dst_value);
template <>
VIEWS_EXPORT uint64_t
ConvertFromString<uint64_t>(const base::string16& source_value,
uint64_t default_value);
VIEWS_EXPORT bool ConvertFromString<uint64_t>(
const base::string16& source_value,
uint64_t* dst_value);
template <>
VIEWS_EXPORT double ConvertFromString<double>(
const base::string16& source_value,
double default_value);
VIEWS_EXPORT bool ConvertFromString<double>(const base::string16& source_value,
double* dst_value);
template <>
VIEWS_EXPORT float ConvertFromString<float>(const base::string16& source_value,
float default_value);
VIEWS_EXPORT bool ConvertFromString<float>(const base::string16& source_value,
float* dst_value);
template <>
VIEWS_EXPORT bool ConvertFromString<bool>(const base::string16& source_value,
bool default_value);
bool* dst_value);
template <>
VIEWS_EXPORT gfx::Size ConvertFromString<gfx::Size>(
VIEWS_EXPORT bool ConvertFromString<gfx::Size>(
const base::string16& source_value,
const gfx::Size& default_value);
gfx::Size* dst_value);
template <typename TTarget>
class TypeConverter<base::string16, TTarget> {
public:
static TTarget Convert(const base::string16& source_value,
ArgType<TTarget> default_value) {
return ConvertFromString<TTarget>(source_value, default_value);
}
};
template <>
VIEWS_EXPORT bool ConvertFromString<base::string16>(
const base::string16& source_value,
base::string16* dst_value);
} // namespace metadata
} // namespace views
......
......@@ -9,30 +9,29 @@
#include "testing/platform_test.h"
#include "ui/gfx/geometry/rect.h"
namespace VM = views::metadata;
namespace TC = views::metadata;
using TypeConversionTest = PlatformTest;
TEST_F(TypeConversionTest, TestConversion_IntToString) {
int from_int = 5;
base::string16 to_string = VM::Convert<int, base::string16>(from_int);
base::string16 to_string = TC::ConvertToString<int>(from_int);
EXPECT_EQ(to_string, base::ASCIIToUTF16("5"));
}
TEST_F(TypeConversionTest, TestConversion_StringToInt) {
base::string16 from_string = base::ASCIIToUTF16("10");
int to_int = VM::Convert<base::string16, int>(from_string, 0);
int to_int = 0;
EXPECT_TRUE(TC::ConvertFromString<int>(from_string, &to_int));
EXPECT_EQ(to_int, 10);
}
// This tests whether the converter handles a bogus input string, in which case
// the default value should be returned.
TEST_F(TypeConversionTest, TestConversion_StringToIntDefault) {
const int default_value = 1000;
// the return value should be false.
TEST_F(TypeConversionTest, TestConversion_BogusStringToInt) {
base::string16 from_string = base::ASCIIToUTF16("Foo");
int to_int = VM::Convert<base::string16, int>(from_string, default_value);
EXPECT_EQ(to_int, default_value);
int to_int = 0;
EXPECT_FALSE(TC::ConvertFromString<int>(from_string, &to_int));
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment