mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-06 14:05:32 +00:00
ICU-21714 Use FixedDecimal instead of double for plural samples in tests
See #1875
This commit is contained in:
parent
0a478416d2
commit
2660845480
6 changed files with 232 additions and 20 deletions
|
@ -1881,8 +1881,8 @@ void FixedDecimal::adjustForMinFractionDigits(int32_t minFractionDigits) {
|
|||
|
||||
double FixedDecimal::getPluralOperand(PluralOperand operand) const {
|
||||
switch(operand) {
|
||||
case PLURAL_OPERAND_N: return source;
|
||||
case PLURAL_OPERAND_I: return static_cast<double>(intValue);
|
||||
case PLURAL_OPERAND_N: return (exponent == 0 ? source : source * pow(10, exponent));
|
||||
case PLURAL_OPERAND_I: return (double) longValue();
|
||||
case PLURAL_OPERAND_F: return static_cast<double>(decimalDigits);
|
||||
case PLURAL_OPERAND_T: return static_cast<double>(decimalDigitsWithoutTrailingZeros);
|
||||
case PLURAL_OPERAND_V: return visibleDecimalDigitCount;
|
||||
|
@ -1931,6 +1931,18 @@ UnicodeString FixedDecimal::toString() const {
|
|||
return UnicodeString(buffer, -1, US_INV);
|
||||
}
|
||||
|
||||
double FixedDecimal::doubleValue() const {
|
||||
return (isNegative ? -source : source) * pow(10, exponent);
|
||||
}
|
||||
|
||||
int64_t FixedDecimal::longValue() const {
|
||||
if (exponent == 0) {
|
||||
return intValue;
|
||||
} else {
|
||||
return (long) (pow(10, exponent) * intValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PluralAvailableLocalesEnumeration::PluralAvailableLocalesEnumeration(UErrorCode &status) {
|
||||
fOpenStatus = status;
|
||||
|
|
|
@ -329,6 +329,9 @@ class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject {
|
|||
|
||||
UnicodeString toString() const;
|
||||
|
||||
double doubleValue() const;
|
||||
int64_t longValue() const;
|
||||
|
||||
double source;
|
||||
int32_t visibleDecimalDigitCount;
|
||||
int64_t decimalDigits;
|
||||
|
|
|
@ -57,6 +57,8 @@ void PluralRulesTest::runIndexedTest( int32_t index, UBool exec, const char* &na
|
|||
TESTCASE_AUTO(testGetAllKeywordValues);
|
||||
TESTCASE_AUTO(testScientificPluralKeyword);
|
||||
TESTCASE_AUTO(testCompactDecimalPluralKeyword);
|
||||
TESTCASE_AUTO(testDoubleValue);
|
||||
TESTCASE_AUTO(testLongValue);
|
||||
TESTCASE_AUTO(testOrdinal);
|
||||
TESTCASE_AUTO(testSelect);
|
||||
TESTCASE_AUTO(testSelectRange);
|
||||
|
@ -898,6 +900,94 @@ PluralRulesTest::testCompactDecimalPluralKeyword() {
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluralRulesTest::testDoubleValue() {
|
||||
IcuTestErrorCode errorCode(*this, "testDoubleValue");
|
||||
|
||||
struct IntTestCase {
|
||||
const int64_t inputNum;
|
||||
const double expVal;
|
||||
} intCases[] = {
|
||||
{-101, -101.0},
|
||||
{-100, -100.0},
|
||||
{-1, -1.0},
|
||||
{0, 0.0},
|
||||
{1, 1.0},
|
||||
{100, 100.0}
|
||||
};
|
||||
for (const auto& cas : intCases) {
|
||||
const int64_t inputNum = cas.inputNum;
|
||||
const double expVal = cas.expVal;
|
||||
|
||||
FixedDecimal fd(inputNum);
|
||||
UnicodeString message(u"FixedDecimal::doubleValue() for" + Int64ToUnicodeString(inputNum));
|
||||
assertEquals(message, expVal, fd.doubleValue());
|
||||
}
|
||||
|
||||
struct DoubleTestCase {
|
||||
const double inputNum;
|
||||
const double expVal;
|
||||
} dblCases[] = {
|
||||
{-0.0, -0.0},
|
||||
{0.1, 0.1},
|
||||
{1.999, 1.999},
|
||||
{2.0, 2.0},
|
||||
{100.001, 100.001}
|
||||
};
|
||||
for (const auto & cas : dblCases) {
|
||||
const double inputNum = cas.inputNum;
|
||||
const double expVal = cas.expVal;
|
||||
|
||||
FixedDecimal fd(inputNum);
|
||||
UnicodeString message(u"FixedDecimal::doubleValue() for" + DoubleToUnicodeString(inputNum));
|
||||
assertEquals(message, expVal, fd.doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluralRulesTest::testLongValue() {
|
||||
IcuTestErrorCode errorCode(*this, "testLongValue");
|
||||
|
||||
struct IntTestCase {
|
||||
const int64_t inputNum;
|
||||
const int64_t expVal;
|
||||
} intCases[] = {
|
||||
{-101, 101},
|
||||
{-100, 100},
|
||||
{-1, 1},
|
||||
{0, 0},
|
||||
{1, 1},
|
||||
{100, 100}
|
||||
};
|
||||
for (const auto& cas : intCases) {
|
||||
const int64_t inputNum = cas.inputNum;
|
||||
const int64_t expVal = cas.expVal;
|
||||
|
||||
FixedDecimal fd(inputNum);
|
||||
UnicodeString message(u"FixedDecimal::longValue() for" + Int64ToUnicodeString(inputNum));
|
||||
assertEquals(message, expVal, fd.longValue());
|
||||
}
|
||||
|
||||
struct DoubleTestCase {
|
||||
const double inputNum;
|
||||
const int64_t expVal;
|
||||
} dblCases[] = {
|
||||
{-0.0, 0},
|
||||
{0.1, 0},
|
||||
{1.999, 1},
|
||||
{2.0, 2},
|
||||
{100.001, 100}
|
||||
};
|
||||
for (const auto & cas : dblCases) {
|
||||
const double inputNum = cas.inputNum;
|
||||
const int64_t expVal = cas.expVal;
|
||||
|
||||
FixedDecimal fd(inputNum);
|
||||
UnicodeString message(u"FixedDecimal::longValue() for" + DoubleToUnicodeString(inputNum));
|
||||
assertEquals(message, expVal, fd.longValue());
|
||||
}
|
||||
}
|
||||
|
||||
UnicodeString PluralRulesTest::getPluralKeyword(const LocalPointer<PluralRules> &rules, Locale locale, double number, const char16_t* skeleton) {
|
||||
IcuTestErrorCode errorCode(*this, "getPluralKeyword");
|
||||
UnlocalizedNumberFormatter ulnf = NumberFormatter::forSkeleton(skeleton, errorCode);
|
||||
|
|
|
@ -36,6 +36,8 @@ private:
|
|||
void testWithin();
|
||||
void testGetAllKeywordValues();
|
||||
void testCompactDecimalPluralKeyword();
|
||||
void testDoubleValue();
|
||||
void testLongValue();
|
||||
void testScientificPluralKeyword();
|
||||
void testOrdinal();
|
||||
void testSelect();
|
||||
|
|
|
@ -688,9 +688,7 @@ public class PluralRules implements Serializable {
|
|||
source = isNegative ? -n : n;
|
||||
visibleDecimalDigitCount = v;
|
||||
decimalDigits = f;
|
||||
integerValue = n > MAX
|
||||
? MAX
|
||||
: (long)n;
|
||||
integerValue = n > MAX ? MAX : (long) source;
|
||||
int initExpVal = e;
|
||||
if (initExpVal == 0) {
|
||||
initExpVal = c;
|
||||
|
@ -922,15 +920,15 @@ public class PluralRules implements Serializable {
|
|||
@Deprecated
|
||||
public double getPluralOperand(Operand operand) {
|
||||
switch(operand) {
|
||||
case n: return source;
|
||||
case i: return integerValue;
|
||||
case n: return (exponent == 0 ? source : source * Math.pow(10, exponent));
|
||||
case i: return intValue();
|
||||
case f: return decimalDigits;
|
||||
case t: return decimalDigitsWithoutTrailingZeros;
|
||||
case v: return visibleDecimalDigitCount;
|
||||
case w: return visibleDecimalDigitCountWithoutTrailingZeros;
|
||||
case e: return exponent;
|
||||
case c: return exponent;
|
||||
default: return source;
|
||||
default: return doubleValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1078,7 +1076,7 @@ public class PluralRules implements Serializable {
|
|||
@Deprecated
|
||||
public long getShiftedValue() {
|
||||
if (exponent != 0 && visibleDecimalDigitCount == 0 && decimalDigits == 0) {
|
||||
// Need to taxe exponent into account if we have it
|
||||
// Need to take exponent into account if we have it
|
||||
return (long)(source * Math.pow(10, exponent));
|
||||
}
|
||||
return integerValue * baseFactor + decimalDigits;
|
||||
|
|
|
@ -465,21 +465,56 @@ public class PluralRulesTest extends TestFmwk {
|
|||
}
|
||||
|
||||
public void checkValue(String title1, PluralRules rules, String expected, String value) {
|
||||
double number = Double.parseDouble(value);
|
||||
int decimalPos = value.indexOf('.') + 1;
|
||||
int countVisibleFractionDigits;
|
||||
int fractionaldigits;
|
||||
if (decimalPos == 0) {
|
||||
countVisibleFractionDigits = fractionaldigits = 0;
|
||||
} else {
|
||||
countVisibleFractionDigits = value.length() - decimalPos;
|
||||
fractionaldigits = Integer.parseInt(value.substring(decimalPos));
|
||||
}
|
||||
String result = rules.select(number, countVisibleFractionDigits, fractionaldigits);
|
||||
FixedDecimal fdNum = new FixedDecimal(value);
|
||||
|
||||
String result = rules.select(fdNum);
|
||||
ULocale locale = null;
|
||||
assertEquals(getAssertMessage(title1, locale, rules, expected) + "; value: " + value, expected, result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the testing helper method checkValue(), which parses a plural
|
||||
* rule's sample string as a {@link FormattedNumber} in order to call
|
||||
* {@code PluralRules.select(FormattedNumber)}, which in turn can support
|
||||
* the exponent in plural sample numbers like 1e6 and 2.8c3.
|
||||
*/
|
||||
@Test
|
||||
public void testCheckValue() {
|
||||
String ruleString =
|
||||
"many: e = 0 and i != 0 and i % 1000000 = 0 and v = 0 or e != 0..5"
|
||||
+ " @integer 1000000, 1e6, 2e6, 3e6, 4e6, 5e6, 6e6, …"
|
||||
+ " @decimal 1.0000001e6, 1.1e6, 2.0000001e6, 2.1e6, 3.0000001e6, 3.1e6, …; "
|
||||
+ "one: i = 1 and v = 0"
|
||||
+ " @integer 1; "
|
||||
+ "other: "
|
||||
+ " @integer 0, 2~16, 100, 1000, 10000, 100000, 1e3, 2e3, 3e3, 4e3, 5e3, 6e3, …"
|
||||
+ " @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, 1.0001e3, 1.1e3, 2.0001e3, 2.1e3, 3.0001e3, 3.1e3, …";
|
||||
PluralRules rules = PluralRules.createRules(ruleString);
|
||||
|
||||
Object[][] casesData = {
|
||||
// expected category, value string
|
||||
{"many", "1000000"},
|
||||
{"many", "1e6"},
|
||||
{"many", "1.1e6"},
|
||||
{"one", "1"},
|
||||
{"other", "0"},
|
||||
{"other", "1e5"},
|
||||
{"other", "100000"},
|
||||
{"other", "0.0"},
|
||||
{"other", "100000.0"},
|
||||
{"other", "1000000.0"}
|
||||
};
|
||||
|
||||
for (Object[] caseDatum : casesData) {
|
||||
String expCategory = (String) caseDatum[0];
|
||||
String inputValueStr = (String) caseDatum[1];
|
||||
|
||||
String msg = "checkValue(" + inputValueStr + ")";
|
||||
|
||||
checkValue(msg, rules, expCategory, inputValueStr);
|
||||
}
|
||||
}
|
||||
|
||||
private static String[][] equalityTestData = {
|
||||
// once we add fractions, we had to retract the "test all possibilities" for equality,
|
||||
// so we only have a limited set of equality tests now.
|
||||
|
@ -1110,6 +1145,78 @@ public class PluralRulesTest extends TestFmwk {
|
|||
return pluralKeyword;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleValue() {
|
||||
Object[][] intCasesData = {
|
||||
// source number, expected double value
|
||||
{-101, -101.0},
|
||||
{-100, -100.0},
|
||||
{-1, -1.0},
|
||||
{0, 0.0},
|
||||
{1, 1.0},
|
||||
{100, 100.0}
|
||||
};
|
||||
|
||||
for (Object[] caseDatum : intCasesData) {
|
||||
double inputNum = (int) caseDatum[0];
|
||||
double expVal = (double) caseDatum[1];
|
||||
FixedDecimal fd = new FixedDecimal(inputNum);
|
||||
assertEquals("FixedDecimal.doubleValue() for " + inputNum, expVal, fd.doubleValue());
|
||||
}
|
||||
|
||||
Object[][] doubleCasesData = {
|
||||
// source number, expected double value
|
||||
{-0.0, -0.0},
|
||||
{0.1, 0.1},
|
||||
{1.999, 1.999},
|
||||
{2.0, 2.0},
|
||||
{100.001, 100.001}
|
||||
};
|
||||
|
||||
for (Object[] caseDatum : doubleCasesData) {
|
||||
double inputNum = (double) caseDatum[0];
|
||||
double expVal = (double) caseDatum[1];
|
||||
FixedDecimal fd = new FixedDecimal(inputNum);
|
||||
assertEquals("FixedDecimal.doubleValue() for " + inputNum, expVal, fd.doubleValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLongValue() {
|
||||
Object[][] intCasesData = {
|
||||
// source number, expected double value
|
||||
{-101, 101},
|
||||
{-100, 100},
|
||||
{-1, 1},
|
||||
{0, 0},
|
||||
{1, 1},
|
||||
{100, 100}
|
||||
};
|
||||
|
||||
for (Object[] caseDatum : intCasesData) {
|
||||
long inputNum = (int) caseDatum[0];
|
||||
long expVal = (int) caseDatum[1];
|
||||
FixedDecimal fd = new FixedDecimal(inputNum);
|
||||
assertEquals("FixedDecimal.longValue() for " + inputNum, expVal, fd.longValue());
|
||||
}
|
||||
|
||||
Object[][] doubleCasesData = {
|
||||
// source number, expected double value
|
||||
{-0.0, 0},
|
||||
{0.1, 0},
|
||||
{1.999, 1},
|
||||
{2.0, 2},
|
||||
{100.001, 100}
|
||||
};
|
||||
|
||||
for (Object[] caseDatum : doubleCasesData) {
|
||||
double inputNum = (double) caseDatum[0];
|
||||
long expVal = (int) caseDatum[1];
|
||||
FixedDecimal fd = new FixedDecimal(inputNum);
|
||||
assertEquals("FixedDecimal.longValue() for " + inputNum, expVal, fd.longValue());
|
||||
}
|
||||
}
|
||||
|
||||
enum StandardPluralCategories {
|
||||
zero, one, two, few, many, other;
|
||||
/**
|
||||
|
|
Loading…
Add table
Reference in a new issue