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
<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" />
<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" />
<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>
<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>
<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" />
<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" />
--- /dev/null
+// © 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 */
--- /dev/null
+// © 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 */
DecimalQuantity quantity1;
DecimalQuantity quantity2;
NumberStringBuilder string;
- UNumberRangeIdentityType identityType;
+ UNumberRangeIdentityType identityType = UNUM_IDENTITY_TYPE_EQUAL_BEFORE_ROUNDING;
// No C conversion methods (no C API yet)
};
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
UNumberRangeCollapse collapse = UNUM_RANGE_COLLAPSE_AUTO;
/** @internal */
- UNumberIdentityFallback identityFallback = UNUM_IDENTITY_APPROXIMATELY;
+ UNumberIdentityFallback identityFallback = UNUM_IDENTITY_FALLBACK_APPROXIMATELY;
/** @internal */
Locale locale;
* @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.
~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);
* @see NumberRangeFormatter
* @see #getSecondDecimal
*/
- UnicodeString getFirstDecimal() const;
+ UnicodeString getFirstDecimal(UErrorCode& status) const;
/**
* Export the second formatted number as a decimal number. This endpoint
* @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
* @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.
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;
};
* @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
* @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.
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)
<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" />
<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>
#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;
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) \
TESTCLASS(8, StringSegmentTest);
TESTCLASS(9, NumberParserTest);
TESTCLASS(10, NumberSkeletonTest);
+ TESTCLASS(11, NumberRangeFormatterTest);
default: name = ""; break; // needed to end loop
}
}
--- /dev/null
+// © 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
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);
}
}