Commit 54241866 authored by Kent Tamura's avatar Kent Tamura Committed by Commit Bot

Parse clamped unsigned integer attribute values correctly.

https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#clamped-to-the-range

We had a bug that an attribute value greater than 2^32-1 was handled as a parse
error, instead of range overflow. We need to clamp such values to a maximum
value defined for a attribute.

Implementation:
The main change is to introduce blink::ParseHTMLClampedNonNegativeInteger(), and
use it in HTMLTableCellElement and HTMLTableColElement.

This CL introduces WTF::NumberParsingState in order to pass "fail by overflow"
information from platform/wtf/StringToNumber code.

Bug: 745376
Change-Id: Ie57a0538816f0f508324573cdcda6d96ad51afb2
Reviewed-on: https://chromium-review.googlesource.com/577428Reviewed-by: default avatarTakayoshi Kochi <kochi@chromium.org>
Commit-Queue: Kent Tamura <tkent@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488143}
parent c5ab5e8c
......@@ -30,9 +30,7 @@ PASS colgroup.className (<colgroup class>): 32 tests
PASS colgroup.hidden: 33 tests
PASS colgroup.accessKey: 32 tests
PASS colgroup.tabIndex: 24 tests
PASS colgroup.span: 11 tests
FAIL colgroup.span: setAttribute() to 4294967296 assert_equals: IDL get expected 1000 but got 1
PASS colgroup.span: 53 tests
PASS colgroup.span: 65 tests
PASS colgroup.align: 32 tests
PASS colgroup.ch (<colgroup char>): 32 tests
PASS colgroup.chOff (<colgroup charoff>): 32 tests
......@@ -45,9 +43,7 @@ PASS col.className (<col class>): 32 tests
PASS col.hidden: 33 tests
PASS col.accessKey: 32 tests
PASS col.tabIndex: 24 tests
PASS col.span: 11 tests
FAIL col.span: setAttribute() to 4294967296 assert_equals: IDL get expected 1000 but got 1
PASS col.span: 53 tests
PASS col.span: 65 tests
PASS col.align: 32 tests
PASS col.ch (<col char>): 32 tests
PASS col.chOff (<col charoff>): 32 tests
......@@ -105,14 +101,10 @@ PASS td.className (<td class>): 32 tests
PASS td.hidden: 33 tests
PASS td.accessKey: 32 tests
PASS td.tabIndex: 24 tests
PASS td.colSpan: 11 tests
FAIL td.colSpan: setAttribute() to 4294967296 assert_equals: IDL get expected 1000 but got 1
PASS td.colSpan: 53 tests
PASS td.colSpan: 65 tests
PASS td.rowSpan: 6 tests
FAIL td.rowSpan: setAttribute() to 0 assert_equals: IDL get expected 0 but got 1
PASS td.rowSpan: 4 tests
FAIL td.rowSpan: setAttribute() to 4294967296 assert_equals: IDL get expected 65534 but got 1
PASS td.rowSpan: 2 tests
PASS td.rowSpan: 7 tests
FAIL td.rowSpan: setAttribute() to "-0" assert_equals: IDL get expected 0 but got 1
FAIL td.rowSpan: setAttribute() to "0" assert_equals: IDL get expected 0 but got 1
PASS td.rowSpan: 40 tests
......@@ -138,14 +130,10 @@ PASS th.className (<th class>): 32 tests
PASS th.hidden: 33 tests
PASS th.accessKey: 32 tests
PASS th.tabIndex: 24 tests
PASS th.colSpan: 11 tests
FAIL th.colSpan: setAttribute() to 4294967296 assert_equals: IDL get expected 1000 but got 1
PASS th.colSpan: 53 tests
PASS th.colSpan: 65 tests
PASS th.rowSpan: 6 tests
FAIL th.rowSpan: setAttribute() to 0 assert_equals: IDL get expected 0 but got 1
PASS th.rowSpan: 4 tests
FAIL th.rowSpan: setAttribute() to 4294967296 assert_equals: IDL get expected 65534 but got 1
PASS th.rowSpan: 2 tests
PASS th.rowSpan: 7 tests
FAIL th.rowSpan: setAttribute() to "-0" assert_equals: IDL get expected 0 but got 1
FAIL th.rowSpan: setAttribute() to "0" assert_equals: IDL get expected 0 but got 1
PASS th.rowSpan: 40 tests
......
......@@ -5,7 +5,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
PASS document.getElementById('case1').span is 1
PASS document.getElementById('case2').span is 1
PASS document.getElementById('case3').span is 1
PASS document.getElementById('case3').span is 1000
PASS document.getElementById('case4').span is 1
PASS document.getElementById('case5').span is 1
PASS document.getElementById('case6').span is 1
......
......@@ -15,7 +15,7 @@
shouldBe("document.getElementById('case1').span", "1");
shouldBe("document.getElementById('case2').span", "1");
shouldBe("document.getElementById('case3').span", "1");
shouldBe("document.getElementById('case3').span", "1000");
shouldBe("document.getElementById('case4').span", "1");
shouldBe("document.getElementById('case5').span", "1");
shouldBe("document.getElementById('case6').span", "1");
......
......@@ -24,7 +24,7 @@ PASS spanAttributeEffect("2" + arabicIndicDigitOne) is 2
PASS spanAttributeEffect("2147483647") is 1000
PASS spanAttributeEffect("2147483648") is 1000
PASS spanAttributeEffect("4294967295") is 1000
PASS spanAttributeEffect("4294967296") is 1
PASS spanAttributeEffect("4294967296") is 1000
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -44,7 +44,7 @@ shouldBe('spanAttributeEffect("2" + arabicIndicDigitOne)', '2');
shouldBe('spanAttributeEffect("2147483647")', '1000');
shouldBe('spanAttributeEffect("2147483648")', '1000');
shouldBe('spanAttributeEffect("4294967295")', '1000');
shouldBe('spanAttributeEffect("4294967296")', '1');
shouldBe('spanAttributeEffect("4294967296")', '1000');
</script>
</body>
</html>
......@@ -23,7 +23,7 @@ PASS colspanAttributeEffect(arabicIndicDigitOne) is 1
PASS colspanAttributeEffect("2" + arabicIndicDigitOne) is 2
PASS colspanAttributeEffect("2147483647") is 1000
PASS colspanAttributeEffect("4294967295") is 1000
PASS colspanAttributeEffect("4294967296") is 1
PASS colspanAttributeEffect("4294967296") is 1000
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -43,7 +43,7 @@ shouldBe('colspanAttributeEffect("2" + arabicIndicDigitOne)', '2');
shouldBe('colspanAttributeEffect("2147483647")', '1000');
shouldBe('colspanAttributeEffect("4294967295")', '1000');
shouldBe('colspanAttributeEffect("4294967296")', '1');
shouldBe('colspanAttributeEffect("4294967296")', '1000');
</script>
</body>
</html>
......@@ -23,7 +23,7 @@ PASS rowspanAttributeEffect(arabicIndicDigitOne) is 1
PASS rowspanAttributeEffect("2" + arabicIndicDigitOne) is 2
PASS rowspanAttributeEffect("2147483647") is 65534
PASS rowspanAttributeEffect("4294967295") is 65534
PASS rowspanAttributeEffect("4294967296") is 1
PASS rowspanAttributeEffect("4294967296") is 65534
PASS successfullyParsed is true
TEST COMPLETE
......
......@@ -43,7 +43,7 @@ shouldBe('rowspanAttributeEffect("2" + arabicIndicDigitOne)', '2');
shouldBe('rowspanAttributeEffect("2147483647")', '65534');
shouldBe('rowspanAttributeEffect("4294967295")', '65534');
shouldBe('rowspanAttributeEffect("4294967296")', '1');
shouldBe('rowspanAttributeEffect("4294967296")', '65534');
</script>
</body>
</html>
......@@ -240,6 +240,7 @@ blink_core_sources("html") {
"RadioNodeList.h",
"RelList.cpp",
"RelList.h",
"TableConstants.h",
"TextControlElement.cpp",
"TextControlElement.h",
"TextDocument.cpp",
......
......@@ -31,6 +31,7 @@
#include "core/dom/ElementTraversal.h"
#include "core/frame/UseCounter.h"
#include "core/html/HTMLTableElement.h"
#include "core/html/TableConstants.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "core/layout/LayoutTableCell.h"
......@@ -38,11 +39,6 @@ namespace blink {
using namespace HTMLNames;
namespace {
const unsigned kDefaultColSpan = 1;
const unsigned kDefaultRowSpan = 1;
} // namespace
inline HTMLTableCellElement::HTMLTableCellElement(const QualifiedName& tag_name,
Document& document)
: HTMLTablePartElement(tag_name, document) {}
......@@ -52,8 +48,8 @@ DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLTableCellElement)
unsigned HTMLTableCellElement::colSpan() const {
const AtomicString& col_span_value = FastGetAttribute(colspanAttr);
unsigned value = 0;
if (col_span_value.IsEmpty() ||
!ParseHTMLNonNegativeInteger(col_span_value, value))
if (!ParseHTMLClampedNonNegativeInteger(col_span_value, kMinColSpan,
kMaxColSpan, value))
return kDefaultColSpan;
// Counting for https://github.com/whatwg/html/issues/1198
UseCounter::Count(GetDocument(), WebFeature::kHTMLTableCellElementColspan);
......@@ -64,16 +60,16 @@ unsigned HTMLTableCellElement::colSpan() const {
UseCounter::Count(GetDocument(),
WebFeature::kHTMLTableCellElementColspanGreaterThan1000);
}
return std::max(1u, std::min(value, MaxColSpan()));
return value;
}
unsigned HTMLTableCellElement::rowSpan() const {
const AtomicString& row_span_value = FastGetAttribute(rowspanAttr);
unsigned value = 0;
if (row_span_value.IsEmpty() ||
!ParseHTMLNonNegativeInteger(row_span_value, value))
if (!ParseHTMLClampedNonNegativeInteger(row_span_value, kMinRowSpan,
kMaxRowSpan, value))
return kDefaultRowSpan;
return std::max(1u, std::min(value, MaxRowSpan()));
return value;
}
int HTMLTableCellElement::cellIndex() const {
......
......@@ -50,13 +50,6 @@ class CORE_EXPORT HTMLTableCellElement final : public HTMLTablePartElement {
const AtomicString& Headers() const;
void setRowSpan(unsigned);
// Public so that HTMLTableColElement can use MaxColSpan. MaxRowSpan is only
// used by this class but keeping them together seems desirable.
// https://html.spec.whatwg.org/#dom-tdth-colspan
static unsigned MaxColSpan() { return 1000u; }
// https://html.spec.whatwg.org/#dom-tdth-rowspan
static unsigned MaxRowSpan() { return 65534u; }
private:
HTMLTableCellElement(const QualifiedName&, Document&);
......
......@@ -24,25 +24,22 @@
#include "core/html/HTMLTableColElement.h"
#include <algorithm>
#include "core/CSSPropertyNames.h"
#include "core/HTMLNames.h"
#include "core/html/HTMLTableCellElement.h"
#include "core/html/HTMLTableElement.h"
#include "core/html/TableConstants.h"
#include "core/html/parser/HTMLParserIdioms.h"
#include "core/layout/LayoutTableCol.h"
#include <algorithm>
namespace blink {
using namespace HTMLNames;
namespace {
const unsigned kDefaultSpan = 1;
} // namespace
inline HTMLTableColElement::HTMLTableColElement(const QualifiedName& tag_name,
Document& document)
: HTMLTablePartElement(tag_name, document), span_(1) {}
: HTMLTablePartElement(tag_name, document), span_(kDefaultColSpan) {}
DEFINE_ELEMENT_FACTORY_WITH_TAGNAME(HTMLTableColElement)
......@@ -68,14 +65,10 @@ void HTMLTableColElement::ParseAttribute(
const AttributeModificationParams& params) {
if (params.name == spanAttr) {
unsigned new_span = 0;
if (params.new_value.IsEmpty() ||
!ParseHTMLNonNegativeInteger(params.new_value, new_span) ||
new_span < 1) {
// If the value of span is not a valid non-negative integer greater than
// zero, set it to 1.
new_span = kDefaultSpan;
if (!ParseHTMLClampedNonNegativeInteger(params.new_value, kMinColSpan,
kMaxColSpan, new_span)) {
new_span = kDefaultColSpan;
}
new_span = std::min(new_span, HTMLTableCellElement::MaxColSpan());
span_ = new_span;
if (GetLayoutObject() && GetLayoutObject()->IsLayoutTableCol())
GetLayoutObject()->UpdateFromElement();
......@@ -104,7 +97,7 @@ HTMLTableColElement::AdditionalPresentationAttributeStyle() {
}
void HTMLTableColElement::setSpan(unsigned n) {
SetUnsignedIntegralAttribute(spanAttr, n, kDefaultSpan);
SetUnsignedIntegralAttribute(spanAttr, n, kDefaultColSpan);
}
const AtomicString& HTMLTableColElement::Width() const {
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TableConstants_h
#define TableConstants_h
namespace blink {
// https://html.spec.whatwg.org/multipage/tables.html#dom-colgroup-span
// https://html.spec.whatwg.org/multipage/tables.html#dom-col-span
// https://html.spec.whatwg.org/multipage/tables.html#dom-tdth-colspan
constexpr unsigned kDefaultColSpan = 1u;
constexpr unsigned kMinColSpan = 1u;
constexpr unsigned kMaxColSpan = 1000u;
// https://html.spec.whatwg.org/multipage/tables.html#dom-tdth-rowspan
constexpr unsigned kDefaultRowSpan = 1u;
constexpr unsigned kMaxRowSpan = 65534u;
// The minimum value is 1 though the standard says it's 0. It's intentional
// because we don't implement rowSpan=0 behavior.
constexpr unsigned kMinRowSpan = 1;
} // namespace blink
#endif // TableConstants_h
......@@ -226,7 +226,8 @@ bool ParseHTMLInteger(const String& input, int& value) {
}
template <typename CharacterType>
static bool ParseHTMLNonNegativeIntegerInternal(const CharacterType* position,
static WTF::NumberParsingState ParseHTMLNonNegativeIntegerInternal(
const CharacterType* position,
const CharacterType* end,
unsigned& value) {
// This function is an implementation of the following algorithm:
......@@ -249,7 +250,7 @@ static bool ParseHTMLNonNegativeIntegerInternal(const CharacterType* position,
// Step 5: If position is past the end of input, return an error.
if (position == end)
return false;
return WTF::NumberParsingState::kError;
DCHECK_LT(position, end);
// Step 6: If the character indicated by position (the first character) is a
......@@ -262,13 +263,13 @@ static bool ParseHTMLNonNegativeIntegerInternal(const CharacterType* position,
}
if (position == end)
return false;
return WTF::NumberParsingState::kError;
DCHECK_LT(position, end);
// Step 7: If the character indicated by position is not an ASCII digit,
// then return an error.
if (!IsASCIIDigit(*position))
return false;
return WTF::NumberParsingState::kError;
// Step 8: Collect a sequence of characters ...
StringBuilder digits;
......@@ -278,26 +279,36 @@ static bool ParseHTMLNonNegativeIntegerInternal(const CharacterType* position,
digits.Append(*position++);
}
bool ok;
WTF::NumberParsingState state;
unsigned digits_value;
if (digits.Is8Bit())
if (digits.Is8Bit()) {
digits_value =
CharactersToUIntStrict(digits.Characters8(), digits.length(), &ok);
else
CharactersToUIntStrict(digits.Characters8(), digits.length(), &state);
} else {
digits_value =
CharactersToUIntStrict(digits.Characters16(), digits.length(), &ok);
if (!ok)
return false;
CharactersToUIntStrict(digits.Characters16(), digits.length(), &state);
}
// TODO(tkent): The following code to adjust NumberParsingState is not simple
// due to "-0" behavior difference between CharactersToUIntStrict() and
// ParseHTMLNonNegativeIntegerInternal(). Simplify the code by updating
// CharactersToUIntStrict() to accept "-0".
if (state == WTF::NumberParsingState::kOverflowMax && sign < 0)
return WTF::NumberParsingState::kError;
if (state == WTF::NumberParsingState::kSuccess) {
if (sign < 0 && digits_value != 0)
return false;
return WTF::NumberParsingState::kError;
value = digits_value;
return true;
}
return state;
}
// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-non-negative-integers
bool ParseHTMLNonNegativeInteger(const String& input, unsigned& value) {
static WTF::NumberParsingState ParseHTMLNonNegativeIntegerInternal(
const String& input,
unsigned& value) {
unsigned length = input.length();
if (length && input.Is8Bit()) {
if (length == 0)
return WTF::NumberParsingState::kError;
if (input.Is8Bit()) {
const LChar* start = input.Characters8();
return ParseHTMLNonNegativeIntegerInternal(start, start + length, value);
}
......@@ -306,6 +317,33 @@ bool ParseHTMLNonNegativeInteger(const String& input, unsigned& value) {
return ParseHTMLNonNegativeIntegerInternal(start, start + length, value);
}
// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-non-negative-integers
bool ParseHTMLNonNegativeInteger(const String& input, unsigned& value) {
return ParseHTMLNonNegativeIntegerInternal(input, value) ==
WTF::NumberParsingState::kSuccess;
}
bool ParseHTMLClampedNonNegativeInteger(const String& input,
unsigned min,
unsigned max,
unsigned& value) {
unsigned parsed_value;
switch (ParseHTMLNonNegativeIntegerInternal(input, parsed_value)) {
case WTF::NumberParsingState::kError:
return false;
case WTF::NumberParsingState::kOverflowMin:
NOTREACHED() << input;
return false;
case WTF::NumberParsingState::kOverflowMax:
value = max;
return true;
case WTF::NumberParsingState::kSuccess:
value = std::max(min, std::min(parsed_value, max));
return true;
}
return false;
}
template <typename CharacterType>
static bool IsSpaceOrDelimiter(CharacterType c) {
return IsHTMLSpace(c) || c == ',' || c == ';';
......
......@@ -63,6 +63,13 @@ CORE_EXPORT bool ParseHTMLInteger(const String&, int&);
// http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-non-negative-integers
CORE_EXPORT bool ParseHTMLNonNegativeInteger(const String&, unsigned&);
// https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#clamped-to-the-range
// without default value processing.
bool ParseHTMLClampedNonNegativeInteger(const String&,
unsigned min,
unsigned max,
unsigned&);
// https://html.spec.whatwg.org/multipage/infrastructure.html#rules-for-parsing-a-list-of-floating-point-numbers
CORE_EXPORT Vector<double> ParseHTMLListOfFloatingPointNumbers(const String&);
......
......@@ -28,7 +28,7 @@ static bool IsCharacterAllowedInBase(UChar c, int base) {
template <typename IntegralType, typename CharType>
static inline IntegralType ToIntegralType(const CharType* data,
size_t length,
bool* ok,
NumberParsingState* parsing_state,
int base) {
static_assert(std::is_integral<IntegralType>::value,
"IntegralType must be an integral type.");
......@@ -38,10 +38,12 @@ static inline IntegralType ToIntegralType(const CharType* data,
std::numeric_limits<IntegralType>::min();
static constexpr bool kIsSigned =
std::numeric_limits<IntegralType>::is_signed;
DCHECK(parsing_state);
IntegralType value = 0;
bool is_ok = false;
NumberParsingState state = NumberParsingState::kError;
bool is_negative = false;
bool overflow = false;
if (!data)
goto bye;
......@@ -75,28 +77,33 @@ static inline IntegralType ToIntegralType(const CharType* data,
else
digit_value = c - 'A' + 10;
bool overflow;
if (is_negative) {
// Overflow condition:
// value * base - digitValue < integralMin
// <=> value < (integralMin + digitValue) / base
// value * base - digit_value < kIntegralMin
// <=> value < (kIntegralMin + digit_value) / base
// We must be careful of rounding errors here, but the default rounding
// mode (round to zero) works well, so we can use this formula as-is.
overflow = value < (kIntegralMin + digit_value) / base;
if (value < (kIntegralMin + digit_value) / base) {
state = NumberParsingState::kOverflowMin;
overflow = true;
}
} else {
// Overflow condition:
// value * base + digitValue > integralMax
// <=> value > (integralMax + digitValue) / base
// value * base + digit_value > kIntegralMax
// <=> value > (kIntegralMax + digit_value) / base
// Ditto regarding rounding errors.
overflow = value > (kIntegralMax - digit_value) / base;
if (value > (kIntegralMax - digit_value) / base) {
state = NumberParsingState::kOverflowMax;
overflow = true;
}
}
if (overflow)
goto bye;
if (!overflow) {
if (is_negative)
value = base * value - digit_value;
else
value = base * value + digit_value;
}
++data;
}
......@@ -106,12 +113,29 @@ static inline IntegralType ToIntegralType(const CharType* data,
++data;
}
if (!length)
is_ok = true;
if (length == 0) {
if (!overflow)
state = NumberParsingState::kSuccess;
} else {
// Even if we detected overflow, we return kError for trailing garbage.
state = NumberParsingState::kError;
}
bye:
*parsing_state = state;
return state == NumberParsingState::kSuccess ? value : 0;
}
template <typename IntegralType, typename CharType>
static inline IntegralType ToIntegralType(const CharType* data,
size_t length,
bool* ok,
int base) {
NumberParsingState state;
IntegralType value =
ToIntegralType<IntegralType, CharType>(data, length, &state, base);
if (ok)
*ok = is_ok;
return is_ok ? value : 0;
*ok = state == NumberParsingState::kSuccess;
return value;
}
template <typename CharType>
......@@ -138,6 +162,18 @@ static unsigned LengthOfCharactersAsInteger(const CharType* data,
return i;
}
unsigned CharactersToUIntStrict(const LChar* data,
size_t length,
NumberParsingState* state) {
return ToIntegralType<unsigned, LChar>(data, length, state, 10);
}
unsigned CharactersToUIntStrict(const UChar* data,
size_t length,
NumberParsingState* state) {
return ToIntegralType<unsigned, UChar>(data, length, state, 10);
}
int CharactersToIntStrict(const LChar* data,
size_t length,
bool* ok,
......
......@@ -26,7 +26,18 @@ WTF_EXPORT int CharactersToInt(const UChar*,
size_t,
bool* ok = 0); // ignores trailing garbage
enum class NumberParsingState {
kSuccess,
kError,
// For UInt functions, kOverflowMin never happens. Negative numbers are
// treated as kError. This behavior matches to the HTML standard.
// https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-non-negative-integers
kOverflowMin,
kOverflowMax,
};
// string -> unsigned.
// These functions do not accept "-0".
WTF_EXPORT unsigned CharactersToUIntStrict(const LChar*,
size_t,
bool* ok = 0,
......@@ -42,6 +53,15 @@ WTF_EXPORT unsigned CharactersToUInt(const UChar*,
size_t,
bool* ok = 0); // ignores trailing garbage
// NumberParsingState versions of CharactersToUIntStrict. They can detect
// overflow. |NumberParsingState*| should not be nullptr;
WTF_EXPORT unsigned CharactersToUIntStrict(const LChar*,
size_t,
NumberParsingState*);
WTF_EXPORT unsigned CharactersToUIntStrict(const UChar*,
size_t,
NumberParsingState*);
// string -> int64_t.
WTF_EXPORT int64_t CharactersToInt64Strict(const LChar*,
size_t,
......@@ -59,6 +79,7 @@ WTF_EXPORT int64_t CharactersToInt64(const UChar*,
bool* ok = 0); // ignores trailing garbage
// string -> uint64_t.
// These functions do not accept "-0".
WTF_EXPORT uint64_t CharactersToUInt64Strict(const LChar*,
size_t,
bool* ok = 0,
......
......@@ -123,4 +123,20 @@ TEST(StringToNumberTest, TestCharactersToIntStrict) {
#undef EXPECT_VALID
#undef EXPECT_INVALID
}
NumberParsingState ParseUInt(const char* str, unsigned* value) {
NumberParsingState state;
*value = CharactersToUIntStrict(reinterpret_cast<const LChar*>(str),
std::strlen(str), &state);
return state;
}
TEST(StringToNumberTest, NumberParsingState) {
unsigned value;
EXPECT_EQ(NumberParsingState::kOverflowMax, ParseUInt("10000000000", &value));
EXPECT_EQ(NumberParsingState::kError, ParseUInt("10000000000abc", &value));
EXPECT_EQ(NumberParsingState::kError, ParseUInt("-10000000000", &value));
EXPECT_EQ(NumberParsingState::kError, ParseUInt("-0", &value));
EXPECT_EQ(NumberParsingState::kSuccess, ParseUInt("10", &value));
}
}
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