ICU-11276 Adding C++ base implementation of NumberRangeFormatter, including unit test.

This commit is contained in:
Shane Carr 2018-08-29 01:22:21 -07:00
parent 7d34740002
commit 9109a388f4
No known key found for this signature in database
GPG key ID: FCED3B24AAB18B5C
14 changed files with 580 additions and 16 deletions

View file

@ -111,9 +111,9 @@ double-conversion-fast-dtoa.o double-conversion-strtod.o \
numparse_stringsegment.o numparse_parsednumber.o numparse_impl.o \
numparse_symbols.o numparse_decimal.o numparse_scientific.o numparse_currency.o \
numparse_affixes.o numparse_compositions.o numparse_validators.o \
numrange_fluent.o numrange_impl.o \
erarules.o
## Header files to install
HEADERS = $(srcdir)/unicode/*.h

View file

@ -289,6 +289,8 @@
<ClCompile Include="numparse_affixes.cpp" />
<ClCompile Include="numparse_compositions.cpp" />
<ClCompile Include="numparse_validators.cpp" />
<ClCompile Include="numrange_fluent.cpp" />
<ClCompile Include="numrange_impl.cpp" />
<ClCompile Include="numfmt.cpp" />
<ClCompile Include="numsys.cpp" />
<ClCompile Include="olsontz.cpp" />
@ -552,6 +554,7 @@
<ClInclude Include="numparse_validators.h" />
<ClInclude Include="numparse_types.h" />
<ClInclude Include="numparse_utils.h" />
<ClInclude Include="numrange_types.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="i18n.rc" />

View file

@ -624,6 +624,12 @@
<ClCompile Include="numparse_validators.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="numrange_fluent.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="numrange_impl.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="dayperiodrules.cpp">
<Filter>formatting</Filter>
</ClCompile>
@ -914,6 +920,9 @@
<ClInclude Include="numparse_utils.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="numrange_types.h">
<Filter>formatting</Filter>
</ClInclude>
<ClInclude Include="olsontz.h">
<Filter>formatting</Filter>
</ClInclude>

View file

@ -396,6 +396,8 @@
<ClCompile Include="numparse_affixes.cpp" />
<ClCompile Include="numparse_compositions.cpp" />
<ClCompile Include="numparse_validators.cpp" />
<ClCompile Include="numrange_fluent.cpp" />
<ClCompile Include="numrange_impl.cpp" />
<ClCompile Include="numfmt.cpp" />
<ClCompile Include="numsys.cpp" />
<ClCompile Include="olsontz.cpp" />
@ -657,6 +659,7 @@
<ClInclude Include="numparse_validators.h" />
<ClInclude Include="numparse_types.h" />
<ClInclude Include="numparse_utils.h" />
<ClInclude Include="numrange_types.h" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="i18n.rc" />

View file

@ -0,0 +1,381 @@
// © 2018 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
// Allow implicit conversion from char16_t* to UnicodeString for this file:
// Helpful in toString methods and elsewhere.
#define UNISTR_FROM_STRING_EXPLICIT
#include "numrange_types.h"
#include "util.h"
#include "number_utypes.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) const& {
Derived copy(*this);
copy.fMacros.formatter1 = formatter;
copy.fMacros.formatter2 = formatter;
return copy;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(const UnlocalizedNumberFormatter& formatter) && {
Derived move(std::move(*this));
move.fMacros.formatter1 = formatter;
move.fMacros.formatter2 = formatter;
return move;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) const& {
Derived copy(*this);
copy.fMacros.formatter1 = formatter;
copy.fMacros.formatter2 = std::move(formatter);
return copy;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterBoth(UnlocalizedNumberFormatter&& formatter) && {
Derived move(std::move(*this));
move.fMacros.formatter1 = formatter;
move.fMacros.formatter2 = std::move(formatter);
return move;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) const& {
Derived copy(*this);
copy.fMacros.formatter1 = formatter;
return copy;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(const UnlocalizedNumberFormatter& formatter) && {
Derived move(std::move(*this));
move.fMacros.formatter1 = formatter;
return move;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) const& {
Derived copy(*this);
copy.fMacros.formatter1 = std::move(formatter);
return copy;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterFirst(UnlocalizedNumberFormatter&& formatter) && {
Derived move(std::move(*this));
move.fMacros.formatter1 = std::move(formatter);
return move;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) const& {
Derived copy(*this);
copy.fMacros.formatter2 = formatter;
return copy;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(const UnlocalizedNumberFormatter& formatter) && {
Derived move(std::move(*this));
move.fMacros.formatter2 = formatter;
return move;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) const& {
Derived copy(*this);
copy.fMacros.formatter2 = std::move(formatter);
return copy;
}
template<typename Derived>
Derived NumberRangeFormatterSettings<Derived>::numberFormatterSecond(UnlocalizedNumberFormatter&& formatter) && {
Derived move(std::move(*this));
move.fMacros.formatter2 = std::move(formatter);
return move;
}
// Declare all classes that implement NumberRangeFormatterSettings
// See https://stackoverflow.com/a/495056/1407170
template
class icu::number::NumberRangeFormatterSettings<icu::number::UnlocalizedNumberRangeFormatter>;
template
class icu::number::NumberRangeFormatterSettings<icu::number::LocalizedNumberRangeFormatter>;
UnlocalizedNumberRangeFormatter NumberRangeFormatter::with() {
UnlocalizedNumberRangeFormatter result;
return result;
}
LocalizedNumberRangeFormatter NumberRangeFormatter::withLocale(const Locale& locale) {
return with().locale(locale);
}
template<typename T> using NFS = NumberRangeFormatterSettings<T>;
using LNF = LocalizedNumberRangeFormatter;
using UNF = UnlocalizedNumberRangeFormatter;
UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const UNF& other)
: UNF(static_cast<const NFS<UNF>&>(other)) {}
UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(const NFS<UNF>& other)
: NFS<UNF>(other) {
// No additional fields to assign
}
UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(UNF&& src) U_NOEXCEPT
: UNF(static_cast<NFS<UNF>&&>(src)) {}
UnlocalizedNumberRangeFormatter::UnlocalizedNumberRangeFormatter(NFS<UNF>&& src) U_NOEXCEPT
: NFS<UNF>(std::move(src)) {
// No additional fields to assign
}
UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(const UNF& other) {
NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
// No additional fields to assign
return *this;
}
UnlocalizedNumberRangeFormatter& UnlocalizedNumberRangeFormatter::operator=(UNF&& src) U_NOEXCEPT {
NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
// No additional fields to assign
return *this;
}
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const LNF& other)
: LNF(static_cast<const NFS<LNF>&>(other)) {}
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const NFS<LNF>& other)
: NFS<LNF>(other) {
// No additional fields to assign
}
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(LocalizedNumberRangeFormatter&& src) U_NOEXCEPT
: LNF(static_cast<NFS<LNF>&&>(src)) {}
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(NFS<LNF>&& src) U_NOEXCEPT
: NFS<LNF>(std::move(src)) {
// No additional fields to assign
}
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(const LNF& other) {
NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
// No additional fields to assign
return *this;
}
LocalizedNumberRangeFormatter& LocalizedNumberRangeFormatter::operator=(LNF&& src) U_NOEXCEPT {
NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
// No additional fields to assign
return *this;
}
LocalizedNumberRangeFormatter::~LocalizedNumberRangeFormatter() = default;
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(const RangeMacroProps& macros, const Locale& locale) {
fMacros = macros;
fMacros.locale = locale;
}
LocalizedNumberRangeFormatter::LocalizedNumberRangeFormatter(RangeMacroProps&& macros, const Locale& locale) {
fMacros = std::move(macros);
fMacros.locale = locale;
}
LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale) const& {
return LocalizedNumberRangeFormatter(fMacros, locale);
}
LocalizedNumberRangeFormatter UnlocalizedNumberRangeFormatter::locale(const Locale& locale)&& {
return LocalizedNumberRangeFormatter(std::move(fMacros), locale);
}
FormattedNumberRange LocalizedNumberRangeFormatter::formatFormattableRange(
const Formattable& first, const Formattable& second, UErrorCode& status) const {
if (U_FAILURE(status)) {
return FormattedNumberRange(U_ILLEGAL_ARGUMENT_ERROR);
}
auto results = new UFormattedNumberRangeData();
if (results == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR;
return FormattedNumberRange(status);
}
first.populateDecimalQuantity(results->quantity1, status);
if (U_FAILURE(status)) {
return FormattedNumberRange(status);
}
second.populateDecimalQuantity(results->quantity2, status);
if (U_FAILURE(status)) {
return FormattedNumberRange(status);
}
formatImpl(results, status);
// Do not save the results object if we encountered a failure.
if (U_SUCCESS(status)) {
return FormattedNumberRange(results);
} else {
delete results;
return FormattedNumberRange(status);
}
}
void LocalizedNumberRangeFormatter::formatImpl(
UFormattedNumberRangeData* results, UErrorCode& status) const {
// TODO: This is a placeholder implementation.
UFormattedNumberData r1;
r1.quantity = results->quantity1;
fMacros.formatter1.locale(fMacros.locale).formatImpl(&r1, status);
if (U_FAILURE(status)) {
return;
}
results->quantity1 = r1.quantity;
UFormattedNumberData r2;
r2.quantity = results->quantity2;
fMacros.formatter2.locale(fMacros.locale).formatImpl(&r2, status);
if (U_FAILURE(status)) {
return;
}
results->quantity2 = r2.quantity;
results->string.append(r1.string, status);
results->string.append(u" --- ", UNUM_FIELD_COUNT, status);
results->string.append(r2.string, status);
if (U_FAILURE(status)) {
return;
}
results->identityType = UNUM_IDENTITY_TYPE_NOT_EQUAL;
}
FormattedNumberRange::FormattedNumberRange(FormattedNumberRange&& src) U_NOEXCEPT
: fResults(src.fResults), fErrorCode(src.fErrorCode) {
// Disown src.fResults to prevent double-deletion
src.fResults = nullptr;
src.fErrorCode = U_INVALID_STATE_ERROR;
}
FormattedNumberRange& FormattedNumberRange::operator=(FormattedNumberRange&& src) U_NOEXCEPT {
delete fResults;
fResults = src.fResults;
fErrorCode = src.fErrorCode;
// Disown src.fResults to prevent double-deletion
src.fResults = nullptr;
src.fErrorCode = U_INVALID_STATE_ERROR;
return *this;
}
UnicodeString FormattedNumberRange::toString(UErrorCode& status) const {
if (U_FAILURE(status)) {
return ICU_Utility::makeBogusString();
}
if (fResults == nullptr) {
status = fErrorCode;
return ICU_Utility::makeBogusString();
}
return fResults->string.toUnicodeString();
}
Appendable& FormattedNumberRange::appendTo(Appendable& appendable, UErrorCode& status) {
if (U_FAILURE(status)) {
return appendable;
}
if (fResults == nullptr) {
status = fErrorCode;
return appendable;
}
appendable.appendString(fResults->string.chars(), fResults->string.length());
return appendable;
}
UBool FormattedNumberRange::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
if (U_FAILURE(status)) {
return FALSE;
}
if (fResults == nullptr) {
status = fErrorCode;
return FALSE;
}
// NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
}
void FormattedNumberRange::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
FieldPositionIteratorHandler fpih(&iterator, status);
getAllFieldPositionsImpl(fpih, status);
}
void FormattedNumberRange::getAllFieldPositionsImpl(
FieldPositionIteratorHandler& fpih, UErrorCode& status) const {
if (U_FAILURE(status)) {
return;
}
if (fResults == nullptr) {
status = fErrorCode;
return;
}
fResults->string.getAllFieldPositions(fpih, status);
}
UnicodeString FormattedNumberRange::getFirstDecimal(UErrorCode& status) const {
if (U_FAILURE(status)) {
return ICU_Utility::makeBogusString();
}
if (fResults == nullptr) {
status = fErrorCode;
return ICU_Utility::makeBogusString();
}
return fResults->quantity1.toScientificString();
}
UnicodeString FormattedNumberRange::getSecondDecimal(UErrorCode& status) const {
if (U_FAILURE(status)) {
return ICU_Utility::makeBogusString();
}
if (fResults == nullptr) {
status = fErrorCode;
return ICU_Utility::makeBogusString();
}
return fResults->quantity2.toScientificString();
}
UNumberRangeIdentityType FormattedNumberRange::getIdentityType(UErrorCode& status) const {
if (U_FAILURE(status)) {
return UNUM_IDENTITY_TYPE_NOT_EQUAL;
}
if (fResults == nullptr) {
status = fErrorCode;
return UNUM_IDENTITY_TYPE_NOT_EQUAL;
}
return fResults->identityType;
}
FormattedNumberRange::~FormattedNumberRange() {
delete fResults;
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -0,0 +1,23 @@
// © 2018 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT
// Allow implicit conversion from char16_t* to UnicodeString for this file:
// Helpful in toString methods and elsewhere.
#define UNISTR_FROM_STRING_EXPLICIT
#include "numrange_types.h"
using namespace icu;
using namespace icu::number;
using namespace icu::number::impl;
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -36,7 +36,7 @@ struct UFormattedNumberRangeData : public UMemory {
DecimalQuantity quantity1;
DecimalQuantity quantity2;
NumberStringBuilder string;
UNumberRangeIdentityType identityType;
UNumberRangeIdentityType identityType = UNUM_IDENTITY_TYPE_EQUAL_BEFORE_ROUNDING;
// No C conversion methods (no C API yet)
};

View file

@ -162,6 +162,22 @@ U_NAMESPACE_BEGIN
namespace number { // icu::number
// Forward declarations:
class UnlocalizedNumberRangeFormatter;
class LocalizedNumberRangeFormatter;
class FormattedNumberRange;
namespace impl {
// Forward declarations:
struct RangeMacroProps;
class DecimalQuantity;
struct UFormattedNumberRangeData;
} // namespace impl
// Other helper classes would go here, but there are none.
namespace impl { // icu::number::impl
// Do not enclose entire MacroProps with #ifndef U_HIDE_INTERNAL_API, needed for a protected field
@ -177,7 +193,7 @@ struct U_I18N_API RangeMacroProps : public UMemory {
UNumberRangeCollapse collapse = UNUM_RANGE_COLLAPSE_AUTO;
/** @internal */
UNumberIdentityFallback identityFallback = UNUM_IDENTITY_APPROXIMATELY;
UNumberIdentityFallback identityFallback = UNUM_IDENTITY_FALLBACK_APPROXIMATELY;
/** @internal */
Locale locale;
@ -532,7 +548,7 @@ class U_I18N_API LocalizedNumberRangeFormatter
* @draft ICU 63
*/
FormattedNumberRange formatFormattableRange(
const Formattable& first, const Formattable& second) const;
const Formattable& first, const Formattable& second, UErrorCode& status) const;
/**
* Default constructor: puts the formatter into a valid but undefined state.
@ -586,10 +602,6 @@ class U_I18N_API LocalizedNumberRangeFormatter
~LocalizedNumberRangeFormatter();
private:
// Note: fCompiled can't be a LocalPointer because impl::NumberFormatterImpl is defined in an internal
// header, and LocalPointer needs the full class definition in order to delete the instance.
const impl::NumberFormatterImpl* fCompiled {nullptr};
char fUnsafeCallCount[8] {}; // internally cast to u_atomic_int32_t
explicit LocalizedNumberRangeFormatter(
const NumberRangeFormatterSettings<LocalizedNumberRangeFormatter>& other);
@ -701,7 +713,7 @@ class U_I18N_API FormattedNumberRange : public UMemory {
* @see NumberRangeFormatter
* @see #getSecondDecimal
*/
UnicodeString getFirstDecimal() const;
UnicodeString getFirstDecimal(UErrorCode& status) const;
/**
* Export the second formatted number as a decimal number. This endpoint
@ -718,7 +730,7 @@ class U_I18N_API FormattedNumberRange : public UMemory {
* @see NumberRangeFormatter
* @see #getFirstDecimal
*/
UnicodeString getSecondDecimal() const;
UnicodeString getSecondDecimal(UErrorCode& status) const;
/**
* Returns whether the pair of numbers was successfully formatted as a range or whether an identity fallback was
@ -730,7 +742,7 @@ class U_I18N_API FormattedNumberRange : public UMemory {
* @provisional This API might change or be removed in a future release.
* @see UNumberRangeIdentityFallback
*/
UNumberRangeIdentityType getIdentityType() const;
UNumberRangeIdentityType getIdentityType(UErrorCode& status) const;
/**
* Copying not supported; use move constructor instead.
@ -779,6 +791,8 @@ class U_I18N_API FormattedNumberRange : public UMemory {
explicit FormattedNumberRange(UErrorCode errorCode)
: fResults(nullptr), fErrorCode(errorCode) {};
void getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, UErrorCode& status) const;
// To give LocalizedNumberRangeFormatter format methods access to this class's constructor:
friend class LocalizedNumberRangeFormatter;
};
@ -797,7 +811,7 @@ class U_I18N_API NumberRangeFormatter final {
* @return An {@link UnlocalizedNumberRangeFormatter}, to be used for chaining.
* @draft ICU 63
*/
static UnlocalizedNumberFormatter with();
static UnlocalizedNumberRangeFormatter with();
/**
* Call this method at the beginning of a NumberRangeFormatter fluent chain in which the locale is known at the call
@ -808,7 +822,7 @@ class U_I18N_API NumberRangeFormatter final {
* @return A {@link LocalizedNumberRangeFormatter}, to be used for chaining.
* @draft ICU 63
*/
static LocalizedNumberFormatter withLocale(const Locale &locale);
static LocalizedNumberRangeFormatter withLocale(const Locale &locale);
/**
* Use factory methods instead of the constructor to create a NumberFormatter.

View file

@ -66,7 +66,7 @@ numbertest_affixutils.o numbertest_api.o numbertest_decimalquantity.o \
numbertest_modifiers.o numbertest_patternmodifier.o numbertest_patternstring.o \
numbertest_stringbuilder.o numbertest_stringsegment.o \
numbertest_parse.o numbertest_doubleconversion.o numbertest_skeletons.o \
static_unisets_test.o numfmtdatadriventest.o erarulestest.o
static_unisets_test.o numfmtdatadriventest.o numbertest_range.o erarulestest.o
DEPS = $(OBJECTS:.o=.d)

View file

@ -256,6 +256,7 @@
<ClCompile Include="numbertest_parse.cpp" />
<ClCompile Include="numbertest_doubleconversion.cpp" />
<ClCompile Include="numbertest_skeletons.cpp" />
<ClCompile Include="numbertest_range.cpp" />
<ClCompile Include="numfmtst.cpp" />
<ClCompile Include="numfmtdatadriventest.cpp" />
<ClCompile Include="numrgts.cpp" />

View file

@ -289,6 +289,9 @@
<ClCompile Include="numbertest_skeletons.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="numbertest_range.cpp">
<Filter>formatting</Filter>
</ClCompile>
<ClCompile Include="numfmtst.cpp">
<Filter>formatting</Filter>
</ClCompile>

View file

@ -11,6 +11,8 @@
#include "number_affixutils.h"
#include "numparse_stringsegment.h"
#include "unicode/locid.h"
#include "unicode/numberformatter.h"
#include "unicode/numberrangeformatter.h"
using namespace icu::number;
using namespace icu::number::impl;
@ -244,6 +246,37 @@ class NumberSkeletonTest : public IntlTest {
void expectedErrorSkeleton(const char16_t** cases, int32_t casesLen);
};
class NumberRangeFormatterTest : public IntlTest {
public:
void testSanity();
void testBasic();
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
private:
void assertFormatRange(
const char16_t* message,
const UnlocalizedNumberRangeFormatter& f,
Locale locale,
const char16_t* expected_10_50,
const char16_t* expected_49_51,
const char16_t* expected_50_50,
const char16_t* expected_00_30,
const char16_t* expected_00_00,
const char16_t* expected_30_3K,
const char16_t* expected_30K_50K,
const char16_t* expected_49K_51K,
const char16_t* expected_50K_50K,
const char16_t* expected_50K_50M);
void assertFormattedRangeEquals(
const char16_t* message,
const LocalizedNumberRangeFormatter& l,
double first,
double second,
const char16_t* expected);
};
// NOTE: This macro is identical to the one in itformat.cpp
#define TESTCLASS(id, TestClass) \
@ -276,6 +309,7 @@ class NumberTest : public IntlTest {
TESTCLASS(8, StringSegmentTest);
TESTCLASS(9, NumberParserTest);
TESTCLASS(10, NumberSkeletonTest);
TESTCLASS(11, NumberRangeFormatterTest);
default: name = ""; break; // needed to end loop
}
}

View file

@ -0,0 +1,93 @@
// © 2018 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
#include "unicode/utypes.h"
#if !UCONFIG_NO_FORMATTING
#include "numbertest.h"
#include "unicode/numberrangeformatter.h"
#include <cmath>
#include <numparse_affixes.h>
using icu::unisets::get;
void NumberRangeFormatterTest::runIndexedTest(int32_t index, UBool exec, const char*& name, char*) {
if (exec) {
logln("TestSuite NumberRangeFormatterTest: ");
}
TESTCASE_AUTO_BEGIN;
TESTCASE_AUTO(testSanity);
TESTCASE_AUTO(testBasic);
TESTCASE_AUTO_END;
}
void NumberRangeFormatterTest::testSanity() {
IcuTestErrorCode status(*this, "testSanity");
LocalizedNumberRangeFormatter lnrf1 = NumberRangeFormatter::withLocale("en-us");
LocalizedNumberRangeFormatter lnrf2 = NumberRangeFormatter::with().locale("en-us");
assertEquals("Formatters should have same behavior 1",
lnrf1.formatFormattableRange(4, 6, status).toString(status),
lnrf2.formatFormattableRange(4, 6, status).toString(status));
}
void NumberRangeFormatterTest::testBasic() {
assertFormatRange(
u"Basic",
NumberRangeFormatter::with(),
Locale("en-us"),
u"1 --- 5",
u"5 --- 5",
u"5 --- 5",
u"0 --- 3",
u"0 --- 0",
u"3 --- 3,000",
u"3,000 --- 5,000",
u"4,999 --- 5,001",
u"5,000 --- 5,000",
u"5,000 --- 5,000,000");
}
void NumberRangeFormatterTest::assertFormatRange(
const char16_t* message,
const UnlocalizedNumberRangeFormatter& f,
Locale locale,
const char16_t* expected_10_50,
const char16_t* expected_49_51,
const char16_t* expected_50_50,
const char16_t* expected_00_30,
const char16_t* expected_00_00,
const char16_t* expected_30_3K,
const char16_t* expected_30K_50K,
const char16_t* expected_49K_51K,
const char16_t* expected_50K_50K,
const char16_t* expected_50K_50M) {
LocalizedNumberRangeFormatter l = f.locale(locale);
assertFormattedRangeEquals(message, l, 1, 5, expected_10_50);
assertFormattedRangeEquals(message, l, 4.9999999, 5.0000001, expected_49_51);
assertFormattedRangeEquals(message, l, 5, 5, expected_50_50);
assertFormattedRangeEquals(message, l, 0, 3, expected_00_30);
assertFormattedRangeEquals(message, l, 0, 0, expected_00_00);
assertFormattedRangeEquals(message, l, 3, 3000, expected_30_3K);
assertFormattedRangeEquals(message, l, 3000, 5000, expected_30K_50K);
assertFormattedRangeEquals(message, l, 4999, 5001, expected_49K_51K);
assertFormattedRangeEquals(message, l, 5000, 5000, expected_50K_50K);
assertFormattedRangeEquals(message, l, 5e3, 5e6, expected_50K_50M);
}
void NumberRangeFormatterTest::assertFormattedRangeEquals(
const char16_t* message,
const LocalizedNumberRangeFormatter& l,
double first,
double second,
const char16_t* expected) {
IcuTestErrorCode status(*this, "assertFormattedRangeEquals");
UnicodeString fullMessage = UnicodeString(message) + u": " + DoubleToUnicodeString(first) + u", " + DoubleToUnicodeString(second);
status.setScope(fullMessage);
UnicodeString actual = l.formatFormattableRange(first, second, status).toString(status);
assertEquals(fullMessage, expected, actual);
}
#endif

View file

@ -153,8 +153,8 @@ public class NumberRangeFormatterTest {
private static void assertFormattedRangeEquals(String message, LocalizedNumberRangeFormatter l, Number first,
Number second, String expected) {
String actual1 = l.formatRange(first, second).toString();
assertEquals(message + ": " + first + ", " + second, expected, actual1);
String actual = l.formatRange(first, second).toString();
assertEquals(message + ": " + first + ", " + second, expected, actual);
}
}